From 54424b2156918d64d1860f579f538793059b4d5d Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org" Date: Mon, 26 Dec 2005 02:49:34 +0000 Subject: o add IPv6 support: main change o removed dead code: iptables_insmod and get_modprobe o compact the commands vs. options table o move working vars from the stack to the BSS section o update manpage o Bumped version to 1.0beta1 o check address family mismatch o fix incomplete copying IPv6 addresses --- ChangeLog | 12 ++ configure.in | 35 +++++- conntrack.8 | 4 + include/conntrack.h | 5 +- src/conntrack.c | 337 +++++++++++++++++++++++++++------------------------- 5 files changed, 230 insertions(+), 163 deletions(-) diff --git a/ChangeLog b/ChangeLog index f002815..2685bf6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2005-12-26 + + o add IPv6 support: main change + o removed dead code: iptables_insmod and get_modprobe + o compact the commands vs. options table + o move working vars from the stack to the BSS section + o update manpage + o Bumped version to 1.0beta1 + + o check address family mismatch + o fix incomplete copying IPv6 addresses + 2005-12-19 o We only support ipv4 at the moment: set l3protonum to AF_INET diff --git a/configure.in b/configure.in index 4dd09c6..7dab80f 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 0.991) +AM_INIT_AUTOMAKE(conntrack, 1.0beta1) #AM_CONFIG_HEADER(config.h) AC_PROG_CC @@ -23,6 +23,39 @@ dnl AC_CHECK_LIB([c], [main]) AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack]) +AC_CHECK_HEADERS(arpa/inet.h) +dnl check for inet_pton +AC_CHECK_FUNCS(inet_pton) +dnl Some systems have it, but not IPv6 +if test "$ac_cv_func_inet_pton" = "yes" ; then +AC_MSG_CHECKING(if inet_pton supports IPv6) +AC_TRY_RUN( + [ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +int main() + { + struct in6_addr addr6; + if (inet_pton(AF_INET6, "::1", &addr6) < 1) + exit(1); + else + exit(0); + } + ], [ AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.]) + ], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) +fi + # Checks for header files. dnl AC_HEADER_STDC dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h]) diff --git a/conntrack.8 b/conntrack.8 index 8dbecb5..307180b 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -97,6 +97,10 @@ Match only entries whose destination address in the reply direction equals the o .BI "-p, --proto " "PROTO " Specify layer four (TCP, UDP, ...) protocol. .TP +.BI "-f, --family " "PROTO" +Specify layer three (ipv4, ipv6) protocol +This option is only required in conjunction with "-L, --dump". If this option is not passed, the default layer 3 protocol will be IPv4. +.TP .BI "-t, --timeout " "TIMEOUT" Specify the timeout. .TP diff --git a/include/conntrack.h b/include/conntrack.h index 1de5b34..e9f1946 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -115,7 +115,10 @@ enum options { CT_OPT_ID_BIT = 15, CT_OPT_ID = (1 << CT_OPT_ID_BIT), - CT_OPT_MAX_BIT = CT_OPT_ID_BIT + CT_OPT_FAMILY_BIT = 16, + CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), + + CT_OPT_MAX_BIT = CT_OPT_FAMILY_BIT }; #define NUMBER_OF_OPT CT_OPT_MAX_BIT+1 diff --git a/src/conntrack.c b/src/conntrack.c index 145ef24..b27cf47 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -43,26 +43,26 @@ #include #include #include +#ifdef HAVE_ARPA_INET_H #include +#endif #include #include #include #include "linux_list.h" #include "conntrack.h" #include - -#ifndef PROC_SYS_MODPROBE -#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" -#endif +#include +#include static const char cmdflags[NUMBER_OF_CMD] = {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; static const char cmd_need_param[NUMBER_OF_CMD] -= {' ','x','x','x','x',' ',' ',' ',' ',' ','x','x','x',' ',' '}; += { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i'}; += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -90,6 +90,7 @@ static struct option original_opts[] = { {"nat-range", 1, 0, 'a'}, {"mark", 1, 0, 'm'}, {"id", 2, 0, 'i'}, + {"family", 1, 0, 'f'}, {0, 0, 0, 0} }; @@ -103,32 +104,30 @@ static unsigned int global_option_offset = 0; * given commands make an option legal, that option is legal (applies to * CMD_LIST and CMD_ZERO only). * Key: - * + compulsory - * x illegal - * optional + * 0 illegal + * 1 compulsory + * 2 optional */ -/* FIXME: I'd need something different than this table to catch up some - * particular cases. Better later Pablo */ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -t -u -z -e -x -y -k -l -a -m -i*/ -/*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x',' '}, -/*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' ',' ','x'}, -/*CT_UPDATE*/ {' ',' ',' ',' ','+',' ',' ','x','x','x','x','x','x','x',' ',' '}, -/*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x','x',' '}, -/*CT_GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x','x',' '}, -/*CT_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*CT_EVENT*/ {'x','x','x','x',' ','x','x','x',' ','x','x','x','x','x','x','x'}, -/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x',' '}, -/*EXP_CREATE*/{'+','+',' ',' ','+','+',' ','x','x','+','+','+','+','x','x','x'}, -/*EXP_DELETE*/{'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_GET*/ {'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_EVENT*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, + /* s d r q p t u z e x y k l a m i f*/ +/*CT_LIST*/ {0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,2}, +/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0}, +/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0}, +/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0}, +/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static char *lib_dir = CONNTRACK_LIB_DIR; @@ -230,7 +229,7 @@ generic_cmd_check(int command, int options) if (!(command & (1<addr)) + return AF_INET; +#ifdef HAVE_INET_PTON_IPV6 + else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0) + return AF_INET6; +#endif - free(buf); - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - return 0; - return -1; + exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); } -in_addr_t parse_inetaddr(const char *cp) +int parse_inetaddr(const char *cp, union nfct_address *address) { - struct in_addr addr; - - if (inet_aton(cp, &addr)) { - return addr.s_addr; - } - - exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); + struct addr_parse parse; + int ret; + + if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET) + address->v4 = parse.addr.s_addr; + else if (ret == AF_INET6) + memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); + return ret; } /* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ @@ -497,7 +459,7 @@ static void nat_parse(char *arg, int portok, struct nfct_nat *range) { char *colon, *dash, *error; - unsigned long ip; + struct addr_parse parse; memset(range, 0, sizeof(range)); colon = strchr(arg, ':'); @@ -551,13 +513,16 @@ nat_parse(char *arg, int portok, struct nfct_nat *range) if (dash) *dash = '\0'; - ip = parse_inetaddr(arg); - range->min_ip = ip; + if (__parse_inetaddr(arg, &parse) != AF_INET) + return; + + range->min_ip = parse.addr.s_addr; if (dash) { - ip = parse_inetaddr(dash+1); - range->max_ip = ip; + if (__parse_inetaddr(dash+1, &parse) != AF_INET) + return; + range->max_ip = parse.addr.s_addr; } else - range->max_ip = range->min_ip; + range->max_ip = parse.addr.s_addr; } static void event_sighandler(int s) @@ -602,6 +567,7 @@ static const char usage_parameters[] = " -r, --reply-src ip\t\tSource addres from reply direction\n" " -q, --reply-dst ip\t\tDestination address from reply direction\n" " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" + " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" " -t, --timeout timeout\t\tSet timeout\n" " -u, --status status\t\tSet status, eg. ASSURED\n" " -i, --id [id]\t\t\tShow or set conntrack ID\n" @@ -619,41 +585,29 @@ void usage(char *prog) { fprintf(stdout, "\n%s", usage_parameters); } +static struct nfct_tuple orig, reply, mask; +static struct nfct_tuple exptuple; +static struct ctproto_handler *h; +static union nfct_protoinfo proto; +static struct nfct_nat range; +static struct nfct_conntrack *ct; +static struct nfct_expect *exp; +static unsigned long timeout; +static unsigned int status; +static unsigned int mark; +static unsigned int id = NFCT_ANY_ID; + int main(int argc, char *argv[]) { char c; unsigned int command = 0, options = 0; - struct nfct_tuple orig, reply, mask; - struct nfct_tuple exptuple; - struct ctproto_handler *h = NULL; - union nfct_protoinfo proto; - struct nfct_nat range; - struct nfct_conntrack *ct; - struct nfct_expect *exp; - unsigned long timeout = 0; - unsigned int status = 0; - unsigned int mark = 0; - unsigned int id = NFCT_ANY_ID; - unsigned int type = 0, extra_flags = 0, event_mask = 0; + unsigned int type = 0, event_mask = 0; + unsigned int l3flags = 0, l4flags = 0; int res = 0; - - memset(&proto, 0, sizeof(union nfct_protoinfo)); - memset(&orig, 0, sizeof(struct nfct_tuple)); - memset(&reply, 0, sizeof(struct nfct_tuple)); - memset(&mask, 0, sizeof(struct nfct_tuple)); - memset(&exptuple, 0, sizeof(struct nfct_tuple)); - memset(&range, 0, sizeof(struct nfct_nat)); - - /* - * FIXME: only IPv4 support available at the moment - */ - orig.l3protonum = AF_INET; - reply.l3protonum = AF_INET; - mask.l3protonum = AF_INET; - exptuple.l3protonum = AF_INET; + int family = AF_UNSPEC; while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::", + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", opts, NULL)) != -1) { switch(c) { case 'L': @@ -714,23 +668,51 @@ int main(int argc, char *argv[]) break; case 's': options |= CT_OPT_ORIG_SRC; - if (optarg) - orig.src.v4 = parse_inetaddr(optarg); + if (optarg) { + orig.l3protonum = + parse_inetaddr(optarg, &orig.src); + set_family(&family, orig.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_ORIG_SRC; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_ORIG_SRC; + } break; case 'd': options |= CT_OPT_ORIG_DST; - if (optarg) - orig.dst.v4 = parse_inetaddr(optarg); + if (optarg) { + orig.l3protonum = + parse_inetaddr(optarg, &orig.dst); + set_family(&family, orig.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_ORIG_DST; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_ORIG_DST; + } break; case 'r': options |= CT_OPT_REPL_SRC; - if (optarg) - reply.src.v4 = parse_inetaddr(optarg); + if (optarg) { + reply.l3protonum = + parse_inetaddr(optarg, &reply.src); + set_family(&family, reply.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_REPL_SRC; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_REPL_SRC; + } break; case 'q': options |= CT_OPT_REPL_DST; - if (optarg) - reply.dst.v4 = parse_inetaddr(optarg); + if (optarg) { + reply.l3protonum = + parse_inetaddr(optarg, &reply.dst); + set_family(&family, reply.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_REPL_DST; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_REPL_DST; + } break; case 'p': options |= CT_OPT_PROTO; @@ -766,26 +748,39 @@ int main(int argc, char *argv[]) break; case '{': options |= CT_OPT_MASK_SRC; - if (optarg) - mask.src.v4 = parse_inetaddr(optarg); + if (optarg) { + mask.l3protonum = + parse_inetaddr(optarg, &mask.src); + set_family(&family, mask.l3protonum); + } break; case '}': options |= CT_OPT_MASK_DST; - if (optarg) - mask.dst.v4 = parse_inetaddr(optarg); + if (optarg) { + mask.l3protonum = + parse_inetaddr(optarg, &mask.dst); + set_family(&family, mask.l3protonum); + } break; case '[': options |= CT_OPT_EXP_SRC; - if (optarg) - exptuple.src.v4 = parse_inetaddr(optarg); + if (optarg) { + exptuple.l3protonum = + parse_inetaddr(optarg, &exptuple.src); + set_family(&family, exptuple.l3protonum); + } break; case ']': options |= CT_OPT_EXP_DST; - if (optarg) - exptuple.dst.v4 = parse_inetaddr(optarg); + if (optarg) { + exptuple.l3protonum = + parse_inetaddr(optarg, &exptuple.dst); + set_family(&family, exptuple.l3protonum); + } break; case 'a': options |= CT_OPT_NATRANGE; + set_family(&family, AF_INET); nat_parse(optarg, 1, &range); break; case 'm': @@ -804,11 +799,21 @@ int main(int argc, char *argv[]) id = atol(s); break; } + case 'f': + options |= CT_OPT_FAMILY; + if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0) + set_family(&family, AF_INET); + else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0) + set_family(&family, AF_INET6); + else + exit_error(PARAMETER_PROBLEM, "Unknown " + "protocol family\n"); + break; default: if (h && h->parse_opts &&!h->parse_opts(c - h->option_offset, argv, &orig, &reply, &mask, &proto, - &extra_flags)) + &l4flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); /* Unknown argument... */ @@ -821,12 +826,16 @@ int main(int argc, char *argv[]) } } + /* default family */ + if (family == AF_UNSPEC) + family = AF_INET; + generic_cmd_check(command, options); generic_opt_check(command, options); if (!(command & CT_HELP) && h && h->final_check - && !h->final_check(extra_flags, command, &orig, &reply)) { + && !h->final_check(l4flags, command, &orig, &reply)) { usage(argv[0]); extension_help(h); exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); @@ -849,9 +858,10 @@ int main(int argc, char *argv[]) NULL); if (options & CT_OPT_ZERO) - res = nfct_dump_conntrack_table_reset_counters(cth, AF_INET); + res = + nfct_dump_conntrack_table_reset_counters(cth, family); else - res = nfct_dump_conntrack_table(cth, AF_INET); + res = nfct_dump_conntrack_table(cth, family); nfct_close(cth); break; @@ -867,19 +877,21 @@ int main(int argc, char *argv[]) nfct_register_callback(cth, nfct_default_expect_display, NULL); - res = nfct_dump_expect_list(cth, AF_INET); + res = nfct_dump_expect_list(cth, family); nfct_close(cth); break; case CT_CREATE: if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) { - reply.src.v4 = orig.dst.v4; - reply.dst.v4 = orig.src.v4; + reply.l3protonum = orig.l3protonum; + memcpy(&reply.src, &orig.dst, sizeof(reply.src)); + memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); } else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) { - orig.src.v4 = reply.dst.v4; - orig.dst.v4 = reply.src.v4; + orig.l3protonum = reply.l3protonum; + memcpy(&orig.src, &reply.dst, sizeof(orig.src)); + memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); } if (options & CT_OPT_NATRANGE) ct = nfct_conntrack_alloc(&orig, &reply, timeout, @@ -925,12 +937,14 @@ int main(int argc, char *argv[]) case CT_UPDATE: if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) { - reply.src.v4 = orig.dst.v4; - reply.dst.v4 = orig.src.v4; + reply.l3protonum = orig.l3protonum; + memcpy(&reply.src, &orig.dst, sizeof(reply.src)); + memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); } else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) { - orig.src.v4 = reply.dst.v4; - orig.dst.v4 = reply.src.v4; + orig.l3protonum = reply.l3protonum; + memcpy(&orig.src, &reply.dst, sizeof(orig.src)); + memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); } ct = nfct_conntrack_alloc(&orig, &reply, timeout, &proto, status, mark, id, @@ -1036,11 +1050,12 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); - if (options & CT_OPT_PROTO) { + if (options & (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL)) { struct nfct_conntrack_compare cmp = { .ct = ct, - .flag = 0, - .protoflag = extra_flags + .flags = 0, + .l3flags = l3flags, + .l4flags = l4flags }; nfct_register_callback(cth, nfct_default_conntrack_event_display, -- cgit v1.2.3