From 2e293f94e43325cb8cc719e27b43e647842c046d Mon Sep 17 00:00:00 2001 From: Planet-Lab Support Date: Fri, 28 Jul 2006 14:34:29 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create branch 'myplc-0_4-branch'. --- extensions/.dccp-test | 3 + extensions/libip6t_CONNMARK.c | 220 ++++++++++ extensions/libip6t_NFQUEUE.c | 114 +++++ extensions/libip6t_NFQUEUE.man | 12 + extensions/libip6t_connmark.c | 151 +++++++ extensions/libip6t_policy.c | 478 +++++++++++++++++++++ extensions/libip6t_policy.man | 48 +++ extensions/libip6t_state.c | 163 +++++++ extensions/libipt_NFQUEUE.c | 114 +++++ extensions/libipt_NFQUEUE.man | 12 + extensions/libipt_dccp.c | 399 +++++++++++++++++ extensions/libipt_dccp.man | 12 + extensions/libipt_policy.c | 436 +++++++++++++++++++ extensions/libipt_policy.man | 48 +++ extensions/libipt_string.man | 15 + include/linux/netfilter_ipv4/ipt_NFQUEUE.h | 16 + include/linux/netfilter_ipv4/ipt_policy.h | 62 +++ include/linux/netfilter_ipv6/ip6t_policy.h | 58 +++ 18 files changed, 2361 insertions(+) create mode 100755 extensions/.dccp-test create mode 100644 extensions/libip6t_CONNMARK.c create mode 100644 extensions/libip6t_NFQUEUE.c create mode 100644 extensions/libip6t_NFQUEUE.man create mode 100644 extensions/libip6t_connmark.c create mode 100644 extensions/libip6t_policy.c create mode 100644 extensions/libip6t_policy.man create mode 100644 extensions/libip6t_state.c create mode 100644 extensions/libipt_NFQUEUE.c create mode 100644 extensions/libipt_NFQUEUE.man create mode 100644 extensions/libipt_dccp.c create mode 100644 extensions/libipt_dccp.man create mode 100644 extensions/libipt_policy.c create mode 100644 extensions/libipt_policy.man create mode 100644 extensions/libipt_string.man create mode 100644 include/linux/netfilter_ipv4/ipt_NFQUEUE.h create mode 100644 include/linux/netfilter_ipv4/ipt_policy.h create mode 100644 include/linux/netfilter_ipv6/ip6t_policy.h diff --git a/extensions/.dccp-test b/extensions/.dccp-test new file mode 100755 index 0000000..5b67527 --- /dev/null +++ b/extensions/.dccp-test @@ -0,0 +1,3 @@ +#!/bin/sh +# True if dccp is applied. +[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_dccp.h ] && echo dccp diff --git a/extensions/libip6t_CONNMARK.c b/extensions/libip6t_CONNMARK.c new file mode 100644 index 0000000..9506f26 --- /dev/null +++ b/extensions/libip6t_CONNMARK.c @@ -0,0 +1,220 @@ +/* Shared library add-on to iptables to add CONNMARK target support. + * + * (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * Version 1.1 + * + * 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 + */ +#include +#include +#include +#include + +#include +#include +#include "../include/linux/netfilter_ipv4/ipt_CONNMARK.h" + +#if 0 +struct markinfo { + struct ipt_entry_target t; + struct ipt_connmark_target_info mark; +}; +#endif + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"CONNMARK target v%s options:\n" +" --set-mark value[/mask] Set conntrack mark value\n" +" --save-mark [--mask mask] Save the packet nfmark in the connection\n" +" --restore-mark [--mask mask] Restore saved nfmark value\n" +"\n", +IPTABLES_VERSION); +} + +static struct option opts[] = { + { "set-mark", 1, 0, '1' }, + { "save-mark", 0, 0, '2' }, + { "restore-mark", 0, 0, '3' }, + { "mask", 1, 0, '4' }, + { 0 } +}; + +/* Initialize the target. */ +static void +init(struct ip6t_entry_target *t, unsigned int *nfcache) +{ +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + struct ip6t_entry_target **target) +{ + struct ipt_connmark_target_info *markinfo + = (struct ipt_connmark_target_info *)(*target)->data; + + markinfo->mask = 0xffffffffUL; + + switch (c) { + char *end; + case '1': + markinfo->mode = IPT_CONNMARK_SET; + + markinfo->mark = strtoul(optarg, &end, 0); + if (*end == '/' && end[1] != '\0') + markinfo->mask = strtoul(end+1, &end, 0); + + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); + if (*flags) + exit_error(PARAMETER_PROBLEM, + "CONNMARK target: Can't specify --set-mark twice"); + *flags = 1; + break; + case '2': + markinfo->mode = IPT_CONNMARK_SAVE; + if (*flags) + exit_error(PARAMETER_PROBLEM, + "CONNMARK target: Can't specify --save-mark twice"); + *flags = 1; + break; + case '3': + markinfo->mode = IPT_CONNMARK_RESTORE; + if (*flags) + exit_error(PARAMETER_PROBLEM, + "CONNMARK target: Can't specify --restore-mark twice"); + *flags = 1; + break; + case '4': + if (!*flags) + exit_error(PARAMETER_PROBLEM, + "CONNMARK target: Can't specify --mask without a operation"); + markinfo->mask = strtoul(optarg, &end, 0); + + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad MASK value `%s'", optarg); + break; + default: + return 0; + } + + return 1; +} + +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "CONNMARK target: No operation specified"); +} + +static void +print_mark(unsigned long mark) +{ + printf("0x%lx", mark); +} + +static void +print_mask(const char *text, unsigned long mask) +{ + if (mask != 0xffffffffUL) + printf("%s0x%lx", text, mask); +} + + +/* Prints out the target info. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_target *target, + int numeric) +{ + const struct ipt_connmark_target_info *markinfo = + (const struct ipt_connmark_target_info *)target->data; + switch (markinfo->mode) { + case IPT_CONNMARK_SET: + printf("CONNMARK set "); + print_mark(markinfo->mark); + print_mask("/", markinfo->mask); + printf(" "); + break; + case IPT_CONNMARK_SAVE: + printf("CONNMARK save "); + print_mask("mask ", markinfo->mask); + printf(" "); + break; + case IPT_CONNMARK_RESTORE: + printf("CONNMARK restore "); + print_mask("mask ", markinfo->mask); + break; + default: + printf("ERROR: UNKNOWN CONNMARK MODE "); + break; + } +} + +/* Saves the target into in parsable form to stdout. */ +static void +save(const struct ip6t_ip6 *ip, const struct ip6t_entry_target *target) +{ + const struct ipt_connmark_target_info *markinfo = + (const struct ipt_connmark_target_info *)target->data; + + switch (markinfo->mode) { + case IPT_CONNMARK_SET: + printf("--set-mark "); + print_mark(markinfo->mark); + print_mask("/", markinfo->mask); + printf(" "); + break; + case IPT_CONNMARK_SAVE: + printf("--save-mark "); + print_mask("--mask ", markinfo->mask); + break; + case IPT_CONNMARK_RESTORE: + printf("--restore-mark "); + print_mask("--mask ", markinfo->mask); + break; + default: + printf("ERROR: UNKNOWN CONNMARK MODE "); + break; + } +} + +static struct ip6tables_target connmark_target = { + .name = "CONNMARK", + .version = IPTABLES_VERSION, + .size = IP6T_ALIGN(sizeof(struct ipt_connmark_target_info)), + .userspacesize = IP6T_ALIGN(sizeof(struct ipt_connmark_target_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + register_target6(&connmark_target); +} diff --git a/extensions/libip6t_NFQUEUE.c b/extensions/libip6t_NFQUEUE.c new file mode 100644 index 0000000..e1964af --- /dev/null +++ b/extensions/libip6t_NFQUEUE.c @@ -0,0 +1,114 @@ +/* Shared library add-on to ip666666tables for NFQ + * + * (C) 2005 by Harald Welte + * + * This program is distributed under the terms of GNU GPL v2, 1991 + * + */ +#include +#include +#include +#include + +#include +#include +#include + +static void init(struct ip6t_entry_target *t, unsigned int *nfcache) +{ +} + +static void help(void) +{ + printf( +"NFQUEUE target options\n" +" --queue-num value Send packet to QUEUE number .\n" +" Valid queue numbers are 0-65535\n" +); +} + +static struct option opts[] = { + { "queue-num", 1, 0, 'F' }, + { 0 } +}; + +static void +parse_num(const char *s, struct ipt_NFQ_info *tinfo) +{ + unsigned int num; + + if (string_to_number(s, 0, 65535, &num) == -1) + exit_error(PARAMETER_PROBLEM, + "Invalid queue number `%s'\n", s); + + tinfo->queuenum = num & 0xffff; + return; +} + +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + struct ip6t_entry_target **target) +{ + struct ipt_NFQ_info *tinfo + = (struct ipt_NFQ_info *)(*target)->data; + + switch (c) { + case 'F': + if (*flags) + exit_error(PARAMETER_PROBLEM, "NFQUEUE target: " + "Only use --queue-num ONCE!"); + parse_num(optarg, tinfo); + break; + default: + return 0; + } + + return 1; +} + +static void +final_check(unsigned int flags) +{ +} + +/* Prints out the targinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_target *target, + int numeric) +{ + const struct ipt_NFQ_info *tinfo = + (const struct ipt_NFQ_info *)target->data; + printf("NFQUEUE num %u", tinfo->queuenum); +} + +/* Saves the union ip6t_targinfo in parsable form to stdout. */ +static void +save(const struct ip6t_ip6 *ip, const struct ip6t_entry_target *target) +{ + const struct ipt_NFQ_info *tinfo = + (const struct ipt_NFQ_info *)target->data; + + printf("--queue-num %u ", tinfo->queuenum); +} + +static struct ip6tables_target nfqueue = { + .next = NULL, + .name = "NFQUEUE", + .version = IPTABLES_VERSION, + .size = IP6T_ALIGN(sizeof(struct ipt_NFQ_info)), + .userspacesize = IP6T_ALIGN(sizeof(struct ipt_NFQ_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + register_target6(&nfqueue); +} diff --git a/extensions/libip6t_NFQUEUE.man b/extensions/libip6t_NFQUEUE.man new file mode 100644 index 0000000..c4e9d11 --- /dev/null +++ b/extensions/libip6t_NFQUEUE.man @@ -0,0 +1,12 @@ +This target is an extension of the QUEUE target. As opposed to QUEUE, it allows +you to put a packet into any specific queue, identified by its 16-bit queue +number. +.TP +.BR "--queue-num " "\fIvalue" +This specifies the QUEUE number to use. Valud queue numbers are 0 to 65535. The default value is 0. +.TP +It can only be used with Kernel versions 2.6.14 or later, since it requires +the +.B +nfnetlink_queue +kernel support. diff --git a/extensions/libip6t_connmark.c b/extensions/libip6t_connmark.c new file mode 100644 index 0000000..419da30 --- /dev/null +++ b/extensions/libip6t_connmark.c @@ -0,0 +1,151 @@ +/* Shared library add-on to iptables to add connmark matching support. + * + * (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * Version 1.1 + * + * 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 + */ +#include +#include +#include +#include +#include + +#include +#include "../include/linux/netfilter_ipv4/ipt_connmark.h" + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"CONNMARK match v%s options:\n" +"[!] --mark value[/mask] Match nfmark value with optional mask\n" +"\n", +IPTABLES_VERSION); +} + +static struct option opts[] = { + { "mark", 1, 0, '1' }, + {0} +}; + +/* Initialize the match. */ +static void +init(struct ip6t_entry_match *m, unsigned int *nfcache) +{ + /* Can't cache this. */ + *nfcache |= NFC_UNKNOWN; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ipt_connmark_info *markinfo = (struct ipt_connmark_info *)(*match)->data; + + switch (c) { + char *end; + case '1': + check_inverse(optarg, &invert, &optind, 0); + + markinfo->mark = strtoul(optarg, &end, 0); + markinfo->mask = 0xffffffffUL; + + if (*end == '/') + markinfo->mask = strtoul(end+1, &end, 0); + + if (*end != '\0' || end == optarg) + exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg); + if (invert) + markinfo->invert = 1; + *flags = 1; + break; + + default: + return 0; + } + return 1; +} + +static void +print_mark(unsigned long mark, unsigned long mask, int numeric) +{ + if(mask != 0xffffffffUL) + printf("0x%lx/0x%lx ", mark, mask); + else + printf("0x%lx ", mark); +} + +/* Final check; must have specified --mark. */ +static void +final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, + "MARK match: You must specify `--mark'"); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, + int numeric) +{ + struct ipt_connmark_info *info = (struct ipt_connmark_info *)match->data; + + printf("CONNMARK match "); + if (info->invert) + printf("!"); + print_mark(info->mark, info->mask, numeric); +} + +/* Saves the matchinfo in parsable form to stdout. */ +static void +save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + struct ipt_connmark_info *info = (struct ipt_connmark_info *)match->data; + + if (info->invert) + printf("! "); + + printf("--mark "); + print_mark(info->mark, info->mask, 0); +} + +static struct ip6tables_match connmark_match = { + .name = "connmark", + .version = IPTABLES_VERSION, + .size = IP6T_ALIGN(sizeof(struct ipt_connmark_info)), + .userspacesize = IP6T_ALIGN(sizeof(struct ipt_connmark_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + register_match6(&connmark_match); +} diff --git a/extensions/libip6t_policy.c b/extensions/libip6t_policy.c new file mode 100644 index 0000000..2f4453e --- /dev/null +++ b/extensions/libip6t_policy.c @@ -0,0 +1,478 @@ +/* Shared library add-on to iptables to add policy support. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../include/linux/netfilter_ipv6/ip6t_policy.h" + +/* + * HACK: global pointer to current matchinfo for making + * final checks and adjustments in final_check. + */ +static struct ip6t_policy_info *policy_info; + +static void help(void) +{ + printf( +"policy v%s 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" +"[!] --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/masklen match tunnel source\n" +"[!] --tunnel-dst addr/masklen match tunnel destination\n" +" --next begin next element in policy\n", + IPTABLES_VERSION); +} + +static struct option opts[] = +{ + { + .name = "dir", + .has_arg = 1, + .val = '1', + }, + { + .name = "pol", + .has_arg = 1, + .val = '2', + }, + { + .name = "strict", + .val = '3' + }, + { + .name = "reqid", + .has_arg = 1, + .val = '4', + }, + { + .name = "spi", + .has_arg = 1, + .val = '5' + }, + { + .name = "tunnel-src", + .has_arg = 1, + .val = '6' + }, + { + .name = "tunnel-dst", + .has_arg = 1, + .val = '7' + }, + { + .name = "proto", + .has_arg = 1, + .val = '8' + }, + { + .name = "mode", + .has_arg = 1, + .val = '9' + }, + { + .name = "next", + .val = 'a' + }, + { } +}; + +/* FIXME - Duplicated code from ip6tables.c */ +/* Duplicated to stop too many changes in other files .... */ +static void +in6addrcpy(struct in6_addr *dst, struct in6_addr *src) +{ + memcpy(dst, src, sizeof(struct in6_addr)); + /* dst->s6_addr = src->s6_addr; */ +} + +static char * +addr_to_numeric(const struct in6_addr *addrp) +{ + /* 0000:0000:0000:0000:0000:000.000.000.000 + * 0000:0000:0000:0000:0000:0000:0000:0000 */ + static char buf[50+1]; + return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); +} + +static char * +mask_to_numeric(const struct in6_addr *addrp) +{ + static char buf[50+2]; + int l = ipv6_prefix_length(addrp); + if (l == -1) { + strcpy(buf, "/"); + strcat(buf, addr_to_numeric(addrp)); + return buf; + } + sprintf(buf, "/%d", l); + return buf; +} + +/* These should be in include/ip6tables.h... */ +extern u_int16_t parse_protocol(const char *s); +extern void parse_hostnetworkmask(const char *name, struct in6_addr **addrpp, + struct in6_addr *maskp, unsigned int *naddrs); + +/* End duplicated code from ip6tables.c */ + +static void init(struct ip6t_entry_match *m, unsigned int *nfcache) +{ + *nfcache |= NFC_UNKNOWN; +} + +static int parse_direction(char *s) +{ + if (strcmp(s, "in") == 0) + return IP6T_POLICY_MATCH_IN; + if (strcmp(s, "out") == 0) + return IP6T_POLICY_MATCH_OUT; + exit_error(PARAMETER_PROBLEM, "policy_match: invalid dir `%s'", s); +} + +static int parse_policy(char *s) +{ + if (strcmp(s, "none") == 0) + return IP6T_POLICY_MATCH_NONE; + if (strcmp(s, "ipsec") == 0) + return 0; + exit_error(PARAMETER_PROBLEM, "policy match: invalid policy `%s'", s); +} + +static int parse_mode(char *s) +{ + if (strcmp(s, "transport") == 0) + return IP6T_POLICY_MODE_TRANSPORT; + if (strcmp(s, "tunnel") == 0) + return IP6T_POLICY_MODE_TUNNEL; + exit_error(PARAMETER_PROBLEM, "policy match: invalid mode `%s'", s); +} + +static int parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ip6t_policy_info *info = (void *)(*match)->data; + struct ip6t_policy_elem *e = &info->pol[info->len]; + struct in6_addr *addr = NULL, mask; + unsigned int naddr = 0; + int mode; + + check_inverse(optarg, &invert, &optind, 0); + + switch (c) { + case '1': + if (info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT)) + exit_error(PARAMETER_PROBLEM, + "policy match: double --dir option"); + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --dir option"); + + info->flags |= parse_direction(argv[optind-1]); + break; + case '2': + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --policy option"); + + info->flags |= parse_policy(argv[optind-1]); + break; + case '3': + if (info->flags & IP6T_POLICY_MATCH_STRICT) + exit_error(PARAMETER_PROBLEM, + "policy match: double --strict option"); + + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --strict option"); + + info->flags |= IP6T_POLICY_MATCH_STRICT; + break; + case '4': + if (e->match.reqid) + exit_error(PARAMETER_PROBLEM, + "policy match: double --reqid option"); + + e->match.reqid = 1; + e->invert.reqid = invert; + e->reqid = strtol(argv[optind-1], NULL, 10); + break; + case '5': + if (e->match.spi) + exit_error(PARAMETER_PROBLEM, + "policy match: double --spi option"); + + e->match.spi = 1; + e->invert.spi = invert; + e->spi = strtol(argv[optind-1], NULL, 0x10); + break; + case '6': + if (e->match.saddr) + exit_error(PARAMETER_PROBLEM, + "policy match: double --tunnel-src option"); + + parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); + if (naddr > 1) + exit_error(PARAMETER_PROBLEM, + "policy match: name resolves to multiple IPs"); + + e->match.saddr = 1; + e->invert.saddr = invert; + in6addrcpy(&e->saddr.a6, addr); + in6addrcpy(&e->smask.a6, &mask); + break; + case '7': + if (e->match.daddr) + exit_error(PARAMETER_PROBLEM, + "policy match: double --tunnel-dst option"); + + parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); + if (naddr > 1) + exit_error(PARAMETER_PROBLEM, + "policy match: name resolves to multiple IPs"); + + e->match.daddr = 1; + e->invert.daddr = invert; + in6addrcpy(&e->daddr.a6, addr); + in6addrcpy(&e->dmask.a6, &mask); + break; + case '8': + if (e->match.proto) + exit_error(PARAMETER_PROBLEM, + "policy match: double --proto option"); + + e->proto = parse_protocol(argv[optind-1]); + if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP && + e->proto != IPPROTO_COMP) + exit_error(PARAMETER_PROBLEM, + "policy match: protocol must ah/esp/ipcomp"); + e->match.proto = 1; + e->invert.proto = invert; + break; + case '9': + if (e->match.mode) + exit_error(PARAMETER_PROBLEM, + "policy match: double --mode option"); + + mode = parse_mode(argv[optind-1]); + e->match.mode = 1; + e->invert.mode = invert; + e->mode = mode; + break; + case 'a': + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --next option"); + + if (++info->len == IP6T_POLICY_MAX_ELEM) + exit_error(PARAMETER_PROBLEM, + "policy match: maximum policy depth reached"); + break; + default: + return 0; + } + + policy_info = info; + return 1; +} + +static void final_check(unsigned int flags) +{ + struct ip6t_policy_info *info = policy_info; + struct ip6t_policy_elem *e; + int i; + + if (info == NULL) + exit_error(PARAMETER_PROBLEM, + "policy match: no parameters given"); + + if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) + exit_error(PARAMETER_PROBLEM, + "policy match: neither --in nor --out specified"); + + if (info->flags & IP6T_POLICY_MATCH_NONE) { + if (info->flags & IP6T_POLICY_MATCH_STRICT) + exit_error(PARAMETER_PROBLEM, + "policy match: policy none but --strict given"); + + if (info->len != 0) + exit_error(PARAMETER_PROBLEM, + "policy match: policy none but policy given"); + } else + info->len++; /* increase len by 1, no --next after last element */ + + if (!(info->flags & IP6T_POLICY_MATCH_STRICT) && info->len > 1) + exit_error(PARAMETER_PROBLEM, + "policy match: multiple elements but no --strict"); + + for (i = 0; i < info->len; i++) { + e = &info->pol[i]; + + if (info->flags & IP6T_POLICY_MATCH_STRICT && + !(e->match.reqid || e->match.spi || e->match.saddr || + e->match.daddr || e->match.proto || e->match.mode)) + exit_error(PARAMETER_PROBLEM, + "policy match: empty policy element"); + + if ((e->match.saddr || e->match.daddr) + && ((e->mode == IP6T_POLICY_MODE_TUNNEL && e->invert.mode) || + (e->mode == IP6T_POLICY_MODE_TRANSPORT && !e->invert.mode))) + exit_error(PARAMETER_PROBLEM, + "policy match: --tunnel-src/--tunnel-dst " + "is only valid in tunnel mode"); + } +} + +static void print_mode(char *prefix, u_int8_t mode, int numeric) +{ + printf("%smode ", prefix); + + switch (mode) { + case IP6T_POLICY_MODE_TRANSPORT: + printf("transport "); + break; + case IP6T_POLICY_MODE_TUNNEL: + printf("tunnel "); + break; + default: + printf("??? "); + break; + } +} + +static void print_proto(char *prefix, u_int8_t proto, int numeric) +{ + 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(char *prefix, const struct ip6t_policy_elem *e, + int numeric) +{ + 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); + printf("%stunnel-dst %s%s ", prefix, + addr_to_numeric((struct in6_addr *)&e->daddr), + mask_to_numeric((struct in6_addr *)&e->dmask)); + } + if (e->match.saddr) { + PRINT_INVERT(e->invert.saddr); + printf("%stunnel-src %s%s ", prefix, + addr_to_numeric((struct in6_addr *)&e->saddr), + mask_to_numeric((struct in6_addr *)&e->smask)); + } +} + +static void print_flags(char *prefix, const struct ip6t_policy_info *info) +{ + if (info->flags & IP6T_POLICY_MATCH_IN) + printf("%sdir in ", prefix); + else + printf("%sdir out ", prefix); + + if (info->flags & IP6T_POLICY_MATCH_NONE) + printf("%spol none ", prefix); + else + printf("%spol ipsec ", prefix); + + if (info->flags & IP6T_POLICY_MATCH_STRICT) + printf("%sstrict ", prefix); +} + +static void print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, + int numeric) +{ + const struct ip6t_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); + } + + printf("\n"); +} + +static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + const struct ip6t_policy_info *info = (void *)match->data; + unsigned int i; + + print_flags("--", info); + for (i = 0; i < info->len; i++) { + print_entry("--", &info->pol[i], 0); + if (i + 1 < info->len) + printf("--next "); + } +} + +struct ip6tables_match policy = { + .name = "policy", + .version = IPTABLES_VERSION, + .size = IP6T_ALIGN(sizeof(struct ip6t_policy_info)), + .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_policy_info)), + .help = help, + .init = init, + .parse = parse, + .final_check = final_check, + .print = print, + .save = save, + .extra_opts = opts +}; + +void _init(void) +{ + register_match6(&policy); +} diff --git a/extensions/libip6t_policy.man b/extensions/libip6t_policy.man new file mode 100644 index 0000000..eed163e --- /dev/null +++ b/extensions/libip6t_policy.man @@ -0,0 +1,48 @@ +This modules matches the policy used by IPsec for handling a packet. +.TP +.BI "--dir " "in|out" +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 +.BI "--pol " "none|ipsec" +Matches if the packet is subject to IPsec processing. +.TP +.BI "--strict" +Selects whether to match the exact policy or match if any rule of +the policy matches the given policy. +.TP +.BI "--reqid " "id" +Matches the reqid of the policy rule. The reqid can be specified with +.B setkey(8) +using +.B unique:id +as level. +.TP +.BI "--spi " "spi" +Matches the SPI of the SA. +.TP +.BI "--proto " "ah|esp|ipcomp" +Matches the encapsulation protocol. +.TP +.BI "--mode " "tunnel|transport" +Matches the encapsulation mode. +.TP +.BI "--tunnel-src " "addr[/mask]" +Matches the source end-point address of a tunnel mode SA. +Only valid with --mode tunnel. +.TP +.BI "--tunnel-dst " "addr[/mask]" +Matches the destination end-point address of a tunnel mode SA. +Only valid with --mode tunnel. +.TP +.BI "--next" +Start the next element in the policy specification. Can only be used with +--strict diff --git a/extensions/libip6t_state.c b/extensions/libip6t_state.c new file mode 100644 index 0000000..84fd1a4 --- /dev/null +++ b/extensions/libip6t_state.c @@ -0,0 +1,163 @@ +/* Ugly hack to make state matching for ipv6 work before iptables-1.4.x is finished */ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef IPT_STATE_UNTRACKED +#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1)) +#endif + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"state v%s options:\n" +" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n" +" State(s) to match\n" +"\n", IPTABLES_VERSION); +} + +static struct option opts[] = { + { "state", 1, 0, '1' }, + {0} +}; + +static int +parse_state(const char *state, size_t strlen, struct ipt_state_info *sinfo) +{ + if (strncasecmp(state, "INVALID", strlen) == 0) + sinfo->statemask |= IPT_STATE_INVALID; + else if (strncasecmp(state, "NEW", strlen) == 0) + sinfo->statemask |= IPT_STATE_BIT(IP_CT_NEW); + else if (strncasecmp(state, "ESTABLISHED", strlen) == 0) + sinfo->statemask |= IPT_STATE_BIT(IP_CT_ESTABLISHED); + else if (strncasecmp(state, "RELATED", strlen) == 0) + sinfo->statemask |= IPT_STATE_BIT(IP_CT_RELATED); + else if (strncasecmp(state, "UNTRACKED", strlen) == 0) + sinfo->statemask |= IPT_STATE_UNTRACKED; + else + return 0; + return 1; +} + +static void +parse_states(const char *arg, struct ipt_state_info *sinfo) +{ + const char *comma; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg || !parse_state(arg, comma-arg, sinfo)) + exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg); + arg = comma+1; + } + + if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo)) + exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg); +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ipt_state_info *sinfo = (struct ipt_state_info *)(*match)->data; + + switch (c) { + case '1': + check_inverse(optarg, &invert, &optind, 0); + + parse_states(argv[optind-1], sinfo); + if (invert) + sinfo->statemask = ~sinfo->statemask; + *flags = 1; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; must have specified --state. */ +static void final_check(unsigned int flags) +{ + if (!flags) + exit_error(PARAMETER_PROBLEM, "You must specify `--state'"); +} + +static void print_state(unsigned int statemask) +{ + const char *sep = ""; + + if (statemask & IPT_STATE_INVALID) { + printf("%sINVALID", sep); + sep = ","; + } + if (statemask & IPT_STATE_BIT(IP_CT_NEW)) { + printf("%sNEW", sep); + sep = ","; + } + if (statemask & IPT_STATE_BIT(IP_CT_RELATED)) { + printf("%sRELATED", sep); + sep = ","; + } + if (statemask & IPT_STATE_BIT(IP_CT_ESTABLISHED)) { + printf("%sESTABLISHED", sep); + sep = ","; + } + if (statemask & IPT_STATE_UNTRACKED) { + printf("%sUNTRACKED", sep); + sep = ","; + } + printf(" "); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, + int numeric) +{ + struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data; + + printf("state "); + print_state(sinfo->statemask); +} + +/* Saves the matchinfo in parsable form to stdout. */ +static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data; + + printf("--state "); + print_state(sinfo->statemask); +} + +static struct ip6tables_match state = { + .next = NULL, + .name = "state", + .version = IPTABLES_VERSION, + .size = IP6T_ALIGN(sizeof(struct ipt_state_info)), + .userspacesize = IP6T_ALIGN(sizeof(struct ipt_state_info)), + .help = &help, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + register_match6(&state); +} diff --git a/extensions/libipt_NFQUEUE.c b/extensions/libipt_NFQUEUE.c new file mode 100644 index 0000000..bc4e82f --- /dev/null +++ b/extensions/libipt_NFQUEUE.c @@ -0,0 +1,114 @@ +/* Shared library add-on to iptables for NFQ + * + * (C) 2005 by Harald Welte + * + * This program is distributed under the terms of GNU GPL v2, 1991 + * + */ +#include +#include +#include +#include + +#include +#include +#include + +static void init(struct ipt_entry_target *t, unsigned int *nfcache) +{ +} + +static void help(void) +{ + printf( +"NFQUEUE target options\n" +" --queue-num value Send packet to QUEUE number .\n" +" Valid queue numbers are 0-65535\n" +); +} + +static struct option opts[] = { + { "queue-num", 1, 0, 'F' }, + { 0 } +}; + +static void +parse_num(const char *s, struct ipt_NFQ_info *tinfo) +{ + unsigned int num; + + if (string_to_number(s, 0, 65535, &num) == -1) + exit_error(PARAMETER_PROBLEM, + "Invalid queue number `%s'\n", s); + + tinfo->queuenum = num & 0xffff; + return; +} + +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + struct ipt_entry_target **target) +{ + struct ipt_NFQ_info *tinfo + = (struct ipt_NFQ_info *)(*target)->data; + + switch (c) { + case 'F': + if (*flags) + exit_error(PARAMETER_PROBLEM, "NFQUEUE target: " + "Only use --queue-num ONCE!"); + parse_num(optarg, tinfo); + break; + default: + return 0; + } + + return 1; +} + +static void +final_check(unsigned int flags) +{ +} + +/* Prints out the targinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_target *target, + int numeric) +{ + const struct ipt_NFQ_info *tinfo = + (const struct ipt_NFQ_info *)target->data; + printf("NFQUEUE num %u", tinfo->queuenum); +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, const struct ipt_entry_target *target) +{ + const struct ipt_NFQ_info *tinfo = + (const struct ipt_NFQ_info *)target->data; + + printf("--queue-num %u ", tinfo->queuenum); +} + +static struct iptables_target nfqueue = { + .next = NULL, + .name = "NFQUEUE", + .version = IPTABLES_VERSION, + .size = IPT_ALIGN(sizeof(struct ipt_NFQ_info)), + .userspacesize = IPT_ALIGN(sizeof(struct ipt_NFQ_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + register_target(&nfqueue); +} diff --git a/extensions/libipt_NFQUEUE.man b/extensions/libipt_NFQUEUE.man new file mode 100644 index 0000000..c4e9d11 --- /dev/null +++ b/extensions/libipt_NFQUEUE.man @@ -0,0 +1,12 @@ +This target is an extension of the QUEUE target. As opposed to QUEUE, it allows +you to put a packet into any specific queue, identified by its 16-bit queue +number. +.TP +.BR "--queue-num " "\fIvalue" +This specifies the QUEUE number to use. Valud queue numbers are 0 to 65535. The default value is 0. +.TP +It can only be used with Kernel versions 2.6.14 or later, since it requires +the +.B +nfnetlink_queue +kernel support. diff --git a/extensions/libipt_dccp.c b/extensions/libipt_dccp.c new file mode 100644 index 0000000..af1d20e --- /dev/null +++ b/extensions/libipt_dccp.c @@ -0,0 +1,399 @@ +/* Shared library add-on to iptables for DCCP matching + * + * (C) 2005 by Harald Welte + * + * This program is distributed under the terms of GNU GPL v2, 1991 + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +#define DEBUGP(format, first...) printf(format, ##first) +#define static +#else +#define DEBUGP(format, fist...) +#endif + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, + unsigned int *nfcache) +{ + struct ipt_dccp_info *einfo = (struct ipt_dccp_info *)m->data; + + memset(einfo, 0, sizeof(struct ipt_dccp_info)); +} + +static void help(void) +{ + printf( +"DCCP match v%s options\n" +" --source-port [!] port[:port] match source port(s)\n" +" --sport ...\n" +" --destination-port [!] port[:port] match destination port(s)\n" +" --dport ...\n" +, + IPTABLES_VERSION); +} + +static struct option opts[] = { + { .name = "source-port", .has_arg = 1, .flag = 0, .val = '1' }, + { .name = "sport", .has_arg = 1, .flag = 0, .val = '1' }, + { .name = "destination-port", .has_arg = 1, .flag = 0, .val = '2' }, + { .name = "dport", .has_arg = 1, .flag = 0, .val = '2' }, + { .name = "dccp-types", .has_arg = 1, .flag = 0, .val = '3' }, + { .name = "dccp-option", .has_arg = 1, .flag = 0, .val = '4' }, + { .name = 0 } +}; + +static int +service_to_port(const char *name) +{ + struct servent *service; + + if ((service = getservbyname(name, "dccp")) != NULL) + return ntohs((unsigned short) service->s_port); + + return -1; +} + +static u_int16_t +parse_dccp_port(const char *port) +{ + unsigned int portnum; + + DEBUGP("%s\n", port); + if (string_to_number(port, 0, 65535, &portnum) != -1 || + (portnum = service_to_port(port)) != -1) + return (u_int16_t)portnum; + + exit_error(PARAMETER_PROBLEM, + "invalid DCCP port/service `%s' specified", port); +} + +static void +parse_dccp_ports(const char *portstring, + u_int16_t *ports) +{ + char *buffer; + char *cp; + + buffer = strdup(portstring); + DEBUGP("%s\n", portstring); + if ((cp = strchr(buffer, ':')) == NULL) { + ports[0] = ports[1] = parse_dccp_port(buffer); + } + else { + *cp = '\0'; + cp++; + + ports[0] = buffer[0] ? parse_dccp_port(buffer) : 0; + ports[1] = cp[0] ? parse_dccp_port(cp) : 0xFFFF; + + if (ports[0] > ports[1]) + exit_error(PARAMETER_PROBLEM, + "invalid portrange (min > max)"); + } + free(buffer); +} + +static char *dccp_pkt_types[] = { + [DCCP_PKT_REQUEST] = "REQUEST", + [DCCP_PKT_RESPONSE] = "RESPONSE", + [DCCP_PKT_DATA] = "DATA", + [DCCP_PKT_ACK] = "ACK", + [DCCP_PKT_DATAACK] = "DATAACK", + [DCCP_PKT_CLOSEREQ] = "CLOSEREQ", + [DCCP_PKT_CLOSE] = "CLOSE", + [DCCP_PKT_RESET] = "RESET", + [DCCP_PKT_SYNC] = "SYNC", + [DCCP_PKT_SYNCACK] = "SYNCACK", + [DCCP_PKT_INVALID] = "INVALID", +}; + +static u_int16_t +parse_dccp_types(const char *typestring) +{ + u_int16_t typemask = 0; + char *ptr, *buffer; + + buffer = strdup(typestring); + + for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { + unsigned int i; + for (i = 0; i < sizeof(dccp_pkt_types)/sizeof(char *); i++) { + if (!strcasecmp(dccp_pkt_types[i], ptr)) { + typemask |= (1 << i); + break; + } + } + if (i == sizeof(dccp_pkt_types)/sizeof(char *)) + exit_error(PARAMETER_PROBLEM, + "Unknown DCCP type `%s'", ptr); + } + + free(buffer); + return typemask; +} + +static u_int8_t parse_dccp_option(char *optstring) +{ + unsigned int ret; + + if (string_to_number(optstring, 1, 255, &ret) == -1) + exit_error(PARAMETER_PROBLEM, "Bad DCCP option `%s'", + optstring); + + return (u_int8_t)ret; +} + +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_dccp_info *einfo + = (struct ipt_dccp_info *)(*match)->data; + + switch (c) { + case '1': + if (*flags & IPT_DCCP_SRC_PORTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--source-port' allowed"); + einfo->flags |= IPT_DCCP_SRC_PORTS; + check_inverse(optarg, &invert, &optind, 0); + parse_dccp_ports(argv[optind-1], einfo->spts); + if (invert) + einfo->invflags |= IPT_DCCP_SRC_PORTS; + *flags |= IPT_DCCP_SRC_PORTS; + break; + + case '2': + if (*flags & IPT_DCCP_DEST_PORTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--destination-port' allowed"); + einfo->flags |= IPT_DCCP_DEST_PORTS; + check_inverse(optarg, &invert, &optind, 0); + parse_dccp_ports(argv[optind-1], einfo->dpts); + if (invert) + einfo->invflags |= IPT_DCCP_DEST_PORTS; + *flags |= IPT_DCCP_DEST_PORTS; + break; + + case '3': + if (*flags & IPT_DCCP_TYPE) + exit_error(PARAMETER_PROBLEM, + "Only one `--dccp-types' allowed"); + einfo->flags |= IPT_DCCP_TYPE; + check_inverse(optarg, &invert, &optind, 0); + einfo->typemask = parse_dccp_types(argv[optind-1]); + if (invert) + einfo->invflags |= IPT_DCCP_TYPE; + *flags |= IPT_DCCP_TYPE; + break; + + case '4': + if (*flags & IPT_DCCP_OPTION) + exit_error(PARAMETER_PROBLEM, + "Only one `--dccp-option' allowed"); + einfo->flags |= IPT_DCCP_OPTION; + check_inverse(optarg, &invert, &optind, 0); + einfo->option = parse_dccp_option(argv[optind-1]); + if (invert) + einfo->invflags |= IPT_DCCP_OPTION; + *flags |= IPT_DCCP_OPTION; + break; + default: + return 0; + } + return 1; +} + +static void +final_check(unsigned int flags) +{ +} + +static char * +port_to_service(int port) +{ + struct servent *service; + + if ((service = getservbyport(htons(port), "dccp"))) + return service->s_name; + + return NULL; +} + +static void +print_port(u_int16_t port, int numeric) +{ + char *service; + + if (numeric || (service = port_to_service(port)) == NULL) + printf("%u", port); + else + printf("%s", service); +} + +static void +print_ports(const char *name, u_int16_t min, u_int16_t max, + int invert, int numeric) +{ + const char *inv = invert ? "!" : ""; + + if (min != 0 || max != 0xFFFF || invert) { + printf("%s", name); + if (min == max) { + printf(":%s", inv); + print_port(min, numeric); + } else { + printf("s:%s", inv); + print_port(min, numeric); + printf(":"); + print_port(max, numeric); + } + printf(" "); + } +} + +static void +print_types(u_int16_t types, int inverted, int numeric) +{ + int have_type = 0; + + if (inverted) + printf("! "); + + while (types) { + unsigned int i; + + for (i = 0; !(types & (1 << i)); i++); + + if (have_type) + printf(","); + else + have_type = 1; + + if (numeric) + printf("%u", i); + else + printf("%s", dccp_pkt_types[i]); + + types &= ~(1 << i); + } +} + +static void +print_option(u_int8_t option, int invert, int numeric) +{ + if (option || invert) + printf("option=%s%u ", invert ? "!" : "", option); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + const struct ipt_dccp_info *einfo = + (const struct ipt_dccp_info *)match->data; + + printf("dccp "); + + if (einfo->flags & IPT_DCCP_SRC_PORTS) { + print_ports("spt", einfo->spts[0], einfo->spts[1], + einfo->invflags & IPT_DCCP_SRC_PORTS, + numeric); + } + + if (einfo->flags & IPT_DCCP_DEST_PORTS) { + print_ports("dpt", einfo->dpts[0], einfo->dpts[1], + einfo->invflags & IPT_DCCP_DEST_PORTS, + numeric); + } + + if (einfo->flags & IPT_DCCP_TYPE) { + print_types(einfo->typemask, + einfo->invflags & IPT_DCCP_TYPE, + numeric); + } + + if (einfo->flags & IPT_DCCP_OPTION) { + print_option(einfo->option, + einfo->invflags & IPT_DCCP_OPTION, numeric); + } +} + +/* Saves the union ipt_matchinfo in parsable form to stdout. */ +static void +save(const struct ipt_ip *ip, + const struct ipt_entry_match *match) +{ + const struct ipt_dccp_info *einfo = + (const struct ipt_dccp_info *)match->data; + + if (einfo->flags & IPT_DCCP_SRC_PORTS) { + if (einfo->invflags & IPT_DCCP_SRC_PORTS) + printf("! "); + if (einfo->spts[0] != einfo->spts[1]) + printf("--sport %u:%u ", + einfo->spts[0], einfo->spts[1]); + else + printf("--sport %u ", einfo->spts[0]); + } + + if (einfo->flags & IPT_DCCP_DEST_PORTS) { + if (einfo->invflags & IPT_DCCP_DEST_PORTS) + printf("! "); + if (einfo->dpts[0] != einfo->dpts[1]) + printf("--dport %u:%u ", + einfo->dpts[0], einfo->dpts[1]); + else + printf("--dport %u ", einfo->dpts[0]); + } + + if (einfo->flags & IPT_DCCP_TYPE) { + printf("--dccp-type "); + print_types(einfo->typemask, einfo->invflags & IPT_DCCP_TYPE,0); + } + + if (einfo->flags & IPT_DCCP_OPTION) { + printf("--dccp-option %s%u ", + einfo->typemask & IPT_DCCP_OPTION ? "! " : "", + einfo->option); + } +} + +static +struct iptables_match dccp += { .name = "dccp", + .version = IPTABLES_VERSION, + .size = IPT_ALIGN(sizeof(struct ipt_dccp_info)), + .userspacesize = IPT_ALIGN(sizeof(struct ipt_dccp_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +void _init(void) +{ + register_match(&dccp); +} + diff --git a/extensions/libipt_dccp.man b/extensions/libipt_dccp.man new file mode 100644 index 0000000..6443ec3 --- /dev/null +++ b/extensions/libipt_dccp.man @@ -0,0 +1,12 @@ +.TP +\fB--source-port\fR,\fB--sport \fR[\fB!\fR] \fIport\fR[\fB:\fIport\fR] +.TP +\fB--destination-port\fR,\fB--dport \fR[\fB!\fR] \fIport\fR[\fB:\fIport\fR] +.TP +\fB--dccp-types\fR [\fB!\fR] \fImask\fP +Match when the DCCP packet type is one of 'mask'. 'mask' is a comma-separated +list of packet types. Packet types are: +.BR "REQUEST RESPONSE DATA ACK DATAACK CLOSEREQ CLOSE RESET SYNC SYNCACK INVALID" . +.TP +\fB--dccp-option\fR [\fB!\fR\] \fInumber\fP +Match if DCP option set. diff --git a/extensions/libipt_policy.c b/extensions/libipt_policy.c new file mode 100644 index 0000000..681995a --- /dev/null +++ b/extensions/libipt_policy.c @@ -0,0 +1,436 @@ +/* Shared library add-on to iptables to add policy support. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../include/linux/netfilter_ipv4/ipt_policy.h" + +/* + * HACK: global pointer to current matchinfo for making + * final checks and adjustments in final_check. + */ +static struct ipt_policy_info *policy_info; + +static void help(void) +{ + printf( +"policy v%s 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" +"[!] --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", + IPTABLES_VERSION); +} + +static struct option opts[] = +{ + { + .name = "dir", + .has_arg = 1, + .val = '1', + }, + { + .name = "pol", + .has_arg = 1, + .val = '2', + }, + { + .name = "strict", + .val = '3' + }, + { + .name = "reqid", + .has_arg = 1, + .val = '4', + }, + { + .name = "spi", + .has_arg = 1, + .val = '5' + }, + { + .name = "tunnel-src", + .has_arg = 1, + .val = '6' + }, + { + .name = "tunnel-dst", + .has_arg = 1, + .val = '7' + }, + { + .name = "proto", + .has_arg = 1, + .val = '8' + }, + { + .name = "mode", + .has_arg = 1, + .val = '9' + }, + { + .name = "next", + .val = 'a' + }, + { } +}; + +static void init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + *nfcache |= NFC_UNKNOWN; +} + +static int parse_direction(char *s) +{ + if (strcmp(s, "in") == 0) + return IPT_POLICY_MATCH_IN; + if (strcmp(s, "out") == 0) + return IPT_POLICY_MATCH_OUT; + exit_error(PARAMETER_PROBLEM, "policy_match: invalid dir `%s'", s); +} + +static int parse_policy(char *s) +{ + if (strcmp(s, "none") == 0) + return IPT_POLICY_MATCH_NONE; + if (strcmp(s, "ipsec") == 0) + return 0; + exit_error(PARAMETER_PROBLEM, "policy match: invalid policy `%s'", s); +} + +static int parse_mode(char *s) +{ + if (strcmp(s, "transport") == 0) + return IPT_POLICY_MODE_TRANSPORT; + if (strcmp(s, "tunnel") == 0) + return IPT_POLICY_MODE_TUNNEL; + exit_error(PARAMETER_PROBLEM, "policy match: invalid mode `%s'", s); +} + +static int parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_policy_info *info = (void *)(*match)->data; + struct ipt_policy_elem *e = &info->pol[info->len]; + struct in_addr *addr = NULL, mask; + unsigned int naddr = 0; + int mode; + + check_inverse(optarg, &invert, &optind, 0); + + switch (c) { + case '1': + if (info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT)) + exit_error(PARAMETER_PROBLEM, + "policy match: double --dir option"); + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --dir option"); + + info->flags |= parse_direction(argv[optind-1]); + break; + case '2': + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --policy option"); + + info->flags |= parse_policy(argv[optind-1]); + break; + case '3': + if (info->flags & IPT_POLICY_MATCH_STRICT) + exit_error(PARAMETER_PROBLEM, + "policy match: double --strict option"); + + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --strict option"); + + info->flags |= IPT_POLICY_MATCH_STRICT; + break; + case '4': + if (e->match.reqid) + exit_error(PARAMETER_PROBLEM, + "policy match: double --reqid option"); + + e->match.reqid = 1; + e->invert.reqid = invert; + e->reqid = strtol(argv[optind-1], NULL, 10); + break; + case '5': + if (e->match.spi) + exit_error(PARAMETER_PROBLEM, + "policy match: double --spi option"); + + e->match.spi = 1; + e->invert.spi = invert; + e->spi = strtol(argv[optind-1], NULL, 0x10); + break; + case '6': + if (e->match.saddr) + exit_error(PARAMETER_PROBLEM, + "policy match: double --tunnel-src option"); + + parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); + if (naddr > 1) + exit_error(PARAMETER_PROBLEM, + "policy match: name resolves to multiple IPs"); + + e->match.saddr = 1; + e->invert.saddr = invert; + e->saddr.a4 = addr[0]; + e->smask.a4 = mask; + break; + case '7': + if (e->match.daddr) + exit_error(PARAMETER_PROBLEM, + "policy match: double --tunnel-dst option"); + + parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); + if (naddr > 1) + exit_error(PARAMETER_PROBLEM, + "policy match: name resolves to multiple IPs"); + + e->match.daddr = 1; + e->invert.daddr = invert; + e->daddr.a4 = addr[0]; + e->dmask.a4 = mask; + break; + case '8': + if (e->match.proto) + exit_error(PARAMETER_PROBLEM, + "policy match: double --proto option"); + + e->proto = parse_protocol(argv[optind-1]); + if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP && + e->proto != IPPROTO_COMP) + exit_error(PARAMETER_PROBLEM, + "policy match: protocol must ah/esp/ipcomp"); + e->match.proto = 1; + e->invert.proto = invert; + break; + case '9': + if (e->match.mode) + exit_error(PARAMETER_PROBLEM, + "policy match: double --mode option"); + + mode = parse_mode(argv[optind-1]); + e->match.mode = 1; + e->invert.mode = invert; + e->mode = mode; + break; + case 'a': + if (invert) + exit_error(PARAMETER_PROBLEM, + "policy match: can't invert --next option"); + + if (++info->len == IPT_POLICY_MAX_ELEM) + exit_error(PARAMETER_PROBLEM, + "policy match: maximum policy depth reached"); + break; + default: + return 0; + } + + policy_info = info; + return 1; +} + +static void final_check(unsigned int flags) +{ + struct ipt_policy_info *info = policy_info; + struct ipt_policy_elem *e; + int i; + + if (info == NULL) + exit_error(PARAMETER_PROBLEM, + "policy match: no parameters given"); + + if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) + exit_error(PARAMETER_PROBLEM, + "policy match: neither --in nor --out specified"); + + if (info->flags & IPT_POLICY_MATCH_NONE) { + if (info->flags & IPT_POLICY_MATCH_STRICT) + exit_error(PARAMETER_PROBLEM, + "policy match: policy none but --strict given"); + + if (info->len != 0) + exit_error(PARAMETER_PROBLEM, + "policy match: policy none but policy given"); + } else + info->len++; /* increase len by 1, no --next after last element */ + + if (!(info->flags & IPT_POLICY_MATCH_STRICT) && info->len > 1) + exit_error(PARAMETER_PROBLEM, + "policy match: multiple elements but no --strict"); + + for (i = 0; i < info->len; i++) { + e = &info->pol[i]; + + if (info->flags & IPT_POLICY_MATCH_STRICT && + !(e->match.reqid || e->match.spi || e->match.saddr || + e->match.daddr || e->match.proto || e->match.mode)) + exit_error(PARAMETER_PROBLEM, + "policy match: empty policy element"); + + if ((e->match.saddr || e->match.daddr) + && ((e->mode == IPT_POLICY_MODE_TUNNEL && e->invert.mode) || + (e->mode == IPT_POLICY_MODE_TRANSPORT && !e->invert.mode))) + exit_error(PARAMETER_PROBLEM, + "policy match: --tunnel-src/--tunnel-dst " + "is only valid in tunnel mode"); + } +} + +static void print_mode(char *prefix, u_int8_t mode, int numeric) +{ + printf("%smode ", prefix); + + switch (mode) { + case IPT_POLICY_MODE_TRANSPORT: + printf("transport "); + break; + case IPT_POLICY_MODE_TUNNEL: + printf("tunnel "); + break; + default: + printf("??? "); + break; + } +} + +static void print_proto(char *prefix, u_int8_t proto, int numeric) +{ + 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(char *prefix, const struct ipt_policy_elem *e, + int numeric) +{ + 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); + printf("%stunnel-dst %s%s ", prefix, + addr_to_dotted((struct in_addr *)&e->daddr), + mask_to_dotted((struct in_addr *)&e->dmask)); + } + if (e->match.saddr) { + PRINT_INVERT(e->invert.saddr); + printf("%stunnel-src %s%s ", prefix, + addr_to_dotted((struct in_addr *)&e->saddr), + mask_to_dotted((struct in_addr *)&e->smask)); + } +} + +static void print_flags(char *prefix, const struct ipt_policy_info *info) +{ + if (info->flags & IPT_POLICY_MATCH_IN) + printf("%sdir in ", prefix); + else + printf("%sdir out ", prefix); + + if (info->flags & IPT_POLICY_MATCH_NONE) + printf("%spol none ", prefix); + else + printf("%spol ipsec ", prefix); + + if (info->flags & IPT_POLICY_MATCH_STRICT) + printf("%sstrict ", prefix); +} + +static void print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + const struct ipt_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); + } +} + +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + const struct ipt_policy_info *info = (void *)match->data; + unsigned int i; + + print_flags("--", info); + for (i = 0; i < info->len; i++) { + print_entry("--", &info->pol[i], 0); + if (i + 1 < info->len) + printf("--next "); + } +} + +struct iptables_match policy = { + .name = "policy", + .version = IPTABLES_VERSION, + .size = IPT_ALIGN(sizeof(struct ipt_policy_info)), + .userspacesize = IPT_ALIGN(sizeof(struct ipt_policy_info)), + .help = help, + .init = init, + .parse = parse, + .final_check = final_check, + .print = print, + .save = save, + .extra_opts = opts +}; + +void _init(void) +{ + register_match(&policy); +} diff --git a/extensions/libipt_policy.man b/extensions/libipt_policy.man new file mode 100644 index 0000000..eed163e --- /dev/null +++ b/extensions/libipt_policy.man @@ -0,0 +1,48 @@ +This modules matches the policy used by IPsec for handling a packet. +.TP +.BI "--dir " "in|out" +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 +.BI "--pol " "none|ipsec" +Matches if the packet is subject to IPsec processing. +.TP +.BI "--strict" +Selects whether to match the exact policy or match if any rule of +the policy matches the given policy. +.TP +.BI "--reqid " "id" +Matches the reqid of the policy rule. The reqid can be specified with +.B setkey(8) +using +.B unique:id +as level. +.TP +.BI "--spi " "spi" +Matches the SPI of the SA. +.TP +.BI "--proto " "ah|esp|ipcomp" +Matches the encapsulation protocol. +.TP +.BI "--mode " "tunnel|transport" +Matches the encapsulation mode. +.TP +.BI "--tunnel-src " "addr[/mask]" +Matches the source end-point address of a tunnel mode SA. +Only valid with --mode tunnel. +.TP +.BI "--tunnel-dst " "addr[/mask]" +Matches the destination end-point address of a tunnel mode SA. +Only valid with --mode tunnel. +.TP +.BI "--next" +Start the next element in the policy specification. Can only be used with +--strict diff --git a/extensions/libipt_string.man b/extensions/libipt_string.man new file mode 100644 index 0000000..3f3e5b7 --- /dev/null +++ b/extensions/libipt_string.man @@ -0,0 +1,15 @@ +This modules matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14. +.TP +.BI "--algo " "bm|kmp" +Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris) +.TP +.BI "--from " "offset" +Set the offset from which it starts looking for any matching. If not passed, default is 0. +.TP +.BI "--to " "offset" +Set the offset from which it starts looking for any matching. If not passed, default is the packet size. +.TP +.BI "--string " "pattern" +Matches the given pattern. +.BI "--hex-string " "pattern" +Matches the given pattern in hex notation. diff --git a/include/linux/netfilter_ipv4/ipt_NFQUEUE.h b/include/linux/netfilter_ipv4/ipt_NFQUEUE.h new file mode 100644 index 0000000..b5b2943 --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_NFQUEUE.h @@ -0,0 +1,16 @@ +/* iptables module for using NFQUEUE mechanism + * + * (C) 2005 Harald Welte + * + * This software is distributed under GNU GPL v2, 1991 + * +*/ +#ifndef _IPT_NFQ_TARGET_H +#define _IPT_NFQ_TARGET_H + +/* target info */ +struct ipt_NFQ_info { + u_int16_t queuenum; +}; + +#endif /* _IPT_DSCP_TARGET_H */ diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h new file mode 100644 index 0000000..74ca65c --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_policy.h @@ -0,0 +1,62 @@ +#ifndef _IPT_POLICY_H +#define _IPT_POLICY_H + +#define IPT_POLICY_MAX_ELEM 4 + +#ifndef __KERNEL__ +#include +#endif + +enum ipt_policy_flags +{ + IPT_POLICY_MATCH_IN = 0x1, + IPT_POLICY_MATCH_OUT = 0x2, + IPT_POLICY_MATCH_NONE = 0x4, + IPT_POLICY_MATCH_STRICT = 0x8, +}; + +enum ipt_policy_modes +{ + IPT_POLICY_MODE_TRANSPORT, + IPT_POLICY_MODE_TUNNEL +}; + +struct ipt_policy_spec +{ + u_int8_t saddr:1, + daddr:1, + proto:1, + mode:1, + spi:1, + reqid:1; +}; + +union ipt_policy_addr +{ + struct in_addr a4; + struct in6_addr a6; +}; + +struct ipt_policy_elem +{ + union ipt_policy_addr saddr; + union ipt_policy_addr smask; + union ipt_policy_addr daddr; + union ipt_policy_addr dmask; + u_int32_t spi; + u_int32_t reqid; + u_int8_t proto; + u_int8_t mode; + + struct ipt_policy_spec match; + struct ipt_policy_spec invert; +}; + +struct ipt_policy_info +{ + struct ipt_policy_elem pol[IPT_POLICY_MAX_ELEM]; + u_int16_t flags; + u_int16_t len; +}; + +#endif /* _IPT_POLICY_H */ diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h new file mode 100644 index 0000000..671bd81 --- /dev/null +++ b/include/linux/netfilter_ipv6/ip6t_policy.h @@ -0,0 +1,58 @@ +#ifndef _IP6T_POLICY_H +#define _IP6T_POLICY_H + +#define IP6T_POLICY_MAX_ELEM 4 + +enum ip6t_policy_flags +{ + IP6T_POLICY_MATCH_IN = 0x1, + IP6T_POLICY_MATCH_OUT = 0x2, + IP6T_POLICY_MATCH_NONE = 0x4, + IP6T_POLICY_MATCH_STRICT = 0x8, +}; + +enum ip6t_policy_modes +{ + IP6T_POLICY_MODE_TRANSPORT, + IP6T_POLICY_MODE_TUNNEL +}; + +struct ip6t_policy_spec +{ + u_int8_t saddr:1, + daddr:1, + proto:1, + mode:1, + spi:1, + reqid:1; +}; + +union ip6t_policy_addr +{ + struct in_addr a4; + struct in6_addr a6; +}; + +struct ip6t_policy_elem +{ + union ip6t_policy_addr saddr; + union ip6t_policy_addr smask; + union ip6t_policy_addr daddr; + union ip6t_policy_addr dmask; + u_int32_t spi; + u_int32_t reqid; + u_int8_t proto; + u_int8_t mode; + + struct ip6t_policy_spec match; + struct ip6t_policy_spec invert; +}; + +struct ip6t_policy_info +{ + struct ip6t_policy_elem pol[IP6T_POLICY_MAX_ELEM]; + u_int16_t flags; + u_int16_t len; +}; + +#endif /* _IP6T_POLICY_H */ -- 2.43.0