X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=extensions%2Flibipt_multiport.c;h=9f5193fa9b93d64176f16dee4f1b73e5d517a5d1;hb=6afea0b41dfbc3824956d11d960ad80097218feb;hp=c9a98b3bcb3a7c5cdd1f2fb7340eee38e938d7cb;hpb=f7b70cf9e00324b89b02de213bcd0dde7044d035;p=iptables.git diff --git a/extensions/libipt_multiport.c b/extensions/libipt_multiport.c index c9a98b3..9f5193f 100644 --- a/extensions/libipt_multiport.c +++ b/extensions/libipt_multiport.c @@ -5,7 +5,8 @@ #include #include #include -#include +/* 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; ipflags[i] = 0; + + for (cp=buffer, i=0; cp && iports[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) @@ -86,6 +144,10 @@ init(struct ipt_entry_match *m, unsigned int *nfcache) static const char * check_proto(const struct ipt_entry *entry) { + if (entry->ip.invflags & IPT_INV_PROTO) + exit_error(PARAMETER_PROBLEM, + "multiport only works with TCP or UDP"); + if (entry->ip.proto == IPPROTO_TCP) return "tcp"; else if (entry->ip.proto == IPPROTO_UDP) @@ -112,33 +174,83 @@ parse(int c, char **argv, int invert, unsigned int *flags, switch (c) { case '1': + check_inverse(argv[optind-1], &invert, &optind, 0); proto = check_proto(entry); multiinfo->count = parse_multi_ports(argv[optind-1], multiinfo->ports, 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); multiinfo->count = parse_multi_ports(argv[optind-1], multiinfo->ports, 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); multiinfo->count = parse_multi_ports(argv[optind-1], multiinfo->ports, 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; +} + +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; + 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; + 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; + break; + + default: + return 0; + } + + if (invert) + multiinfo->invert = 1; + if (*flags) exit_error(PARAMETER_PROBLEM, "multiport can only have one option"); @@ -214,6 +326,49 @@ 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; + } + + if (multiinfo->invert) + printf("! "); + + 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) { @@ -242,24 +397,76 @@ static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) printf(" "); } -static -struct iptables_match multiport -= { NULL, - "multiport", - IPTABLES_VERSION, - IPT_ALIGN(sizeof(struct ipt_multiport)), - IPT_ALIGN(sizeof(struct ipt_multiport)), - &help, - &init, - &parse, - &final_check, - &print, - &save, - opts +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; + } + + if (multiinfo->invert) + printf("! "); + + 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)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .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); }