blob: c7f80e0d685fa14dd6d984f19f08aee6b6b4e397 [file] [log] [blame]
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001/*
2 * libxt_conntrack
3 * Shared library add-on to iptables for conntrack matching support.
4 *
5 * GPL (C) 2001 Marc Boucher (marc@mbsi.ca).
6 * Copyright © CC Computer Consultants GmbH, 2007 - 2008
7 * Jan Engelhardt <jengelh@computergmbh.de>
Marc Boucher5054e852002-01-19 10:59:12 +00008 */
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00009#include <sys/socket.h>
10#include <sys/types.h>
Marc Boucher5054e852002-01-19 10:59:12 +000011#include <ctype.h>
Jan Engelhardta80b6042008-01-20 13:34:07 +000012#include <getopt.h>
13#include <netdb.h>
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000014#include <stdbool.h>
Jan Engelhardta80b6042008-01-20 13:34:07 +000015#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
Marc Boucher5054e852002-01-19 10:59:12 +000018#include <iptables.h>
Jan Engelhardt08b16162008-01-20 13:36:08 +000019#include <xtables.h>
Jan Engelhardta80b6042008-01-20 13:34:07 +000020#include <linux/netfilter.h>
21#include <linux/netfilter/xt_conntrack.h>
Patrick McHardy40d54752007-04-18 07:00:36 +000022#include <linux/netfilter/nf_conntrack_common.h>
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000023#include <arpa/inet.h>
Harald Welte4dc734c2003-10-07 18:55:13 +000024
Jan Engelhardta80b6042008-01-20 13:34:07 +000025static void conntrack_mt_help(void)
Marc Boucher5054e852002-01-19 10:59:12 +000026{
27 printf(
Jan Engelhardta80b6042008-01-20 13:34:07 +000028"conntrack match options:\n"
29"[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n"
30" State(s) to match\n"
31"[!] --ctproto proto Protocol to match; by number or name, e.g. \"tcp\"\n"
32"[!] --ctorigsrc address[/mask]\n"
33"[!] --ctorigdst address[/mask]\n"
34"[!] --ctreplsrc address[/mask]\n"
35"[!] --ctrepldst address[/mask]\n"
36" Original/Reply source/destination address\n"
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000037"[!] --ctorigsrcport port\n"
38"[!] --ctorigdstport port\n"
39"[!] --ctreplsrcport port\n"
40"[!] --ctrepldstport port\n"
41" TCP/UDP/SCTP orig./reply source/destination port\n"
Jan Engelhardta80b6042008-01-20 13:34:07 +000042"[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n"
43" Status(es) to match\n"
44"[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n"
45" value or range of values (inclusive)\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020046" --ctdir {ORIGINAL|REPLY} Flow direction of packet\n");
Marc Boucher5054e852002-01-19 10:59:12 +000047}
48
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000049static const struct option conntrack_mt_opts_v0[] = {
Jan Engelhardta80b6042008-01-20 13:34:07 +000050 {.name = "ctstate", .has_arg = true, .val = '1'},
51 {.name = "ctproto", .has_arg = true, .val = '2'},
52 {.name = "ctorigsrc", .has_arg = true, .val = '3'},
53 {.name = "ctorigdst", .has_arg = true, .val = '4'},
54 {.name = "ctreplsrc", .has_arg = true, .val = '5'},
55 {.name = "ctrepldst", .has_arg = true, .val = '6'},
56 {.name = "ctstatus", .has_arg = true, .val = '7'},
57 {.name = "ctexpire", .has_arg = true, .val = '8'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000058 { .name = NULL }
Marc Boucher5054e852002-01-19 10:59:12 +000059};
60
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000061static const struct option conntrack_mt_opts[] = {
62 {.name = "ctstate", .has_arg = true, .val = '1'},
63 {.name = "ctproto", .has_arg = true, .val = '2'},
64 {.name = "ctorigsrc", .has_arg = true, .val = '3'},
65 {.name = "ctorigdst", .has_arg = true, .val = '4'},
66 {.name = "ctreplsrc", .has_arg = true, .val = '5'},
67 {.name = "ctrepldst", .has_arg = true, .val = '6'},
68 {.name = "ctstatus", .has_arg = true, .val = '7'},
69 {.name = "ctexpire", .has_arg = true, .val = '8'},
70 {.name = "ctorigsrcport", .has_arg = true, .val = 'a'},
71 {.name = "ctorigdstport", .has_arg = true, .val = 'b'},
72 {.name = "ctreplsrcport", .has_arg = true, .val = 'c'},
73 {.name = "ctrepldstport", .has_arg = true, .val = 'd'},
74 {.name = "ctdir", .has_arg = true, .val = 'e'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000075 {.name = NULL},
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000076};
77
Marc Boucher5054e852002-01-19 10:59:12 +000078static int
Jan Engelhardtdbb77542008-02-11 00:33:30 +010079parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +000080{
Jan Engelhardtdbb77542008-02-11 00:33:30 +010081 if (strncasecmp(state, "INVALID", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000082 sinfo->statemask |= XT_CONNTRACK_STATE_INVALID;
Jan Engelhardtdbb77542008-02-11 00:33:30 +010083 else if (strncasecmp(state, "NEW", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000084 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
Jan Engelhardtdbb77542008-02-11 00:33:30 +010085 else if (strncasecmp(state, "ESTABLISHED", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000086 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
Jan Engelhardtdbb77542008-02-11 00:33:30 +010087 else if (strncasecmp(state, "RELATED", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000088 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
Jan Engelhardtdbb77542008-02-11 00:33:30 +010089 else if (strncasecmp(state, "UNTRACKED", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000090 sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED;
Jan Engelhardtdbb77542008-02-11 00:33:30 +010091 else if (strncasecmp(state, "SNAT", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000092 sinfo->statemask |= XT_CONNTRACK_STATE_SNAT;
Jan Engelhardtdbb77542008-02-11 00:33:30 +010093 else if (strncasecmp(state, "DNAT", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000094 sinfo->statemask |= XT_CONNTRACK_STATE_DNAT;
Marc Boucher5054e852002-01-19 10:59:12 +000095 else
96 return 0;
97 return 1;
98}
99
100static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000101parse_states(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000102{
103 const char *comma;
104
105 while ((comma = strchr(arg, ',')) != NULL) {
106 if (comma == arg || !parse_state(arg, comma-arg, sinfo))
107 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
108 arg = comma+1;
109 }
Pablo Neira Ayuso0ec8c0f2008-11-19 19:01:26 +0100110 if (!*arg)
111 exit_error(PARAMETER_PROBLEM, "`--ctstate' requires a list of "
112 "states with no spaces, e.g. "
113 "ESTABLISHED,RELATED");
Marc Boucher5054e852002-01-19 10:59:12 +0000114 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
115 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
116}
117
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000118static bool
119conntrack_ps_state(struct xt_conntrack_mtinfo1 *info, const char *state,
120 size_t z)
121{
122 if (strncasecmp(state, "INVALID", z) == 0)
123 info->state_mask |= XT_CONNTRACK_STATE_INVALID;
124 else if (strncasecmp(state, "NEW", z) == 0)
125 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
126 else if (strncasecmp(state, "ESTABLISHED", z) == 0)
127 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
128 else if (strncasecmp(state, "RELATED", z) == 0)
129 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
130 else if (strncasecmp(state, "UNTRACKED", z) == 0)
131 info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED;
132 else if (strncasecmp(state, "SNAT", z) == 0)
133 info->state_mask |= XT_CONNTRACK_STATE_SNAT;
134 else if (strncasecmp(state, "DNAT", z) == 0)
135 info->state_mask |= XT_CONNTRACK_STATE_DNAT;
136 else
137 return false;
138 return true;
139}
140
141static void
142conntrack_ps_states(struct xt_conntrack_mtinfo1 *info, const char *arg)
143{
144 const char *comma;
145
146 while ((comma = strchr(arg, ',')) != NULL) {
147 if (comma == arg || !conntrack_ps_state(info, arg, comma - arg))
148 exit_error(PARAMETER_PROBLEM,
149 "Bad ctstate \"%s\"", arg);
150 arg = comma + 1;
151 }
152
153 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg)))
154 exit_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
155}
156
Marc Boucher5054e852002-01-19 10:59:12 +0000157static int
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100158parse_status(const char *status, size_t len, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000159{
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100160 if (strncasecmp(status, "NONE", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000161 sinfo->statusmask |= 0;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100162 else if (strncasecmp(status, "EXPECTED", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000163 sinfo->statusmask |= IPS_EXPECTED;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100164 else if (strncasecmp(status, "SEEN_REPLY", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000165 sinfo->statusmask |= IPS_SEEN_REPLY;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100166 else if (strncasecmp(status, "ASSURED", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000167 sinfo->statusmask |= IPS_ASSURED;
Harald Weltea643c3e2003-08-25 11:08:52 +0000168#ifdef IPS_CONFIRMED
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100169 else if (strncasecmp(status, "CONFIRMED", len) == 0)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000170 sinfo->statusmask |= IPS_CONFIRMED;
Harald Weltea643c3e2003-08-25 11:08:52 +0000171#endif
Marc Boucher5054e852002-01-19 10:59:12 +0000172 else
173 return 0;
174 return 1;
175}
176
177static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000178parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000179{
180 const char *comma;
181
182 while ((comma = strchr(arg, ',')) != NULL) {
183 if (comma == arg || !parse_status(arg, comma-arg, sinfo))
184 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
185 arg = comma+1;
186 }
187
188 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo))
189 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
190}
191
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000192static bool
193conntrack_ps_status(struct xt_conntrack_mtinfo1 *info, const char *status,
194 size_t z)
195{
196 if (strncasecmp(status, "NONE", z) == 0)
197 info->status_mask |= 0;
198 else if (strncasecmp(status, "EXPECTED", z) == 0)
199 info->status_mask |= IPS_EXPECTED;
200 else if (strncasecmp(status, "SEEN_REPLY", z) == 0)
201 info->status_mask |= IPS_SEEN_REPLY;
202 else if (strncasecmp(status, "ASSURED", z) == 0)
203 info->status_mask |= IPS_ASSURED;
204 else if (strncasecmp(status, "CONFIRMED", z) == 0)
205 info->status_mask |= IPS_CONFIRMED;
206 else
207 return false;
208 return true;
209}
210
211static void
212conntrack_ps_statuses(struct xt_conntrack_mtinfo1 *info, const char *arg)
213{
214 const char *comma;
215
216 while ((comma = strchr(arg, ',')) != NULL) {
217 if (comma == arg || !conntrack_ps_status(info, arg, comma - arg))
218 exit_error(PARAMETER_PROBLEM,
219 "Bad ctstatus \"%s\"", arg);
220 arg = comma + 1;
221 }
222
223 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg)))
224 exit_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
225}
226
Marc Boucher5054e852002-01-19 10:59:12 +0000227static unsigned long
228parse_expire(const char *s)
229{
230 unsigned int len;
Jan Engelhardta80b6042008-01-20 13:34:07 +0000231
Martin Josefsson1da399c2004-05-26 15:50:57 +0000232 if (string_to_number(s, 0, 0, &len) == -1)
Marc Boucher5054e852002-01-19 10:59:12 +0000233 exit_error(PARAMETER_PROBLEM, "expire value invalid: `%s'\n", s);
234 else
235 return len;
236}
237
238/* If a single value is provided, min and max are both set to the value */
239static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000240parse_expires(const char *s, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000241{
242 char *buffer;
243 char *cp;
244
245 buffer = strdup(s);
246 if ((cp = strchr(buffer, ':')) == NULL)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000247 sinfo->expires_min = sinfo->expires_max =
248 parse_expire(buffer);
Marc Boucher5054e852002-01-19 10:59:12 +0000249 else {
250 *cp = '\0';
251 cp++;
252
253 sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0;
Max Kellermann9ee386a2008-01-29 13:48:05 +0000254 sinfo->expires_max = cp[0]
255 ? parse_expire(cp)
256 : (unsigned long)-1;
Marc Boucher5054e852002-01-19 10:59:12 +0000257 }
258 free(buffer);
Jan Engelhardta80b6042008-01-20 13:34:07 +0000259
Marc Boucher5054e852002-01-19 10:59:12 +0000260 if (sinfo->expires_min > sinfo->expires_max)
261 exit_error(PARAMETER_PROBLEM,
262 "expire min. range value `%lu' greater than max. "
263 "range value `%lu'", sinfo->expires_min, sinfo->expires_max);
Marc Boucher5054e852002-01-19 10:59:12 +0000264}
265
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000266static void
267conntrack_ps_expires(struct xt_conntrack_mtinfo1 *info, const char *s)
268{
269 unsigned int min, max;
270 char *end;
271
272 if (!strtonum(s, &end, &min, 0, ~0))
273 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
274 max = min;
275 if (*end == ':')
276 if (!strtonum(s, &end, &max, 0, ~0U))
277 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
278 if (*end != '\0')
279 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
280
281 if (min > max)
282 exit_error(PARAMETER_PROBLEM,
283 "expire min. range value \"%u\" greater than max. "
284 "range value \"%u\"", min, max);
285
286 info->expires_min = min;
287 info->expires_max = max;
288}
289
Jan Engelhardt59d16402007-10-04 16:28:39 +0000290static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags,
291 const void *entry, struct xt_entry_match **match)
Marc Boucher5054e852002-01-19 10:59:12 +0000292{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000293 struct xt_conntrack_info *sinfo = (void *)(*match)->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000294 char *protocol = NULL;
295 unsigned int naddrs = 0;
296 struct in_addr *addrs = NULL;
297
298
299 switch (c) {
300 case '1':
Harald Welteb77f1da2002-03-14 11:35:58 +0000301 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000302
303 parse_states(argv[optind-1], sinfo);
304 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000305 sinfo->invflags |= XT_CONNTRACK_STATE;
Marc Boucher5054e852002-01-19 10:59:12 +0000306 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000307 sinfo->flags |= XT_CONNTRACK_STATE;
Marc Boucher5054e852002-01-19 10:59:12 +0000308 break;
309
310 case '2':
Harald Welte3c5bd602002-03-14 19:54:34 +0000311 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000312
313 if(invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000314 sinfo->invflags |= XT_CONNTRACK_PROTO;
Marc Boucher5054e852002-01-19 10:59:12 +0000315
316 /* Canonicalize into lower case */
317 for (protocol = argv[optind-1]; *protocol; protocol++)
318 *protocol = tolower(*protocol);
319
320 protocol = argv[optind-1];
321 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = parse_protocol(protocol);
322
323 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0
Jan Engelhardta80b6042008-01-20 13:34:07 +0000324 && (sinfo->invflags & XT_INV_PROTO))
Marc Boucher5054e852002-01-19 10:59:12 +0000325 exit_error(PARAMETER_PROBLEM,
326 "rule would never match protocol");
327
Jan Engelhardta80b6042008-01-20 13:34:07 +0000328 sinfo->flags |= XT_CONNTRACK_PROTO;
Marc Boucher5054e852002-01-19 10:59:12 +0000329 break;
330
331 case '3':
Jan Engelhardt40eaf2a2007-11-25 15:25:23 +0000332 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000333
334 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000335 sinfo->invflags |= XT_CONNTRACK_ORIGSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000336
Jan Engelhardtbd943842008-01-20 13:38:08 +0000337 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000338 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
339 &naddrs);
340 if(naddrs > 1)
341 exit_error(PARAMETER_PROBLEM,
342 "multiple IP addresses not allowed");
343
344 if(naddrs == 1) {
345 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr;
346 }
347
Jan Engelhardta80b6042008-01-20 13:34:07 +0000348 sinfo->flags |= XT_CONNTRACK_ORIGSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000349 break;
350
351 case '4':
Harald Welteb77f1da2002-03-14 11:35:58 +0000352 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000353
354 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000355 sinfo->invflags |= XT_CONNTRACK_ORIGDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000356
Jan Engelhardtbd943842008-01-20 13:38:08 +0000357 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000358 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
359 &naddrs);
360 if(naddrs > 1)
361 exit_error(PARAMETER_PROBLEM,
362 "multiple IP addresses not allowed");
363
364 if(naddrs == 1) {
365 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr;
366 }
367
Jan Engelhardta80b6042008-01-20 13:34:07 +0000368 sinfo->flags |= XT_CONNTRACK_ORIGDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000369 break;
370
371 case '5':
Harald Welteb77f1da2002-03-14 11:35:58 +0000372 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000373
374 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000375 sinfo->invflags |= XT_CONNTRACK_REPLSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000376
Jan Engelhardtbd943842008-01-20 13:38:08 +0000377 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000378 &sinfo->sipmsk[IP_CT_DIR_REPLY],
379 &naddrs);
380 if(naddrs > 1)
381 exit_error(PARAMETER_PROBLEM,
382 "multiple IP addresses not allowed");
383
384 if(naddrs == 1) {
385 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr;
386 }
387
Jan Engelhardta80b6042008-01-20 13:34:07 +0000388 sinfo->flags |= XT_CONNTRACK_REPLSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000389 break;
390
391 case '6':
Harald Welteb77f1da2002-03-14 11:35:58 +0000392 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000393
394 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000395 sinfo->invflags |= XT_CONNTRACK_REPLDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000396
Jan Engelhardtbd943842008-01-20 13:38:08 +0000397 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000398 &sinfo->dipmsk[IP_CT_DIR_REPLY],
399 &naddrs);
400 if(naddrs > 1)
401 exit_error(PARAMETER_PROBLEM,
402 "multiple IP addresses not allowed");
403
404 if(naddrs == 1) {
405 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr;
406 }
407
Jan Engelhardta80b6042008-01-20 13:34:07 +0000408 sinfo->flags |= XT_CONNTRACK_REPLDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000409 break;
410
411 case '7':
Harald Welteb77f1da2002-03-14 11:35:58 +0000412 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000413
414 parse_statuses(argv[optind-1], sinfo);
415 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000416 sinfo->invflags |= XT_CONNTRACK_STATUS;
Marc Boucher5054e852002-01-19 10:59:12 +0000417 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000418 sinfo->flags |= XT_CONNTRACK_STATUS;
Marc Boucher5054e852002-01-19 10:59:12 +0000419 break;
420
421 case '8':
Harald Welteb77f1da2002-03-14 11:35:58 +0000422 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000423
424 parse_expires(argv[optind-1], sinfo);
425 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000426 sinfo->invflags |= XT_CONNTRACK_EXPIRES;
Marc Boucher5054e852002-01-19 10:59:12 +0000427 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000428 sinfo->flags |= XT_CONNTRACK_EXPIRES;
Marc Boucher5054e852002-01-19 10:59:12 +0000429 break;
430
431 default:
432 return 0;
433 }
434
435 *flags = sinfo->flags;
436 return 1;
437}
438
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000439static int
440conntrack_mt_parse(int c, char **argv, int invert, unsigned int *flags,
441 struct xt_entry_match **match)
442{
443 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
444 unsigned int port;
445 char *p;
446
447 switch (c) {
448 case '1': /* --ctstate */
449 conntrack_ps_states(info, optarg);
450 info->match_flags |= XT_CONNTRACK_STATE;
451 if (invert)
452 info->invert_flags |= XT_CONNTRACK_STATE;
453 break;
454
455 case '2': /* --ctproto */
456 /* Canonicalize into lower case */
457 for (p = optarg; *p != '\0'; ++p)
458 *p = tolower(*p);
459 info->l4proto = parse_protocol(optarg);
460
461 if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO))
462 exit_error(PARAMETER_PROBLEM, "conntrack: rule would "
463 "never match protocol");
464
465 info->match_flags |= XT_CONNTRACK_PROTO;
466 if (invert)
467 info->invert_flags |= XT_CONNTRACK_PROTO;
468 break;
469
470 case '7': /* --ctstatus */
471 conntrack_ps_statuses(info, optarg);
472 info->match_flags |= XT_CONNTRACK_STATUS;
473 if (invert)
474 info->invert_flags |= XT_CONNTRACK_STATUS;
475 break;
476
477 case '8': /* --ctexpire */
478 conntrack_ps_expires(info, optarg);
479 info->match_flags |= XT_CONNTRACK_EXPIRES;
480 if (invert)
481 info->invert_flags |= XT_CONNTRACK_EXPIRES;
482 break;
483
484 case 'a': /* --ctorigsrcport */
485 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
486 param_act(P_BAD_VALUE, "conntrack",
487 "--ctorigsrcport", optarg);
488 info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT;
489 info->origsrc_port = htons(port);
490 if (invert)
491 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT;
492 break;
493
494 case 'b': /* --ctorigdstport */
495 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
496 param_act(P_BAD_VALUE, "conntrack",
497 "--ctorigdstport", optarg);
498 info->match_flags |= XT_CONNTRACK_ORIGDST_PORT;
499 info->origdst_port = htons(port);
500 if (invert)
501 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT;
502 break;
503
504 case 'c': /* --ctreplsrcport */
505 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
506 param_act(P_BAD_VALUE, "conntrack",
507 "--ctreplsrcport", optarg);
508 info->match_flags |= XT_CONNTRACK_REPLSRC_PORT;
509 info->replsrc_port = htons(port);
510 if (invert)
511 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT;
512 break;
513
514 case 'd': /* --ctrepldstport */
515 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
516 param_act(P_BAD_VALUE, "conntrack",
517 "--ctrepldstport", optarg);
518 info->match_flags |= XT_CONNTRACK_REPLDST_PORT;
519 info->repldst_port = htons(port);
520 if (invert)
521 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT;
522 break;
523
524 case 'e': /* --ctdir */
525 param_act(P_NO_INVERT, "conntrack", "--ctdir", invert);
526 if (strcasecmp(optarg, "ORIGINAL") == 0) {
527 info->match_flags |= XT_CONNTRACK_DIRECTION;
528 info->invert_flags &= ~XT_CONNTRACK_DIRECTION;
529 } else if (strcasecmp(optarg, "REPLY") == 0) {
530 info->match_flags |= XT_CONNTRACK_DIRECTION;
531 info->invert_flags |= XT_CONNTRACK_DIRECTION;
532 } else {
533 param_act(P_BAD_VALUE, "conntrack", "--ctdir", optarg);
534 }
535 break;
536
537 default:
538 return false;
539 }
540
541 *flags = info->match_flags;
542 return true;
543}
544
545static int
546conntrack_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
547 const void *entry, struct xt_entry_match **match)
548{
549 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
550 struct in_addr *addr = NULL;
551 unsigned int naddrs = 0;
552
553 switch (c) {
554 case '3': /* --ctorigsrc */
555 ipparse_hostnetworkmask(optarg, &addr, &info->origsrc_mask.in,
556 &naddrs);
557 if (naddrs > 1)
558 exit_error(PARAMETER_PROBLEM,
559 "multiple IP addresses not allowed");
560 if (naddrs == 1)
561 memcpy(&info->origsrc_addr.in, addr, sizeof(*addr));
562 info->match_flags |= XT_CONNTRACK_ORIGSRC;
563 if (invert)
564 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
565 break;
566
567 case '4': /* --ctorigdst */
568 ipparse_hostnetworkmask(optarg, &addr, &info->origdst_mask.in,
569 &naddrs);
570 if (naddrs > 1)
571 exit_error(PARAMETER_PROBLEM,
572 "multiple IP addresses not allowed");
573 if (naddrs == 1)
574 memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
575 info->match_flags |= XT_CONNTRACK_ORIGDST;
576 if (invert)
577 info->invert_flags |= XT_CONNTRACK_ORIGDST;
578 break;
579
580 case '5': /* --ctreplsrc */
581 ipparse_hostnetworkmask(optarg, &addr, &info->replsrc_mask.in,
582 &naddrs);
583 if (naddrs > 1)
584 exit_error(PARAMETER_PROBLEM,
585 "multiple IP addresses not allowed");
586 if (naddrs == 1)
587 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
588 info->match_flags |= XT_CONNTRACK_REPLSRC;
589 if (invert)
590 info->invert_flags |= XT_CONNTRACK_REPLSRC;
591 break;
592
593 case '6': /* --ctrepldst */
594 ipparse_hostnetworkmask(optarg, &addr, &info->repldst_mask.in,
595 &naddrs);
596 if (naddrs > 1)
597 exit_error(PARAMETER_PROBLEM,
598 "multiple IP addresses not allowed");
599 if (naddrs == 1)
600 memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
601 info->match_flags |= XT_CONNTRACK_REPLDST;
602 if (invert)
603 info->invert_flags |= XT_CONNTRACK_REPLDST;
604 break;
605
606
607 default:
608 return conntrack_mt_parse(c, argv, invert, flags, match);
609 }
610
611 *flags = info->match_flags;
612 return true;
613}
614
615static int
616conntrack_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
617 const void *entry, struct xt_entry_match **match)
618{
619 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
620 struct in6_addr *addr = NULL;
621 unsigned int naddrs = 0;
622
623 switch (c) {
624 case '3': /* --ctorigsrc */
625 ip6parse_hostnetworkmask(optarg, &addr,
626 &info->origsrc_mask.in6, &naddrs);
627 if (naddrs > 1)
628 exit_error(PARAMETER_PROBLEM,
629 "multiple IP addresses not allowed");
630 if (naddrs == 1)
631 memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr));
632 info->match_flags |= XT_CONNTRACK_ORIGSRC;
633 if (invert)
634 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
635 break;
636
637 case '4': /* --ctorigdst */
638 ip6parse_hostnetworkmask(optarg, &addr,
639 &info->origdst_mask.in6, &naddrs);
640 if (naddrs > 1)
641 exit_error(PARAMETER_PROBLEM,
642 "multiple IP addresses not allowed");
643 if (naddrs == 1)
644 memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
645 info->match_flags |= XT_CONNTRACK_ORIGDST;
646 if (invert)
647 info->invert_flags |= XT_CONNTRACK_ORIGDST;
648 break;
649
650 case '5': /* --ctreplsrc */
651 ip6parse_hostnetworkmask(optarg, &addr,
652 &info->replsrc_mask.in6, &naddrs);
653 if (naddrs > 1)
654 exit_error(PARAMETER_PROBLEM,
655 "multiple IP addresses not allowed");
656 if (naddrs == 1)
657 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
658 info->match_flags |= XT_CONNTRACK_REPLSRC;
659 if (invert)
660 info->invert_flags |= XT_CONNTRACK_REPLSRC;
661 break;
662
663 case '6': /* --ctrepldst */
664 ip6parse_hostnetworkmask(optarg, &addr,
665 &info->repldst_mask.in6, &naddrs);
666 if (naddrs > 1)
667 exit_error(PARAMETER_PROBLEM,
668 "multiple IP addresses not allowed");
669 if (naddrs == 1)
670 memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
671 info->match_flags |= XT_CONNTRACK_REPLDST;
672 if (invert)
673 info->invert_flags |= XT_CONNTRACK_REPLDST;
674 break;
675
676
677 default:
678 return conntrack_mt_parse(c, argv, invert, flags, match);
679 }
680
681 *flags = info->match_flags;
682 return true;
683}
684
Jan Engelhardta80b6042008-01-20 13:34:07 +0000685static void conntrack_mt_check(unsigned int flags)
Marc Boucher5054e852002-01-19 10:59:12 +0000686{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000687 if (flags == 0)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000688 exit_error(PARAMETER_PROBLEM, "conntrack: At least one option "
689 "is required");
Marc Boucher5054e852002-01-19 10:59:12 +0000690}
691
692static void
693print_state(unsigned int statemask)
694{
695 const char *sep = "";
696
Jan Engelhardta80b6042008-01-20 13:34:07 +0000697 if (statemask & XT_CONNTRACK_STATE_INVALID) {
Marc Boucher5054e852002-01-19 10:59:12 +0000698 printf("%sINVALID", sep);
699 sep = ",";
700 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000701 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000702 printf("%sNEW", sep);
703 sep = ",";
704 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000705 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000706 printf("%sRELATED", sep);
707 sep = ",";
708 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000709 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000710 printf("%sESTABLISHED", sep);
711 sep = ",";
712 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000713 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
Harald Welte4dc734c2003-10-07 18:55:13 +0000714 printf("%sUNTRACKED", sep);
715 sep = ",";
716 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000717 if (statemask & XT_CONNTRACK_STATE_SNAT) {
Marc Boucher5054e852002-01-19 10:59:12 +0000718 printf("%sSNAT", sep);
719 sep = ",";
720 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000721 if (statemask & XT_CONNTRACK_STATE_DNAT) {
Marc Boucher5054e852002-01-19 10:59:12 +0000722 printf("%sDNAT", sep);
723 sep = ",";
724 }
725 printf(" ");
726}
727
728static void
729print_status(unsigned int statusmask)
730{
731 const char *sep = "";
732
733 if (statusmask & IPS_EXPECTED) {
734 printf("%sEXPECTED", sep);
735 sep = ",";
736 }
737 if (statusmask & IPS_SEEN_REPLY) {
738 printf("%sSEEN_REPLY", sep);
739 sep = ",";
740 }
741 if (statusmask & IPS_ASSURED) {
742 printf("%sASSURED", sep);
743 sep = ",";
744 }
Harald Weltea643c3e2003-08-25 11:08:52 +0000745 if (statusmask & IPS_CONFIRMED) {
746 printf("%sCONFIRMED", sep);
Marc Boucher5054e852002-01-19 10:59:12 +0000747 sep = ",";
748 }
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000749 if (statusmask == 0)
750 printf("%sNONE", sep);
Marc Boucher5054e852002-01-19 10:59:12 +0000751 printf(" ");
752}
753
754static void
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000755conntrack_dump_addr(const union nf_inet_addr *addr,
756 const union nf_inet_addr *mask,
757 unsigned int family, bool numeric)
758{
Jan Engelhardt03d99482008-11-18 12:27:54 +0100759 if (family == NFPROTO_IPV4) {
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000760 if (!numeric && addr->ip == 0) {
761 printf("anywhere ");
762 return;
763 }
Jan Engelhardt6b6c0962008-11-10 17:08:07 +0100764 if (numeric)
765 printf("%s ", ipaddr_to_numeric(&addr->in));
766 else
767 printf("%s ", ipaddr_to_anyname(&addr->in));
Jan Engelhardt03d99482008-11-18 12:27:54 +0100768 } else if (family == NFPROTO_IPV6) {
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000769 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
770 addr->ip6[2] == 0 && addr->ip6[3] == 0) {
771 printf("anywhere ");
772 return;
773 }
Jan Engelhardt6b6c0962008-11-10 17:08:07 +0100774 if (numeric)
775 printf("%s ", ip6addr_to_numeric(&addr->in6));
776 else
777 printf("%s ", ip6addr_to_anyname(&addr->in6));
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000778 }
779}
780
781static void
Marc Boucher5054e852002-01-19 10:59:12 +0000782print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric)
783{
784 char buf[BUFSIZ];
785
Jan Engelhardta80b6042008-01-20 13:34:07 +0000786 if (inv)
787 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000788
789 if (mask->s_addr == 0L && !numeric)
790 printf("%s ", "anywhere");
791 else {
792 if (numeric)
Jan Engelhardt08b16162008-01-20 13:36:08 +0000793 sprintf(buf, "%s", ipaddr_to_numeric(addr));
Marc Boucher5054e852002-01-19 10:59:12 +0000794 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000795 sprintf(buf, "%s", ipaddr_to_anyname(addr));
796 strcat(buf, ipmask_to_numeric(mask));
Marc Boucher5054e852002-01-19 10:59:12 +0000797 printf("%s ", buf);
798 }
799}
800
Marc Boucher5054e852002-01-19 10:59:12 +0000801static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000802matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx)
Marc Boucher5054e852002-01-19 10:59:12 +0000803{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000804 struct xt_conntrack_info *sinfo = (void *)match->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000805
Jan Engelhardta80b6042008-01-20 13:34:07 +0000806 if(sinfo->flags & XT_CONNTRACK_STATE) {
807 if (sinfo->invflags & XT_CONNTRACK_STATE)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000808 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000809 printf("%sctstate ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000810 print_state(sinfo->statemask);
811 }
812
Jan Engelhardta80b6042008-01-20 13:34:07 +0000813 if(sinfo->flags & XT_CONNTRACK_PROTO) {
814 if (sinfo->invflags & XT_CONNTRACK_PROTO)
Phil Oester5a4892b2005-11-17 13:34:51 +0000815 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000816 printf("%sctproto ", optpfx);
Phil Oester5a4892b2005-11-17 13:34:51 +0000817 printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum);
818 }
819
Jan Engelhardta80b6042008-01-20 13:34:07 +0000820 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
821 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC)
822 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000823 printf("%sctorigsrc ", optpfx);
824
825 print_addr(
826 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
827 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000828 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000829 numeric);
830 }
831
Jan Engelhardta80b6042008-01-20 13:34:07 +0000832 if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
833 if (sinfo->invflags & XT_CONNTRACK_ORIGDST)
834 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000835 printf("%sctorigdst ", optpfx);
836
837 print_addr(
838 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
839 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000840 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000841 numeric);
842 }
843
Jan Engelhardta80b6042008-01-20 13:34:07 +0000844 if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
845 if (sinfo->invflags & XT_CONNTRACK_REPLSRC)
846 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000847 printf("%sctreplsrc ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000848
849 print_addr(
850 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
851 &sinfo->sipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000852 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000853 numeric);
854 }
855
Jan Engelhardta80b6042008-01-20 13:34:07 +0000856 if(sinfo->flags & XT_CONNTRACK_REPLDST) {
857 if (sinfo->invflags & XT_CONNTRACK_REPLDST)
858 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000859 printf("%sctrepldst ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000860
861 print_addr(
862 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
863 &sinfo->dipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000864 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000865 numeric);
866 }
867
Jan Engelhardta80b6042008-01-20 13:34:07 +0000868 if(sinfo->flags & XT_CONNTRACK_STATUS) {
869 if (sinfo->invflags & XT_CONNTRACK_STATUS)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000870 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000871 printf("%sctstatus ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000872 print_status(sinfo->statusmask);
873 }
874
Jan Engelhardta80b6042008-01-20 13:34:07 +0000875 if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
876 if (sinfo->invflags & XT_CONNTRACK_EXPIRES)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000877 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000878 printf("%sctexpire ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000879
880 if (sinfo->expires_max == sinfo->expires_min)
881 printf("%lu ", sinfo->expires_min);
882 else
883 printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max);
884 }
Jan Engelhardtc7fc1da2008-11-12 12:03:25 +0100885
886 if (sinfo->flags & XT_CONNTRACK_DIRECTION) {
887 if (sinfo->invflags & XT_CONNTRACK_DIRECTION)
888 printf("%sctdir REPLY", optpfx);
889 else
890 printf("%sctdir ORIGINAL", optpfx);
891 }
892
Marc Boucher5054e852002-01-19 10:59:12 +0000893}
894
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000895static void
896conntrack_dump(const struct xt_conntrack_mtinfo1 *info, const char *prefix,
897 unsigned int family, bool numeric)
898{
899 if (info->match_flags & XT_CONNTRACK_STATE) {
900 if (info->invert_flags & XT_CONNTRACK_STATE)
901 printf("! ");
902 printf("%sctstate ", prefix);
903 print_state(info->state_mask);
904 }
905
906 if (info->match_flags & XT_CONNTRACK_PROTO) {
907 if (info->invert_flags & XT_CONNTRACK_PROTO)
908 printf("! ");
909 printf("%sctproto %u ", prefix, info->l4proto);
910 }
911
912 if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
913 if (info->invert_flags & XT_CONNTRACK_PROTO)
914 printf("! ");
915 printf("%sctorigsrc ", prefix);
916 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask,
917 family, numeric);
918 }
919
920 if (info->match_flags & XT_CONNTRACK_ORIGDST) {
921 if (info->invert_flags & XT_CONNTRACK_PROTO)
922 printf("! ");
923 printf("%sctorigdst ", prefix);
924 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask,
925 family, numeric);
926 }
927
928 if (info->match_flags & XT_CONNTRACK_REPLSRC) {
929 if (info->invert_flags & XT_CONNTRACK_PROTO)
930 printf("! ");
931 printf("%sctreplsrc ", prefix);
932 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask,
933 family, numeric);
934 }
935
936 if (info->match_flags & XT_CONNTRACK_REPLDST) {
937 if (info->invert_flags & XT_CONNTRACK_PROTO)
938 printf("! ");
939 printf("%sctrepldst ", prefix);
940 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask,
941 family, numeric);
942 }
943
944 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
945 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)
946 printf("! ");
947 printf("%sctorigsrcport %u ", prefix,
948 ntohs(info->origsrc_port));
949 }
950
951 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
952 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)
953 printf("! ");
954 printf("%sctorigdstport %u ", prefix,
955 ntohs(info->origdst_port));
956 }
957
958 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
959 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)
960 printf("! ");
961 printf("%sctreplsrcport %u ", prefix,
962 ntohs(info->replsrc_port));
963 }
964
965 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) {
966 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT)
967 printf("! ");
968 printf("%sctrepldstport %u ", prefix,
969 ntohs(info->repldst_port));
970 }
971
972 if (info->match_flags & XT_CONNTRACK_STATUS) {
973 if (info->invert_flags & XT_CONNTRACK_STATUS)
974 printf("! ");
975 printf("%sctstatus ", prefix);
976 print_status(info->status_mask);
977 }
978
979 if (info->match_flags & XT_CONNTRACK_EXPIRES) {
980 if (info->invert_flags & XT_CONNTRACK_EXPIRES)
981 printf("! ");
982 printf("%sctexpire ", prefix);
983
984 if (info->expires_max == info->expires_min)
985 printf("%u ", (unsigned int)info->expires_min);
986 else
987 printf("%u:%u ", (unsigned int)info->expires_min,
988 (unsigned int)info->expires_max);
989 }
Jan Engelhardtc7fc1da2008-11-12 12:03:25 +0100990
991 if (info->match_flags & XT_CONNTRACK_DIRECTION) {
992 if (info->invert_flags & XT_CONNTRACK_DIRECTION)
993 printf("%sctdir REPLY", prefix);
994 else
995 printf("%sctdir ORIGINAL", prefix);
996 }
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000997}
998
Jan Engelhardt59d16402007-10-04 16:28:39 +0000999static void conntrack_print(const void *ip, const struct xt_entry_match *match,
1000 int numeric)
Marc Boucher5054e852002-01-19 10:59:12 +00001001{
1002 matchinfo_print(ip, match, numeric, "");
1003}
1004
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001005static void
1006conntrack_mt_print(const void *ip, const struct xt_entry_match *match,
1007 int numeric)
1008{
Jan Engelhardt03d99482008-11-18 12:27:54 +01001009 conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric);
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001010}
1011
1012static void
1013conntrack_mt6_print(const void *ip, const struct xt_entry_match *match,
1014 int numeric)
1015{
Jan Engelhardt03d99482008-11-18 12:27:54 +01001016 conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric);
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001017}
1018
Jan Engelhardt59d16402007-10-04 16:28:39 +00001019static void conntrack_save(const void *ip, const struct xt_entry_match *match)
Marc Boucher5054e852002-01-19 10:59:12 +00001020{
Joszef Kadlecsikdb503f92004-05-05 10:10:33 +00001021 matchinfo_print(ip, match, 1, "--");
Marc Boucher5054e852002-01-19 10:59:12 +00001022}
1023
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001024static void conntrack_mt_save(const void *ip,
1025 const struct xt_entry_match *match)
1026{
Jan Engelhardt03d99482008-11-18 12:27:54 +01001027 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true);
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001028}
1029
1030static void conntrack_mt6_save(const void *ip,
1031 const struct xt_entry_match *match)
1032{
Jan Engelhardt03d99482008-11-18 12:27:54 +01001033 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true);
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001034}
1035
Jan Engelhardta80b6042008-01-20 13:34:07 +00001036static struct xtables_match conntrack_match = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +02001037 .version = XTABLES_VERSION,
Jan Engelhardta80b6042008-01-20 13:34:07 +00001038 .name = "conntrack",
1039 .revision = 0,
Jan Engelhardt03d99482008-11-18 12:27:54 +01001040 .family = NFPROTO_IPV4,
Jan Engelhardta80b6042008-01-20 13:34:07 +00001041 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)),
1042 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)),
1043 .help = conntrack_mt_help,
1044 .parse = conntrack_parse,
1045 .final_check = conntrack_mt_check,
1046 .print = conntrack_print,
1047 .save = conntrack_save,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001048 .extra_opts = conntrack_mt_opts_v0,
1049};
1050
1051static struct xtables_match conntrack_mt_reg = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +02001052 .version = XTABLES_VERSION,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001053 .name = "conntrack",
1054 .revision = 1,
Jan Engelhardt03d99482008-11-18 12:27:54 +01001055 .family = NFPROTO_IPV4,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001056 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1057 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1058 .help = conntrack_mt_help,
1059 .parse = conntrack_mt4_parse,
1060 .final_check = conntrack_mt_check,
1061 .print = conntrack_mt_print,
1062 .save = conntrack_mt_save,
1063 .extra_opts = conntrack_mt_opts,
1064};
1065
1066static struct xtables_match conntrack_mt6_reg = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +02001067 .version = XTABLES_VERSION,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001068 .name = "conntrack",
1069 .revision = 1,
Jan Engelhardt03d99482008-11-18 12:27:54 +01001070 .family = NFPROTO_IPV6,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001071 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1072 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1073 .help = conntrack_mt_help,
1074 .parse = conntrack_mt6_parse,
1075 .final_check = conntrack_mt_check,
1076 .print = conntrack_mt6_print,
1077 .save = conntrack_mt6_save,
Jan Engelhardta80b6042008-01-20 13:34:07 +00001078 .extra_opts = conntrack_mt_opts,
Marc Boucher5054e852002-01-19 10:59:12 +00001079};
1080
1081void _init(void)
1082{
Jan Engelhardta80b6042008-01-20 13:34:07 +00001083 xtables_register_match(&conntrack_match);
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001084 xtables_register_match(&conntrack_mt_reg);
1085 xtables_register_match(&conntrack_mt6_reg);
Marc Boucher5054e852002-01-19 10:59:12 +00001086}