blob: 1d339a03d0b0b6ff756b5cb0bea845d66c644a9c [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
Marc Boucher5054e852002-01-19 10:59:12 +000025/* Function which prints out usage message. */
Jan Engelhardta80b6042008-01-20 13:34:07 +000026static void conntrack_mt_help(void)
Marc Boucher5054e852002-01-19 10:59:12 +000027{
28 printf(
Jan Engelhardta80b6042008-01-20 13:34:07 +000029"conntrack match options:\n"
30"[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n"
31" State(s) to match\n"
32"[!] --ctproto proto Protocol to match; by number or name, e.g. \"tcp\"\n"
33"[!] --ctorigsrc address[/mask]\n"
34"[!] --ctorigdst address[/mask]\n"
35"[!] --ctreplsrc address[/mask]\n"
36"[!] --ctrepldst address[/mask]\n"
37" Original/Reply source/destination address\n"
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000038"[!] --ctorigsrcport port\n"
39"[!] --ctorigdstport port\n"
40"[!] --ctreplsrcport port\n"
41"[!] --ctrepldstport port\n"
42" TCP/UDP/SCTP orig./reply source/destination port\n"
Jan Engelhardta80b6042008-01-20 13:34:07 +000043"[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n"
44" Status(es) to match\n"
45"[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n"
46" value or range of values (inclusive)\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020047" --ctdir {ORIGINAL|REPLY} Flow direction of packet\n");
Marc Boucher5054e852002-01-19 10:59:12 +000048}
49
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000050static const struct option conntrack_mt_opts_v0[] = {
Jan Engelhardta80b6042008-01-20 13:34:07 +000051 {.name = "ctstate", .has_arg = true, .val = '1'},
52 {.name = "ctproto", .has_arg = true, .val = '2'},
53 {.name = "ctorigsrc", .has_arg = true, .val = '3'},
54 {.name = "ctorigdst", .has_arg = true, .val = '4'},
55 {.name = "ctreplsrc", .has_arg = true, .val = '5'},
56 {.name = "ctrepldst", .has_arg = true, .val = '6'},
57 {.name = "ctstatus", .has_arg = true, .val = '7'},
58 {.name = "ctexpire", .has_arg = true, .val = '8'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000059 { .name = NULL }
Marc Boucher5054e852002-01-19 10:59:12 +000060};
61
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000062static const struct option conntrack_mt_opts[] = {
63 {.name = "ctstate", .has_arg = true, .val = '1'},
64 {.name = "ctproto", .has_arg = true, .val = '2'},
65 {.name = "ctorigsrc", .has_arg = true, .val = '3'},
66 {.name = "ctorigdst", .has_arg = true, .val = '4'},
67 {.name = "ctreplsrc", .has_arg = true, .val = '5'},
68 {.name = "ctrepldst", .has_arg = true, .val = '6'},
69 {.name = "ctstatus", .has_arg = true, .val = '7'},
70 {.name = "ctexpire", .has_arg = true, .val = '8'},
71 {.name = "ctorigsrcport", .has_arg = true, .val = 'a'},
72 {.name = "ctorigdstport", .has_arg = true, .val = 'b'},
73 {.name = "ctreplsrcport", .has_arg = true, .val = 'c'},
74 {.name = "ctrepldstport", .has_arg = true, .val = 'd'},
75 {.name = "ctdir", .has_arg = true, .val = 'e'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000076 {.name = NULL},
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000077};
78
Marc Boucher5054e852002-01-19 10:59:12 +000079static int
Jan Engelhardtdbb77542008-02-11 00:33:30 +010080parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +000081{
Jan Engelhardtdbb77542008-02-11 00:33:30 +010082 if (strncasecmp(state, "INVALID", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000083 sinfo->statemask |= XT_CONNTRACK_STATE_INVALID;
Jan Engelhardtdbb77542008-02-11 00:33:30 +010084 else if (strncasecmp(state, "NEW", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000085 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
Jan Engelhardtdbb77542008-02-11 00:33:30 +010086 else if (strncasecmp(state, "ESTABLISHED", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000087 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
Jan Engelhardtdbb77542008-02-11 00:33:30 +010088 else if (strncasecmp(state, "RELATED", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000089 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
Jan Engelhardtdbb77542008-02-11 00:33:30 +010090 else if (strncasecmp(state, "UNTRACKED", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000091 sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED;
Jan Engelhardtdbb77542008-02-11 00:33:30 +010092 else if (strncasecmp(state, "SNAT", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000093 sinfo->statemask |= XT_CONNTRACK_STATE_SNAT;
Jan Engelhardtdbb77542008-02-11 00:33:30 +010094 else if (strncasecmp(state, "DNAT", len) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000095 sinfo->statemask |= XT_CONNTRACK_STATE_DNAT;
Marc Boucher5054e852002-01-19 10:59:12 +000096 else
97 return 0;
98 return 1;
99}
100
101static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000102parse_states(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000103{
104 const char *comma;
105
106 while ((comma = strchr(arg, ',')) != NULL) {
107 if (comma == arg || !parse_state(arg, comma-arg, sinfo))
108 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
109 arg = comma+1;
110 }
111
112 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
113 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
114}
115
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000116static bool
117conntrack_ps_state(struct xt_conntrack_mtinfo1 *info, const char *state,
118 size_t z)
119{
120 if (strncasecmp(state, "INVALID", z) == 0)
121 info->state_mask |= XT_CONNTRACK_STATE_INVALID;
122 else if (strncasecmp(state, "NEW", z) == 0)
123 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
124 else if (strncasecmp(state, "ESTABLISHED", z) == 0)
125 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
126 else if (strncasecmp(state, "RELATED", z) == 0)
127 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
128 else if (strncasecmp(state, "UNTRACKED", z) == 0)
129 info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED;
130 else if (strncasecmp(state, "SNAT", z) == 0)
131 info->state_mask |= XT_CONNTRACK_STATE_SNAT;
132 else if (strncasecmp(state, "DNAT", z) == 0)
133 info->state_mask |= XT_CONNTRACK_STATE_DNAT;
134 else
135 return false;
136 return true;
137}
138
139static void
140conntrack_ps_states(struct xt_conntrack_mtinfo1 *info, const char *arg)
141{
142 const char *comma;
143
144 while ((comma = strchr(arg, ',')) != NULL) {
145 if (comma == arg || !conntrack_ps_state(info, arg, comma - arg))
146 exit_error(PARAMETER_PROBLEM,
147 "Bad ctstate \"%s\"", arg);
148 arg = comma + 1;
149 }
150
151 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg)))
152 exit_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
153}
154
Marc Boucher5054e852002-01-19 10:59:12 +0000155static int
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100156parse_status(const char *status, size_t len, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000157{
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100158 if (strncasecmp(status, "NONE", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000159 sinfo->statusmask |= 0;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100160 else if (strncasecmp(status, "EXPECTED", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000161 sinfo->statusmask |= IPS_EXPECTED;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100162 else if (strncasecmp(status, "SEEN_REPLY", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000163 sinfo->statusmask |= IPS_SEEN_REPLY;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100164 else if (strncasecmp(status, "ASSURED", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000165 sinfo->statusmask |= IPS_ASSURED;
Harald Weltea643c3e2003-08-25 11:08:52 +0000166#ifdef IPS_CONFIRMED
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100167 else if (strncasecmp(status, "CONFIRMED", len) == 0)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000168 sinfo->statusmask |= IPS_CONFIRMED;
Harald Weltea643c3e2003-08-25 11:08:52 +0000169#endif
Marc Boucher5054e852002-01-19 10:59:12 +0000170 else
171 return 0;
172 return 1;
173}
174
175static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000176parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000177{
178 const char *comma;
179
180 while ((comma = strchr(arg, ',')) != NULL) {
181 if (comma == arg || !parse_status(arg, comma-arg, sinfo))
182 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
183 arg = comma+1;
184 }
185
186 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo))
187 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
188}
189
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000190static bool
191conntrack_ps_status(struct xt_conntrack_mtinfo1 *info, const char *status,
192 size_t z)
193{
194 if (strncasecmp(status, "NONE", z) == 0)
195 info->status_mask |= 0;
196 else if (strncasecmp(status, "EXPECTED", z) == 0)
197 info->status_mask |= IPS_EXPECTED;
198 else if (strncasecmp(status, "SEEN_REPLY", z) == 0)
199 info->status_mask |= IPS_SEEN_REPLY;
200 else if (strncasecmp(status, "ASSURED", z) == 0)
201 info->status_mask |= IPS_ASSURED;
202 else if (strncasecmp(status, "CONFIRMED", z) == 0)
203 info->status_mask |= IPS_CONFIRMED;
204 else
205 return false;
206 return true;
207}
208
209static void
210conntrack_ps_statuses(struct xt_conntrack_mtinfo1 *info, const char *arg)
211{
212 const char *comma;
213
214 while ((comma = strchr(arg, ',')) != NULL) {
215 if (comma == arg || !conntrack_ps_status(info, arg, comma - arg))
216 exit_error(PARAMETER_PROBLEM,
217 "Bad ctstatus \"%s\"", arg);
218 arg = comma + 1;
219 }
220
221 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg)))
222 exit_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
223}
224
Marc Boucher5054e852002-01-19 10:59:12 +0000225static unsigned long
226parse_expire(const char *s)
227{
228 unsigned int len;
Jan Engelhardta80b6042008-01-20 13:34:07 +0000229
Martin Josefsson1da399c2004-05-26 15:50:57 +0000230 if (string_to_number(s, 0, 0, &len) == -1)
Marc Boucher5054e852002-01-19 10:59:12 +0000231 exit_error(PARAMETER_PROBLEM, "expire value invalid: `%s'\n", s);
232 else
233 return len;
234}
235
236/* If a single value is provided, min and max are both set to the value */
237static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000238parse_expires(const char *s, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000239{
240 char *buffer;
241 char *cp;
242
243 buffer = strdup(s);
244 if ((cp = strchr(buffer, ':')) == NULL)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000245 sinfo->expires_min = sinfo->expires_max =
246 parse_expire(buffer);
Marc Boucher5054e852002-01-19 10:59:12 +0000247 else {
248 *cp = '\0';
249 cp++;
250
251 sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0;
Max Kellermann9ee386a2008-01-29 13:48:05 +0000252 sinfo->expires_max = cp[0]
253 ? parse_expire(cp)
254 : (unsigned long)-1;
Marc Boucher5054e852002-01-19 10:59:12 +0000255 }
256 free(buffer);
Jan Engelhardta80b6042008-01-20 13:34:07 +0000257
Marc Boucher5054e852002-01-19 10:59:12 +0000258 if (sinfo->expires_min > sinfo->expires_max)
259 exit_error(PARAMETER_PROBLEM,
260 "expire min. range value `%lu' greater than max. "
261 "range value `%lu'", sinfo->expires_min, sinfo->expires_max);
Marc Boucher5054e852002-01-19 10:59:12 +0000262}
263
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000264static void
265conntrack_ps_expires(struct xt_conntrack_mtinfo1 *info, const char *s)
266{
267 unsigned int min, max;
268 char *end;
269
270 if (!strtonum(s, &end, &min, 0, ~0))
271 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
272 max = min;
273 if (*end == ':')
274 if (!strtonum(s, &end, &max, 0, ~0U))
275 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
276 if (*end != '\0')
277 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
278
279 if (min > max)
280 exit_error(PARAMETER_PROBLEM,
281 "expire min. range value \"%u\" greater than max. "
282 "range value \"%u\"", min, max);
283
284 info->expires_min = min;
285 info->expires_max = max;
286}
287
Marc Boucher5054e852002-01-19 10:59:12 +0000288/* Function which parses command options; returns true if it
289 ate an option */
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{
759 if (family == AF_INET) {
760 if (!numeric && addr->ip == 0) {
761 printf("anywhere ");
762 return;
763 }
764 printf("%s ", ipaddr_to_anyname(&addr->in));
765 } else if (family == AF_INET6) {
766 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
767 addr->ip6[2] == 0 && addr->ip6[3] == 0) {
768 printf("anywhere ");
769 return;
770 }
771 printf("%s ", ip6addr_to_anyname(&addr->in6));
772 }
773}
774
775static void
Marc Boucher5054e852002-01-19 10:59:12 +0000776print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric)
777{
778 char buf[BUFSIZ];
779
Jan Engelhardta80b6042008-01-20 13:34:07 +0000780 if (inv)
781 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000782
783 if (mask->s_addr == 0L && !numeric)
784 printf("%s ", "anywhere");
785 else {
786 if (numeric)
Jan Engelhardt08b16162008-01-20 13:36:08 +0000787 sprintf(buf, "%s", ipaddr_to_numeric(addr));
Marc Boucher5054e852002-01-19 10:59:12 +0000788 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000789 sprintf(buf, "%s", ipaddr_to_anyname(addr));
790 strcat(buf, ipmask_to_numeric(mask));
Marc Boucher5054e852002-01-19 10:59:12 +0000791 printf("%s ", buf);
792 }
793}
794
795/* Saves the matchinfo in parsable form to stdout. */
796static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000797matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx)
Marc Boucher5054e852002-01-19 10:59:12 +0000798{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000799 struct xt_conntrack_info *sinfo = (void *)match->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000800
Jan Engelhardta80b6042008-01-20 13:34:07 +0000801 if(sinfo->flags & XT_CONNTRACK_STATE) {
802 if (sinfo->invflags & XT_CONNTRACK_STATE)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000803 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000804 printf("%sctstate ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000805 print_state(sinfo->statemask);
806 }
807
Jan Engelhardta80b6042008-01-20 13:34:07 +0000808 if(sinfo->flags & XT_CONNTRACK_PROTO) {
809 if (sinfo->invflags & XT_CONNTRACK_PROTO)
Phil Oester5a4892b2005-11-17 13:34:51 +0000810 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000811 printf("%sctproto ", optpfx);
Phil Oester5a4892b2005-11-17 13:34:51 +0000812 printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum);
813 }
814
Jan Engelhardta80b6042008-01-20 13:34:07 +0000815 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
816 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC)
817 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000818 printf("%sctorigsrc ", optpfx);
819
820 print_addr(
821 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
822 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000823 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000824 numeric);
825 }
826
Jan Engelhardta80b6042008-01-20 13:34:07 +0000827 if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
828 if (sinfo->invflags & XT_CONNTRACK_ORIGDST)
829 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000830 printf("%sctorigdst ", optpfx);
831
832 print_addr(
833 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
834 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000835 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000836 numeric);
837 }
838
Jan Engelhardta80b6042008-01-20 13:34:07 +0000839 if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
840 if (sinfo->invflags & XT_CONNTRACK_REPLSRC)
841 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000842 printf("%sctreplsrc ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000843
844 print_addr(
845 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
846 &sinfo->sipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000847 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000848 numeric);
849 }
850
Jan Engelhardta80b6042008-01-20 13:34:07 +0000851 if(sinfo->flags & XT_CONNTRACK_REPLDST) {
852 if (sinfo->invflags & XT_CONNTRACK_REPLDST)
853 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000854 printf("%sctrepldst ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000855
856 print_addr(
857 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
858 &sinfo->dipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000859 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000860 numeric);
861 }
862
Jan Engelhardta80b6042008-01-20 13:34:07 +0000863 if(sinfo->flags & XT_CONNTRACK_STATUS) {
864 if (sinfo->invflags & XT_CONNTRACK_STATUS)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000865 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000866 printf("%sctstatus ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000867 print_status(sinfo->statusmask);
868 }
869
Jan Engelhardta80b6042008-01-20 13:34:07 +0000870 if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
871 if (sinfo->invflags & XT_CONNTRACK_EXPIRES)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000872 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000873 printf("%sctexpire ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000874
875 if (sinfo->expires_max == sinfo->expires_min)
876 printf("%lu ", sinfo->expires_min);
877 else
878 printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max);
879 }
880}
881
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000882static void
883conntrack_dump(const struct xt_conntrack_mtinfo1 *info, const char *prefix,
884 unsigned int family, bool numeric)
885{
886 if (info->match_flags & XT_CONNTRACK_STATE) {
887 if (info->invert_flags & XT_CONNTRACK_STATE)
888 printf("! ");
889 printf("%sctstate ", prefix);
890 print_state(info->state_mask);
891 }
892
893 if (info->match_flags & XT_CONNTRACK_PROTO) {
894 if (info->invert_flags & XT_CONNTRACK_PROTO)
895 printf("! ");
896 printf("%sctproto %u ", prefix, info->l4proto);
897 }
898
899 if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
900 if (info->invert_flags & XT_CONNTRACK_PROTO)
901 printf("! ");
902 printf("%sctorigsrc ", prefix);
903 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask,
904 family, numeric);
905 }
906
907 if (info->match_flags & XT_CONNTRACK_ORIGDST) {
908 if (info->invert_flags & XT_CONNTRACK_PROTO)
909 printf("! ");
910 printf("%sctorigdst ", prefix);
911 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask,
912 family, numeric);
913 }
914
915 if (info->match_flags & XT_CONNTRACK_REPLSRC) {
916 if (info->invert_flags & XT_CONNTRACK_PROTO)
917 printf("! ");
918 printf("%sctreplsrc ", prefix);
919 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask,
920 family, numeric);
921 }
922
923 if (info->match_flags & XT_CONNTRACK_REPLDST) {
924 if (info->invert_flags & XT_CONNTRACK_PROTO)
925 printf("! ");
926 printf("%sctrepldst ", prefix);
927 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask,
928 family, numeric);
929 }
930
931 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
932 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)
933 printf("! ");
934 printf("%sctorigsrcport %u ", prefix,
935 ntohs(info->origsrc_port));
936 }
937
938 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
939 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)
940 printf("! ");
941 printf("%sctorigdstport %u ", prefix,
942 ntohs(info->origdst_port));
943 }
944
945 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
946 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)
947 printf("! ");
948 printf("%sctreplsrcport %u ", prefix,
949 ntohs(info->replsrc_port));
950 }
951
952 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) {
953 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT)
954 printf("! ");
955 printf("%sctrepldstport %u ", prefix,
956 ntohs(info->repldst_port));
957 }
958
959 if (info->match_flags & XT_CONNTRACK_STATUS) {
960 if (info->invert_flags & XT_CONNTRACK_STATUS)
961 printf("! ");
962 printf("%sctstatus ", prefix);
963 print_status(info->status_mask);
964 }
965
966 if (info->match_flags & XT_CONNTRACK_EXPIRES) {
967 if (info->invert_flags & XT_CONNTRACK_EXPIRES)
968 printf("! ");
969 printf("%sctexpire ", prefix);
970
971 if (info->expires_max == info->expires_min)
972 printf("%u ", (unsigned int)info->expires_min);
973 else
974 printf("%u:%u ", (unsigned int)info->expires_min,
975 (unsigned int)info->expires_max);
976 }
977}
978
Marc Boucher5054e852002-01-19 10:59:12 +0000979/* Prints out the matchinfo. */
Jan Engelhardt59d16402007-10-04 16:28:39 +0000980static void conntrack_print(const void *ip, const struct xt_entry_match *match,
981 int numeric)
Marc Boucher5054e852002-01-19 10:59:12 +0000982{
983 matchinfo_print(ip, match, numeric, "");
984}
985
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000986static void
987conntrack_mt_print(const void *ip, const struct xt_entry_match *match,
988 int numeric)
989{
990 conntrack_dump((const void *)match->data, "", AF_INET, numeric);
991}
992
993static void
994conntrack_mt6_print(const void *ip, const struct xt_entry_match *match,
995 int numeric)
996{
997 conntrack_dump((const void *)match->data, "", AF_INET6, numeric);
998}
999
Marc Boucher5054e852002-01-19 10:59:12 +00001000/* Saves the matchinfo in parsable form to stdout. */
Jan Engelhardt59d16402007-10-04 16:28:39 +00001001static void conntrack_save(const void *ip, const struct xt_entry_match *match)
Marc Boucher5054e852002-01-19 10:59:12 +00001002{
Joszef Kadlecsikdb503f92004-05-05 10:10:33 +00001003 matchinfo_print(ip, match, 1, "--");
Marc Boucher5054e852002-01-19 10:59:12 +00001004}
1005
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001006static void conntrack_mt_save(const void *ip,
1007 const struct xt_entry_match *match)
1008{
1009 conntrack_dump((const void *)match->data, "--", AF_INET, true);
1010}
1011
1012static void conntrack_mt6_save(const void *ip,
1013 const struct xt_entry_match *match)
1014{
1015 conntrack_dump((const void *)match->data, "--", AF_INET6, true);
1016}
1017
Jan Engelhardta80b6042008-01-20 13:34:07 +00001018static struct xtables_match conntrack_match = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +02001019 .version = XTABLES_VERSION,
Jan Engelhardta80b6042008-01-20 13:34:07 +00001020 .name = "conntrack",
1021 .revision = 0,
1022 .family = AF_INET,
1023 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)),
1024 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)),
1025 .help = conntrack_mt_help,
1026 .parse = conntrack_parse,
1027 .final_check = conntrack_mt_check,
1028 .print = conntrack_print,
1029 .save = conntrack_save,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001030 .extra_opts = conntrack_mt_opts_v0,
1031};
1032
1033static struct xtables_match conntrack_mt_reg = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +02001034 .version = XTABLES_VERSION,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001035 .name = "conntrack",
1036 .revision = 1,
1037 .family = AF_INET,
1038 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1039 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1040 .help = conntrack_mt_help,
1041 .parse = conntrack_mt4_parse,
1042 .final_check = conntrack_mt_check,
1043 .print = conntrack_mt_print,
1044 .save = conntrack_mt_save,
1045 .extra_opts = conntrack_mt_opts,
1046};
1047
1048static struct xtables_match conntrack_mt6_reg = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +02001049 .version = XTABLES_VERSION,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001050 .name = "conntrack",
1051 .revision = 1,
1052 .family = AF_INET6,
1053 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1054 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1055 .help = conntrack_mt_help,
1056 .parse = conntrack_mt6_parse,
1057 .final_check = conntrack_mt_check,
1058 .print = conntrack_mt6_print,
1059 .save = conntrack_mt6_save,
Jan Engelhardta80b6042008-01-20 13:34:07 +00001060 .extra_opts = conntrack_mt_opts,
Marc Boucher5054e852002-01-19 10:59:12 +00001061};
1062
1063void _init(void)
1064{
Jan Engelhardta80b6042008-01-20 13:34:07 +00001065 xtables_register_match(&conntrack_match);
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001066 xtables_register_match(&conntrack_mt_reg);
1067 xtables_register_match(&conntrack_mt6_reg);
Marc Boucher5054e852002-01-19 10:59:12 +00001068}