diff options
-rw-r--r-- | extensions/libipt_multiport.c | 200 | ||||
-rw-r--r-- | include/linux/netfilter_ipv4/ipt_multiport.h | 28 |
2 files changed, 227 insertions, 1 deletions
diff --git a/extensions/libipt_multiport.c b/extensions/libipt_multiport.c index 9420d5c0..7442f94b 100644 --- a/extensions/libipt_multiport.c +++ b/extensions/libipt_multiport.c @@ -5,7 +5,8 @@ #include <stdlib.h> #include <getopt.h> #include <iptables.h> -#include <linux/netfilter_ipv4/ipt_multiport.h> +/* To ensure that iptables compiles with an old kernel */ +#include "../include/linux/netfilter_ipv4/ipt_multiport.h" /* Function which prints out usage message. */ static void @@ -20,6 +21,23 @@ help(void) " --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", +IPTABLES_VERSION); +} + +static void +help_v1(void) +{ + printf( +"multiport v%s 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", IPTABLES_VERSION); } @@ -77,6 +95,46 @@ parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto) return i; } +static void +parse_multi_ports_v1(const char *portstring, + struct ipt_multiport_v1 *multiinfo, + const char *proto) +{ + char *buffer, *cp, *next, *range; + unsigned int i; + u_int16_t m; + + buffer = strdup(portstring); + if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); + + for (i=0; i<IPT_MULTI_PORTS; i++) + multiinfo->pflags[i] = 0; + + for (cp=buffer, i=0; cp && i<IPT_MULTI_PORTS; cp=next, i++) { + next=strchr(cp, ','); + if (next) *next++='\0'; + range = strchr(cp, ':'); + if (range) { + if (i == IPT_MULTI_PORTS-1) + exit_error(PARAMETER_PROBLEM, + "too many ports specified"); + *range++ = '\0'; + } + multiinfo->ports[i] = parse_port(cp, proto); + if (range) { + multiinfo->pflags[i] = 1; + multiinfo->ports[++i] = parse_port(range, proto); + if (multiinfo->ports[i-1] >= multiinfo->ports[i]) + exit_error(PARAMETER_PROBLEM, + "invalid portrange specified"); + m <<= 1; + } + } + multiinfo->count = i; + if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified"); + free(buffer); +} + /* Initialize the match. */ static void init(struct ipt_entry_match *m, unsigned int *nfcache) @@ -153,6 +211,56 @@ parse(int c, char **argv, int invert, unsigned int *flags, return 1; } +static int +parse_v1(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + const char *proto; + struct ipt_multiport_v1 *multiinfo + = (struct ipt_multiport_v1 *)(*match)->data; + + switch (c) { + case '1': + check_inverse(argv[optind-1], &invert, &optind, 0); + proto = check_proto(entry); + parse_multi_ports_v1(argv[optind-1], multiinfo, proto); + multiinfo->flags = IPT_MULTIPORT_SOURCE; + *nfcache |= NFC_IP_SRC_PT; + break; + + case '2': + check_inverse(argv[optind-1], &invert, &optind, 0); + proto = check_proto(entry); + parse_multi_ports_v1(argv[optind-1], multiinfo, proto); + multiinfo->flags = IPT_MULTIPORT_DESTINATION; + *nfcache |= NFC_IP_DST_PT; + break; + + case '3': + check_inverse(argv[optind-1], &invert, &optind, 0); + proto = check_proto(entry); + parse_multi_ports_v1(argv[optind-1], multiinfo, proto); + multiinfo->flags = IPT_MULTIPORT_EITHER; + *nfcache |= NFC_IP_SRC_PT | NFC_IP_DST_PT; + break; + + default: + return 0; + } + + if (invert) + exit_error(PARAMETER_PROBLEM, + "multiport does not support invert"); + + if (*flags) + exit_error(PARAMETER_PROBLEM, + "multiport can only have one option"); + *flags = 1; + return 1; +} + /* Final check; must specify something. */ static void final_check(unsigned int flags) @@ -221,6 +329,46 @@ print(const struct ipt_ip *ip, printf(" "); } +static void +print_v1(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + const struct ipt_multiport_v1 *multiinfo + = (const struct ipt_multiport_v1 *)match->data; + unsigned int i; + + printf("multiport "); + + switch (multiinfo->flags) { + case IPT_MULTIPORT_SOURCE: + printf("sports "); + break; + + case IPT_MULTIPORT_DESTINATION: + printf("dports "); + break; + + case IPT_MULTIPORT_EITHER: + printf("ports "); + break; + + default: + printf("ERROR "); + break; + } + + for (i=0; i < multiinfo->count; i++) { + printf("%s", i ? "," : ""); + print_port(multiinfo->ports[i], ip->proto, numeric); + if (multiinfo->pflags[i]) { + printf(":"); + print_port(multiinfo->ports[++i], ip->proto, numeric); + } + } + printf(" "); +} + /* Saves the union ipt_matchinfo in parsable form to stdout. */ static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) { @@ -249,9 +397,42 @@ static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) printf(" "); } +static void save_v1(const struct ipt_ip *ip, + const struct ipt_entry_match *match) +{ + const struct ipt_multiport_v1 *multiinfo + = (const struct ipt_multiport_v1 *)match->data; + unsigned int i; + + switch (multiinfo->flags) { + case IPT_MULTIPORT_SOURCE: + printf("--sports "); + break; + + case IPT_MULTIPORT_DESTINATION: + printf("--dports "); + break; + + case IPT_MULTIPORT_EITHER: + printf("--ports "); + break; + } + + for (i=0; i < multiinfo->count; i++) { + printf("%s", i ? "," : ""); + print_port(multiinfo->ports[i], ip->proto, 1); + if (multiinfo->pflags[i]) { + printf(":"); + print_port(multiinfo->ports[++i], ip->proto, 1); + } + } + printf(" "); +} + static struct iptables_match multiport = { .next = NULL, .name = "multiport", + .revision = 0, .version = IPTABLES_VERSION, .size = IPT_ALIGN(sizeof(struct ipt_multiport)), .userspacesize = IPT_ALIGN(sizeof(struct ipt_multiport)), @@ -264,8 +445,25 @@ static struct iptables_match multiport = { .extra_opts = opts }; +static struct iptables_match multiport_v1 = { + .next = NULL, + .name = "multiport", + .version = IPTABLES_VERSION, + .revision = 1, + .size = IPT_ALIGN(sizeof(struct ipt_multiport_v1)), + .userspacesize = IPT_ALIGN(sizeof(struct ipt_multiport_v1)), + .help = &help_v1, + .init = &init, + .parse = &parse_v1, + .final_check = &final_check, + .print = &print_v1, + .save = &save_v1, + .extra_opts = opts +}; + void _init(void) { register_match(&multiport); + register_match(&multiport_v1); } diff --git a/include/linux/netfilter_ipv4/ipt_multiport.h b/include/linux/netfilter_ipv4/ipt_multiport.h new file mode 100644 index 00000000..3af85cf4 --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_multiport.h @@ -0,0 +1,28 @@ +#ifndef _IPT_MULTIPORT_H +#define _IPT_MULTIPORT_H + +enum ipt_multiport_flags +{ + IPT_MULTIPORT_SOURCE, + IPT_MULTIPORT_DESTINATION, + IPT_MULTIPORT_EITHER +}; + +#define IPT_MULTI_PORTS 15 + +/* Must fit inside union ipt_matchinfo: 16 bytes */ +struct ipt_multiport +{ + u_int8_t flags; /* Type of comparison */ + u_int8_t count; /* Number of ports */ + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ +}; + +struct ipt_multiport_v1 +{ + u_int8_t flags; /* Type of comparison */ + u_int8_t count; /* Number of ports */ + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ + u_int8_t pflags[IPT_MULTI_PORTS]; /* Port flags */ +}; +#endif /*_IPT_MULTIPORT_H*/ |