blob: d076d494d53645224e679e4f8893257930f54a7a [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 Engelhardta8ad34c2008-01-29 13:37:21 +000047" --ctdir {ORIGINAL|REPLY} Flow direction of packet\n"
Jan Engelhardta80b6042008-01-20 13:34:07 +000048"\n");
Marc Boucher5054e852002-01-19 10:59:12 +000049}
50
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000051static const struct option conntrack_mt_opts_v0[] = {
Jan Engelhardta80b6042008-01-20 13:34:07 +000052 {.name = "ctstate", .has_arg = true, .val = '1'},
53 {.name = "ctproto", .has_arg = true, .val = '2'},
54 {.name = "ctorigsrc", .has_arg = true, .val = '3'},
55 {.name = "ctorigdst", .has_arg = true, .val = '4'},
56 {.name = "ctreplsrc", .has_arg = true, .val = '5'},
57 {.name = "ctrepldst", .has_arg = true, .val = '6'},
58 {.name = "ctstatus", .has_arg = true, .val = '7'},
59 {.name = "ctexpire", .has_arg = true, .val = '8'},
60 {},
Marc Boucher5054e852002-01-19 10:59:12 +000061};
62
Jan Engelhardta8ad34c2008-01-29 13:37:21 +000063static const struct option conntrack_mt_opts[] = {
64 {.name = "ctstate", .has_arg = true, .val = '1'},
65 {.name = "ctproto", .has_arg = true, .val = '2'},
66 {.name = "ctorigsrc", .has_arg = true, .val = '3'},
67 {.name = "ctorigdst", .has_arg = true, .val = '4'},
68 {.name = "ctreplsrc", .has_arg = true, .val = '5'},
69 {.name = "ctrepldst", .has_arg = true, .val = '6'},
70 {.name = "ctstatus", .has_arg = true, .val = '7'},
71 {.name = "ctexpire", .has_arg = true, .val = '8'},
72 {.name = "ctorigsrcport", .has_arg = true, .val = 'a'},
73 {.name = "ctorigdstport", .has_arg = true, .val = 'b'},
74 {.name = "ctreplsrcport", .has_arg = true, .val = 'c'},
75 {.name = "ctrepldstport", .has_arg = true, .val = 'd'},
76 {.name = "ctdir", .has_arg = true, .val = 'e'},
77 {},
78};
79
Marc Boucher5054e852002-01-19 10:59:12 +000080static int
Jan Engelhardta80b6042008-01-20 13:34:07 +000081parse_state(const char *state, size_t strlen, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +000082{
83 if (strncasecmp(state, "INVALID", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000084 sinfo->statemask |= XT_CONNTRACK_STATE_INVALID;
Marc Boucher5054e852002-01-19 10:59:12 +000085 else if (strncasecmp(state, "NEW", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000086 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
Marc Boucher5054e852002-01-19 10:59:12 +000087 else if (strncasecmp(state, "ESTABLISHED", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000088 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
Marc Boucher5054e852002-01-19 10:59:12 +000089 else if (strncasecmp(state, "RELATED", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000090 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
Harald Welte4dc734c2003-10-07 18:55:13 +000091 else if (strncasecmp(state, "UNTRACKED", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000092 sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED;
Marc Boucher5054e852002-01-19 10:59:12 +000093 else if (strncasecmp(state, "SNAT", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000094 sinfo->statemask |= XT_CONNTRACK_STATE_SNAT;
Marc Boucher5054e852002-01-19 10:59:12 +000095 else if (strncasecmp(state, "DNAT", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000096 sinfo->statemask |= XT_CONNTRACK_STATE_DNAT;
Marc Boucher5054e852002-01-19 10:59:12 +000097 else
98 return 0;
99 return 1;
100}
101
102static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000103parse_states(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000104{
105 const char *comma;
106
107 while ((comma = strchr(arg, ',')) != NULL) {
108 if (comma == arg || !parse_state(arg, comma-arg, sinfo))
109 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
110 arg = comma+1;
111 }
112
113 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
114 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
115}
116
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000117static bool
118conntrack_ps_state(struct xt_conntrack_mtinfo1 *info, const char *state,
119 size_t z)
120{
121 if (strncasecmp(state, "INVALID", z) == 0)
122 info->state_mask |= XT_CONNTRACK_STATE_INVALID;
123 else if (strncasecmp(state, "NEW", z) == 0)
124 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
125 else if (strncasecmp(state, "ESTABLISHED", z) == 0)
126 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
127 else if (strncasecmp(state, "RELATED", z) == 0)
128 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
129 else if (strncasecmp(state, "UNTRACKED", z) == 0)
130 info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED;
131 else if (strncasecmp(state, "SNAT", z) == 0)
132 info->state_mask |= XT_CONNTRACK_STATE_SNAT;
133 else if (strncasecmp(state, "DNAT", z) == 0)
134 info->state_mask |= XT_CONNTRACK_STATE_DNAT;
135 else
136 return false;
137 return true;
138}
139
140static void
141conntrack_ps_states(struct xt_conntrack_mtinfo1 *info, const char *arg)
142{
143 const char *comma;
144
145 while ((comma = strchr(arg, ',')) != NULL) {
146 if (comma == arg || !conntrack_ps_state(info, arg, comma - arg))
147 exit_error(PARAMETER_PROBLEM,
148 "Bad ctstate \"%s\"", arg);
149 arg = comma + 1;
150 }
151
152 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg)))
153 exit_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
154}
155
Marc Boucher5054e852002-01-19 10:59:12 +0000156static int
Jan Engelhardta80b6042008-01-20 13:34:07 +0000157parse_status(const char *status, size_t strlen, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000158{
159 if (strncasecmp(status, "NONE", strlen) == 0)
160 sinfo->statusmask |= 0;
161 else if (strncasecmp(status, "EXPECTED", strlen) == 0)
162 sinfo->statusmask |= IPS_EXPECTED;
163 else if (strncasecmp(status, "SEEN_REPLY", strlen) == 0)
164 sinfo->statusmask |= IPS_SEEN_REPLY;
165 else if (strncasecmp(status, "ASSURED", strlen) == 0)
166 sinfo->statusmask |= IPS_ASSURED;
Harald Weltea643c3e2003-08-25 11:08:52 +0000167#ifdef IPS_CONFIRMED
168 else if (strncasecmp(status, "CONFIRMED", strlen) == 0)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000169 sinfo->statusmask |= IPS_CONFIRMED;
Harald Weltea643c3e2003-08-25 11:08:52 +0000170#endif
Marc Boucher5054e852002-01-19 10:59:12 +0000171 else
172 return 0;
173 return 1;
174}
175
176static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000177parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000178{
179 const char *comma;
180
181 while ((comma = strchr(arg, ',')) != NULL) {
182 if (comma == arg || !parse_status(arg, comma-arg, sinfo))
183 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
184 arg = comma+1;
185 }
186
187 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo))
188 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
189}
190
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000191static bool
192conntrack_ps_status(struct xt_conntrack_mtinfo1 *info, const char *status,
193 size_t z)
194{
195 if (strncasecmp(status, "NONE", z) == 0)
196 info->status_mask |= 0;
197 else if (strncasecmp(status, "EXPECTED", z) == 0)
198 info->status_mask |= IPS_EXPECTED;
199 else if (strncasecmp(status, "SEEN_REPLY", z) == 0)
200 info->status_mask |= IPS_SEEN_REPLY;
201 else if (strncasecmp(status, "ASSURED", z) == 0)
202 info->status_mask |= IPS_ASSURED;
203 else if (strncasecmp(status, "CONFIRMED", z) == 0)
204 info->status_mask |= IPS_CONFIRMED;
205 else
206 return false;
207 return true;
208}
209
210static void
211conntrack_ps_statuses(struct xt_conntrack_mtinfo1 *info, const char *arg)
212{
213 const char *comma;
214
215 while ((comma = strchr(arg, ',')) != NULL) {
216 if (comma == arg || !conntrack_ps_status(info, arg, comma - arg))
217 exit_error(PARAMETER_PROBLEM,
218 "Bad ctstatus \"%s\"", arg);
219 arg = comma + 1;
220 }
221
222 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg)))
223 exit_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
224}
225
Marc Boucher5054e852002-01-19 10:59:12 +0000226static unsigned long
227parse_expire(const char *s)
228{
229 unsigned int len;
Jan Engelhardta80b6042008-01-20 13:34:07 +0000230
Martin Josefsson1da399c2004-05-26 15:50:57 +0000231 if (string_to_number(s, 0, 0, &len) == -1)
Marc Boucher5054e852002-01-19 10:59:12 +0000232 exit_error(PARAMETER_PROBLEM, "expire value invalid: `%s'\n", s);
233 else
234 return len;
235}
236
237/* If a single value is provided, min and max are both set to the value */
238static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000239parse_expires(const char *s, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000240{
241 char *buffer;
242 char *cp;
243
244 buffer = strdup(s);
245 if ((cp = strchr(buffer, ':')) == NULL)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000246 sinfo->expires_min = sinfo->expires_max =
247 parse_expire(buffer);
Marc Boucher5054e852002-01-19 10:59:12 +0000248 else {
249 *cp = '\0';
250 cp++;
251
252 sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0;
Martin Josefsson1da399c2004-05-26 15:50:57 +0000253 sinfo->expires_max = cp[0] ? parse_expire(cp) : -1;
Marc Boucher5054e852002-01-19 10:59:12 +0000254 }
255 free(buffer);
Jan Engelhardta80b6042008-01-20 13:34:07 +0000256
Marc Boucher5054e852002-01-19 10:59:12 +0000257 if (sinfo->expires_min > sinfo->expires_max)
258 exit_error(PARAMETER_PROBLEM,
259 "expire min. range value `%lu' greater than max. "
260 "range value `%lu'", sinfo->expires_min, sinfo->expires_max);
Marc Boucher5054e852002-01-19 10:59:12 +0000261}
262
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000263static void
264conntrack_ps_expires(struct xt_conntrack_mtinfo1 *info, const char *s)
265{
266 unsigned int min, max;
267 char *end;
268
269 if (!strtonum(s, &end, &min, 0, ~0))
270 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
271 max = min;
272 if (*end == ':')
273 if (!strtonum(s, &end, &max, 0, ~0U))
274 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
275 if (*end != '\0')
276 param_act(P_BAD_VALUE, "conntrack", "--expires", s);
277
278 if (min > max)
279 exit_error(PARAMETER_PROBLEM,
280 "expire min. range value \"%u\" greater than max. "
281 "range value \"%u\"", min, max);
282
283 info->expires_min = min;
284 info->expires_max = max;
285}
286
Marc Boucher5054e852002-01-19 10:59:12 +0000287/* Function which parses command options; returns true if it
288 ate an option */
Jan Engelhardt59d16402007-10-04 16:28:39 +0000289static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags,
290 const void *entry, struct xt_entry_match **match)
Marc Boucher5054e852002-01-19 10:59:12 +0000291{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000292 struct xt_conntrack_info *sinfo = (void *)(*match)->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000293 char *protocol = NULL;
294 unsigned int naddrs = 0;
295 struct in_addr *addrs = NULL;
296
297
298 switch (c) {
299 case '1':
Harald Welteb77f1da2002-03-14 11:35:58 +0000300 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000301
302 parse_states(argv[optind-1], sinfo);
303 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000304 sinfo->invflags |= XT_CONNTRACK_STATE;
Marc Boucher5054e852002-01-19 10:59:12 +0000305 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000306 sinfo->flags |= XT_CONNTRACK_STATE;
Marc Boucher5054e852002-01-19 10:59:12 +0000307 break;
308
309 case '2':
Harald Welte3c5bd602002-03-14 19:54:34 +0000310 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000311
312 if(invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000313 sinfo->invflags |= XT_CONNTRACK_PROTO;
Marc Boucher5054e852002-01-19 10:59:12 +0000314
315 /* Canonicalize into lower case */
316 for (protocol = argv[optind-1]; *protocol; protocol++)
317 *protocol = tolower(*protocol);
318
319 protocol = argv[optind-1];
320 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = parse_protocol(protocol);
321
322 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0
Jan Engelhardta80b6042008-01-20 13:34:07 +0000323 && (sinfo->invflags & XT_INV_PROTO))
Marc Boucher5054e852002-01-19 10:59:12 +0000324 exit_error(PARAMETER_PROBLEM,
325 "rule would never match protocol");
326
Jan Engelhardta80b6042008-01-20 13:34:07 +0000327 sinfo->flags |= XT_CONNTRACK_PROTO;
Marc Boucher5054e852002-01-19 10:59:12 +0000328 break;
329
330 case '3':
Jan Engelhardt40eaf2a2007-11-25 15:25:23 +0000331 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000332
333 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000334 sinfo->invflags |= XT_CONNTRACK_ORIGSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000335
Jan Engelhardtbd943842008-01-20 13:38:08 +0000336 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000337 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
338 &naddrs);
339 if(naddrs > 1)
340 exit_error(PARAMETER_PROBLEM,
341 "multiple IP addresses not allowed");
342
343 if(naddrs == 1) {
344 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr;
345 }
346
Jan Engelhardta80b6042008-01-20 13:34:07 +0000347 sinfo->flags |= XT_CONNTRACK_ORIGSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000348 break;
349
350 case '4':
Harald Welteb77f1da2002-03-14 11:35:58 +0000351 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000352
353 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000354 sinfo->invflags |= XT_CONNTRACK_ORIGDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000355
Jan Engelhardtbd943842008-01-20 13:38:08 +0000356 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000357 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
358 &naddrs);
359 if(naddrs > 1)
360 exit_error(PARAMETER_PROBLEM,
361 "multiple IP addresses not allowed");
362
363 if(naddrs == 1) {
364 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr;
365 }
366
Jan Engelhardta80b6042008-01-20 13:34:07 +0000367 sinfo->flags |= XT_CONNTRACK_ORIGDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000368 break;
369
370 case '5':
Harald Welteb77f1da2002-03-14 11:35:58 +0000371 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000372
373 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000374 sinfo->invflags |= XT_CONNTRACK_REPLSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000375
Jan Engelhardtbd943842008-01-20 13:38:08 +0000376 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000377 &sinfo->sipmsk[IP_CT_DIR_REPLY],
378 &naddrs);
379 if(naddrs > 1)
380 exit_error(PARAMETER_PROBLEM,
381 "multiple IP addresses not allowed");
382
383 if(naddrs == 1) {
384 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr;
385 }
386
Jan Engelhardta80b6042008-01-20 13:34:07 +0000387 sinfo->flags |= XT_CONNTRACK_REPLSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000388 break;
389
390 case '6':
Harald Welteb77f1da2002-03-14 11:35:58 +0000391 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000392
393 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000394 sinfo->invflags |= XT_CONNTRACK_REPLDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000395
Jan Engelhardtbd943842008-01-20 13:38:08 +0000396 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000397 &sinfo->dipmsk[IP_CT_DIR_REPLY],
398 &naddrs);
399 if(naddrs > 1)
400 exit_error(PARAMETER_PROBLEM,
401 "multiple IP addresses not allowed");
402
403 if(naddrs == 1) {
404 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr;
405 }
406
Jan Engelhardta80b6042008-01-20 13:34:07 +0000407 sinfo->flags |= XT_CONNTRACK_REPLDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000408 break;
409
410 case '7':
Harald Welteb77f1da2002-03-14 11:35:58 +0000411 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000412
413 parse_statuses(argv[optind-1], sinfo);
414 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000415 sinfo->invflags |= XT_CONNTRACK_STATUS;
Marc Boucher5054e852002-01-19 10:59:12 +0000416 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000417 sinfo->flags |= XT_CONNTRACK_STATUS;
Marc Boucher5054e852002-01-19 10:59:12 +0000418 break;
419
420 case '8':
Harald Welteb77f1da2002-03-14 11:35:58 +0000421 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000422
423 parse_expires(argv[optind-1], sinfo);
424 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000425 sinfo->invflags |= XT_CONNTRACK_EXPIRES;
Marc Boucher5054e852002-01-19 10:59:12 +0000426 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000427 sinfo->flags |= XT_CONNTRACK_EXPIRES;
Marc Boucher5054e852002-01-19 10:59:12 +0000428 break;
429
430 default:
431 return 0;
432 }
433
434 *flags = sinfo->flags;
435 return 1;
436}
437
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000438static int
439conntrack_mt_parse(int c, char **argv, int invert, unsigned int *flags,
440 struct xt_entry_match **match)
441{
442 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
443 unsigned int port;
444 char *p;
445
446 switch (c) {
447 case '1': /* --ctstate */
448 conntrack_ps_states(info, optarg);
449 info->match_flags |= XT_CONNTRACK_STATE;
450 if (invert)
451 info->invert_flags |= XT_CONNTRACK_STATE;
452 break;
453
454 case '2': /* --ctproto */
455 /* Canonicalize into lower case */
456 for (p = optarg; *p != '\0'; ++p)
457 *p = tolower(*p);
458 info->l4proto = parse_protocol(optarg);
459
460 if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO))
461 exit_error(PARAMETER_PROBLEM, "conntrack: rule would "
462 "never match protocol");
463
464 info->match_flags |= XT_CONNTRACK_PROTO;
465 if (invert)
466 info->invert_flags |= XT_CONNTRACK_PROTO;
467 break;
468
469 case '7': /* --ctstatus */
470 conntrack_ps_statuses(info, optarg);
471 info->match_flags |= XT_CONNTRACK_STATUS;
472 if (invert)
473 info->invert_flags |= XT_CONNTRACK_STATUS;
474 break;
475
476 case '8': /* --ctexpire */
477 conntrack_ps_expires(info, optarg);
478 info->match_flags |= XT_CONNTRACK_EXPIRES;
479 if (invert)
480 info->invert_flags |= XT_CONNTRACK_EXPIRES;
481 break;
482
483 case 'a': /* --ctorigsrcport */
484 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
485 param_act(P_BAD_VALUE, "conntrack",
486 "--ctorigsrcport", optarg);
487 info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT;
488 info->origsrc_port = htons(port);
489 if (invert)
490 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT;
491 break;
492
493 case 'b': /* --ctorigdstport */
494 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
495 param_act(P_BAD_VALUE, "conntrack",
496 "--ctorigdstport", optarg);
497 info->match_flags |= XT_CONNTRACK_ORIGDST_PORT;
498 info->origdst_port = htons(port);
499 if (invert)
500 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT;
501 break;
502
503 case 'c': /* --ctreplsrcport */
504 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
505 param_act(P_BAD_VALUE, "conntrack",
506 "--ctreplsrcport", optarg);
507 info->match_flags |= XT_CONNTRACK_REPLSRC_PORT;
508 info->replsrc_port = htons(port);
509 if (invert)
510 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT;
511 break;
512
513 case 'd': /* --ctrepldstport */
514 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
515 param_act(P_BAD_VALUE, "conntrack",
516 "--ctrepldstport", optarg);
517 info->match_flags |= XT_CONNTRACK_REPLDST_PORT;
518 info->repldst_port = htons(port);
519 if (invert)
520 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT;
521 break;
522
523 case 'e': /* --ctdir */
524 param_act(P_NO_INVERT, "conntrack", "--ctdir", invert);
525 if (strcasecmp(optarg, "ORIGINAL") == 0) {
526 info->match_flags |= XT_CONNTRACK_DIRECTION;
527 info->invert_flags &= ~XT_CONNTRACK_DIRECTION;
528 } else if (strcasecmp(optarg, "REPLY") == 0) {
529 info->match_flags |= XT_CONNTRACK_DIRECTION;
530 info->invert_flags |= XT_CONNTRACK_DIRECTION;
531 } else {
532 param_act(P_BAD_VALUE, "conntrack", "--ctdir", optarg);
533 }
534 break;
535
536 default:
537 return false;
538 }
539
540 *flags = info->match_flags;
541 return true;
542}
543
544static int
545conntrack_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
546 const void *entry, struct xt_entry_match **match)
547{
548 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
549 struct in_addr *addr = NULL;
550 unsigned int naddrs = 0;
551
552 switch (c) {
553 case '3': /* --ctorigsrc */
554 ipparse_hostnetworkmask(optarg, &addr, &info->origsrc_mask.in,
555 &naddrs);
556 if (naddrs > 1)
557 exit_error(PARAMETER_PROBLEM,
558 "multiple IP addresses not allowed");
559 if (naddrs == 1)
560 memcpy(&info->origsrc_addr.in, addr, sizeof(*addr));
561 info->match_flags |= XT_CONNTRACK_ORIGSRC;
562 if (invert)
563 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
564 break;
565
566 case '4': /* --ctorigdst */
567 ipparse_hostnetworkmask(optarg, &addr, &info->origdst_mask.in,
568 &naddrs);
569 if (naddrs > 1)
570 exit_error(PARAMETER_PROBLEM,
571 "multiple IP addresses not allowed");
572 if (naddrs == 1)
573 memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
574 info->match_flags |= XT_CONNTRACK_ORIGDST;
575 if (invert)
576 info->invert_flags |= XT_CONNTRACK_ORIGDST;
577 break;
578
579 case '5': /* --ctreplsrc */
580 ipparse_hostnetworkmask(optarg, &addr, &info->replsrc_mask.in,
581 &naddrs);
582 if (naddrs > 1)
583 exit_error(PARAMETER_PROBLEM,
584 "multiple IP addresses not allowed");
585 if (naddrs == 1)
586 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
587 info->match_flags |= XT_CONNTRACK_REPLSRC;
588 if (invert)
589 info->invert_flags |= XT_CONNTRACK_REPLSRC;
590 break;
591
592 case '6': /* --ctrepldst */
593 ipparse_hostnetworkmask(optarg, &addr, &info->repldst_mask.in,
594 &naddrs);
595 if (naddrs > 1)
596 exit_error(PARAMETER_PROBLEM,
597 "multiple IP addresses not allowed");
598 if (naddrs == 1)
599 memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
600 info->match_flags |= XT_CONNTRACK_REPLDST;
601 if (invert)
602 info->invert_flags |= XT_CONNTRACK_REPLDST;
603 break;
604
605
606 default:
607 return conntrack_mt_parse(c, argv, invert, flags, match);
608 }
609
610 *flags = info->match_flags;
611 return true;
612}
613
614static int
615conntrack_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
616 const void *entry, struct xt_entry_match **match)
617{
618 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
619 struct in6_addr *addr = NULL;
620 unsigned int naddrs = 0;
621
622 switch (c) {
623 case '3': /* --ctorigsrc */
624 ip6parse_hostnetworkmask(optarg, &addr,
625 &info->origsrc_mask.in6, &naddrs);
626 if (naddrs > 1)
627 exit_error(PARAMETER_PROBLEM,
628 "multiple IP addresses not allowed");
629 if (naddrs == 1)
630 memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr));
631 info->match_flags |= XT_CONNTRACK_ORIGSRC;
632 if (invert)
633 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
634 break;
635
636 case '4': /* --ctorigdst */
637 ip6parse_hostnetworkmask(optarg, &addr,
638 &info->origdst_mask.in6, &naddrs);
639 if (naddrs > 1)
640 exit_error(PARAMETER_PROBLEM,
641 "multiple IP addresses not allowed");
642 if (naddrs == 1)
643 memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
644 info->match_flags |= XT_CONNTRACK_ORIGDST;
645 if (invert)
646 info->invert_flags |= XT_CONNTRACK_ORIGDST;
647 break;
648
649 case '5': /* --ctreplsrc */
650 ip6parse_hostnetworkmask(optarg, &addr,
651 &info->replsrc_mask.in6, &naddrs);
652 if (naddrs > 1)
653 exit_error(PARAMETER_PROBLEM,
654 "multiple IP addresses not allowed");
655 if (naddrs == 1)
656 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
657 info->match_flags |= XT_CONNTRACK_REPLSRC;
658 if (invert)
659 info->invert_flags |= XT_CONNTRACK_REPLSRC;
660 break;
661
662 case '6': /* --ctrepldst */
663 ip6parse_hostnetworkmask(optarg, &addr,
664 &info->repldst_mask.in6, &naddrs);
665 if (naddrs > 1)
666 exit_error(PARAMETER_PROBLEM,
667 "multiple IP addresses not allowed");
668 if (naddrs == 1)
669 memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
670 info->match_flags |= XT_CONNTRACK_REPLDST;
671 if (invert)
672 info->invert_flags |= XT_CONNTRACK_REPLDST;
673 break;
674
675
676 default:
677 return conntrack_mt_parse(c, argv, invert, flags, match);
678 }
679
680 *flags = info->match_flags;
681 return true;
682}
683
Jan Engelhardta80b6042008-01-20 13:34:07 +0000684static void conntrack_mt_check(unsigned int flags)
Marc Boucher5054e852002-01-19 10:59:12 +0000685{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000686 if (flags == 0)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000687 exit_error(PARAMETER_PROBLEM, "conntrack: At least one option "
688 "is required");
Marc Boucher5054e852002-01-19 10:59:12 +0000689}
690
691static void
692print_state(unsigned int statemask)
693{
694 const char *sep = "";
695
Jan Engelhardta80b6042008-01-20 13:34:07 +0000696 if (statemask & XT_CONNTRACK_STATE_INVALID) {
Marc Boucher5054e852002-01-19 10:59:12 +0000697 printf("%sINVALID", sep);
698 sep = ",";
699 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000700 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000701 printf("%sNEW", sep);
702 sep = ",";
703 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000704 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000705 printf("%sRELATED", sep);
706 sep = ",";
707 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000708 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000709 printf("%sESTABLISHED", sep);
710 sep = ",";
711 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000712 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
Harald Welte4dc734c2003-10-07 18:55:13 +0000713 printf("%sUNTRACKED", sep);
714 sep = ",";
715 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000716 if (statemask & XT_CONNTRACK_STATE_SNAT) {
Marc Boucher5054e852002-01-19 10:59:12 +0000717 printf("%sSNAT", sep);
718 sep = ",";
719 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000720 if (statemask & XT_CONNTRACK_STATE_DNAT) {
Marc Boucher5054e852002-01-19 10:59:12 +0000721 printf("%sDNAT", sep);
722 sep = ",";
723 }
724 printf(" ");
725}
726
727static void
728print_status(unsigned int statusmask)
729{
730 const char *sep = "";
731
732 if (statusmask & IPS_EXPECTED) {
733 printf("%sEXPECTED", sep);
734 sep = ",";
735 }
736 if (statusmask & IPS_SEEN_REPLY) {
737 printf("%sSEEN_REPLY", sep);
738 sep = ",";
739 }
740 if (statusmask & IPS_ASSURED) {
741 printf("%sASSURED", sep);
742 sep = ",";
743 }
Harald Weltea643c3e2003-08-25 11:08:52 +0000744 if (statusmask & IPS_CONFIRMED) {
745 printf("%sCONFIRMED", sep);
Marc Boucher5054e852002-01-19 10:59:12 +0000746 sep = ",";
747 }
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000748 if (statusmask == 0)
749 printf("%sNONE", sep);
Marc Boucher5054e852002-01-19 10:59:12 +0000750 printf(" ");
751}
752
753static void
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000754conntrack_dump_addr(const union nf_inet_addr *addr,
755 const union nf_inet_addr *mask,
756 unsigned int family, bool numeric)
757{
758 if (family == AF_INET) {
759 if (!numeric && addr->ip == 0) {
760 printf("anywhere ");
761 return;
762 }
763 printf("%s ", ipaddr_to_anyname(&addr->in));
764 } else if (family == AF_INET6) {
765 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
766 addr->ip6[2] == 0 && addr->ip6[3] == 0) {
767 printf("anywhere ");
768 return;
769 }
770 printf("%s ", ip6addr_to_anyname(&addr->in6));
771 }
772}
773
774static void
Marc Boucher5054e852002-01-19 10:59:12 +0000775print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric)
776{
777 char buf[BUFSIZ];
778
Jan Engelhardta80b6042008-01-20 13:34:07 +0000779 if (inv)
780 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000781
782 if (mask->s_addr == 0L && !numeric)
783 printf("%s ", "anywhere");
784 else {
785 if (numeric)
Jan Engelhardt08b16162008-01-20 13:36:08 +0000786 sprintf(buf, "%s", ipaddr_to_numeric(addr));
Marc Boucher5054e852002-01-19 10:59:12 +0000787 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000788 sprintf(buf, "%s", ipaddr_to_anyname(addr));
789 strcat(buf, ipmask_to_numeric(mask));
Marc Boucher5054e852002-01-19 10:59:12 +0000790 printf("%s ", buf);
791 }
792}
793
794/* Saves the matchinfo in parsable form to stdout. */
795static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000796matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx)
Marc Boucher5054e852002-01-19 10:59:12 +0000797{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000798 struct xt_conntrack_info *sinfo = (void *)match->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000799
Jan Engelhardta80b6042008-01-20 13:34:07 +0000800 if(sinfo->flags & XT_CONNTRACK_STATE) {
801 if (sinfo->invflags & XT_CONNTRACK_STATE)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000802 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000803 printf("%sctstate ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000804 print_state(sinfo->statemask);
805 }
806
Jan Engelhardta80b6042008-01-20 13:34:07 +0000807 if(sinfo->flags & XT_CONNTRACK_PROTO) {
808 if (sinfo->invflags & XT_CONNTRACK_PROTO)
Phil Oester5a4892b2005-11-17 13:34:51 +0000809 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000810 printf("%sctproto ", optpfx);
Phil Oester5a4892b2005-11-17 13:34:51 +0000811 printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum);
812 }
813
Jan Engelhardta80b6042008-01-20 13:34:07 +0000814 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
815 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC)
816 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000817 printf("%sctorigsrc ", optpfx);
818
819 print_addr(
820 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
821 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000822 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000823 numeric);
824 }
825
Jan Engelhardta80b6042008-01-20 13:34:07 +0000826 if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
827 if (sinfo->invflags & XT_CONNTRACK_ORIGDST)
828 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000829 printf("%sctorigdst ", optpfx);
830
831 print_addr(
832 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
833 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000834 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000835 numeric);
836 }
837
Jan Engelhardta80b6042008-01-20 13:34:07 +0000838 if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
839 if (sinfo->invflags & XT_CONNTRACK_REPLSRC)
840 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000841 printf("%sctreplsrc ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000842
843 print_addr(
844 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
845 &sinfo->sipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000846 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000847 numeric);
848 }
849
Jan Engelhardta80b6042008-01-20 13:34:07 +0000850 if(sinfo->flags & XT_CONNTRACK_REPLDST) {
851 if (sinfo->invflags & XT_CONNTRACK_REPLDST)
852 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000853 printf("%sctrepldst ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000854
855 print_addr(
856 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
857 &sinfo->dipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000858 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000859 numeric);
860 }
861
Jan Engelhardta80b6042008-01-20 13:34:07 +0000862 if(sinfo->flags & XT_CONNTRACK_STATUS) {
863 if (sinfo->invflags & XT_CONNTRACK_STATUS)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000864 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000865 printf("%sctstatus ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000866 print_status(sinfo->statusmask);
867 }
868
Jan Engelhardta80b6042008-01-20 13:34:07 +0000869 if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
870 if (sinfo->invflags & XT_CONNTRACK_EXPIRES)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000871 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000872 printf("%sctexpire ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000873
874 if (sinfo->expires_max == sinfo->expires_min)
875 printf("%lu ", sinfo->expires_min);
876 else
877 printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max);
878 }
879}
880
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000881static void
882conntrack_dump(const struct xt_conntrack_mtinfo1 *info, const char *prefix,
883 unsigned int family, bool numeric)
884{
885 if (info->match_flags & XT_CONNTRACK_STATE) {
886 if (info->invert_flags & XT_CONNTRACK_STATE)
887 printf("! ");
888 printf("%sctstate ", prefix);
889 print_state(info->state_mask);
890 }
891
892 if (info->match_flags & XT_CONNTRACK_PROTO) {
893 if (info->invert_flags & XT_CONNTRACK_PROTO)
894 printf("! ");
895 printf("%sctproto %u ", prefix, info->l4proto);
896 }
897
898 if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
899 if (info->invert_flags & XT_CONNTRACK_PROTO)
900 printf("! ");
901 printf("%sctorigsrc ", prefix);
902 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask,
903 family, numeric);
904 }
905
906 if (info->match_flags & XT_CONNTRACK_ORIGDST) {
907 if (info->invert_flags & XT_CONNTRACK_PROTO)
908 printf("! ");
909 printf("%sctorigdst ", prefix);
910 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask,
911 family, numeric);
912 }
913
914 if (info->match_flags & XT_CONNTRACK_REPLSRC) {
915 if (info->invert_flags & XT_CONNTRACK_PROTO)
916 printf("! ");
917 printf("%sctreplsrc ", prefix);
918 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask,
919 family, numeric);
920 }
921
922 if (info->match_flags & XT_CONNTRACK_REPLDST) {
923 if (info->invert_flags & XT_CONNTRACK_PROTO)
924 printf("! ");
925 printf("%sctrepldst ", prefix);
926 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask,
927 family, numeric);
928 }
929
930 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
931 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)
932 printf("! ");
933 printf("%sctorigsrcport %u ", prefix,
934 ntohs(info->origsrc_port));
935 }
936
937 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
938 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)
939 printf("! ");
940 printf("%sctorigdstport %u ", prefix,
941 ntohs(info->origdst_port));
942 }
943
944 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
945 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)
946 printf("! ");
947 printf("%sctreplsrcport %u ", prefix,
948 ntohs(info->replsrc_port));
949 }
950
951 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) {
952 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT)
953 printf("! ");
954 printf("%sctrepldstport %u ", prefix,
955 ntohs(info->repldst_port));
956 }
957
958 if (info->match_flags & XT_CONNTRACK_STATUS) {
959 if (info->invert_flags & XT_CONNTRACK_STATUS)
960 printf("! ");
961 printf("%sctstatus ", prefix);
962 print_status(info->status_mask);
963 }
964
965 if (info->match_flags & XT_CONNTRACK_EXPIRES) {
966 if (info->invert_flags & XT_CONNTRACK_EXPIRES)
967 printf("! ");
968 printf("%sctexpire ", prefix);
969
970 if (info->expires_max == info->expires_min)
971 printf("%u ", (unsigned int)info->expires_min);
972 else
973 printf("%u:%u ", (unsigned int)info->expires_min,
974 (unsigned int)info->expires_max);
975 }
976}
977
Marc Boucher5054e852002-01-19 10:59:12 +0000978/* Prints out the matchinfo. */
Jan Engelhardt59d16402007-10-04 16:28:39 +0000979static void conntrack_print(const void *ip, const struct xt_entry_match *match,
980 int numeric)
Marc Boucher5054e852002-01-19 10:59:12 +0000981{
982 matchinfo_print(ip, match, numeric, "");
983}
984
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000985static void
986conntrack_mt_print(const void *ip, const struct xt_entry_match *match,
987 int numeric)
988{
989 conntrack_dump((const void *)match->data, "", AF_INET, numeric);
990}
991
992static void
993conntrack_mt6_print(const void *ip, const struct xt_entry_match *match,
994 int numeric)
995{
996 conntrack_dump((const void *)match->data, "", AF_INET6, numeric);
997}
998
Marc Boucher5054e852002-01-19 10:59:12 +0000999/* Saves the matchinfo in parsable form to stdout. */
Jan Engelhardt59d16402007-10-04 16:28:39 +00001000static void conntrack_save(const void *ip, const struct xt_entry_match *match)
Marc Boucher5054e852002-01-19 10:59:12 +00001001{
Joszef Kadlecsikdb503f92004-05-05 10:10:33 +00001002 matchinfo_print(ip, match, 1, "--");
Marc Boucher5054e852002-01-19 10:59:12 +00001003}
1004
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001005static void conntrack_mt_save(const void *ip,
1006 const struct xt_entry_match *match)
1007{
1008 conntrack_dump((const void *)match->data, "--", AF_INET, true);
1009}
1010
1011static void conntrack_mt6_save(const void *ip,
1012 const struct xt_entry_match *match)
1013{
1014 conntrack_dump((const void *)match->data, "--", AF_INET6, true);
1015}
1016
Jan Engelhardta80b6042008-01-20 13:34:07 +00001017static struct xtables_match conntrack_match = {
1018 .version = IPTABLES_VERSION,
1019 .name = "conntrack",
1020 .revision = 0,
1021 .family = AF_INET,
1022 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)),
1023 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)),
1024 .help = conntrack_mt_help,
1025 .parse = conntrack_parse,
1026 .final_check = conntrack_mt_check,
1027 .print = conntrack_print,
1028 .save = conntrack_save,
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001029 .extra_opts = conntrack_mt_opts_v0,
1030};
1031
1032static struct xtables_match conntrack_mt_reg = {
1033 .version = IPTABLES_VERSION,
1034 .name = "conntrack",
1035 .revision = 1,
1036 .family = AF_INET,
1037 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1038 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1039 .help = conntrack_mt_help,
1040 .parse = conntrack_mt4_parse,
1041 .final_check = conntrack_mt_check,
1042 .print = conntrack_mt_print,
1043 .save = conntrack_mt_save,
1044 .extra_opts = conntrack_mt_opts,
1045};
1046
1047static struct xtables_match conntrack_mt6_reg = {
1048 .version = IPTABLES_VERSION,
1049 .name = "conntrack",
1050 .revision = 1,
1051 .family = AF_INET6,
1052 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1053 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1054 .help = conntrack_mt_help,
1055 .parse = conntrack_mt6_parse,
1056 .final_check = conntrack_mt_check,
1057 .print = conntrack_mt6_print,
1058 .save = conntrack_mt6_save,
Jan Engelhardta80b6042008-01-20 13:34:07 +00001059 .extra_opts = conntrack_mt_opts,
Marc Boucher5054e852002-01-19 10:59:12 +00001060};
1061
1062void _init(void)
1063{
Jan Engelhardta80b6042008-01-20 13:34:07 +00001064 xtables_register_match(&conntrack_match);
Jan Engelhardta8ad34c2008-01-29 13:37:21 +00001065 xtables_register_match(&conntrack_mt_reg);
1066 xtables_register_match(&conntrack_mt6_reg);
Marc Boucher5054e852002-01-19 10:59:12 +00001067}