summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@medozas.de>2008-01-29 13:37:21 +0000
committerPatrick McHardy <kaber@trash.net>2008-01-29 13:37:21 +0000
commita8ad34cf11540d147b8aded6826a1452841d2aa7 (patch)
tree463c2bf3e811e918d07ba50120700ad8d971ea83
parentff068719055ae2327d94c79048381c09d3b744c4 (diff)
[IPTABLES]: libxt_conntrack revision 1
Add support for xt_conntrack match revision 1. Signed-off-by: Jan Engelhardt <jengelh@computergmbh.de>
-rw-r--r--extensions/libxt_conntrack.c575
-rw-r--r--extensions/libxt_conntrack.man18
2 files changed, 576 insertions, 17 deletions
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 9c7b01a1..d076d494 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1,10 +1,17 @@
-/* Shared library add-on to iptables for conntrack matching support.
- * GPL (C) 2001 Marc Boucher (marc@mbsi.ca).
+/*
+ * libxt_conntrack
+ * Shared library add-on to iptables for conntrack matching support.
+ *
+ * GPL (C) 2001 Marc Boucher (marc@mbsi.ca).
+ * Copyright © CC Computer Consultants GmbH, 2007 - 2008
+ * Jan Engelhardt <jengelh@computergmbh.de>
*/
-
+#include <sys/socket.h>
+#include <sys/types.h>
#include <ctype.h>
#include <getopt.h>
#include <netdb.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -13,6 +20,7 @@
#include <linux/netfilter.h>
#include <linux/netfilter/xt_conntrack.h>
#include <linux/netfilter/nf_conntrack_common.h>
+#include <arpa/inet.h>
/* Function which prints out usage message. */
static void conntrack_mt_help(void)
@@ -27,14 +35,20 @@ static void conntrack_mt_help(void)
"[!] --ctreplsrc address[/mask]\n"
"[!] --ctrepldst address[/mask]\n"
" Original/Reply source/destination address\n"
+"[!] --ctorigsrcport port\n"
+"[!] --ctorigdstport port\n"
+"[!] --ctreplsrcport port\n"
+"[!] --ctrepldstport port\n"
+" TCP/UDP/SCTP orig./reply source/destination port\n"
"[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n"
" Status(es) to match\n"
"[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n"
" value or range of values (inclusive)\n"
+" --ctdir {ORIGINAL|REPLY} Flow direction of packet\n"
"\n");
}
-static const struct option conntrack_mt_opts[] = {
+static const struct option conntrack_mt_opts_v0[] = {
{.name = "ctstate", .has_arg = true, .val = '1'},
{.name = "ctproto", .has_arg = true, .val = '2'},
{.name = "ctorigsrc", .has_arg = true, .val = '3'},
@@ -46,6 +60,23 @@ static const struct option conntrack_mt_opts[] = {
{},
};
+static const struct option conntrack_mt_opts[] = {
+ {.name = "ctstate", .has_arg = true, .val = '1'},
+ {.name = "ctproto", .has_arg = true, .val = '2'},
+ {.name = "ctorigsrc", .has_arg = true, .val = '3'},
+ {.name = "ctorigdst", .has_arg = true, .val = '4'},
+ {.name = "ctreplsrc", .has_arg = true, .val = '5'},
+ {.name = "ctrepldst", .has_arg = true, .val = '6'},
+ {.name = "ctstatus", .has_arg = true, .val = '7'},
+ {.name = "ctexpire", .has_arg = true, .val = '8'},
+ {.name = "ctorigsrcport", .has_arg = true, .val = 'a'},
+ {.name = "ctorigdstport", .has_arg = true, .val = 'b'},
+ {.name = "ctreplsrcport", .has_arg = true, .val = 'c'},
+ {.name = "ctrepldstport", .has_arg = true, .val = 'd'},
+ {.name = "ctdir", .has_arg = true, .val = 'e'},
+ {},
+};
+
static int
parse_state(const char *state, size_t strlen, struct xt_conntrack_info *sinfo)
{
@@ -83,6 +114,45 @@ parse_states(const char *arg, struct xt_conntrack_info *sinfo)
exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
}
+static bool
+conntrack_ps_state(struct xt_conntrack_mtinfo1 *info, const char *state,
+ size_t z)
+{
+ if (strncasecmp(state, "INVALID", z) == 0)
+ info->state_mask |= XT_CONNTRACK_STATE_INVALID;
+ else if (strncasecmp(state, "NEW", z) == 0)
+ info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
+ else if (strncasecmp(state, "ESTABLISHED", z) == 0)
+ info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
+ else if (strncasecmp(state, "RELATED", z) == 0)
+ info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
+ else if (strncasecmp(state, "UNTRACKED", z) == 0)
+ info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED;
+ else if (strncasecmp(state, "SNAT", z) == 0)
+ info->state_mask |= XT_CONNTRACK_STATE_SNAT;
+ else if (strncasecmp(state, "DNAT", z) == 0)
+ info->state_mask |= XT_CONNTRACK_STATE_DNAT;
+ else
+ return false;
+ return true;
+}
+
+static void
+conntrack_ps_states(struct xt_conntrack_mtinfo1 *info, const char *arg)
+{
+ const char *comma;
+
+ while ((comma = strchr(arg, ',')) != NULL) {
+ if (comma == arg || !conntrack_ps_state(info, arg, comma - arg))
+ exit_error(PARAMETER_PROBLEM,
+ "Bad ctstate \"%s\"", arg);
+ arg = comma + 1;
+ }
+
+ if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg)))
+ exit_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
+}
+
static int
parse_status(const char *status, size_t strlen, struct xt_conntrack_info *sinfo)
{
@@ -96,7 +166,7 @@ parse_status(const char *status, size_t strlen, struct xt_conntrack_info *sinfo)
sinfo->statusmask |= IPS_ASSURED;
#ifdef IPS_CONFIRMED
else if (strncasecmp(status, "CONFIRMED", strlen) == 0)
- sinfo->stausmask |= IPS_CONFIRMED;
+ sinfo->statusmask |= IPS_CONFIRMED;
#endif
else
return 0;
@@ -118,6 +188,41 @@ parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
}
+static bool
+conntrack_ps_status(struct xt_conntrack_mtinfo1 *info, const char *status,
+ size_t z)
+{
+ if (strncasecmp(status, "NONE", z) == 0)
+ info->status_mask |= 0;
+ else if (strncasecmp(status, "EXPECTED", z) == 0)
+ info->status_mask |= IPS_EXPECTED;
+ else if (strncasecmp(status, "SEEN_REPLY", z) == 0)
+ info->status_mask |= IPS_SEEN_REPLY;
+ else if (strncasecmp(status, "ASSURED", z) == 0)
+ info->status_mask |= IPS_ASSURED;
+ else if (strncasecmp(status, "CONFIRMED", z) == 0)
+ info->status_mask |= IPS_CONFIRMED;
+ else
+ return false;
+ return true;
+}
+
+static void
+conntrack_ps_statuses(struct xt_conntrack_mtinfo1 *info, const char *arg)
+{
+ const char *comma;
+
+ while ((comma = strchr(arg, ',')) != NULL) {
+ if (comma == arg || !conntrack_ps_status(info, arg, comma - arg))
+ exit_error(PARAMETER_PROBLEM,
+ "Bad ctstatus \"%s\"", arg);
+ arg = comma + 1;
+ }
+
+ if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg)))
+ exit_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
+}
+
static unsigned long
parse_expire(const char *s)
{
@@ -138,7 +243,8 @@ parse_expires(const char *s, struct xt_conntrack_info *sinfo)
buffer = strdup(s);
if ((cp = strchr(buffer, ':')) == NULL)
- sinfo->expires_min = sinfo->expires_max = parse_expire(buffer);
+ sinfo->expires_min = sinfo->expires_max =
+ parse_expire(buffer);
else {
*cp = '\0';
cp++;
@@ -154,6 +260,30 @@ parse_expires(const char *s, struct xt_conntrack_info *sinfo)
"range value `%lu'", sinfo->expires_min, sinfo->expires_max);
}
+static void
+conntrack_ps_expires(struct xt_conntrack_mtinfo1 *info, const char *s)
+{
+ unsigned int min, max;
+ char *end;
+
+ if (!strtonum(s, &end, &min, 0, ~0))
+ param_act(P_BAD_VALUE, "conntrack", "--expires", s);
+ max = min;
+ if (*end == ':')
+ if (!strtonum(s, &end, &max, 0, ~0U))
+ param_act(P_BAD_VALUE, "conntrack", "--expires", s);
+ if (*end != '\0')
+ param_act(P_BAD_VALUE, "conntrack", "--expires", s);
+
+ if (min > max)
+ exit_error(PARAMETER_PROBLEM,
+ "expire min. range value \"%u\" greater than max. "
+ "range value \"%u\"", min, max);
+
+ info->expires_min = min;
+ info->expires_max = max;
+}
+
/* Function which parses command options; returns true if it
ate an option */
static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags,
@@ -305,10 +435,257 @@ static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags,
return 1;
}
+static int
+conntrack_mt_parse(int c, char **argv, int invert, unsigned int *flags,
+ struct xt_entry_match **match)
+{
+ struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
+ unsigned int port;
+ char *p;
+
+ switch (c) {
+ case '1': /* --ctstate */
+ conntrack_ps_states(info, optarg);
+ info->match_flags |= XT_CONNTRACK_STATE;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_STATE;
+ break;
+
+ case '2': /* --ctproto */
+ /* Canonicalize into lower case */
+ for (p = optarg; *p != '\0'; ++p)
+ *p = tolower(*p);
+ info->l4proto = parse_protocol(optarg);
+
+ if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO))
+ exit_error(PARAMETER_PROBLEM, "conntrack: rule would "
+ "never match protocol");
+
+ info->match_flags |= XT_CONNTRACK_PROTO;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_PROTO;
+ break;
+
+ case '7': /* --ctstatus */
+ conntrack_ps_statuses(info, optarg);
+ info->match_flags |= XT_CONNTRACK_STATUS;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_STATUS;
+ break;
+
+ case '8': /* --ctexpire */
+ conntrack_ps_expires(info, optarg);
+ info->match_flags |= XT_CONNTRACK_EXPIRES;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_EXPIRES;
+ break;
+
+ case 'a': /* --ctorigsrcport */
+ if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
+ param_act(P_BAD_VALUE, "conntrack",
+ "--ctorigsrcport", optarg);
+ info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT;
+ info->origsrc_port = htons(port);
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT;
+ break;
+
+ case 'b': /* --ctorigdstport */
+ if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
+ param_act(P_BAD_VALUE, "conntrack",
+ "--ctorigdstport", optarg);
+ info->match_flags |= XT_CONNTRACK_ORIGDST_PORT;
+ info->origdst_port = htons(port);
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT;
+ break;
+
+ case 'c': /* --ctreplsrcport */
+ if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
+ param_act(P_BAD_VALUE, "conntrack",
+ "--ctreplsrcport", optarg);
+ info->match_flags |= XT_CONNTRACK_REPLSRC_PORT;
+ info->replsrc_port = htons(port);
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT;
+ break;
+
+ case 'd': /* --ctrepldstport */
+ if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
+ param_act(P_BAD_VALUE, "conntrack",
+ "--ctrepldstport", optarg);
+ info->match_flags |= XT_CONNTRACK_REPLDST_PORT;
+ info->repldst_port = htons(port);
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_REPLDST_PORT;
+ break;
+
+ case 'e': /* --ctdir */
+ param_act(P_NO_INVERT, "conntrack", "--ctdir", invert);
+ if (strcasecmp(optarg, "ORIGINAL") == 0) {
+ info->match_flags |= XT_CONNTRACK_DIRECTION;
+ info->invert_flags &= ~XT_CONNTRACK_DIRECTION;
+ } else if (strcasecmp(optarg, "REPLY") == 0) {
+ info->match_flags |= XT_CONNTRACK_DIRECTION;
+ info->invert_flags |= XT_CONNTRACK_DIRECTION;
+ } else {
+ param_act(P_BAD_VALUE, "conntrack", "--ctdir", optarg);
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ *flags = info->match_flags;
+ return true;
+}
+
+static int
+conntrack_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_match **match)
+{
+ struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
+ struct in_addr *addr = NULL;
+ unsigned int naddrs = 0;
+
+ switch (c) {
+ case '3': /* --ctorigsrc */
+ ipparse_hostnetworkmask(optarg, &addr, &info->origsrc_mask.in,
+ &naddrs);
+ if (naddrs > 1)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple IP addresses not allowed");
+ if (naddrs == 1)
+ memcpy(&info->origsrc_addr.in, addr, sizeof(*addr));
+ info->match_flags |= XT_CONNTRACK_ORIGSRC;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_ORIGSRC;
+ break;
+
+ case '4': /* --ctorigdst */
+ ipparse_hostnetworkmask(optarg, &addr, &info->origdst_mask.in,
+ &naddrs);
+ if (naddrs > 1)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple IP addresses not allowed");
+ if (naddrs == 1)
+ memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
+ info->match_flags |= XT_CONNTRACK_ORIGDST;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_ORIGDST;
+ break;
+
+ case '5': /* --ctreplsrc */
+ ipparse_hostnetworkmask(optarg, &addr, &info->replsrc_mask.in,
+ &naddrs);
+ if (naddrs > 1)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple IP addresses not allowed");
+ if (naddrs == 1)
+ memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
+ info->match_flags |= XT_CONNTRACK_REPLSRC;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_REPLSRC;
+ break;
+
+ case '6': /* --ctrepldst */
+ ipparse_hostnetworkmask(optarg, &addr, &info->repldst_mask.in,
+ &naddrs);
+ if (naddrs > 1)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple IP addresses not allowed");
+ if (naddrs == 1)
+ memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
+ info->match_flags |= XT_CONNTRACK_REPLDST;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_REPLDST;
+ break;
+
+
+ default:
+ return conntrack_mt_parse(c, argv, invert, flags, match);
+ }
+
+ *flags = info->match_flags;
+ return true;
+}
+
+static int
+conntrack_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_match **match)
+{
+ struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
+ struct in6_addr *addr = NULL;
+ unsigned int naddrs = 0;
+
+ switch (c) {
+ case '3': /* --ctorigsrc */
+ ip6parse_hostnetworkmask(optarg, &addr,
+ &info->origsrc_mask.in6, &naddrs);
+ if (naddrs > 1)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple IP addresses not allowed");
+ if (naddrs == 1)
+ memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr));
+ info->match_flags |= XT_CONNTRACK_ORIGSRC;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_ORIGSRC;
+ break;
+
+ case '4': /* --ctorigdst */
+ ip6parse_hostnetworkmask(optarg, &addr,
+ &info->origdst_mask.in6, &naddrs);
+ if (naddrs > 1)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple IP addresses not allowed");
+ if (naddrs == 1)
+ memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
+ info->match_flags |= XT_CONNTRACK_ORIGDST;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_ORIGDST;
+ break;
+
+ case '5': /* --ctreplsrc */
+ ip6parse_hostnetworkmask(optarg, &addr,
+ &info->replsrc_mask.in6, &naddrs);
+ if (naddrs > 1)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple IP addresses not allowed");
+ if (naddrs == 1)
+ memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
+ info->match_flags |= XT_CONNTRACK_REPLSRC;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_REPLSRC;
+ break;
+
+ case '6': /* --ctrepldst */
+ ip6parse_hostnetworkmask(optarg, &addr,
+ &info->repldst_mask.in6, &naddrs);
+ if (naddrs > 1)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple IP addresses not allowed");
+ if (naddrs == 1)
+ memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
+ info->match_flags |= XT_CONNTRACK_REPLDST;
+ if (invert)
+ info->invert_flags |= XT_CONNTRACK_REPLDST;
+ break;
+
+
+ default:
+ return conntrack_mt_parse(c, argv, invert, flags, match);
+ }
+
+ *flags = info->match_flags;
+ return true;
+}
+
static void conntrack_mt_check(unsigned int flags)
{
if (flags == 0)
- exit_error(PARAMETER_PROBLEM, "You must specify one or more options");
+ exit_error(PARAMETER_PROBLEM, "conntrack: At least one option "
+ "is required");
}
static void
@@ -364,20 +741,37 @@ print_status(unsigned int statusmask)
printf("%sASSURED", sep);
sep = ",";
}
-#ifdef IPS_CONFIRMED
if (statusmask & IPS_CONFIRMED) {
printf("%sCONFIRMED", sep);
- sep =",";
- }
-#endif
- if (statusmask == 0) {
- printf("%sNONE", sep);
sep = ",";
}
+ if (statusmask == 0)
+ printf("%sNONE", sep);
printf(" ");
}
static void
+conntrack_dump_addr(const union nf_inet_addr *addr,
+ const union nf_inet_addr *mask,
+ unsigned int family, bool numeric)
+{
+ if (family == AF_INET) {
+ if (!numeric && addr->ip == 0) {
+ printf("anywhere ");
+ return;
+ }
+ printf("%s ", ipaddr_to_anyname(&addr->in));
+ } else if (family == AF_INET6) {
+ if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
+ addr->ip6[2] == 0 && addr->ip6[3] == 0) {
+ printf("anywhere ");
+ return;
+ }
+ printf("%s ", ip6addr_to_anyname(&addr->in6));
+ }
+}
+
+static void
print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric)
{
char buf[BUFSIZ];
@@ -484,6 +878,103 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric,
}
}
+static void
+conntrack_dump(const struct xt_conntrack_mtinfo1 *info, const char *prefix,
+ unsigned int family, bool numeric)
+{
+ if (info->match_flags & XT_CONNTRACK_STATE) {
+ if (info->invert_flags & XT_CONNTRACK_STATE)
+ printf("! ");
+ printf("%sctstate ", prefix);
+ print_state(info->state_mask);
+ }
+
+ if (info->match_flags & XT_CONNTRACK_PROTO) {
+ if (info->invert_flags & XT_CONNTRACK_PROTO)
+ printf("! ");
+ printf("%sctproto %u ", prefix, info->l4proto);
+ }
+
+ if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
+ if (info->invert_flags & XT_CONNTRACK_PROTO)
+ printf("! ");
+ printf("%sctorigsrc ", prefix);
+ conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask,
+ family, numeric);
+ }
+
+ if (info->match_flags & XT_CONNTRACK_ORIGDST) {
+ if (info->invert_flags & XT_CONNTRACK_PROTO)
+ printf("! ");
+ printf("%sctorigdst ", prefix);
+ conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask,
+ family, numeric);
+ }
+
+ if (info->match_flags & XT_CONNTRACK_REPLSRC) {
+ if (info->invert_flags & XT_CONNTRACK_PROTO)
+ printf("! ");
+ printf("%sctreplsrc ", prefix);
+ conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask,
+ family, numeric);
+ }
+
+ if (info->match_flags & XT_CONNTRACK_REPLDST) {
+ if (info->invert_flags & XT_CONNTRACK_PROTO)
+ printf("! ");
+ printf("%sctrepldst ", prefix);
+ conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask,
+ family, numeric);
+ }
+
+ if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
+ if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)
+ printf("! ");
+ printf("%sctorigsrcport %u ", prefix,
+ ntohs(info->origsrc_port));
+ }
+
+ if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
+ if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)
+ printf("! ");
+ printf("%sctorigdstport %u ", prefix,
+ ntohs(info->origdst_port));
+ }
+
+ if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
+ if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)
+ printf("! ");
+ printf("%sctreplsrcport %u ", prefix,
+ ntohs(info->replsrc_port));
+ }
+
+ if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) {
+ if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT)
+ printf("! ");
+ printf("%sctrepldstport %u ", prefix,
+ ntohs(info->repldst_port));
+ }
+
+ if (info->match_flags & XT_CONNTRACK_STATUS) {
+ if (info->invert_flags & XT_CONNTRACK_STATUS)
+ printf("! ");
+ printf("%sctstatus ", prefix);
+ print_status(info->status_mask);
+ }
+
+ if (info->match_flags & XT_CONNTRACK_EXPIRES) {
+ if (info->invert_flags & XT_CONNTRACK_EXPIRES)
+ printf("! ");
+ printf("%sctexpire ", prefix);
+
+ if (info->expires_max == info->expires_min)
+ printf("%u ", (unsigned int)info->expires_min);
+ else
+ printf("%u:%u ", (unsigned int)info->expires_min,
+ (unsigned int)info->expires_max);
+ }
+}
+
/* Prints out the matchinfo. */
static void conntrack_print(const void *ip, const struct xt_entry_match *match,
int numeric)
@@ -491,12 +982,38 @@ static void conntrack_print(const void *ip, const struct xt_entry_match *match,
matchinfo_print(ip, match, numeric, "");
}
+static void
+conntrack_mt_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ conntrack_dump((const void *)match->data, "", AF_INET, numeric);
+}
+
+static void
+conntrack_mt6_print(const void *ip, const struct xt_entry_match *match,
+ int numeric)
+{
+ conntrack_dump((const void *)match->data, "", AF_INET6, numeric);
+}
+
/* Saves the matchinfo in parsable form to stdout. */
static void conntrack_save(const void *ip, const struct xt_entry_match *match)
{
matchinfo_print(ip, match, 1, "--");
}
+static void conntrack_mt_save(const void *ip,
+ const struct xt_entry_match *match)
+{
+ conntrack_dump((const void *)match->data, "--", AF_INET, true);
+}
+
+static void conntrack_mt6_save(const void *ip,
+ const struct xt_entry_match *match)
+{
+ conntrack_dump((const void *)match->data, "--", AF_INET6, true);
+}
+
static struct xtables_match conntrack_match = {
.version = IPTABLES_VERSION,
.name = "conntrack",
@@ -509,10 +1026,42 @@ static struct xtables_match conntrack_match = {
.final_check = conntrack_mt_check,
.print = conntrack_print,
.save = conntrack_save,
+ .extra_opts = conntrack_mt_opts_v0,
+};
+
+static struct xtables_match conntrack_mt_reg = {
+ .version = IPTABLES_VERSION,
+ .name = "conntrack",
+ .revision = 1,
+ .family = AF_INET,
+ .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
+ .help = conntrack_mt_help,
+ .parse = conntrack_mt4_parse,
+ .final_check = conntrack_mt_check,
+ .print = conntrack_mt_print,
+ .save = conntrack_mt_save,
+ .extra_opts = conntrack_mt_opts,
+};
+
+static struct xtables_match conntrack_mt6_reg = {
+ .version = IPTABLES_VERSION,
+ .name = "conntrack",
+ .revision = 1,
+ .family = AF_INET6,
+ .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
+ .help = conntrack_mt_help,
+ .parse = conntrack_mt6_parse,
+ .final_check = conntrack_mt_check,
+ .print = conntrack_mt6_print,
+ .save = conntrack_mt6_save,
.extra_opts = conntrack_mt_opts,
};
void _init(void)
{
xtables_register_match(&conntrack_match);
+ xtables_register_match(&conntrack_mt_reg);
+ xtables_register_match(&conntrack_mt6_reg);
}
diff --git a/extensions/libxt_conntrack.man b/extensions/libxt_conntrack.man
index b852bca9..17c6dd20 100644
--- a/extensions/libxt_conntrack.man
+++ b/extensions/libxt_conntrack.man
@@ -9,16 +9,22 @@ Possible states are listed below.
Layer-4 protocol to match (by number or name)
.TP
[\fB!\fR] \fB--ctorigsrc\fR \fIaddress\fR[\fB/\fR\fImask\fR]
-Match against original source address
.TP
[\fB!\fR] \fB--ctorigdst\fR \fIaddress\fR[\fB/\fR\fImask\fR]
-Match against original destination address
.TP
[\fB!\fR] \fB--ctreplsrc\fR \fIaddress\fR[\fB/\fR\fImask\fR]
-Match against reply source address
.TP
[\fB!\fR] \fB--ctrepldst\fR \fIaddress\fR[\fB/\fR\fImask\fR]
-Match against reply destination address
+Match against original/reply source/destination address
+.TP
+[\fB!\fR] \fB--ctorigsrcport\fR \fIport\fR
+.TP
+[\fB!\fR] \fB--ctorigdstport\fR \fIport\fR
+.TP
+[\fB!\fR] \fB--ctreplsrcport\fR \fIport\fR
+.TP
+[\fB!\fR] \fB--ctrepldstport\fR \fIport\fR
+Match against original/reply source/destination port (TCP/UDP/etc.) or GRE key.
.TP
[\fB!\fR] \fB--ctstatus\fR \fIstatelist\fR
\fIstatuslist\fR is a comma separated list of the connection statuses to match.
@@ -27,6 +33,10 @@ Possible statuses are listed below.
[\fB!\fR] \fB--ctexpire\fR \fItime\fR[\fB:\fR\fItime\fR]
Match remaining lifetime in seconds against given value or range of values
(inclusive)
+.TP
+\fB--ctdir\fR {\fBORIGINAL\fR|\fBREPLY\fR}
+Match packets that are flowing in the specified direction. If this flag is not
+specified at all, matches packets in both directions.
.PP
States for \fB--ctstate\fR:
.TP