blob: 2a205e40f433af31df4e6a3e9f20c21ea636a999 [file] [log] [blame]
Marc Boucher5054e852002-01-19 10:59:12 +00001/* Shared library add-on to iptables for conntrack matching support.
2 * GPL (C) 2001 Marc Boucher (marc@mbsi.ca).
3 */
4
Marc Boucher5054e852002-01-19 10:59:12 +00005#include <ctype.h>
Jan Engelhardta80b6042008-01-20 13:34:07 +00006#include <getopt.h>
7#include <netdb.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
Marc Boucher5054e852002-01-19 10:59:12 +000011#include <iptables.h>
Jan Engelhardt08b16162008-01-20 13:36:08 +000012#include <xtables.h>
Jan Engelhardta80b6042008-01-20 13:34:07 +000013#include <linux/netfilter.h>
14#include <linux/netfilter/xt_conntrack.h>
Patrick McHardy40d54752007-04-18 07:00:36 +000015#include <linux/netfilter/nf_conntrack_common.h>
Harald Welte4dc734c2003-10-07 18:55:13 +000016
Marc Boucher5054e852002-01-19 10:59:12 +000017/* Function which prints out usage message. */
Jan Engelhardta80b6042008-01-20 13:34:07 +000018static void conntrack_mt_help(void)
Marc Boucher5054e852002-01-19 10:59:12 +000019{
20 printf(
Jan Engelhardta80b6042008-01-20 13:34:07 +000021"conntrack match options:\n"
22"[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n"
23" State(s) to match\n"
24"[!] --ctproto proto Protocol to match; by number or name, e.g. \"tcp\"\n"
25"[!] --ctorigsrc address[/mask]\n"
26"[!] --ctorigdst address[/mask]\n"
27"[!] --ctreplsrc address[/mask]\n"
28"[!] --ctrepldst address[/mask]\n"
29" Original/Reply source/destination address\n"
30"[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n"
31" Status(es) to match\n"
32"[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n"
33" value or range of values (inclusive)\n"
34"\n");
Marc Boucher5054e852002-01-19 10:59:12 +000035}
36
Jan Engelhardta80b6042008-01-20 13:34:07 +000037static const struct option conntrack_mt_opts[] = {
38 {.name = "ctstate", .has_arg = true, .val = '1'},
39 {.name = "ctproto", .has_arg = true, .val = '2'},
40 {.name = "ctorigsrc", .has_arg = true, .val = '3'},
41 {.name = "ctorigdst", .has_arg = true, .val = '4'},
42 {.name = "ctreplsrc", .has_arg = true, .val = '5'},
43 {.name = "ctrepldst", .has_arg = true, .val = '6'},
44 {.name = "ctstatus", .has_arg = true, .val = '7'},
45 {.name = "ctexpire", .has_arg = true, .val = '8'},
46 {},
Marc Boucher5054e852002-01-19 10:59:12 +000047};
48
Marc Boucher5054e852002-01-19 10:59:12 +000049static int
Jan Engelhardta80b6042008-01-20 13:34:07 +000050parse_state(const char *state, size_t strlen, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +000051{
52 if (strncasecmp(state, "INVALID", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000053 sinfo->statemask |= XT_CONNTRACK_STATE_INVALID;
Marc Boucher5054e852002-01-19 10:59:12 +000054 else if (strncasecmp(state, "NEW", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000055 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
Marc Boucher5054e852002-01-19 10:59:12 +000056 else if (strncasecmp(state, "ESTABLISHED", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000057 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
Marc Boucher5054e852002-01-19 10:59:12 +000058 else if (strncasecmp(state, "RELATED", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000059 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
Harald Welte4dc734c2003-10-07 18:55:13 +000060 else if (strncasecmp(state, "UNTRACKED", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000061 sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED;
Marc Boucher5054e852002-01-19 10:59:12 +000062 else if (strncasecmp(state, "SNAT", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000063 sinfo->statemask |= XT_CONNTRACK_STATE_SNAT;
Marc Boucher5054e852002-01-19 10:59:12 +000064 else if (strncasecmp(state, "DNAT", strlen) == 0)
Jan Engelhardta80b6042008-01-20 13:34:07 +000065 sinfo->statemask |= XT_CONNTRACK_STATE_DNAT;
Marc Boucher5054e852002-01-19 10:59:12 +000066 else
67 return 0;
68 return 1;
69}
70
71static void
Jan Engelhardta80b6042008-01-20 13:34:07 +000072parse_states(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +000073{
74 const char *comma;
75
76 while ((comma = strchr(arg, ',')) != NULL) {
77 if (comma == arg || !parse_state(arg, comma-arg, sinfo))
78 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
79 arg = comma+1;
80 }
81
82 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
83 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg);
84}
85
86static int
Jan Engelhardta80b6042008-01-20 13:34:07 +000087parse_status(const char *status, size_t strlen, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +000088{
89 if (strncasecmp(status, "NONE", strlen) == 0)
90 sinfo->statusmask |= 0;
91 else if (strncasecmp(status, "EXPECTED", strlen) == 0)
92 sinfo->statusmask |= IPS_EXPECTED;
93 else if (strncasecmp(status, "SEEN_REPLY", strlen) == 0)
94 sinfo->statusmask |= IPS_SEEN_REPLY;
95 else if (strncasecmp(status, "ASSURED", strlen) == 0)
96 sinfo->statusmask |= IPS_ASSURED;
Harald Weltea643c3e2003-08-25 11:08:52 +000097#ifdef IPS_CONFIRMED
98 else if (strncasecmp(status, "CONFIRMED", strlen) == 0)
99 sinfo->stausmask |= IPS_CONFIRMED;
100#endif
Marc Boucher5054e852002-01-19 10:59:12 +0000101 else
102 return 0;
103 return 1;
104}
105
106static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000107parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000108{
109 const char *comma;
110
111 while ((comma = strchr(arg, ',')) != NULL) {
112 if (comma == arg || !parse_status(arg, comma-arg, sinfo))
113 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
114 arg = comma+1;
115 }
116
117 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo))
118 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg);
119}
120
Marc Boucher5054e852002-01-19 10:59:12 +0000121static unsigned long
122parse_expire(const char *s)
123{
124 unsigned int len;
Jan Engelhardta80b6042008-01-20 13:34:07 +0000125
Martin Josefsson1da399c2004-05-26 15:50:57 +0000126 if (string_to_number(s, 0, 0, &len) == -1)
Marc Boucher5054e852002-01-19 10:59:12 +0000127 exit_error(PARAMETER_PROBLEM, "expire value invalid: `%s'\n", s);
128 else
129 return len;
130}
131
132/* If a single value is provided, min and max are both set to the value */
133static void
Jan Engelhardta80b6042008-01-20 13:34:07 +0000134parse_expires(const char *s, struct xt_conntrack_info *sinfo)
Marc Boucher5054e852002-01-19 10:59:12 +0000135{
136 char *buffer;
137 char *cp;
138
139 buffer = strdup(s);
140 if ((cp = strchr(buffer, ':')) == NULL)
141 sinfo->expires_min = sinfo->expires_max = parse_expire(buffer);
142 else {
143 *cp = '\0';
144 cp++;
145
146 sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0;
Martin Josefsson1da399c2004-05-26 15:50:57 +0000147 sinfo->expires_max = cp[0] ? parse_expire(cp) : -1;
Marc Boucher5054e852002-01-19 10:59:12 +0000148 }
149 free(buffer);
Jan Engelhardta80b6042008-01-20 13:34:07 +0000150
Marc Boucher5054e852002-01-19 10:59:12 +0000151 if (sinfo->expires_min > sinfo->expires_max)
152 exit_error(PARAMETER_PROBLEM,
153 "expire min. range value `%lu' greater than max. "
154 "range value `%lu'", sinfo->expires_min, sinfo->expires_max);
Marc Boucher5054e852002-01-19 10:59:12 +0000155}
156
157/* Function which parses command options; returns true if it
158 ate an option */
Jan Engelhardt59d16402007-10-04 16:28:39 +0000159static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags,
160 const void *entry, struct xt_entry_match **match)
Marc Boucher5054e852002-01-19 10:59:12 +0000161{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000162 struct xt_conntrack_info *sinfo = (void *)(*match)->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000163 char *protocol = NULL;
164 unsigned int naddrs = 0;
165 struct in_addr *addrs = NULL;
166
167
168 switch (c) {
169 case '1':
Harald Welteb77f1da2002-03-14 11:35:58 +0000170 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000171
172 parse_states(argv[optind-1], sinfo);
173 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000174 sinfo->invflags |= XT_CONNTRACK_STATE;
Marc Boucher5054e852002-01-19 10:59:12 +0000175 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000176 sinfo->flags |= XT_CONNTRACK_STATE;
Marc Boucher5054e852002-01-19 10:59:12 +0000177 break;
178
179 case '2':
Harald Welte3c5bd602002-03-14 19:54:34 +0000180 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000181
182 if(invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000183 sinfo->invflags |= XT_CONNTRACK_PROTO;
Marc Boucher5054e852002-01-19 10:59:12 +0000184
185 /* Canonicalize into lower case */
186 for (protocol = argv[optind-1]; *protocol; protocol++)
187 *protocol = tolower(*protocol);
188
189 protocol = argv[optind-1];
190 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = parse_protocol(protocol);
191
192 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0
Jan Engelhardta80b6042008-01-20 13:34:07 +0000193 && (sinfo->invflags & XT_INV_PROTO))
Marc Boucher5054e852002-01-19 10:59:12 +0000194 exit_error(PARAMETER_PROBLEM,
195 "rule would never match protocol");
196
Jan Engelhardta80b6042008-01-20 13:34:07 +0000197 sinfo->flags |= XT_CONNTRACK_PROTO;
Marc Boucher5054e852002-01-19 10:59:12 +0000198 break;
199
200 case '3':
Jan Engelhardt40eaf2a2007-11-25 15:25:23 +0000201 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000202
203 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000204 sinfo->invflags |= XT_CONNTRACK_ORIGSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000205
206 parse_hostnetworkmask(argv[optind-1], &addrs,
207 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
208 &naddrs);
209 if(naddrs > 1)
210 exit_error(PARAMETER_PROBLEM,
211 "multiple IP addresses not allowed");
212
213 if(naddrs == 1) {
214 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr;
215 }
216
Jan Engelhardta80b6042008-01-20 13:34:07 +0000217 sinfo->flags |= XT_CONNTRACK_ORIGSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000218 break;
219
220 case '4':
Harald Welteb77f1da2002-03-14 11:35:58 +0000221 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000222
223 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000224 sinfo->invflags |= XT_CONNTRACK_ORIGDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000225
226 parse_hostnetworkmask(argv[optind-1], &addrs,
227 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
228 &naddrs);
229 if(naddrs > 1)
230 exit_error(PARAMETER_PROBLEM,
231 "multiple IP addresses not allowed");
232
233 if(naddrs == 1) {
234 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr;
235 }
236
Jan Engelhardta80b6042008-01-20 13:34:07 +0000237 sinfo->flags |= XT_CONNTRACK_ORIGDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000238 break;
239
240 case '5':
Harald Welteb77f1da2002-03-14 11:35:58 +0000241 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000242
243 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000244 sinfo->invflags |= XT_CONNTRACK_REPLSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000245
246 parse_hostnetworkmask(argv[optind-1], &addrs,
247 &sinfo->sipmsk[IP_CT_DIR_REPLY],
248 &naddrs);
249 if(naddrs > 1)
250 exit_error(PARAMETER_PROBLEM,
251 "multiple IP addresses not allowed");
252
253 if(naddrs == 1) {
254 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr;
255 }
256
Jan Engelhardta80b6042008-01-20 13:34:07 +0000257 sinfo->flags |= XT_CONNTRACK_REPLSRC;
Marc Boucher5054e852002-01-19 10:59:12 +0000258 break;
259
260 case '6':
Harald Welteb77f1da2002-03-14 11:35:58 +0000261 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000262
263 if (invert)
Jan Engelhardta80b6042008-01-20 13:34:07 +0000264 sinfo->invflags |= XT_CONNTRACK_REPLDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000265
266 parse_hostnetworkmask(argv[optind-1], &addrs,
267 &sinfo->dipmsk[IP_CT_DIR_REPLY],
268 &naddrs);
269 if(naddrs > 1)
270 exit_error(PARAMETER_PROBLEM,
271 "multiple IP addresses not allowed");
272
273 if(naddrs == 1) {
274 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr;
275 }
276
Jan Engelhardta80b6042008-01-20 13:34:07 +0000277 sinfo->flags |= XT_CONNTRACK_REPLDST;
Marc Boucher5054e852002-01-19 10:59:12 +0000278 break;
279
280 case '7':
Harald Welteb77f1da2002-03-14 11:35:58 +0000281 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000282
283 parse_statuses(argv[optind-1], sinfo);
284 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000285 sinfo->invflags |= XT_CONNTRACK_STATUS;
Marc Boucher5054e852002-01-19 10:59:12 +0000286 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000287 sinfo->flags |= XT_CONNTRACK_STATUS;
Marc Boucher5054e852002-01-19 10:59:12 +0000288 break;
289
290 case '8':
Harald Welteb77f1da2002-03-14 11:35:58 +0000291 check_inverse(optarg, &invert, &optind, 0);
Marc Boucher5054e852002-01-19 10:59:12 +0000292
293 parse_expires(argv[optind-1], sinfo);
294 if (invert) {
Jan Engelhardta80b6042008-01-20 13:34:07 +0000295 sinfo->invflags |= XT_CONNTRACK_EXPIRES;
Marc Boucher5054e852002-01-19 10:59:12 +0000296 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000297 sinfo->flags |= XT_CONNTRACK_EXPIRES;
Marc Boucher5054e852002-01-19 10:59:12 +0000298 break;
299
300 default:
301 return 0;
302 }
303
304 *flags = sinfo->flags;
305 return 1;
306}
307
Jan Engelhardta80b6042008-01-20 13:34:07 +0000308static void conntrack_mt_check(unsigned int flags)
Marc Boucher5054e852002-01-19 10:59:12 +0000309{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000310 if (flags == 0)
Marc Boucher5054e852002-01-19 10:59:12 +0000311 exit_error(PARAMETER_PROBLEM, "You must specify one or more options");
312}
313
314static void
315print_state(unsigned int statemask)
316{
317 const char *sep = "";
318
Jan Engelhardta80b6042008-01-20 13:34:07 +0000319 if (statemask & XT_CONNTRACK_STATE_INVALID) {
Marc Boucher5054e852002-01-19 10:59:12 +0000320 printf("%sINVALID", sep);
321 sep = ",";
322 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000323 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000324 printf("%sNEW", sep);
325 sep = ",";
326 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000327 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000328 printf("%sRELATED", sep);
329 sep = ",";
330 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000331 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
Marc Boucher5054e852002-01-19 10:59:12 +0000332 printf("%sESTABLISHED", sep);
333 sep = ",";
334 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000335 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
Harald Welte4dc734c2003-10-07 18:55:13 +0000336 printf("%sUNTRACKED", sep);
337 sep = ",";
338 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000339 if (statemask & XT_CONNTRACK_STATE_SNAT) {
Marc Boucher5054e852002-01-19 10:59:12 +0000340 printf("%sSNAT", sep);
341 sep = ",";
342 }
Jan Engelhardta80b6042008-01-20 13:34:07 +0000343 if (statemask & XT_CONNTRACK_STATE_DNAT) {
Marc Boucher5054e852002-01-19 10:59:12 +0000344 printf("%sDNAT", sep);
345 sep = ",";
346 }
347 printf(" ");
348}
349
350static void
351print_status(unsigned int statusmask)
352{
353 const char *sep = "";
354
355 if (statusmask & IPS_EXPECTED) {
356 printf("%sEXPECTED", sep);
357 sep = ",";
358 }
359 if (statusmask & IPS_SEEN_REPLY) {
360 printf("%sSEEN_REPLY", sep);
361 sep = ",";
362 }
363 if (statusmask & IPS_ASSURED) {
364 printf("%sASSURED", sep);
365 sep = ",";
366 }
Harald Weltea643c3e2003-08-25 11:08:52 +0000367#ifdef IPS_CONFIRMED
368 if (statusmask & IPS_CONFIRMED) {
369 printf("%sCONFIRMED", sep);
370 sep =",";
371 }
372#endif
Marc Boucher5054e852002-01-19 10:59:12 +0000373 if (statusmask == 0) {
374 printf("%sNONE", sep);
375 sep = ",";
376 }
377 printf(" ");
378}
379
380static void
381print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric)
382{
383 char buf[BUFSIZ];
384
Jan Engelhardta80b6042008-01-20 13:34:07 +0000385 if (inv)
386 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000387
388 if (mask->s_addr == 0L && !numeric)
389 printf("%s ", "anywhere");
390 else {
391 if (numeric)
Jan Engelhardt08b16162008-01-20 13:36:08 +0000392 sprintf(buf, "%s", ipaddr_to_numeric(addr));
Marc Boucher5054e852002-01-19 10:59:12 +0000393 else
Jan Engelhardt08b16162008-01-20 13:36:08 +0000394 sprintf(buf, "%s", ipaddr_to_anyname(addr));
395 strcat(buf, ipmask_to_numeric(mask));
Marc Boucher5054e852002-01-19 10:59:12 +0000396 printf("%s ", buf);
397 }
398}
399
400/* Saves the matchinfo in parsable form to stdout. */
401static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000402matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx)
Marc Boucher5054e852002-01-19 10:59:12 +0000403{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000404 struct xt_conntrack_info *sinfo = (void *)match->data;
Marc Boucher5054e852002-01-19 10:59:12 +0000405
Jan Engelhardta80b6042008-01-20 13:34:07 +0000406 if(sinfo->flags & XT_CONNTRACK_STATE) {
407 if (sinfo->invflags & XT_CONNTRACK_STATE)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000408 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000409 printf("%sctstate ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000410 print_state(sinfo->statemask);
411 }
412
Jan Engelhardta80b6042008-01-20 13:34:07 +0000413 if(sinfo->flags & XT_CONNTRACK_PROTO) {
414 if (sinfo->invflags & XT_CONNTRACK_PROTO)
Phil Oester5a4892b2005-11-17 13:34:51 +0000415 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000416 printf("%sctproto ", optpfx);
Phil Oester5a4892b2005-11-17 13:34:51 +0000417 printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum);
418 }
419
Jan Engelhardta80b6042008-01-20 13:34:07 +0000420 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
421 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC)
422 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000423 printf("%sctorigsrc ", optpfx);
424
425 print_addr(
426 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
427 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000428 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000429 numeric);
430 }
431
Jan Engelhardta80b6042008-01-20 13:34:07 +0000432 if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
433 if (sinfo->invflags & XT_CONNTRACK_ORIGDST)
434 printf("! ");
Marc Boucher5054e852002-01-19 10:59:12 +0000435 printf("%sctorigdst ", optpfx);
436
437 print_addr(
438 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
439 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000440 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000441 numeric);
442 }
443
Jan Engelhardta80b6042008-01-20 13:34:07 +0000444 if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
445 if (sinfo->invflags & XT_CONNTRACK_REPLSRC)
446 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000447 printf("%sctreplsrc ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000448
449 print_addr(
450 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
451 &sinfo->sipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000452 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000453 numeric);
454 }
455
Jan Engelhardta80b6042008-01-20 13:34:07 +0000456 if(sinfo->flags & XT_CONNTRACK_REPLDST) {
457 if (sinfo->invflags & XT_CONNTRACK_REPLDST)
458 printf("! ");
Lutz Preßlerd0ae04e2003-03-04 14:50:50 +0000459 printf("%sctrepldst ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000460
461 print_addr(
462 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
463 &sinfo->dipmsk[IP_CT_DIR_REPLY],
Jan Engelhardta80b6042008-01-20 13:34:07 +0000464 false,
Marc Boucher5054e852002-01-19 10:59:12 +0000465 numeric);
466 }
467
Jan Engelhardta80b6042008-01-20 13:34:07 +0000468 if(sinfo->flags & XT_CONNTRACK_STATUS) {
469 if (sinfo->invflags & XT_CONNTRACK_STATUS)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000470 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000471 printf("%sctstatus ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000472 print_status(sinfo->statusmask);
473 }
474
Jan Engelhardta80b6042008-01-20 13:34:07 +0000475 if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
476 if (sinfo->invflags & XT_CONNTRACK_EXPIRES)
Michael Schwendtdfba3ac2002-12-05 20:20:29 +0000477 printf("! ");
Jan Engelhardta80b6042008-01-20 13:34:07 +0000478 printf("%sctexpire ", optpfx);
Marc Boucher5054e852002-01-19 10:59:12 +0000479
480 if (sinfo->expires_max == sinfo->expires_min)
481 printf("%lu ", sinfo->expires_min);
482 else
483 printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max);
484 }
485}
486
487/* Prints out the matchinfo. */
Jan Engelhardt59d16402007-10-04 16:28:39 +0000488static void conntrack_print(const void *ip, const struct xt_entry_match *match,
489 int numeric)
Marc Boucher5054e852002-01-19 10:59:12 +0000490{
491 matchinfo_print(ip, match, numeric, "");
492}
493
494/* Saves the matchinfo in parsable form to stdout. */
Jan Engelhardt59d16402007-10-04 16:28:39 +0000495static void conntrack_save(const void *ip, const struct xt_entry_match *match)
Marc Boucher5054e852002-01-19 10:59:12 +0000496{
Joszef Kadlecsikdb503f92004-05-05 10:10:33 +0000497 matchinfo_print(ip, match, 1, "--");
Marc Boucher5054e852002-01-19 10:59:12 +0000498}
499
Jan Engelhardta80b6042008-01-20 13:34:07 +0000500static struct xtables_match conntrack_match = {
501 .version = IPTABLES_VERSION,
502 .name = "conntrack",
503 .revision = 0,
504 .family = AF_INET,
505 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)),
506 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)),
507 .help = conntrack_mt_help,
508 .parse = conntrack_parse,
509 .final_check = conntrack_mt_check,
510 .print = conntrack_print,
511 .save = conntrack_save,
512 .extra_opts = conntrack_mt_opts,
Marc Boucher5054e852002-01-19 10:59:12 +0000513};
514
515void _init(void)
516{
Jan Engelhardta80b6042008-01-20 13:34:07 +0000517 xtables_register_match(&conntrack_match);
Marc Boucher5054e852002-01-19 10:59:12 +0000518}