Commit 7e95a8db authored by Arturo Borrero Gonzalez's avatar Arturo Borrero Gonzalez
Browse files

Imported Upstream version 1.4.21

parents
This module matches at a limited rate using a token bucket filter.
A rule using this extension will match until this limit is reached.
It can be used in combination with the
.B LOG
target to give limited logging, for example.
.PP
xt_limit has no negation support - you will have to use \-m hashlimit !
\-\-hashlimit \fIrate\fP in this case whilst omitting \-\-hashlimit\-mode.
.TP
\fB\-\-limit\fP \fIrate\fP[\fB/second\fP|\fB/minute\fP|\fB/hour\fP|\fB/day\fP]
Maximum average matching rate: specified as a number, with an optional
`/second', `/minute', `/hour', or `/day' suffix; the default is
3/hour.
.TP
\fB\-\-limit\-burst\fP \fInumber\fP
Maximum initial number of packets to match: this number gets
recharged by one every time the limit specified above is not reached,
up to this number; the default is 5.
#include <stdio.h>
#if defined(__GLIBC__) && __GLIBC__ == 2
#include <net/ethernet.h>
#else
#include <linux/if_ether.h>
#endif
#include <xtables.h>
#include <linux/netfilter/xt_mac.h>
enum {
O_MAC = 0,
};
static void mac_help(void)
{
printf(
"mac match options:\n"
"[!] --mac-source XX:XX:XX:XX:XX:XX\n"
" Match source MAC address\n");
}
#define s struct xt_mac_info
static const struct xt_option_entry mac_opts[] = {
{.name = "mac-source", .id = O_MAC, .type = XTTYPE_ETHERMAC,
.flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT,
XTOPT_POINTER(s, srcaddr)},
XTOPT_TABLEEND,
};
#undef s
static void mac_parse(struct xt_option_call *cb)
{
struct xt_mac_info *macinfo = cb->data;
xtables_option_parse(cb);
if (cb->invert)
macinfo->invert = 1;
}
static void print_mac(const unsigned char *macaddress)
{
unsigned int i;
printf(" %02X", macaddress[0]);
for (i = 1; i < ETH_ALEN; ++i)
printf(":%02X", macaddress[i]);
}
static void
mac_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_mac_info *info = (void *)match->data;
printf(" MAC");
if (info->invert)
printf(" !");
print_mac(info->srcaddr);
}
static void mac_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_mac_info *info = (void *)match->data;
if (info->invert)
printf(" !");
printf(" --mac-source");
print_mac(info->srcaddr);
}
static struct xtables_match mac_match = {
.family = NFPROTO_UNSPEC,
.name = "mac",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_mac_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_mac_info)),
.help = mac_help,
.x6_parse = mac_parse,
.print = mac_print,
.save = mac_save,
.x6_options = mac_opts,
};
void _init(void)
{
xtables_register_match(&mac_match);
}
.TP
[\fB!\fP] \fB\-\-mac\-source\fP \fIaddress\fP
Match source MAC address. It must be of the form XX:XX:XX:XX:XX:XX.
Note that this only makes sense for packets coming from an Ethernet device
and entering the
.BR PREROUTING ,
.B FORWARD
or
.B INPUT
chains.
#include <stdbool.h>
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter/xt_mark.h>
struct xt_mark_info {
unsigned long mark, mask;
uint8_t invert;
};
enum {
O_MARK = 0,
};
static void mark_mt_help(void)
{
printf(
"mark match options:\n"
"[!] --mark value[/mask] Match nfmark value with optional mask\n");
}
static const struct xt_option_entry mark_mt_opts[] = {
{.name = "mark", .id = O_MARK, .type = XTTYPE_MARKMASK32,
.flags = XTOPT_MAND | XTOPT_INVERT},
XTOPT_TABLEEND,
};
static void mark_mt_parse(struct xt_option_call *cb)
{
struct xt_mark_mtinfo1 *info = cb->data;
xtables_option_parse(cb);
if (cb->invert)
info->invert = true;
info->mark = cb->val.mark;
info->mask = cb->val.mask;
}
static void mark_parse(struct xt_option_call *cb)
{
struct xt_mark_info *markinfo = cb->data;
xtables_option_parse(cb);
if (cb->invert)
markinfo->invert = 1;
markinfo->mark = cb->val.mark;
markinfo->mask = cb->val.mask;
}
static void print_mark(unsigned int mark, unsigned int mask)
{
if (mask != 0xffffffffU)
printf(" 0x%x/0x%x", mark, mask);
else
printf(" 0x%x", mark);
}
static void
mark_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_mark_mtinfo1 *info = (const void *)match->data;
printf(" mark match");
if (info->invert)
printf(" !");
print_mark(info->mark, info->mask);
}
static void
mark_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_mark_info *info = (const void *)match->data;
printf(" MARK match");
if (info->invert)
printf(" !");
print_mark(info->mark, info->mask);
}
static void mark_mt_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_mark_mtinfo1 *info = (const void *)match->data;
if (info->invert)
printf(" !");
printf(" --mark");
print_mark(info->mark, info->mask);
}
static void
mark_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_mark_info *info = (const void *)match->data;
if (info->invert)
printf(" !");
printf(" --mark");
print_mark(info->mark, info->mask);
}
static struct xtables_match mark_mt_reg[] = {
{
.family = NFPROTO_UNSPEC,
.name = "mark",
.revision = 0,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_mark_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_mark_info)),
.help = mark_mt_help,
.print = mark_print,
.save = mark_save,
.x6_parse = mark_parse,
.x6_options = mark_mt_opts,
},
{
.version = XTABLES_VERSION,
.name = "mark",
.revision = 1,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)),
.userspacesize = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)),
.help = mark_mt_help,
.print = mark_mt_print,
.save = mark_mt_save,
.x6_parse = mark_mt_parse,
.x6_options = mark_mt_opts,
},
};
void _init(void)
{
xtables_register_matches(mark_mt_reg, ARRAY_SIZE(mark_mt_reg));
}
This module matches the netfilter mark field associated with a packet
(which can be set using the
.B MARK
target below).
.TP
[\fB!\fP] \fB\-\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
Matches packets with the given unsigned mark value (if a \fImask\fP is
specified, this is logically ANDed with the \fImask\fP before the
comparison).
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter/xt_multiport.h>
enum {
O_SOURCE_PORTS = 0,
O_DEST_PORTS,
O_SD_PORTS,
F_SOURCE_PORTS = 1 << O_SOURCE_PORTS,
F_DEST_PORTS = 1 << O_DEST_PORTS,
F_SD_PORTS = 1 << O_SD_PORTS,
F_ANY = F_SOURCE_PORTS | F_DEST_PORTS | F_SD_PORTS,
};
/* Function which prints out usage message. */
static void multiport_help(void)
{
printf(
"multiport match options:\n"
" --source-ports port[,port,port...]\n"
" --sports ...\n"
" match source port(s)\n"
" --destination-ports port[,port,port...]\n"
" --dports ...\n"
" match destination port(s)\n"
" --ports port[,port,port]\n"
" match both source and destination port(s)\n"
" NOTE: this kernel does not support port ranges in multiport.\n");
}
static void multiport_help_v1(void)
{
printf(
"multiport match options:\n"
"[!] --source-ports port[,port:port,port...]\n"
" --sports ...\n"
" match source port(s)\n"
"[!] --destination-ports port[,port:port,port...]\n"
" --dports ...\n"
" match destination port(s)\n"
"[!] --ports port[,port:port,port]\n"
" match both source and destination port(s)\n");
}
static const struct xt_option_entry multiport_opts[] = {
{.name = "source-ports", .id = O_SOURCE_PORTS, .type = XTTYPE_STRING,
.excl = F_ANY, .flags = XTOPT_INVERT},
{.name = "sports", .id = O_SOURCE_PORTS, .type = XTTYPE_STRING,
.excl = F_ANY, .flags = XTOPT_INVERT},
{.name = "destination-ports", .id = O_DEST_PORTS,
.type = XTTYPE_STRING, .excl = F_ANY, .flags = XTOPT_INVERT},
{.name = "dports", .id = O_DEST_PORTS, .type = XTTYPE_STRING,
.excl = F_ANY, .flags = XTOPT_INVERT},
{.name = "ports", .id = O_SD_PORTS, .type = XTTYPE_STRING,
.excl = F_ANY, .flags = XTOPT_INVERT},
XTOPT_TABLEEND,
};
static const char *
proto_to_name(uint8_t proto)
{
switch (proto) {
case IPPROTO_TCP:
return "tcp";
case IPPROTO_UDP:
return "udp";
case IPPROTO_UDPLITE:
return "udplite";
case IPPROTO_SCTP:
return "sctp";
case IPPROTO_DCCP:
return "dccp";
default:
return NULL;
}
}
static unsigned int
parse_multi_ports(const char *portstring, uint16_t *ports, const char *proto)
{
char *buffer, *cp, *next;
unsigned int i;
buffer = strdup(portstring);
if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next,i++)
{
next=strchr(cp, ',');
if (next) *next++='\0';
ports[i] = xtables_parse_port(cp, proto);
}
if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
free(buffer);
return i;
}
static void
parse_multi_ports_v1(const char *portstring,
struct xt_multiport_v1 *multiinfo,
const char *proto)
{
char *buffer, *cp, *next, *range;
unsigned int i;
uint16_t m;
buffer = strdup(portstring);
if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
for (i=0; i<XT_MULTI_PORTS; i++)
multiinfo->pflags[i] = 0;
for (cp=buffer, i=0; cp && i<XT_MULTI_PORTS; cp=next, i++) {
next=strchr(cp, ',');
if (next) *next++='\0';
range = strchr(cp, ':');
if (range) {
if (i == XT_MULTI_PORTS-1)
xtables_error(PARAMETER_PROBLEM,
"too many ports specified");
*range++ = '\0';
}
multiinfo->ports[i] = xtables_parse_port(cp, proto);
if (range) {
multiinfo->pflags[i] = 1;
multiinfo->ports[++i] = xtables_parse_port(range, proto);
if (multiinfo->ports[i-1] >= multiinfo->ports[i])
xtables_error(PARAMETER_PROBLEM,
"invalid portrange specified");
m <<= 1;
}
}
multiinfo->count = i;
if (cp) xtables_error(PARAMETER_PROBLEM, "too many ports specified");
free(buffer);
}
static const char *
check_proto(uint16_t pnum, uint8_t invflags)
{
const char *proto;
if (invflags & XT_INV_PROTO)
xtables_error(PARAMETER_PROBLEM,
"multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
if ((proto = proto_to_name(pnum)) != NULL)
return proto;
else if (!pnum)
xtables_error(PARAMETER_PROBLEM,
"multiport needs `-p tcp', `-p udp', `-p udplite', "
"`-p sctp' or `-p dccp'");
else
xtables_error(PARAMETER_PROBLEM,
"multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP");
}
static void __multiport_parse(struct xt_option_call *cb, uint16_t pnum,
uint8_t invflags)
{
const char *proto;
struct xt_multiport *multiinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SOURCE_PORTS:
proto = check_proto(pnum, invflags);
multiinfo->count = parse_multi_ports(cb->arg,
multiinfo->ports, proto);
multiinfo->flags = XT_MULTIPORT_SOURCE;
break;
case O_DEST_PORTS:
proto = check_proto(pnum, invflags);
multiinfo->count = parse_multi_ports(cb->arg,
multiinfo->ports, proto);
multiinfo->flags = XT_MULTIPORT_DESTINATION;
break;
case O_SD_PORTS:
proto = check_proto(pnum, invflags);
multiinfo->count = parse_multi_ports(cb->arg,
multiinfo->ports, proto);
multiinfo->flags = XT_MULTIPORT_EITHER;
break;
}
if (cb->invert)
xtables_error(PARAMETER_PROBLEM,
"multiport.0 does not support invert");
}
static void multiport_parse(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
return __multiport_parse(cb,
entry->ip.proto, entry->ip.invflags);
}
static void multiport_parse6(struct xt_option_call *cb)
{
const struct ip6t_entry *entry = cb->xt_entry;
return __multiport_parse(cb,
entry->ipv6.proto, entry->ipv6.invflags);
}
static void __multiport_parse_v1(struct xt_option_call *cb, uint16_t pnum,
uint8_t invflags)
{
const char *proto;
struct xt_multiport_v1 *multiinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SOURCE_PORTS:
proto = check_proto(pnum, invflags);
parse_multi_ports_v1(cb->arg, multiinfo, proto);
multiinfo->flags = XT_MULTIPORT_SOURCE;
break;
case O_DEST_PORTS:
proto = check_proto(pnum, invflags);
parse_multi_ports_v1(cb->arg, multiinfo, proto);
multiinfo->flags = XT_MULTIPORT_DESTINATION;
break;
case O_SD_PORTS:
proto = check_proto(pnum, invflags);
parse_multi_ports_v1(cb->arg, multiinfo, proto);
multiinfo->flags = XT_MULTIPORT_EITHER;
break;
}
if (cb->invert)
multiinfo->invert = 1;
}
static void multiport_parse_v1(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
return __multiport_parse_v1(cb,
entry->ip.proto, entry->ip.invflags);
}
static void multiport_parse6_v1(struct xt_option_call *cb)
{
const struct ip6t_entry *entry = cb->xt_entry;
return __multiport_parse_v1(cb,
entry->ipv6.proto, entry->ipv6.invflags);
}
static void multiport_check(struct xt_fcheck_call *cb)
{
if (cb->xflags == 0)
xtables_error(PARAMETER_PROBLEM, "multiport expection an option");
}
static const char *
port_to_service(int port, uint8_t proto)
{
const struct servent *service;
if ((service = getservbyport(htons(port), proto_to_name(proto))))
return service->s_name;
return NULL;
}
static void
print_port(uint16_t port, uint8_t protocol, int numeric)
{
const char *service;
if (numeric || (service = port_to_service(port, protocol)) == NULL)
printf("%u", port);
else
printf("%s", service);
}
static void
__multiport_print(const struct xt_entry_match *match, int numeric,
uint16_t proto)
{
const struct xt_multiport *multiinfo
= (const struct xt_multiport *)match->data;
unsigned int i;
printf(" multiport ");
switch (multiinfo->flags) {
case XT_MULTIPORT_SOURCE:
printf("sports ");
break;
case XT_MULTIPORT_DESTINATION:
printf("dports ");
break;
case XT_MULTIPORT_EITHER:
printf("ports ");
break;
default:
printf("ERROR ");
break;
}
for (i=0; i < multiinfo->count; i++) {
printf("%s", i ? "," : "");
print_port(multiinfo->ports[i], proto, numeric);
}
}
static void multiport_print(const void *ip_void,
const struct xt_entry_match *match, int numeric)
{
const struct ipt_ip *ip = ip_void;
__multiport_print(match, numeric, ip->proto);
}
static void multiport_print6(const void *ip_void,
const struct xt_entry_match *match, int numeric)
{
const struct ip6t_ip6 *ip = ip_void;
__multiport_print(match, numeric, ip->proto);
}
static void __multiport_print_v1(const struct xt_entry_match *match,
int numeric, uint16_t proto)
{
const struct xt_multiport_v1 *multiinfo
= (const struct xt_multiport_v1 *)match->data;
unsigned int i;
printf(" multiport ");
switch (multiinfo->flags) {
case XT_MULTIPORT_SOURCE:
printf("sports ");
break;
case XT_MULTIPORT_DESTINATION:
printf("dports ");
break;
case XT_MULTIPORT_EITHER:
printf("ports ");
break;
default:
printf("ERROR ");
break;
}
if (multiinfo->invert)
printf(" !");
for (i=0; i < multiinfo->count; i++) {
printf("%s", i ? "," : "");
print_port(multiinfo->ports[i], proto, numeric);
if (multiinfo->pflags[i]) {
printf(":");
print_port(multiinfo->ports[++i], proto, numeric);
}
}
}
static void multiport_print_v1(const void *ip_void,
const struct xt_entry_match *match, int numeric)
{
const struct ipt_ip *ip = ip_void;
__multiport_print_v1(match, numeric, ip->proto);
}
static void multiport_print6_v1(const void *ip_void,
const struct xt_entry_match *match, int numeric)
{
const struct ip6t_ip6 *ip = ip_void;
__multiport_print_v1(match, numeric, ip->proto);
}
static void __multiport_save(const struct xt_entry_match *match,
uint16_t proto)
{
const struct xt_multiport *multiinfo
= (const struct xt_multiport *)match->data;
unsigned int i;
switch (multiinfo->flags) {
case XT_MULTIPORT_SOURCE:
printf(" --sports ");
break;
case XT_MULTIPORT_DESTINATION:
printf(" --dports ");
break;
case XT_MULTIPORT_EITHER:
printf(" --ports ");
break;
}
for (i=0; i < multiinfo->count; i++) {
printf("%s", i ? "," : "");
print_port(multiinfo->ports[i], proto, 1);
}
}
static void multiport_save(const void *ip_void,
const struct xt_entry_match *match)
{
const struct ipt_ip *ip = ip_void;
__multiport_save(match, ip->proto);
}
static void multiport_save6(const void *ip_void,
const struct xt_entry_match *match)
{
const struct ip6t_ip6 *ip = ip_void;
__multiport_save(match, ip->proto);
}
static void __multiport_save_v1(const struct xt_entry_match *match,
uint16_t proto)
{
const struct xt_multiport_v1 *multiinfo
= (const struct xt_multiport_v1 *)match->data;
unsigned int i;
if (multiinfo->invert)
printf(" !");
switch (multiinfo->flags) {
case XT_MULTIPORT_SOURCE:
printf(" --sports ");
break;
case XT_MULTIPORT_DESTINATION:
printf(" --dports ");
break;
case XT_MULTIPORT_EITHER:
printf(" --ports ");
break;
}
for (i=0; i < multiinfo->count; i++) {
printf("%s", i ? "," : "");
print_port(multiinfo->ports[i], proto, 1);
if (multiinfo->pflags[i]) {
printf(":");
print_port(multiinfo->ports[++i], proto, 1);
}
}
}
static void multiport_save_v1(const void *ip_void,
const struct xt_entry_match *match)
{
const struct ipt_ip *ip = ip_void;
__multiport_save_v1(match, ip->proto);
}
static void multiport_save6_v1(const void *ip_void,
const struct xt_entry_match *match)
{
const struct ip6t_ip6 *ip = ip_void;
__multiport_save_v1(match, ip->proto);
}
static struct xtables_match multiport_mt_reg[] = {
{
.family = NFPROTO_IPV4,
.name = "multiport",
.revision = 0,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_multiport)),
.userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
.help = multiport_help,
.x6_parse = multiport_parse,
.x6_fcheck = multiport_check,
.print = multiport_print,
.save = multiport_save,
.x6_options = multiport_opts,
},
{
.family = NFPROTO_IPV6,
.name = "multiport",
.revision = 0,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_multiport)),
.userspacesize = XT_ALIGN(sizeof(struct xt_multiport)),
.help = multiport_help,
.x6_parse = multiport_parse6,
.x6_fcheck = multiport_check,
.print = multiport_print6,
.save = multiport_save6,
.x6_options = multiport_opts,
},
{
.family = NFPROTO_IPV4,
.name = "multiport",
.version = XTABLES_VERSION,
.revision = 1,
.size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
.userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
.help = multiport_help_v1,
.x6_parse = multiport_parse_v1,
.x6_fcheck = multiport_check,
.print = multiport_print_v1,
.save = multiport_save_v1,
.x6_options = multiport_opts,
},
{
.family = NFPROTO_IPV6,
.name = "multiport",
.version = XTABLES_VERSION,
.revision = 1,
.size = XT_ALIGN(sizeof(struct xt_multiport_v1)),
.userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)),
.help = multiport_help_v1,
.x6_parse = multiport_parse6_v1,
.x6_fcheck = multiport_check,
.print = multiport_print6_v1,
.save = multiport_save6_v1,
.x6_options = multiport_opts,
},
};
void
_init(void)
{
xtables_register_matches(multiport_mt_reg, ARRAY_SIZE(multiport_mt_reg));
}
This module matches a set of source or destination ports. Up to 15
ports can be specified. A port range (port:port) counts as two
ports. It can only be used in conjunction with one of the
following protocols:
\fBtcp\fP, \fBudp\fP, \fBudplite\fP, \fBdccp\fP and \fBsctp\fP.
.TP
[\fB!\fP] \fB\-\-source\-ports\fP,\fB\-\-sports\fP \fIport\fP[\fB,\fP\fIport\fP|\fB,\fP\fIport\fP\fB:\fP\fIport\fP]...
Match if the source port is one of the given ports. The flag
\fB\-\-sports\fP
is a convenient alias for this option. Multiple ports or port ranges are
separated using a comma, and a port range is specified using a colon.
\fB53,1024:65535\fP would therefore match ports 53 and all from 1024 through
65535.
.TP
[\fB!\fP] \fB\-\-destination\-ports\fP,\fB\-\-dports\fP \fIport\fP[\fB,\fP\fIport\fP|\fB,\fP\fIport\fP\fB:\fP\fIport\fP]...
Match if the destination port is one of the given ports. The flag
\fB\-\-dports\fP
is a convenient alias for this option.
.TP
[\fB!\fP] \fB\-\-ports\fP \fIport\fP[\fB,\fP\fIport\fP|\fB,\fP\fIport\fP\fB:\fP\fIport\fP]...
Match if either the source or destination ports are equal to one of
the given ports.
/*
* (C) 2011 by Pablo Neira Ayuso <pablo@netfilter.org>
* (C) 2011 by Intra2Net AG <http://www.intra2net.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 (or
* any later at your option) as published by the Free Software Foundation.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_nfacct.h>
enum {
O_NAME = 0,
};
#define s struct xt_nfacct_match_info
static const struct xt_option_entry nfacct_opts[] = {
{.name = "nfacct-name", .id = O_NAME, .type = XTTYPE_STRING,
.min = 1, .flags = XTOPT_MAND|XTOPT_PUT, XTOPT_POINTER(s, name)},
XTOPT_TABLEEND,
};
#undef s
static void nfacct_help(void)
{
printf("nfacct match options:\n"
" --nfacct-name STRING Name of accouting area\n");
}
static void nfacct_parse(struct xt_option_call *cb)
{
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_NAME:
if (strchr(cb->arg, '\n') != NULL)
xtables_error(PARAMETER_PROBLEM,
"Newlines not allowed in --nfacct-name");
break;
}
}
static void
nfacct_print_name(const struct xt_nfacct_match_info *info, char *name)
{
printf(" %snfacct-name ", name);
xtables_save_string(info->name);
}
static void nfacct_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_nfacct_match_info *info =
(struct xt_nfacct_match_info *)match->data;
nfacct_print_name(info, "");
}
static void nfacct_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_nfacct_match_info *info =
(struct xt_nfacct_match_info *)match->data;
nfacct_print_name(info, "--");
}
static struct xtables_match nfacct_match = {
.family = NFPROTO_UNSPEC,
.name = "nfacct",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_nfacct_match_info)),
.userspacesize = offsetof(struct xt_nfacct_match_info, nfacct),
.help = nfacct_help,
.x6_parse = nfacct_parse,
.print = nfacct_print,
.save = nfacct_save,
.x6_options = nfacct_opts,
};
void _init(void)
{
xtables_register_match(&nfacct_match);
}
The nfacct match provides the extended accounting infrastructure for iptables.
You have to use this match together with the standalone user-space utility
.B nfacct(8)
.PP
The only option available for this match is the following:
.TP
\fB\-\-nfacct\-name\fP \fIname\fP
This allows you to specify the existing object name that will be use for
accounting the traffic that this rule-set is matching.
.PP
To use this extension, you have to create an accounting object:
.IP
nfacct add http\-traffic
.PP
Then, you have to attach it to the accounting object via iptables:
.IP
iptables \-I INPUT \-p tcp \-\-sport 80 \-m nfacct \-\-nfacct\-name http\-traffic
.IP
iptables \-I OUTPUT \-p tcp \-\-dport 80 \-m nfacct \-\-nfacct\-name http\-traffic
.PP
Then, you can check for the amount of traffic that the rules match:
.IP
nfacct get http\-traffic
.IP
{ pkts = 00000000000000000156, bytes = 00000000000000151786 } = http-traffic;
.PP
You can obtain
.B nfacct(8)
from http://www.netfilter.org or, alternatively, from the git.netfilter.org
repository.
/*
* Copyright (c) 2003+ Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* xtables interface for OS fingerprint matching module.
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <linux/netfilter/xt_osf.h>
enum {
O_GENRE = 0,
O_TTL,
O_LOGLEVEL,
};
static void osf_help(void)
{
printf("OS fingerprint match options:\n"
"[!] --genre string Match a OS genre by passive fingerprinting.\n"
"--ttl level Use some TTL check extensions to determine OS:\n"
" 0 true ip and fingerprint TTL comparison. Works for LAN.\n"
" 1 check if ip TTL is less than fingerprint one. Works for global addresses.\n"
" 2 do not compare TTL at all. Allows to detect NMAP, but can produce false results.\n"
"--log level Log determined genres into dmesg even if they do not match desired one:\n"
" 0 log all matched or unknown signatures.\n"
" 1 log only first one.\n"
" 2 log all known matched signatures.\n"
);
}
#define s struct xt_osf_info
static const struct xt_option_entry osf_opts[] = {
{.name = "genre", .id = O_GENRE, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT,
XTOPT_POINTER(s, genre)},
{.name = "ttl", .id = O_TTL, .type = XTTYPE_UINT32,
.flags = XTOPT_PUT, XTOPT_POINTER(s, ttl), .min = 0, .max = 2},
{.name = "log", .id = O_LOGLEVEL, .type = XTTYPE_UINT32,
.flags = XTOPT_PUT, XTOPT_POINTER(s, loglevel), .min = 0, .max = 2},
XTOPT_TABLEEND,
};
#undef s
static void osf_parse(struct xt_option_call *cb)
{
struct xt_osf_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_GENRE:
if (cb->invert)
info->flags |= XT_OSF_INVERT;
info->len = strlen(info->genre);
break;
case O_TTL:
info->flags |= XT_OSF_TTL;
break;
case O_LOGLEVEL:
info->flags |= XT_OSF_LOG;
break;
}
}
static void osf_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_osf_info *info = (const struct xt_osf_info*) match->data;
printf(" OS fingerprint match %s%s", (info->flags & XT_OSF_INVERT) ? "! " : "", info->genre);
}
static void osf_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_osf_info *info = (const struct xt_osf_info*) match->data;
if (info->flags & XT_OSF_INVERT)
printf(" !");
printf(" --genre %s", info->genre);
if (info->flags & XT_OSF_TTL)
printf(" --ttl %u", info->ttl);
if (info->flags & XT_OSF_LOG)
printf(" --log %u", info->loglevel);
}
static struct xtables_match osf_match = {
.name = "osf",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_osf_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_osf_info)),
.help = osf_help,
.x6_parse = osf_parse,
.print = osf_print,
.save = osf_save,
.x6_options = osf_opts,
.family = NFPROTO_IPV4,
};
void _init(void)
{
xtables_register_match(&osf_match);
}
The osf module does passive operating system fingerprinting. This modules
compares some data (Window Size, MSS, options and their order, TTL, DF,
and others) from packets with the SYN bit set.
.TP
[\fB!\fP] \fB\-\-genre\fP \fIstring\fP
Match an operating system genre by using a passive fingerprinting.
.TP
\fB\-\-ttl\fP \fIlevel\fP
Do additional TTL checks on the packet to determine the operating system.
\fIlevel\fP can be one of the following values:
.IP \(bu 4
0 - True IP address and fingerprint TTL comparison. This generally works for
LANs.
.IP \(bu 4
1 - Check if the IP header's TTL is less than the fingerprint one. Works for
globally-routable addresses.
.IP \(bu 4
2 - Do not compare the TTL at all.
.TP
\fB\-\-log\fP \fIlevel\fP
Log determined genres into dmesg even if they do not match the desired one.
\fIlevel\fP can be one of the following values:
.IP \(bu 4
0 - Log all matched or unknown signatures
.IP \(bu 4
1 - Log only the first one
.IP \(bu 4
2 - Log all known matched signatures
.PP
You may find something like this in syslog:
.PP
Windows [2000:SP3:Windows XP Pro SP1, 2000 SP3]: 11.22.33.55:4024 ->
11.22.33.44:139 hops=3 Linux [2.5-2.6:] : 1.2.3.4:42624 -> 1.2.3.5:22 hops=4
.PP
OS fingerprints are loadable using the \fBnfnl_osf\fP program. To load
fingerprints from a file, use:
.PP
\fBnfnl_osf -f /usr/share/xtables/pf.os\fP
.PP
To remove them again,
.PP
\fBnfnl_osf -f /usr/share/xtables/pf.os -d\fP
.PP
The fingerprint database can be downlaoded from
http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os .
/*
* libxt_owner - iptables addon for xt_owner
*
* Copyright © CC Computer Consultants GmbH, 2007 - 2008
* Jan Engelhardt <jengelh@computergmbh.de>
*/
#include <grp.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <limits.h>
#include <xtables.h>
#include <linux/netfilter/xt_owner.h>
/* match and invert flags */
enum {
IPT_OWNER_UID = 0x01,
IPT_OWNER_GID = 0x02,
IPT_OWNER_PID = 0x04,
IPT_OWNER_SID = 0x08,
IPT_OWNER_COMM = 0x10,
IP6T_OWNER_UID = IPT_OWNER_UID,
IP6T_OWNER_GID = IPT_OWNER_GID,
IP6T_OWNER_PID = IPT_OWNER_PID,
IP6T_OWNER_SID = IPT_OWNER_SID,
IP6T_OWNER_COMM = IPT_OWNER_COMM,
};
struct ipt_owner_info {
uid_t uid;
gid_t gid;
pid_t pid;
pid_t sid;
char comm[16];
uint8_t match, invert; /* flags */
};
struct ip6t_owner_info {
uid_t uid;
gid_t gid;
pid_t pid;
pid_t sid;
char comm[16];
uint8_t match, invert; /* flags */
};
/*
* Note: "UINT32_MAX - 1" is used in the code because -1 is a reserved
* UID/GID value anyway.
*/
enum {
O_USER = 0,
O_GROUP,
O_SOCK_EXISTS,
O_PROCESS,
O_SESSION,
O_COMM,
};
static void owner_mt_help_v0(void)
{
printf(
"owner match options:\n"
"[!] --uid-owner userid Match local UID\n"
"[!] --gid-owner groupid Match local GID\n"
"[!] --pid-owner processid Match local PID\n"
"[!] --sid-owner sessionid Match local SID\n"
"[!] --cmd-owner name Match local command name\n"
"NOTE: PID, SID and command matching are broken on SMP\n");
}
static void owner_mt6_help_v0(void)
{
printf(
"owner match options:\n"
"[!] --uid-owner userid Match local UID\n"
"[!] --gid-owner groupid Match local GID\n"
"[!] --pid-owner processid Match local PID\n"
"[!] --sid-owner sessionid Match local SID\n"
"NOTE: PID and SID matching are broken on SMP\n");
}
static void owner_mt_help(void)
{
printf(
"owner match options:\n"
"[!] --uid-owner userid[-userid] Match local UID\n"
"[!] --gid-owner groupid[-groupid] Match local GID\n"
"[!] --socket-exists Match if socket exists\n");
}
#define s struct ipt_owner_info
static const struct xt_option_entry owner_mt_opts_v0[] = {
{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid),
.max = INT_MAX},
{.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid),
.max = INT_MAX},
{.name = "cmd-owner", .id = O_COMM, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, comm)},
XTOPT_TABLEEND,
};
#undef s
#define s struct ip6t_owner_info
static const struct xt_option_entry owner_mt6_opts_v0[] = {
{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid),
.max = INT_MAX},
{.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid),
.max = INT_MAX},
XTOPT_TABLEEND,
};
#undef s
static const struct xt_option_entry owner_mt_opts[] = {
{.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "socket-exists", .id = O_SOCK_EXISTS, .type = XTTYPE_NONE,
.flags = XTOPT_INVERT},
XTOPT_TABLEEND,
};
static void owner_mt_parse_v0(struct xt_option_call *cb)
{
struct ipt_owner_info *info = cb->data;
struct passwd *pwd;
struct group *grp;
unsigned int id;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_USER:
if ((pwd = getpwnam(cb->arg)) != NULL)
id = pwd->pw_uid;
else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg);
if (cb->invert)
info->invert |= IPT_OWNER_UID;
info->match |= IPT_OWNER_UID;
info->uid = id;
break;
case O_GROUP:
if ((grp = getgrnam(cb->arg)) != NULL)
id = grp->gr_gid;
else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg);
if (cb->invert)
info->invert |= IPT_OWNER_GID;
info->match |= IPT_OWNER_GID;
info->gid = id;
break;
case O_PROCESS:
if (cb->invert)
info->invert |= IPT_OWNER_PID;
info->match |= IPT_OWNER_PID;
break;
case O_SESSION:
if (cb->invert)
info->invert |= IPT_OWNER_SID;
info->match |= IPT_OWNER_SID;
break;
case O_COMM:
if (cb->invert)
info->invert |= IPT_OWNER_COMM;
info->match |= IPT_OWNER_COMM;
break;
}
}
static void owner_mt6_parse_v0(struct xt_option_call *cb)
{
struct ip6t_owner_info *info = cb->data;
struct passwd *pwd;
struct group *grp;
unsigned int id;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_USER:
if ((pwd = getpwnam(cb->arg)) != NULL)
id = pwd->pw_uid;
else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg);
if (cb->invert)
info->invert |= IP6T_OWNER_UID;
info->match |= IP6T_OWNER_UID;
info->uid = id;
break;
case O_GROUP:
if ((grp = getgrnam(cb->arg)) != NULL)
id = grp->gr_gid;
else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1))
xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg);
if (cb->invert)
info->invert |= IP6T_OWNER_GID;
info->match |= IP6T_OWNER_GID;
info->gid = id;
break;
case O_PROCESS:
if (cb->invert)
info->invert |= IP6T_OWNER_PID;
info->match |= IP6T_OWNER_PID;
break;
case O_SESSION:
if (cb->invert)
info->invert |= IP6T_OWNER_SID;
info->match |= IP6T_OWNER_SID;
break;
}
}
static void owner_parse_range(const char *s, unsigned int *from,
unsigned int *to, const char *opt)
{
char *end;
/* -1 is reversed, so the max is one less than that. */
if (!xtables_strtoui(s, &end, from, 0, UINT32_MAX - 1))
xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
*to = *from;
if (*end == '-' || *end == ':')
if (!xtables_strtoui(end + 1, &end, to, 0, UINT32_MAX - 1))
xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
if (*end != '\0')
xtables_param_act(XTF_BAD_VALUE, "owner", opt, s);
}
static void owner_mt_parse(struct xt_option_call *cb)
{
struct xt_owner_match_info *info = cb->data;
struct passwd *pwd;
struct group *grp;
unsigned int from, to;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_USER:
if ((pwd = getpwnam(cb->arg)) != NULL)
from = to = pwd->pw_uid;
else
owner_parse_range(cb->arg, &from, &to, "--uid-owner");
if (cb->invert)
info->invert |= XT_OWNER_UID;
info->match |= XT_OWNER_UID;
info->uid_min = from;
info->uid_max = to;
break;
case O_GROUP:
if ((grp = getgrnam(cb->arg)) != NULL)
from = to = grp->gr_gid;
else
owner_parse_range(cb->arg, &from, &to, "--gid-owner");
if (cb->invert)
info->invert |= XT_OWNER_GID;
info->match |= XT_OWNER_GID;
info->gid_min = from;
info->gid_max = to;
break;
case O_SOCK_EXISTS:
if (cb->invert)
info->invert |= XT_OWNER_SOCKET;
info->match |= XT_OWNER_SOCKET;
break;
}
}
static void owner_mt_check(struct xt_fcheck_call *cb)
{
if (cb->xflags == 0)
xtables_error(PARAMETER_PROBLEM, "owner: At least one of "
"--uid-owner, --gid-owner or --socket-exists "
"is required");
}
static void
owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label,
uint8_t flag, bool numeric)
{
if (!(info->match & flag))
return;
if (info->invert & flag)
printf(" !");
printf(" %s", label);
switch (info->match & flag) {
case IPT_OWNER_UID:
if (!numeric) {
struct passwd *pwd = getpwuid(info->uid);
if (pwd != NULL && pwd->pw_name != NULL) {
printf(" %s", pwd->pw_name);
break;
}
}
printf(" %u", (unsigned int)info->uid);
break;
case IPT_OWNER_GID:
if (!numeric) {
struct group *grp = getgrgid(info->gid);
if (grp != NULL && grp->gr_name != NULL) {
printf(" %s", grp->gr_name);
break;
}
}
printf(" %u", (unsigned int)info->gid);
break;
case IPT_OWNER_PID:
printf(" %u", (unsigned int)info->pid);
break;
case IPT_OWNER_SID:
printf(" %u", (unsigned int)info->sid);
break;
case IPT_OWNER_COMM:
printf(" %.*s", (int)sizeof(info->comm), info->comm);
break;
}
}
static void
owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label,
uint8_t flag, bool numeric)
{
if (!(info->match & flag))
return;
if (info->invert & flag)
printf(" !");
printf(" %s", label);
switch (info->match & flag) {
case IP6T_OWNER_UID:
if (!numeric) {
struct passwd *pwd = getpwuid(info->uid);
if (pwd != NULL && pwd->pw_name != NULL) {
printf(" %s", pwd->pw_name);
break;
}
}
printf(" %u", (unsigned int)info->uid);
break;
case IP6T_OWNER_GID:
if (!numeric) {
struct group *grp = getgrgid(info->gid);
if (grp != NULL && grp->gr_name != NULL) {
printf(" %s", grp->gr_name);
break;
}
}
printf(" %u", (unsigned int)info->gid);
break;
case IP6T_OWNER_PID:
printf(" %u", (unsigned int)info->pid);
break;
case IP6T_OWNER_SID:
printf(" %u", (unsigned int)info->sid);
break;
}
}
static void
owner_mt_print_item(const struct xt_owner_match_info *info, const char *label,
uint8_t flag, bool numeric)
{
if (!(info->match & flag))
return;
if (info->invert & flag)
printf(" !");
printf(" %s", label);
switch (info->match & flag) {
case XT_OWNER_UID:
if (info->uid_min != info->uid_max) {
printf(" %u-%u", (unsigned int)info->uid_min,
(unsigned int)info->uid_max);
break;
} else if (!numeric) {
const struct passwd *pwd = getpwuid(info->uid_min);
if (pwd != NULL && pwd->pw_name != NULL) {
printf(" %s", pwd->pw_name);
break;
}
}
printf(" %u", (unsigned int)info->uid_min);
break;
case XT_OWNER_GID:
if (info->gid_min != info->gid_max) {
printf(" %u-%u", (unsigned int)info->gid_min,
(unsigned int)info->gid_max);
break;
} else if (!numeric) {
const struct group *grp = getgrgid(info->gid_min);
if (grp != NULL && grp->gr_name != NULL) {
printf(" %s", grp->gr_name);
break;
}
}
printf(" %u", (unsigned int)info->gid_min);
break;
}
}
static void
owner_mt_print_v0(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ipt_owner_info *info = (void *)match->data;
owner_mt_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
owner_mt_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
owner_mt_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
owner_mt_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
owner_mt_print_item_v0(info, "owner CMD match", IPT_OWNER_COMM, numeric);
}
static void
owner_mt6_print_v0(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_owner_info *info = (void *)match->data;
owner_mt6_print_item_v0(info, "owner UID match", IPT_OWNER_UID, numeric);
owner_mt6_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric);
owner_mt6_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric);
owner_mt6_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric);
}
static void owner_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_owner_match_info *info = (void *)match->data;
owner_mt_print_item(info, "owner socket exists", XT_OWNER_SOCKET, numeric);
owner_mt_print_item(info, "owner UID match", XT_OWNER_UID, numeric);
owner_mt_print_item(info, "owner GID match", XT_OWNER_GID, numeric);
}
static void
owner_mt_save_v0(const void *ip, const struct xt_entry_match *match)
{
const struct ipt_owner_info *info = (void *)match->data;
owner_mt_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
owner_mt_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
owner_mt_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
owner_mt_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
owner_mt_print_item_v0(info, "--cmd-owner", IPT_OWNER_COMM, true);
}
static void
owner_mt6_save_v0(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_owner_info *info = (void *)match->data;
owner_mt6_print_item_v0(info, "--uid-owner", IPT_OWNER_UID, true);
owner_mt6_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true);
owner_mt6_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true);
owner_mt6_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true);
}
static void owner_mt_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_owner_match_info *info = (void *)match->data;
owner_mt_print_item(info, "--socket-exists", XT_OWNER_SOCKET, true);
owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, true);
owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, true);
}
static struct xtables_match owner_mt_reg[] = {
{
.version = XTABLES_VERSION,
.name = "owner",
.revision = 0,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_owner_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)),
.help = owner_mt_help_v0,
.x6_parse = owner_mt_parse_v0,
.x6_fcheck = owner_mt_check,
.print = owner_mt_print_v0,
.save = owner_mt_save_v0,
.x6_options = owner_mt_opts_v0,
},
{
.version = XTABLES_VERSION,
.name = "owner",
.revision = 0,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_owner_info)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)),
.help = owner_mt6_help_v0,
.x6_parse = owner_mt6_parse_v0,
.x6_fcheck = owner_mt_check,
.print = owner_mt6_print_v0,
.save = owner_mt6_save_v0,
.x6_options = owner_mt6_opts_v0,
},
{
.version = XTABLES_VERSION,
.name = "owner",
.revision = 1,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_owner_match_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)),
.help = owner_mt_help,
.x6_parse = owner_mt_parse,
.x6_fcheck = owner_mt_check,
.print = owner_mt_print,
.save = owner_mt_save,
.x6_options = owner_mt_opts,
},
};
void _init(void)
{
xtables_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg));
}
This module attempts to match various characteristics of the packet creator,
for locally generated packets. This match is only valid in the OUTPUT and
POSTROUTING chains. Forwarded packets do not have any socket associated with
them. Packets from kernel threads do have a socket, but usually no owner.
.TP
[\fB!\fP] \fB\-\-uid\-owner\fP \fIusername\fP
.TP
[\fB!\fP] \fB\-\-uid\-owner\fP \fIuserid\fP[\fB\-\fP\fIuserid\fP]
Matches if the packet socket's file structure (if it has one) is owned by the
given user. You may also specify a numerical UID, or an UID range.
.TP
[\fB!\fP] \fB\-\-gid\-owner\fP \fIgroupname\fP
.TP
[\fB!\fP] \fB\-\-gid\-owner\fP \fIgroupid\fP[\fB\-\fP\fIgroupid\fP]
Matches if the packet socket's file structure is owned by the given group.
You may also specify a numerical GID, or a GID range.
.TP
[\fB!\fP] \fB\-\-socket\-exists\fP
Matches if the packet is associated with a socket.
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter/xt_physdev.h>
enum {
O_PHYSDEV_IN = 0,
O_PHYSDEV_OUT,
O_PHYSDEV_IS_IN,
O_PHYSDEV_IS_OUT,
O_PHYSDEV_IS_BRIDGED,
};
static void physdev_help(void)
{
printf(
"physdev match options:\n"
" [!] --physdev-in inputname[+] bridge port name ([+] for wildcard)\n"
" [!] --physdev-out outputname[+] bridge port name ([+] for wildcard)\n"
" [!] --physdev-is-in arrived on a bridge device\n"
" [!] --physdev-is-out will leave on a bridge device\n"
" [!] --physdev-is-bridged it's a bridged packet\n");
}
#define s struct xt_physdev_info
static const struct xt_option_entry physdev_opts[] = {
{.name = "physdev-in", .id = O_PHYSDEV_IN, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, physindev)},
{.name = "physdev-out", .id = O_PHYSDEV_OUT, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, physoutdev)},
{.name = "physdev-is-in", .id = O_PHYSDEV_IS_IN, .type = XTTYPE_NONE,
.flags = XTOPT_INVERT},
{.name = "physdev-is-out", .id = O_PHYSDEV_IS_OUT,
.type = XTTYPE_NONE, .flags = XTOPT_INVERT},
{.name = "physdev-is-bridged", .id = O_PHYSDEV_IS_BRIDGED,
.type = XTTYPE_NONE, .flags = XTOPT_INVERT},
XTOPT_TABLEEND,
};
#undef s
static void physdev_parse(struct xt_option_call *cb)
{
struct xt_physdev_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_PHYSDEV_IN:
xtables_parse_interface(cb->arg, info->physindev,
(unsigned char *)info->in_mask);
if (cb->invert)
info->invert |= XT_PHYSDEV_OP_IN;
info->bitmask |= XT_PHYSDEV_OP_IN;
break;
case O_PHYSDEV_OUT:
xtables_parse_interface(cb->arg, info->physoutdev,
(unsigned char *)info->out_mask);
if (cb->invert)
info->invert |= XT_PHYSDEV_OP_OUT;
info->bitmask |= XT_PHYSDEV_OP_OUT;
break;
case O_PHYSDEV_IS_IN:
info->bitmask |= XT_PHYSDEV_OP_ISIN;
if (cb->invert)
info->invert |= XT_PHYSDEV_OP_ISIN;
break;
case O_PHYSDEV_IS_OUT:
info->bitmask |= XT_PHYSDEV_OP_ISOUT;
if (cb->invert)
info->invert |= XT_PHYSDEV_OP_ISOUT;
break;
case O_PHYSDEV_IS_BRIDGED:
if (cb->invert)
info->invert |= XT_PHYSDEV_OP_BRIDGED;
info->bitmask |= XT_PHYSDEV_OP_BRIDGED;
break;
}
}
static void physdev_check(struct xt_fcheck_call *cb)
{
if (cb->xflags == 0)
xtables_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified");
}
static void
physdev_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_physdev_info *info = (const void *)match->data;
printf(" PHYSDEV match");
if (info->bitmask & XT_PHYSDEV_OP_ISIN)
printf("%s --physdev-is-in",
info->invert & XT_PHYSDEV_OP_ISIN ? " !":"");
if (info->bitmask & XT_PHYSDEV_OP_IN)
printf("%s --physdev-in %s",
(info->invert & XT_PHYSDEV_OP_IN) ? " !":"", info->physindev);
if (info->bitmask & XT_PHYSDEV_OP_ISOUT)
printf("%s --physdev-is-out",
info->invert & XT_PHYSDEV_OP_ISOUT ? " !":"");
if (info->bitmask & XT_PHYSDEV_OP_OUT)
printf("%s --physdev-out %s",
(info->invert & XT_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
if (info->bitmask & XT_PHYSDEV_OP_BRIDGED)
printf("%s --physdev-is-bridged",
info->invert & XT_PHYSDEV_OP_BRIDGED ? " !":"");
}
static void physdev_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_physdev_info *info = (const void *)match->data;
if (info->bitmask & XT_PHYSDEV_OP_ISIN)
printf("%s --physdev-is-in",
(info->invert & XT_PHYSDEV_OP_ISIN) ? " !" : "");
if (info->bitmask & XT_PHYSDEV_OP_IN)
printf("%s --physdev-in %s",
(info->invert & XT_PHYSDEV_OP_IN) ? " !" : "",
info->physindev);
if (info->bitmask & XT_PHYSDEV_OP_ISOUT)
printf("%s --physdev-is-out",
(info->invert & XT_PHYSDEV_OP_ISOUT) ? " !" : "");
if (info->bitmask & XT_PHYSDEV_OP_OUT)
printf("%s --physdev-out %s",
(info->invert & XT_PHYSDEV_OP_OUT) ? " !" : "",
info->physoutdev);
if (info->bitmask & XT_PHYSDEV_OP_BRIDGED)
printf("%s --physdev-is-bridged",
(info->invert & XT_PHYSDEV_OP_BRIDGED) ? " !" : "");
}
static struct xtables_match physdev_match = {
.family = NFPROTO_UNSPEC,
.name = "physdev",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_physdev_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_physdev_info)),
.help = physdev_help,
.print = physdev_print,
.save = physdev_save,
.x6_parse = physdev_parse,
.x6_fcheck = physdev_check,
.x6_options = physdev_opts,
};
void _init(void)
{
xtables_register_match(&physdev_match);
}
This module matches on the bridge port input and output devices enslaved
to a bridge device. This module is a part of the infrastructure that enables
a transparent bridging IP firewall and is only useful for kernel versions
above version 2.5.44.
.TP
[\fB!\fP] \fB\-\-physdev\-in\fP \fIname\fP
Name of a bridge port via which a packet is received (only for
packets entering the
.BR INPUT ,
.B FORWARD
and
.B PREROUTING
chains). If the interface name ends in a "+", then any
interface which begins with this name will match. If the packet didn't arrive
through a bridge device, this packet won't match this option, unless '!' is used.
.TP
[\fB!\fP] \fB\-\-physdev\-out\fP \fIname\fP
Name of a bridge port via which a packet is going to be sent (for packets
entering the
.BR FORWARD ,
.B OUTPUT
and
.B POSTROUTING
chains). If the interface name ends in a "+", then any
interface which begins with this name will match. Note that in the
.BR nat " and " mangle
.B OUTPUT
chains one cannot match on the bridge output port, however one can in the
.B "filter OUTPUT"
chain. If the packet won't leave by a bridge device or if it is yet unknown what
the output device will be, then the packet won't match this option,
unless '!' is used.
.TP
[\fB!\fP] \fB\-\-physdev\-is\-in\fP
Matches if the packet has entered through a bridge interface.
.TP
[\fB!\fP] \fB\-\-physdev\-is\-out\fP
Matches if the packet will leave through a bridge interface.
.TP
[\fB!\fP] \fB\-\-physdev\-is\-bridged\fP
Matches if the packet is being bridged and therefore is not being routed.
This is only useful in the FORWARD and POSTROUTING chains.
/*
* Shared library add-on to iptables to match
* packets by their type (BROADCAST, UNICAST, MULTICAST).
*
* Michal Ludvig <michal@logix.cz>
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/if_packet.h>
#include <linux/netfilter/xt_pkttype.h>
enum {
O_PKTTYPE = 0,
};
struct pkttypes {
const char *name;
unsigned char pkttype;
unsigned char printhelp;
const char *help;
};
static const struct pkttypes supported_types[] = {
{"unicast", PACKET_HOST, 1, "to us"},
{"broadcast", PACKET_BROADCAST, 1, "to all"},
{"multicast", PACKET_MULTICAST, 1, "to group"},
/*
{"otherhost", PACKET_OTHERHOST, 1, "to someone else"},
{"outgoing", PACKET_OUTGOING, 1, "outgoing of any type"},
*/
/* aliases */
{"bcast", PACKET_BROADCAST, 0, NULL},
{"mcast", PACKET_MULTICAST, 0, NULL},
{"host", PACKET_HOST, 0, NULL}
};
static void print_types(void)
{
unsigned int i;
printf("Valid packet types:\n");
for (i = 0; i < ARRAY_SIZE(supported_types); ++i)
if(supported_types[i].printhelp == 1)
printf("\t%-14s\t\t%s\n", supported_types[i].name, supported_types[i].help);
printf("\n");
}
static void pkttype_help(void)
{
printf(
"pkttype match options:\n"
"[!] --pkt-type packettype match packet type\n");
print_types();
}
static const struct xt_option_entry pkttype_opts[] = {
{.name = "pkt-type", .id = O_PKTTYPE, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_INVERT},
XTOPT_TABLEEND,
};
static void parse_pkttype(const char *pkttype, struct xt_pkttype_info *info)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(supported_types); ++i)
if(strcasecmp(pkttype, supported_types[i].name)==0)
{
info->pkttype=supported_types[i].pkttype;
return;
}
xtables_error(PARAMETER_PROBLEM, "Bad packet type '%s'", pkttype);
}
static void pkttype_parse(struct xt_option_call *cb)
{
struct xt_pkttype_info *info = cb->data;
xtables_option_parse(cb);
parse_pkttype(cb->arg, info);
if (cb->invert)
info->invert = 1;
}
static void print_pkttype(const struct xt_pkttype_info *info)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(supported_types); ++i)
if(supported_types[i].pkttype==info->pkttype)
{
printf("%s", supported_types[i].name);
return;
}
printf("%d", info->pkttype); /* in case we didn't find an entry in named-packtes */
}
static void pkttype_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_pkttype_info *info = (const void *)match->data;
printf(" PKTTYPE %s= ", info->invert ? "!" : "");
print_pkttype(info);
}
static void pkttype_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_pkttype_info *info = (const void *)match->data;
printf("%s --pkt-type ", info->invert ? " !" : "");
print_pkttype(info);
}
static struct xtables_match pkttype_match = {
.family = NFPROTO_UNSPEC,
.name = "pkttype",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_pkttype_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_pkttype_info)),
.help = pkttype_help,
.print = pkttype_print,
.save = pkttype_save,
.x6_parse = pkttype_parse,
.x6_options = pkttype_opts,
};
void _init(void)
{
xtables_register_match(&pkttype_match);
}
This module matches the link-layer packet type.
.TP
[\fB!\fP] \fB\-\-pkt\-type\fP {\fBunicast\fP|\fBbroadcast\fP|\fBmulticast\fP}
/*
* Copyright (c) 2005-2013 Patrick McHardy <kaber@trash.net>
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <xtables.h>
#include <linux/netfilter/xt_policy.h>
enum {
O_DIRECTION = 0,
O_POLICY,
O_STRICT,
O_REQID,
O_SPI,
O_PROTO,
O_MODE,
O_TUNNELSRC,
O_TUNNELDST,
O_NEXT,
F_STRICT = 1 << O_STRICT,
};
static void policy_help(void)
{
printf(
"policy match options:\n"
" --dir in|out match policy applied during decapsulation/\n"
" policy to be applied during encapsulation\n"
" --pol none|ipsec match policy\n"
" --strict match entire policy instead of single element\n"
" at any position\n"
"These options may be used repeatedly, to describe policy elements:\n"
"[!] --reqid reqid match reqid\n"
"[!] --spi spi match SPI\n"
"[!] --proto proto match protocol (ah/esp/ipcomp)\n"
"[!] --mode mode match mode (transport/tunnel)\n"
"[!] --tunnel-src addr/mask match tunnel source\n"
"[!] --tunnel-dst addr/mask match tunnel destination\n"
" --next begin next element in policy\n");
}
static const struct xt_option_entry policy_opts[] = {
{.name = "dir", .id = O_DIRECTION, .type = XTTYPE_STRING},
{.name = "pol", .id = O_POLICY, .type = XTTYPE_STRING},
{.name = "strict", .id = O_STRICT, .type = XTTYPE_NONE},
{.name = "reqid", .id = O_REQID, .type = XTTYPE_UINT32,
.flags = XTOPT_MULTI | XTOPT_INVERT},
{.name = "spi", .id = O_SPI, .type = XTTYPE_UINT32,
.flags = XTOPT_MULTI | XTOPT_INVERT},
{.name = "tunnel-src", .id = O_TUNNELSRC, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_MULTI | XTOPT_INVERT},
{.name = "tunnel-dst", .id = O_TUNNELDST, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_MULTI | XTOPT_INVERT},
{.name = "proto", .id = O_PROTO, .type = XTTYPE_PROTOCOL,
.flags = XTOPT_MULTI | XTOPT_INVERT},
{.name = "mode", .id = O_MODE, .type = XTTYPE_STRING,
.flags = XTOPT_MULTI | XTOPT_INVERT},
{.name = "next", .id = O_NEXT, .type = XTTYPE_NONE,
.flags = XTOPT_MULTI, .also = F_STRICT},
XTOPT_TABLEEND,
};
static int parse_direction(const char *s)
{
if (strcmp(s, "in") == 0)
return XT_POLICY_MATCH_IN;
if (strcmp(s, "out") == 0)
return XT_POLICY_MATCH_OUT;
xtables_error(PARAMETER_PROBLEM, "policy_match: invalid dir \"%s\"", s);
}
static int parse_policy(const char *s)
{
if (strcmp(s, "none") == 0)
return XT_POLICY_MATCH_NONE;
if (strcmp(s, "ipsec") == 0)
return 0;
xtables_error(PARAMETER_PROBLEM, "policy match: invalid policy \"%s\"", s);
}
static int parse_mode(const char *s)
{
if (strcmp(s, "transport") == 0)
return XT_POLICY_MODE_TRANSPORT;
if (strcmp(s, "tunnel") == 0)
return XT_POLICY_MODE_TUNNEL;
xtables_error(PARAMETER_PROBLEM, "policy match: invalid mode \"%s\"", s);
}
static void policy_parse(struct xt_option_call *cb)
{
struct xt_policy_info *info = cb->data;
struct xt_policy_elem *e = &info->pol[info->len];
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_DIRECTION:
info->flags |= parse_direction(cb->arg);
break;
case O_POLICY:
info->flags |= parse_policy(cb->arg);
break;
case O_STRICT:
info->flags |= XT_POLICY_MATCH_STRICT;
break;
case O_REQID:
if (e->match.reqid)
xtables_error(PARAMETER_PROBLEM,
"policy match: double --reqid option");
e->match.reqid = 1;
e->invert.reqid = cb->invert;
e->reqid = cb->val.u32;
break;
case O_SPI:
if (e->match.spi)
xtables_error(PARAMETER_PROBLEM,
"policy match: double --spi option");
e->match.spi = 1;
e->invert.spi = cb->invert;
e->spi = cb->val.u32;
break;
case O_TUNNELSRC:
if (e->match.saddr)
xtables_error(PARAMETER_PROBLEM,
"policy match: double --tunnel-src option");
e->match.saddr = 1;
e->invert.saddr = cb->invert;
memcpy(&e->saddr, &cb->val.haddr, sizeof(cb->val.haddr));
memcpy(&e->smask, &cb->val.hmask, sizeof(cb->val.hmask));
break;
case O_TUNNELDST:
if (e->match.daddr)
xtables_error(PARAMETER_PROBLEM,
"policy match: double --tunnel-dst option");
e->match.daddr = 1;
e->invert.daddr = cb->invert;
memcpy(&e->daddr, &cb->val.haddr, sizeof(cb->val.haddr));
memcpy(&e->dmask, &cb->val.hmask, sizeof(cb->val.hmask));
break;
case O_PROTO:
if (e->match.proto)
xtables_error(PARAMETER_PROBLEM,
"policy match: double --proto option");
e->proto = cb->val.protocol;
if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
e->proto != IPPROTO_COMP)
xtables_error(PARAMETER_PROBLEM,
"policy match: protocol must be ah/esp/ipcomp");
e->match.proto = 1;
e->invert.proto = cb->invert;
break;
case O_MODE:
if (e->match.mode)
xtables_error(PARAMETER_PROBLEM,
"policy match: double --mode option");
e->match.mode = 1;
e->invert.mode = cb->invert;
e->mode = parse_mode(cb->arg);
break;
case O_NEXT:
if (++info->len == XT_POLICY_MAX_ELEM)
xtables_error(PARAMETER_PROBLEM,
"policy match: maximum policy depth reached");
break;
}
}
static void policy_check(struct xt_fcheck_call *cb)
{
struct xt_policy_info *info = cb->data;
const struct xt_policy_elem *e;
int i;
/*
* The old "no parameters given" check is carried out
* by testing for --dir.
*/
if (!(info->flags & (XT_POLICY_MATCH_IN | XT_POLICY_MATCH_OUT)))
xtables_error(PARAMETER_PROBLEM,
"policy match: neither --dir in nor --dir out specified");
if (info->flags & XT_POLICY_MATCH_NONE) {
if (info->flags & XT_POLICY_MATCH_STRICT)
xtables_error(PARAMETER_PROBLEM,
"policy match: policy none but --strict given");
if (info->len != 0)
xtables_error(PARAMETER_PROBLEM,
"policy match: policy none but policy given");
} else
info->len++; /* increase len by 1, no --next after last element */
/*
* This is already represented with O_NEXT requiring F_STRICT in the
* options table, but will keep this code as a comment for reference.
*
if (!(info->flags & XT_POLICY_MATCH_STRICT) && info->len > 1)
xtables_error(PARAMETER_PROBLEM,
"policy match: multiple elements but no --strict");
*/
for (i = 0; i < info->len; i++) {
e = &info->pol[i];
if (info->flags & XT_POLICY_MATCH_STRICT &&
!(e->match.reqid || e->match.spi || e->match.saddr ||
e->match.daddr || e->match.proto || e->match.mode))
xtables_error(PARAMETER_PROBLEM,
"policy match: empty policy element %u. "
"--strict is in effect, but at least one of "
"reqid, spi, tunnel-src, tunnel-dst, proto or "
"mode is required.", i);
if ((e->match.saddr || e->match.daddr)
&& ((e->mode == XT_POLICY_MODE_TUNNEL && e->invert.mode) ||
(e->mode == XT_POLICY_MODE_TRANSPORT && !e->invert.mode)))
xtables_error(PARAMETER_PROBLEM,
"policy match: --tunnel-src/--tunnel-dst "
"is only valid in tunnel mode");
}
}
static void print_mode(const char *prefix, uint8_t mode, int numeric)
{
printf(" %smode ", prefix);
switch (mode) {
case XT_POLICY_MODE_TRANSPORT:
printf("transport");
break;
case XT_POLICY_MODE_TUNNEL:
printf("tunnel");
break;
default:
printf("???");
break;
}
}
static void print_proto(const char *prefix, uint8_t proto, int numeric)
{
const struct protoent *p = NULL;
printf(" %sproto ", prefix);
if (!numeric)
p = getprotobynumber(proto);
if (p != NULL)
printf("%s", p->p_name);
else
printf("%u", proto);
}
#define PRINT_INVERT(x) \
do { \
if (x) \
printf(" !"); \
} while(0)
static void print_entry(const char *prefix, const struct xt_policy_elem *e,
bool numeric, uint8_t family)
{
if (e->match.reqid) {
PRINT_INVERT(e->invert.reqid);
printf(" %sreqid %u", prefix, e->reqid);
}
if (e->match.spi) {
PRINT_INVERT(e->invert.spi);
printf(" %sspi 0x%x", prefix, e->spi);
}
if (e->match.proto) {
PRINT_INVERT(e->invert.proto);
print_proto(prefix, e->proto, numeric);
}
if (e->match.mode) {
PRINT_INVERT(e->invert.mode);
print_mode(prefix, e->mode, numeric);
}
if (e->match.daddr) {
PRINT_INVERT(e->invert.daddr);
if (family == NFPROTO_IPV6)
printf(" %stunnel-dst %s%s", prefix,
xtables_ip6addr_to_numeric(&e->daddr.a6),
xtables_ip6mask_to_numeric(&e->dmask.a6));
else
printf(" %stunnel-dst %s%s", prefix,
xtables_ipaddr_to_numeric(&e->daddr.a4),
xtables_ipmask_to_numeric(&e->dmask.a4));
}
if (e->match.saddr) {
PRINT_INVERT(e->invert.saddr);
if (family == NFPROTO_IPV6)
printf(" %stunnel-src %s%s", prefix,
xtables_ip6addr_to_numeric(&e->saddr.a6),
xtables_ip6mask_to_numeric(&e->smask.a6));
else
printf(" %stunnel-src %s%s", prefix,
xtables_ipaddr_to_numeric(&e->saddr.a4),
xtables_ipmask_to_numeric(&e->smask.a4));
}
}
static void print_flags(const char *prefix, const struct xt_policy_info *info)
{
if (info->flags & XT_POLICY_MATCH_IN)
printf(" %sdir in", prefix);
else
printf(" %sdir out", prefix);
if (info->flags & XT_POLICY_MATCH_NONE)
printf(" %spol none", prefix);
else
printf(" %spol ipsec", prefix);
if (info->flags & XT_POLICY_MATCH_STRICT)
printf(" %sstrict", prefix);
}
static void policy4_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_policy_info *info = (void *)match->data;
unsigned int i;
printf(" policy match");
print_flags("", info);
for (i = 0; i < info->len; i++) {
if (info->len > 1)
printf(" [%u]", i);
print_entry("", &info->pol[i], numeric, NFPROTO_IPV4);
}
}
static void policy6_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_policy_info *info = (void *)match->data;
unsigned int i;
printf(" policy match");
print_flags("", info);
for (i = 0; i < info->len; i++) {
if (info->len > 1)
printf(" [%u]", i);
print_entry("", &info->pol[i], numeric, NFPROTO_IPV6);
}
}
static void policy4_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_policy_info *info = (void *)match->data;
unsigned int i;
print_flags("--", info);
for (i = 0; i < info->len; i++) {
print_entry("--", &info->pol[i], false, NFPROTO_IPV4);
if (i + 1 < info->len)
printf(" --next");
}
}
static void policy6_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_policy_info *info = (void *)match->data;
unsigned int i;
print_flags("--", info);
for (i = 0; i < info->len; i++) {
print_entry("--", &info->pol[i], false, NFPROTO_IPV6);
if (i + 1 < info->len)
printf(" --next");
}
}
static struct xtables_match policy_mt_reg[] = {
{
.name = "policy",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_policy_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_policy_info)),
.help = policy_help,
.x6_parse = policy_parse,
.x6_fcheck = policy_check,
.print = policy4_print,
.save = policy4_save,
.x6_options = policy_opts,
},
{
.name = "policy",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct xt_policy_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_policy_info)),
.help = policy_help,
.x6_parse = policy_parse,
.x6_fcheck = policy_check,
.print = policy6_print,
.save = policy6_save,
.x6_options = policy_opts,
},
};
void _init(void)
{
xtables_register_matches(policy_mt_reg, ARRAY_SIZE(policy_mt_reg));
}
This modules matches the policy used by IPsec for handling a packet.
.TP
\fB\-\-dir\fP {\fBin\fP|\fBout\fP}
Used to select whether to match the policy used for decapsulation or the
policy that will be used for encapsulation.
.B in
is valid in the
.B PREROUTING, INPUT and FORWARD
chains,
.B out
is valid in the
.B POSTROUTING, OUTPUT and FORWARD
chains.
.TP
\fB\-\-pol\fP {\fBnone\fP|\fBipsec\fP}
Matches if the packet is subject to IPsec processing. \fB\-\-pol none\fP
cannot be combined with \fB\-\-strict\fP.
.TP
\fB\-\-strict\fP
Selects whether to match the exact policy or match if any rule of
the policy matches the given policy.
.PP
For each policy element that is to be described, one can use one or more of
the following options. When \fB\-\-strict\fP is in effect, at least one must be
used per element.
.TP
[\fB!\fP] \fB\-\-reqid\fP \fIid\fP
Matches the reqid of the policy rule. The reqid can be specified with
.B setkey(8)
using
.B unique:id
as level.
.TP
[\fB!\fP] \fB\-\-spi\fP \fIspi\fP
Matches the SPI of the SA.
.TP
[\fB!\fP] \fB\-\-proto\fP {\fBah\fP|\fBesp\fP|\fBipcomp\fP}
Matches the encapsulation protocol.
.TP
[\fB!\fP] \fB\-\-mode\fP {\fBtunnel\fP|\fBtransport\fP}
Matches the encapsulation mode.
.TP
[\fB!\fP] \fB\-\-tunnel\-src\fP \fIaddr\fP[\fB/\fP\fImask\fP]
Matches the source end-point address of a tunnel mode SA.
Only valid with \fB\-\-mode tunnel\fP.
.TP
[\fB!\fP] \fB\-\-tunnel\-dst\fP \fIaddr\fP[\fB/\fP\fImask\fP]
Matches the destination end-point address of a tunnel mode SA.
Only valid with \fB\-\-mode tunnel\fP.
.TP
\fB\-\-next\fP
Start the next element in the policy specification. Can only be used with
\fB\-\-strict\fP.
/*
* Shared library add-on to iptables to add quota support
*
* Sam Johnston <samj@samj.net>
*/
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter/xt_quota.h>
enum {
O_QUOTA = 0,
};
static const struct xt_option_entry quota_opts[] = {
{.name = "quota", .id = O_QUOTA, .type = XTTYPE_UINT64,
.flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT,
XTOPT_POINTER(struct xt_quota_info, quota)},
XTOPT_TABLEEND,
};
static void quota_help(void)
{
printf("quota match options:\n"
"[!] --quota quota quota (bytes)\n");
}
static void
quota_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_quota_info *q = (const void *)match->data;
printf(" quota: %llu bytes", (unsigned long long)q->quota);
}
static void
quota_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_quota_info *q = (const void *)match->data;
if (q->flags & XT_QUOTA_INVERT)
printf("! ");
printf(" --quota %llu", (unsigned long long) q->quota);
}
static void quota_parse(struct xt_option_call *cb)
{
struct xt_quota_info *info = cb->data;
xtables_option_parse(cb);
if (cb->invert)
info->flags |= XT_QUOTA_INVERT;
}
static struct xtables_match quota_match = {
.family = NFPROTO_UNSPEC,
.name = "quota",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof (struct xt_quota_info)),
.userspacesize = offsetof(struct xt_quota_info, master),
.help = quota_help,
.print = quota_print,
.save = quota_save,
.x6_parse = quota_parse,
.x6_options = quota_opts,
};
void
_init(void)
{
xtables_register_match(&quota_match);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment