blob: 987e1af4397bdbfda8d99206fab1f37299066127 [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 }
110
111 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
112 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
113}
114
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000115static bool
116conntrack_ps_state(struct xt_conntrack_mtinfo1 *info, const char *state,
117 size_t z)
118{
119 if (strncasecmp(state, "INVALID", z) == 0)
120 info->state_mask |= XT_CONNTRACK_STATE_INVALID;
121 else if (strncasecmp(state, "NEW", z) == 0)
122 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
123 else if (strncasecmp(state, "ESTABLISHED", z) == 0)
124 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
125 else if (strncasecmp(state, "RELATED", z) == 0)
126 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
127 else if (strncasecmp(state, "UNTRACKED", z) == 0)
128 info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED;
129 else if (strncasecmp(state, "SNAT", z) == 0)
130 info->state_mask |= XT_CONNTRACK_STATE_SNAT;
131 else if (strncasecmp(state, "DNAT", z) == 0)
132 info->state_mask |= XT_CONNTRACK_STATE_DNAT;
133 else
134 return false;
135 return true;
136}
137
138static void
139conntrack_ps_states(struct xt_conntrack_mtinfo1 *info, const char *arg)
140{
141 const char *comma;
142
143 while ((comma = strchr(arg, ',')) != NULL) {
144 if (comma == arg || !conntrack_ps_state(info, arg, comma - arg))
145 exit_error(PARAMETER_PROBLEM,
146 "Bad ctstate \"%s\"", arg);
147 arg = comma + 1;
148 }
149
150 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg)))
151 exit_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
152}
153
Marc Boucher5054e852002-01-19 10:59:12 +0000154static int
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100155parse_status(const char *status, size_t len, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000156{
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100157 if (strncasecmp(status, "NONE", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000158 sinfo->statusmask |= 0;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100159 else if (strncasecmp(status, "EXPECTED", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000160 sinfo->statusmask |= IPS_EXPECTED;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100161 else if (strncasecmp(status, "SEEN_REPLY", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000162 sinfo->statusmask |= IPS_SEEN_REPLY;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100163 else if (strncasecmp(status, "ASSURED", len) == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000164 sinfo->statusmask |= IPS_ASSURED;
Harald Weltea643c3e2003-08-25 11:08:52 +0000165#ifdef IPS_CONFIRMED
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100166 else if (strncasecmp(status, "CONFIRMED", len) == 0)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000167 sinfo->statusmask |= IPS_CONFIRMED;
Harald Weltea643c3e2003-08-25 11:08:52 +0000168#endif
Marc Boucher5054e852002-01-19 10:59:12 +0000169 else
170 return 0;
171 return 1;
172}
173
174static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000175parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000176{
177 const char *comma;
178
179 while ((comma = strchr(arg, ',')) != NULL) {
180 if (comma == arg || !parse_status(arg, comma-arg, sinfo))
181 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
182 arg = comma+1;
183 }
184
185 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo))
186 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
187}
188
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000189static bool
190conntrack_ps_status(struct xt_conntrack_mtinfo1 *info, const char *status,
191 size_t z)
192{
193 if (strncasecmp(status, "NONE", z) == 0)
194 info->status_mask |= 0;
195 else if (strncasecmp(status, "EXPECTED", z) == 0)
196 info->status_mask |= IPS_EXPECTED;
197 else if (strncasecmp(status, "SEEN_REPLY", z) == 0)
198 info->status_mask |= IPS_SEEN_REPLY;
199 else if (strncasecmp(status, "ASSURED", z) == 0)
200 info->status_mask |= IPS_ASSURED;
201 else if (strncasecmp(status, "CONFIRMED", z) == 0)
202 info->status_mask |= IPS_CONFIRMED;
203 else
204 return false;
205 return true;
206}
207
208static void
209conntrack_ps_statuses(struct xt_conntrack_mtinfo1 *info, const char *arg)
210{
211 const char *comma;
212
213 while ((comma = strchr(arg, ',')) != NULL) {
214 if (comma == arg || !conntrack_ps_status(info, arg, comma - arg))
215 exit_error(PARAMETER_PROBLEM,
216 "Bad ctstatus \"%s\"", arg);
217 arg = comma + 1;
218 }
219
220 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg)))
221 exit_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
222}
223
Marc Boucher5054e852002-01-19 10:59:12 +0000224static unsigned long
225parse_expire(const char *s)
226{
227 unsigned int len;
Jan Engelhardta80b6042008-01-20 13:34:07 +0000228
Martin Josefsson1da399c2004-05-26 15:50:57 +0000229 if (string_to_number(s, 0, 0, &len) == -1)
Marc Boucher5054e852002-01-19 10:59:12 +0000230 exit_error(PARAMETER_PROBLEM, "expire value invalid: `%s'\n", s);
231 else
232 return len;
233}
234
235/* If a single value is provided, min and max are both set to the value */
236static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000237parse_expires(const char *s, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000238{
239 char *buffer;
240 char *cp;
241
242 buffer = strdup(s);
243 if ((cp = strchr(buffer, ':')) == NULL)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000244 sinfo->expires_min = sinfo->expires_max =
245 parse_expire(buffer);
Marc Boucher5054e852002-01-19 10:59:12 +0000246 else {
247 *cp = '\0';
248 cp++;
249
250 sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0;
Max Kellermann9ee386a2008-01-29 13:48:05 +0000251 sinfo->expires_max = cp[0]
252 ? parse_expire(cp)
253 : (unsigned long)-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
Jan Engelhardt59d16402007-10-04 16:28:39 +0000287static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags,
288 const void *entry, struct xt_entry_match **match)
Marc Boucher5054e852002-01-19 10:59:12 +0000289{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000290 struct xt_conntrack_info *sinfo = (void *)(*match)->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000291 char *protocol = NULL;
292 unsigned int naddrs = 0;
293 struct in_addr *addrs = NULL;
294
295
296 switch (c) {
297 case '1':
Harald Welteb77f1da2002-03-14 11:35:58 +0000298 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000299
300 parse_states(argv[optind-1], sinfo);
301 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000302 sinfo->invflags |= XT_CONNTRACK_STATE;
Marc Boucher5054e852002-01-19 10:59:12 +0000303 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000304 sinfo->flags |= XT_CONNTRACK_STATE;
Marc Boucher5054e852002-01-19 10:59:12 +0000305 break;
306
307 case '2':
Harald Welte3c5bd602002-03-14 19:54:34 +0000308 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000309
310 if(invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000311 sinfo->invflags |= XT_CONNTRACK_PROTO;
Marc Boucher5054e852002-01-19 10:59:12 +0000312
313 /* Canonicalize into lower case */
314 for (protocol = argv[optind-1]; *protocol; protocol++)
315 *protocol = tolower(*protocol);
316
317 protocol = argv[optind-1];
318 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = parse_protocol(protocol);
319
320 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0
Jan Engelhardta80b6042008-01-20 13:34:07 +0000321 && (sinfo->invflags & XT_INV_PROTO))
Marc Boucher5054e852002-01-19 10:59:12 +0000322 exit_error(PARAMETER_PROBLEM,
323 "rule would never match protocol");
324
Jan Engelhardta80b6042008-01-20 13:34:07 +0000325 sinfo->flags |= XT_CONNTRACK_PROTO;
Marc Boucher5054e852002-01-19 10:59:12 +0000326 break;
327
328 case '3':
Jan Engelhardt40eaf2a2007-11-25 15:25:23 +0000329 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000330
331 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000332 sinfo->invflags |= XT_CONNTRACK_ORIGSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000333
Jan Engelhardtbd943842008-01-20 13:38:08 +0000334 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000335 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
336 &naddrs);
337 if(naddrs > 1)
338 exit_error(PARAMETER_PROBLEM,
339 "multiple IP addresses not allowed");
340
341 if(naddrs == 1) {
342 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr;
343 }
344
Jan Engelhardta80b6042008-01-20 13:34:07 +0000345 sinfo->flags |= XT_CONNTRACK_ORIGSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000346 break;
347
348 case '4':
Harald Welteb77f1da2002-03-14 11:35:58 +0000349 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000350
351 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000352 sinfo->invflags |= XT_CONNTRACK_ORIGDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000353
Jan Engelhardtbd943842008-01-20 13:38:08 +0000354 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000355 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
356 &naddrs);
357 if(naddrs > 1)
358 exit_error(PARAMETER_PROBLEM,
359 "multiple IP addresses not allowed");
360
361 if(naddrs == 1) {
362 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr;
363 }
364
Jan Engelhardta80b6042008-01-20 13:34:07 +0000365 sinfo->flags |= XT_CONNTRACK_ORIGDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000366 break;
367
368 case '5':
Harald Welteb77f1da2002-03-14 11:35:58 +0000369 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000370
371 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000372 sinfo->invflags |= XT_CONNTRACK_REPLSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000373
Jan Engelhardtbd943842008-01-20 13:38:08 +0000374 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000375 &sinfo->sipmsk[IP_CT_DIR_REPLY],
376 &naddrs);
377 if(naddrs > 1)
378 exit_error(PARAMETER_PROBLEM,
379 "multiple IP addresses not allowed");
380
381 if(naddrs == 1) {
382 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr;
383 }
384
Jan Engelhardta80b6042008-01-20 13:34:07 +0000385 sinfo->flags |= XT_CONNTRACK_REPLSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000386 break;
387
388 case '6':
Harald Welteb77f1da2002-03-14 11:35:58 +0000389 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000390
391 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000392 sinfo->invflags |= XT_CONNTRACK_REPLDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000393
Jan Engelhardtbd943842008-01-20 13:38:08 +0000394 ipparse_hostnetworkmask(argv[optind-1], &addrs,
Marc Boucher5054e852002-01-19 10:59:12 +0000395 &sinfo->dipmsk[IP_CT_DIR_REPLY],
396 &naddrs);
397 if(naddrs > 1)
398 exit_error(PARAMETER_PROBLEM,
399 "multiple IP addresses not allowed");
400
401 if(naddrs == 1) {
402 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr;
403 }
404
Jan Engelhardta80b6042008-01-20 13:34:07 +0000405 sinfo->flags |= XT_CONNTRACK_REPLDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000406 break;
407
408 case '7':
Harald Welteb77f1da2002-03-14 11:35:58 +0000409 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000410
411 parse_statuses(argv[optind-1], sinfo);
412 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000413 sinfo->invflags |= XT_CONNTRACK_STATUS;
Marc Boucher5054e852002-01-19 10:59:12 +0000414 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000415 sinfo->flags |= XT_CONNTRACK_STATUS;
Marc Boucher5054e852002-01-19 10:59:12 +0000416 break;
417
418 case '8':
Harald Welteb77f1da2002-03-14 11:35:58 +0000419 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000420
421 parse_expires(argv[optind-1], sinfo);
422 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000423 sinfo->invflags |= XT_CONNTRACK_EXPIRES;
Marc Boucher5054e852002-01-19 10:59:12 +0000424 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000425 sinfo->flags |= XT_CONNTRACK_EXPIRES;
Marc Boucher5054e852002-01-19 10:59:12 +0000426 break;
427
428 default:
429 return 0;
430 }
431
432 *flags = sinfo->flags;
433 return 1;
434}
435
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000436static int
437conntrack_mt_parse(int c, char **argv, int invert, unsigned int *flags,
438 struct xt_entry_match **match)
439{
440 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
441 unsigned int port;
442 char *p;
443
444 switch (c) {
445 case '1': /* --ctstate */
446 conntrack_ps_states(info, optarg);
447 info->match_flags |= XT_CONNTRACK_STATE;
448 if (invert)
449 info->invert_flags |= XT_CONNTRACK_STATE;
450 break;
451
452 case '2': /* --ctproto */
453 /* Canonicalize into lower case */
454 for (p = optarg; *p != '\0'; ++p)
455 *p = tolower(*p);
456 info->l4proto = parse_protocol(optarg);
457
458 if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO))
459 exit_error(PARAMETER_PROBLEM, "conntrack: rule would "
460 "never match protocol");
461
462 info->match_flags |= XT_CONNTRACK_PROTO;
463 if (invert)
464 info->invert_flags |= XT_CONNTRACK_PROTO;
465 break;
466
467 case '7': /* --ctstatus */
468 conntrack_ps_statuses(info, optarg);
469 info->match_flags |= XT_CONNTRACK_STATUS;
470 if (invert)
471 info->invert_flags |= XT_CONNTRACK_STATUS;
472 break;
473
474 case '8': /* --ctexpire */
475 conntrack_ps_expires(info, optarg);
476 info->match_flags |= XT_CONNTRACK_EXPIRES;
477 if (invert)
478 info->invert_flags |= XT_CONNTRACK_EXPIRES;
479 break;
480
481 case 'a': /* --ctorigsrcport */
482 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
483 param_act(P_BAD_VALUE, "conntrack",
484 "--ctorigsrcport", optarg);
485 info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT;
486 info->origsrc_port = htons(port);
487 if (invert)
488 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT;
489 break;
490
491 case 'b': /* --ctorigdstport */
492 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
493 param_act(P_BAD_VALUE, "conntrack",
494 "--ctorigdstport", optarg);
495 info->match_flags |= XT_CONNTRACK_ORIGDST_PORT;
496 info->origdst_port = htons(port);
497 if (invert)
498 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT;
499 break;
500
501 case 'c': /* --ctreplsrcport */
502 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
503 param_act(P_BAD_VALUE, "conntrack",
504 "--ctreplsrcport", optarg);
505 info->match_flags |= XT_CONNTRACK_REPLSRC_PORT;
506 info->replsrc_port = htons(port);
507 if (invert)
508 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT;
509 break;
510
511 case 'd': /* --ctrepldstport */
512 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0))
513 param_act(P_BAD_VALUE, "conntrack",
514 "--ctrepldstport", optarg);
515 info->match_flags |= XT_CONNTRACK_REPLDST_PORT;
516 info->repldst_port = htons(port);
517 if (invert)
518 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT;
519 break;
520
521 case 'e': /* --ctdir */
522 param_act(P_NO_INVERT, "conntrack", "--ctdir", invert);
523 if (strcasecmp(optarg, "ORIGINAL") == 0) {
524 info->match_flags |= XT_CONNTRACK_DIRECTION;
525 info->invert_flags &= ~XT_CONNTRACK_DIRECTION;
526 } else if (strcasecmp(optarg, "REPLY") == 0) {
527 info->match_flags |= XT_CONNTRACK_DIRECTION;
528 info->invert_flags |= XT_CONNTRACK_DIRECTION;
529 } else {
530 param_act(P_BAD_VALUE, "conntrack", "--ctdir", optarg);
531 }
532 break;
533
534 default:
535 return false;
536 }
537
538 *flags = info->match_flags;
539 return true;
540}
541
542static int
543conntrack_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
544 const void *entry, struct xt_entry_match **match)
545{
546 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
547 struct in_addr *addr = NULL;
548 unsigned int naddrs = 0;
549
550 switch (c) {
551 case '3': /* --ctorigsrc */
552 ipparse_hostnetworkmask(optarg, &addr, &info->origsrc_mask.in,
553 &naddrs);
554 if (naddrs > 1)
555 exit_error(PARAMETER_PROBLEM,
556 "multiple IP addresses not allowed");
557 if (naddrs == 1)
558 memcpy(&info->origsrc_addr.in, addr, sizeof(*addr));
559 info->match_flags |= XT_CONNTRACK_ORIGSRC;
560 if (invert)
561 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
562 break;
563
564 case '4': /* --ctorigdst */
565 ipparse_hostnetworkmask(optarg, &addr, &info->origdst_mask.in,
566 &naddrs);
567 if (naddrs > 1)
568 exit_error(PARAMETER_PROBLEM,
569 "multiple IP addresses not allowed");
570 if (naddrs == 1)
571 memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
572 info->match_flags |= XT_CONNTRACK_ORIGDST;
573 if (invert)
574 info->invert_flags |= XT_CONNTRACK_ORIGDST;
575 break;
576
577 case '5': /* --ctreplsrc */
578 ipparse_hostnetworkmask(optarg, &addr, &info->replsrc_mask.in,
579 &naddrs);
580 if (naddrs > 1)
581 exit_error(PARAMETER_PROBLEM,
582 "multiple IP addresses not allowed");
583 if (naddrs == 1)
584 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
585 info->match_flags |= XT_CONNTRACK_REPLSRC;
586 if (invert)
587 info->invert_flags |= XT_CONNTRACK_REPLSRC;
588 break;
589
590 case '6': /* --ctrepldst */
591 ipparse_hostnetworkmask(optarg, &addr, &info->repldst_mask.in,
592 &naddrs);
593 if (naddrs > 1)
594 exit_error(PARAMETER_PROBLEM,
595 "multiple IP addresses not allowed");
596 if (naddrs == 1)
597 memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
598 info->match_flags |= XT_CONNTRACK_REPLDST;
599 if (invert)
600 info->invert_flags |= XT_CONNTRACK_REPLDST;
601 break;
602
603
604 default:
605 return conntrack_mt_parse(c, argv, invert, flags, match);
606 }
607
608 *flags = info->match_flags;
609 return true;
610}
611
612static int
613conntrack_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
614 const void *entry, struct xt_entry_match **match)
615{
616 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data;
617 struct in6_addr *addr = NULL;
618 unsigned int naddrs = 0;
619
620 switch (c) {
621 case '3': /* --ctorigsrc */
622 ip6parse_hostnetworkmask(optarg, &addr,
623 &info->origsrc_mask.in6, &naddrs);
624 if (naddrs > 1)
625 exit_error(PARAMETER_PROBLEM,
626 "multiple IP addresses not allowed");
627 if (naddrs == 1)
628 memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr));
629 info->match_flags |= XT_CONNTRACK_ORIGSRC;
630 if (invert)
631 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
632 break;
633
634 case '4': /* --ctorigdst */
635 ip6parse_hostnetworkmask(optarg, &addr,
636 &info->origdst_mask.in6, &naddrs);
637 if (naddrs > 1)
638 exit_error(PARAMETER_PROBLEM,
639 "multiple IP addresses not allowed");
640 if (naddrs == 1)
641 memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
642 info->match_flags |= XT_CONNTRACK_ORIGDST;
643 if (invert)
644 info->invert_flags |= XT_CONNTRACK_ORIGDST;
645 break;
646
647 case '5': /* --ctreplsrc */
648 ip6parse_hostnetworkmask(optarg, &addr,
649 &info->replsrc_mask.in6, &naddrs);
650 if (naddrs > 1)
651 exit_error(PARAMETER_PROBLEM,
652 "multiple IP addresses not allowed");
653 if (naddrs == 1)
654 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
655 info->match_flags |= XT_CONNTRACK_REPLSRC;
656 if (invert)
657 info->invert_flags |= XT_CONNTRACK_REPLSRC;
658 break;
659
660 case '6': /* --ctrepldst */
661 ip6parse_hostnetworkmask(optarg, &addr,
662 &info->repldst_mask.in6, &naddrs);
663 if (naddrs > 1)
664 exit_error(PARAMETER_PROBLEM,
665 "multiple IP addresses not allowed");
666 if (naddrs == 1)
667 memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
668 info->match_flags |= XT_CONNTRACK_REPLDST;
669 if (invert)
670 info->invert_flags |= XT_CONNTRACK_REPLDST;
671 break;
672
673
674 default:
675 return conntrack_mt_parse(c, argv, invert, flags, match);
676 }
677
678 *flags = info->match_flags;
679 return true;
680}
681
Jan Engelhardta80b6042008-01-20 13:34:07 +0000682static void conntrack_mt_check(unsigned int flags)
Marc Boucher5054e852002-01-19 10:59:12 +0000683{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000684 if (flags == 0)
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000685 exit_error(PARAMETER_PROBLEM, "conntrack: At least one option "
686 "is required");
Marc Boucher5054e852002-01-19 10:59:12 +0000687}
688
689static void
690print_state(unsigned int statemask)
691{
692 const char *sep = "";
693
Jan Engelhardta80b6042008-01-20 13:34:07 +0000694 if (statemask & XT_CONNTRACK_STATE_INVALID) {
Marc Boucher5054e852002-01-19 10:59:12 +0000695 printf("%sINVALID", sep);
696 sep = ",";
697 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000698 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000699 printf("%sNEW", sep);
700 sep = ",";
701 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000702 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000703 printf("%sRELATED", sep);
704 sep = ",";
705 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000706 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000707 printf("%sESTABLISHED", sep);
708 sep = ",";
709 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000710 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
Harald Welte4dc734c2003-10-07 18:55:13 +0000711 printf("%sUNTRACKED", sep);
712 sep = ",";
713 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000714 if (statemask & XT_CONNTRACK_STATE_SNAT) {
Marc Boucher5054e852002-01-19 10:59:12 +0000715 printf("%sSNAT", sep);
716 sep = ",";
717 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000718 if (statemask & XT_CONNTRACK_STATE_DNAT) {
Marc Boucher5054e852002-01-19 10:59:12 +0000719 printf("%sDNAT", sep);
720 sep = ",";
721 }
722 printf(" ");
723}
724
725static void
726print_status(unsigned int statusmask)
727{
728 const char *sep = "";
729
730 if (statusmask & IPS_EXPECTED) {
731 printf("%sEXPECTED", sep);
732 sep = ",";
733 }
734 if (statusmask & IPS_SEEN_REPLY) {
735 printf("%sSEEN_REPLY", sep);
736 sep = ",";
737 }
738 if (statusmask & IPS_ASSURED) {
739 printf("%sASSURED", sep);
740 sep = ",";
741 }
Harald Weltea643c3e2003-08-25 11:08:52 +0000742 if (statusmask & IPS_CONFIRMED) {
743 printf("%sCONFIRMED", sep);
Marc Boucher5054e852002-01-19 10:59:12 +0000744 sep = ",";
745 }
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000746 if (statusmask == 0)
747 printf("%sNONE", sep);
Marc Boucher5054e852002-01-19 10:59:12 +0000748 printf(" ");
749}
750
751static void
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000752conntrack_dump_addr(const union nf_inet_addr *addr,
753 const union nf_inet_addr *mask,
754 unsigned int family, bool numeric)
755{
756 if (family == AF_INET) {
757 if (!numeric && addr->ip == 0) {
758 printf("anywhere ");
759 return;
760 }
Jan Engelhardt6b6c0962008-11-10 17:08:07 +0100761 if (numeric)
762 printf("%s ", ipaddr_to_numeric(&addr->in));
763 else
764 printf("%s ", ipaddr_to_anyname(&addr->in));
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000765 } 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 }
Jan Engelhardt6b6c0962008-11-10 17:08:07 +0100771 if (numeric)
772 printf("%s ", ip6addr_to_numeric(&addr->in6));
773 else
774 printf("%s ", ip6addr_to_anyname(&addr->in6));
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000775 }
776}
777
778static void
Marc Boucher5054e852002-01-19 10:59:12 +0000779print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric)
780{
781 char buf[BUFSIZ];
782
Jan Engelhardta80b6042008-01-20 13:34:07 +0000783 if (inv)
784 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000785
786 if (mask->s_addr == 0L && !numeric)
787 printf("%s ", "anywhere");
788 else {
789 if (numeric)
Jan Engelhardt08b16162008-01-20 13:36:08 +0000790 sprintf(buf, "%s", ipaddr_to_numeric(addr));
Marc Boucher5054e852002-01-19 10:59:12 +0000791 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000792 sprintf(buf, "%s", ipaddr_to_anyname(addr));
793 strcat(buf, ipmask_to_numeric(mask));
Marc Boucher5054e852002-01-19 10:59:12 +0000794 printf("%s ", buf);
795 }
796}
797
Marc Boucher5054e852002-01-19 10:59:12 +0000798static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000799matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx)
Marc Boucher5054e852002-01-19 10:59:12 +0000800{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000801 struct xt_conntrack_info *sinfo = (void *)match->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000802
Jan Engelhardta80b6042008-01-20 13:34:07 +0000803 if(sinfo->flags & XT_CONNTRACK_STATE) {
804 if (sinfo->invflags & XT_CONNTRACK_STATE)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000805 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000806 printf("%sctstate ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000807 print_state(sinfo->statemask);
808 }
809
Jan Engelhardta80b6042008-01-20 13:34:07 +0000810 if(sinfo->flags & XT_CONNTRACK_PROTO) {
811 if (sinfo->invflags & XT_CONNTRACK_PROTO)
Phil Oester5a4892b2005-11-17 13:34:51 +0000812 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000813 printf("%sctproto ", optpfx);
Phil Oester5a4892b2005-11-17 13:34:51 +0000814 printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum);
815 }
816
Jan Engelhardta80b6042008-01-20 13:34:07 +0000817 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
818 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC)
819 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000820 printf("%sctorigsrc ", optpfx);
821
822 print_addr(
823 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
824 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000825 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000826 numeric);
827 }
828
Jan Engelhardta80b6042008-01-20 13:34:07 +0000829 if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
830 if (sinfo->invflags & XT_CONNTRACK_ORIGDST)
831 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000832 printf("%sctorigdst ", optpfx);
833
834 print_addr(
835 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
836 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000837 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000838 numeric);
839 }
840
Jan Engelhardta80b6042008-01-20 13:34:07 +0000841 if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
842 if (sinfo->invflags & XT_CONNTRACK_REPLSRC)
843 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000844 printf("%sctreplsrc ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000845
846 print_addr(
847 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
848 &sinfo->sipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000849 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000850 numeric);
851 }
852
Jan Engelhardta80b6042008-01-20 13:34:07 +0000853 if(sinfo->flags & XT_CONNTRACK_REPLDST) {
854 if (sinfo->invflags & XT_CONNTRACK_REPLDST)
855 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000856 printf("%sctrepldst ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000857
858 print_addr(
859 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
860 &sinfo->dipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000861 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000862 numeric);
863 }
864
Jan Engelhardta80b6042008-01-20 13:34:07 +0000865 if(sinfo->flags & XT_CONNTRACK_STATUS) {
866 if (sinfo->invflags & XT_CONNTRACK_STATUS)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000867 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000868 printf("%sctstatus ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000869 print_status(sinfo->statusmask);
870 }
871
Jan Engelhardta80b6042008-01-20 13:34:07 +0000872 if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
873 if (sinfo->invflags & XT_CONNTRACK_EXPIRES)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000874 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000875 printf("%sctexpire ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000876
877 if (sinfo->expires_max == sinfo->expires_min)
878 printf("%lu ", sinfo->expires_min);
879 else
880 printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max);
881 }
882}
883
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000884static void
885conntrack_dump(const struct xt_conntrack_mtinfo1 *info, const char *prefix,
886 unsigned int family, bool numeric)
887{
888 if (info->match_flags & XT_CONNTRACK_STATE) {
889 if (info->invert_flags & XT_CONNTRACK_STATE)
890 printf("! ");
891 printf("%sctstate ", prefix);
892 print_state(info->state_mask);
893 }
894
895 if (info->match_flags & XT_CONNTRACK_PROTO) {
896 if (info->invert_flags & XT_CONNTRACK_PROTO)
897 printf("! ");
898 printf("%sctproto %u ", prefix, info->l4proto);
899 }
900
901 if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
902 if (info->invert_flags & XT_CONNTRACK_PROTO)
903 printf("! ");
904 printf("%sctorigsrc ", prefix);
905 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask,
906 family, numeric);
907 }
908
909 if (info->match_flags & XT_CONNTRACK_ORIGDST) {
910 if (info->invert_flags & XT_CONNTRACK_PROTO)
911 printf("! ");
912 printf("%sctorigdst ", prefix);
913 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask,
914 family, numeric);
915 }
916
917 if (info->match_flags & XT_CONNTRACK_REPLSRC) {
918 if (info->invert_flags & XT_CONNTRACK_PROTO)
919 printf("! ");
920 printf("%sctreplsrc ", prefix);
921 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask,
922 family, numeric);
923 }
924
925 if (info->match_flags & XT_CONNTRACK_REPLDST) {
926 if (info->invert_flags & XT_CONNTRACK_PROTO)
927 printf("! ");
928 printf("%sctrepldst ", prefix);
929 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask,
930 family, numeric);
931 }
932
933 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
934 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)
935 printf("! ");
936 printf("%sctorigsrcport %u ", prefix,
937 ntohs(info->origsrc_port));
938 }
939
940 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
941 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)
942 printf("! ");
943 printf("%sctorigdstport %u ", prefix,
944 ntohs(info->origdst_port));
945 }
946
947 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
948 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)
949 printf("! ");
950 printf("%sctreplsrcport %u ", prefix,
951 ntohs(info->replsrc_port));
952 }
953
954 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) {
955 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT)
956 printf("! ");
957 printf("%sctrepldstport %u ", prefix,
958 ntohs(info->repldst_port));
959 }
960
961 if (info->match_flags & XT_CONNTRACK_STATUS) {
962 if (info->invert_flags & XT_CONNTRACK_STATUS)
963 printf("! ");
964 printf("%sctstatus ", prefix);
965 print_status(info->status_mask);
966 }
967
968 if (info->match_flags & XT_CONNTRACK_EXPIRES) {
969 if (info->invert_flags & XT_CONNTRACK_EXPIRES)
970 printf("! ");
971 printf("%sctexpire ", prefix);
972
973 if (info->expires_max == info->expires_min)
974 printf("%u ", (unsigned int)info->expires_min);
975 else
976 printf("%u:%u ", (unsigned int)info->expires_min,
977 (unsigned int)info->expires_max);
978 }
979}
980
Jan Engelhardt59d16402007-10-04 16:28:39 +0000981static void conntrack_print(const void *ip, const struct xt_entry_match *match,
982 int numeric)
Marc Boucher5054e852002-01-19 10:59:12 +0000983{
984 matchinfo_print(ip, match, numeric, "");
985}
986
Jan Engelhardta8ad34c2008-01-29 13:37:21 +0000987static void
988conntrack_mt_print(const void *ip, const struct xt_entry_match *match,
989 int numeric)
990{
991 conntrack_dump((const void *)match->data, "", AF_INET, numeric);
992}
993
994static void
995conntrack_mt6_print(const void *ip, const struct xt_entry_match *match,
996 int numeric)
997{
998 conntrack_dump((const void *)match->data, "", AF_INET6, numeric);
999}
1000
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}