1 /*
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>
8 */
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <xtables.h>
15 #include <linux/netfilter/xt_conntrack.h>
16 #include <linux/netfilter/xt_state.h>
17 #include <linux/netfilter/nf_conntrack_common.h>
18 #ifndef XT_STATE_UNTRACKED
19 #define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
20 #endif
21
22 struct ip_conntrack_old_tuple {
23 struct {
24 __be32 ip;
25 union {
26 __u16 all;
27 } u;
28 } src;
29
30 struct {
31 __be32 ip;
32 union {
33 __u16 all;
34 } u;
35
36 /* The protocol. */
37 __u16 protonum;
38 } dst;
39 };
40
41 struct xt_conntrack_info {
42 unsigned int statemask, statusmask;
43
44 struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX];
45 struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
46
47 unsigned long expires_min, expires_max;
48
49 /* Flags word */
50 uint8_t flags;
51 /* Inverse flags */
52 uint8_t invflags;
53 };
54
55 enum {
56 O_CTSTATE = 0,
57 O_CTPROTO,
58 O_CTORIGSRC,
59 O_CTORIGDST,
60 O_CTREPLSRC,
61 O_CTREPLDST,
62 O_CTORIGSRCPORT,
63 O_CTORIGDSTPORT,
64 O_CTREPLSRCPORT,
65 O_CTREPLDSTPORT,
66 O_CTSTATUS,
67 O_CTEXPIRE,
68 O_CTDIR,
69 };
70
conntrack_mt_help(void)71 static void conntrack_mt_help(void)
72 {
73 printf(
74 "conntrack match options:\n"
75 "[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n"
76 " State(s) to match\n"
77 "[!] --ctproto proto Protocol to match; by number or name, e.g. \"tcp\"\n"
78 "[!] --ctorigsrc address[/mask]\n"
79 "[!] --ctorigdst address[/mask]\n"
80 "[!] --ctreplsrc address[/mask]\n"
81 "[!] --ctrepldst address[/mask]\n"
82 " Original/Reply source/destination address\n"
83 "[!] --ctorigsrcport port\n"
84 "[!] --ctorigdstport port\n"
85 "[!] --ctreplsrcport port\n"
86 "[!] --ctrepldstport port\n"
87 " TCP/UDP/SCTP orig./reply source/destination port\n"
88 "[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n"
89 " Status(es) to match\n"
90 "[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n"
91 " value or range of values (inclusive)\n"
92 " --ctdir {ORIGINAL|REPLY} Flow direction of packet\n");
93 }
94
95 #define s struct xt_conntrack_info /* for v0 */
96 static const struct xt_option_entry conntrack_mt_opts_v0[] = {
97 {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING,
98 .flags = XTOPT_INVERT},
99 {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL,
100 .flags = XTOPT_INVERT},
101 {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOST,
102 .flags = XTOPT_INVERT},
103 {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOST,
104 .flags = XTOPT_INVERT},
105 {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOST,
106 .flags = XTOPT_INVERT},
107 {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOST,
108 .flags = XTOPT_INVERT},
109 {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING,
110 .flags = XTOPT_INVERT},
111 {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC,
112 .flags = XTOPT_INVERT},
113 XTOPT_TABLEEND,
114 };
115 #undef s
116
117 #define s struct xt_conntrack_mtinfo2
118 /* We exploit the fact that v1-v2 share the same xt_o_e layout */
119 static const struct xt_option_entry conntrack2_mt_opts[] = {
120 {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING,
121 .flags = XTOPT_INVERT},
122 {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL,
123 .flags = XTOPT_INVERT},
124 {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOSTMASK,
125 .flags = XTOPT_INVERT},
126 {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOSTMASK,
127 .flags = XTOPT_INVERT},
128 {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOSTMASK,
129 .flags = XTOPT_INVERT},
130 {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOSTMASK,
131 .flags = XTOPT_INVERT},
132 {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING,
133 .flags = XTOPT_INVERT},
134 {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC,
135 .flags = XTOPT_INVERT},
136 /*
137 * Rev 1 and 2 only store one port, and we would normally use
138 * %XTTYPE_PORT (rather than %XTTYPE_PORTRC) for that. The resulting
139 * error message - in case a user passed a range nevertheless -
140 * "port 22:23 resolved to nothing" is not quite as useful as using
141 * %XTTYPE_PORTC and libxt_conntrack's own range test.
142 */
143 {.name = "ctorigsrcport", .id = O_CTORIGSRCPORT, .type = XTTYPE_PORTRC,
144 .flags = XTOPT_INVERT | XTOPT_NBO},
145 {.name = "ctorigdstport", .id = O_CTORIGDSTPORT, .type = XTTYPE_PORTRC,
146 .flags = XTOPT_INVERT | XTOPT_NBO},
147 {.name = "ctreplsrcport", .id = O_CTREPLSRCPORT, .type = XTTYPE_PORTRC,
148 .flags = XTOPT_INVERT | XTOPT_NBO},
149 {.name = "ctrepldstport", .id = O_CTREPLDSTPORT, .type = XTTYPE_PORTRC,
150 .flags = XTOPT_INVERT | XTOPT_NBO},
151 {.name = "ctdir", .id = O_CTDIR, .type = XTTYPE_STRING},
152 XTOPT_TABLEEND,
153 };
154 #undef s
155
156 #define s struct xt_conntrack_mtinfo3
157 /* Difference from v2 is the non-NBO form. */
158 static const struct xt_option_entry conntrack3_mt_opts[] = {
159 {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING,
160 .flags = XTOPT_INVERT},
161 {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL,
162 .flags = XTOPT_INVERT},
163 {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOSTMASK,
164 .flags = XTOPT_INVERT},
165 {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOSTMASK,
166 .flags = XTOPT_INVERT},
167 {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOSTMASK,
168 .flags = XTOPT_INVERT},
169 {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOSTMASK,
170 .flags = XTOPT_INVERT},
171 {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING,
172 .flags = XTOPT_INVERT},
173 {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC,
174 .flags = XTOPT_INVERT},
175 {.name = "ctorigsrcport", .id = O_CTORIGSRCPORT, .type = XTTYPE_PORTRC,
176 .flags = XTOPT_INVERT},
177 {.name = "ctorigdstport", .id = O_CTORIGDSTPORT, .type = XTTYPE_PORTRC,
178 .flags = XTOPT_INVERT},
179 {.name = "ctreplsrcport", .id = O_CTREPLSRCPORT, .type = XTTYPE_PORTRC,
180 .flags = XTOPT_INVERT},
181 {.name = "ctrepldstport", .id = O_CTREPLDSTPORT, .type = XTTYPE_PORTRC,
182 .flags = XTOPT_INVERT},
183 {.name = "ctdir", .id = O_CTDIR, .type = XTTYPE_STRING},
184 XTOPT_TABLEEND,
185 };
186 #undef s
187
188 static int
parse_state(const char * state,size_t len,struct xt_conntrack_info * sinfo)189 parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo)
190 {
191 if (strncasecmp(state, "INVALID", len) == 0)
192 sinfo->statemask |= XT_CONNTRACK_STATE_INVALID;
193 else if (strncasecmp(state, "NEW", len) == 0)
194 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
195 else if (strncasecmp(state, "ESTABLISHED", len) == 0)
196 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
197 else if (strncasecmp(state, "RELATED", len) == 0)
198 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
199 else if (strncasecmp(state, "UNTRACKED", len) == 0)
200 sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED;
201 else if (strncasecmp(state, "SNAT", len) == 0)
202 sinfo->statemask |= XT_CONNTRACK_STATE_SNAT;
203 else if (strncasecmp(state, "DNAT", len) == 0)
204 sinfo->statemask |= XT_CONNTRACK_STATE_DNAT;
205 else
206 return 0;
207 return 1;
208 }
209
210 static void
parse_states(const char * arg,struct xt_conntrack_info * sinfo)211 parse_states(const char *arg, struct xt_conntrack_info *sinfo)
212 {
213 const char *comma;
214
215 while ((comma = strchr(arg, ',')) != NULL) {
216 if (comma == arg || !parse_state(arg, comma-arg, sinfo))
217 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
218 arg = comma+1;
219 }
220 if (!*arg)
221 xtables_error(PARAMETER_PROBLEM, "\"--ctstate\" requires a list of "
222 "states with no spaces, e.g. "
223 "ESTABLISHED,RELATED");
224 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
225 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
226 }
227
228 static bool
conntrack_ps_state(struct xt_conntrack_mtinfo3 * info,const char * state,size_t z)229 conntrack_ps_state(struct xt_conntrack_mtinfo3 *info, const char *state,
230 size_t z)
231 {
232 if (strncasecmp(state, "INVALID", z) == 0)
233 info->state_mask |= XT_CONNTRACK_STATE_INVALID;
234 else if (strncasecmp(state, "NEW", z) == 0)
235 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
236 else if (strncasecmp(state, "ESTABLISHED", z) == 0)
237 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
238 else if (strncasecmp(state, "RELATED", z) == 0)
239 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
240 else if (strncasecmp(state, "UNTRACKED", z) == 0)
241 info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED;
242 else if (strncasecmp(state, "SNAT", z) == 0)
243 info->state_mask |= XT_CONNTRACK_STATE_SNAT;
244 else if (strncasecmp(state, "DNAT", z) == 0)
245 info->state_mask |= XT_CONNTRACK_STATE_DNAT;
246 else
247 return false;
248 return true;
249 }
250
251 static void
conntrack_ps_states(struct xt_conntrack_mtinfo3 * info,const char * arg)252 conntrack_ps_states(struct xt_conntrack_mtinfo3 *info, const char *arg)
253 {
254 const char *comma;
255
256 while ((comma = strchr(arg, ',')) != NULL) {
257 if (comma == arg || !conntrack_ps_state(info, arg, comma - arg))
258 xtables_error(PARAMETER_PROBLEM,
259 "Bad ctstate \"%s\"", arg);
260 arg = comma + 1;
261 }
262
263 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg)))
264 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
265 }
266
267 static int
parse_status(const char * status,size_t len,struct xt_conntrack_info * sinfo)268 parse_status(const char *status, size_t len, struct xt_conntrack_info *sinfo)
269 {
270 if (strncasecmp(status, "NONE", len) == 0)
271 sinfo->statusmask |= 0;
272 else if (strncasecmp(status, "EXPECTED", len) == 0)
273 sinfo->statusmask |= IPS_EXPECTED;
274 else if (strncasecmp(status, "SEEN_REPLY", len) == 0)
275 sinfo->statusmask |= IPS_SEEN_REPLY;
276 else if (strncasecmp(status, "ASSURED", len) == 0)
277 sinfo->statusmask |= IPS_ASSURED;
278 #ifdef IPS_CONFIRMED
279 else if (strncasecmp(status, "CONFIRMED", len) == 0)
280 sinfo->statusmask |= IPS_CONFIRMED;
281 #endif
282 else
283 return 0;
284 return 1;
285 }
286
287 static void
parse_statuses(const char * arg,struct xt_conntrack_info * sinfo)288 parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
289 {
290 const char *comma;
291
292 while ((comma = strchr(arg, ',')) != NULL) {
293 if (comma == arg || !parse_status(arg, comma-arg, sinfo))
294 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
295 arg = comma+1;
296 }
297
298 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo))
299 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
300 }
301
302 static bool
conntrack_ps_status(struct xt_conntrack_mtinfo3 * info,const char * status,size_t z)303 conntrack_ps_status(struct xt_conntrack_mtinfo3 *info, const char *status,
304 size_t z)
305 {
306 if (strncasecmp(status, "NONE", z) == 0)
307 info->status_mask |= 0;
308 else if (strncasecmp(status, "EXPECTED", z) == 0)
309 info->status_mask |= IPS_EXPECTED;
310 else if (strncasecmp(status, "SEEN_REPLY", z) == 0)
311 info->status_mask |= IPS_SEEN_REPLY;
312 else if (strncasecmp(status, "ASSURED", z) == 0)
313 info->status_mask |= IPS_ASSURED;
314 else if (strncasecmp(status, "CONFIRMED", z) == 0)
315 info->status_mask |= IPS_CONFIRMED;
316 else
317 return false;
318 return true;
319 }
320
321 static void
conntrack_ps_statuses(struct xt_conntrack_mtinfo3 * info,const char * arg)322 conntrack_ps_statuses(struct xt_conntrack_mtinfo3 *info, const char *arg)
323 {
324 const char *comma;
325
326 while ((comma = strchr(arg, ',')) != NULL) {
327 if (comma == arg || !conntrack_ps_status(info, arg, comma - arg))
328 xtables_error(PARAMETER_PROBLEM,
329 "Bad ctstatus \"%s\"", arg);
330 arg = comma + 1;
331 }
332
333 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg)))
334 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
335 }
336
conntrack_parse(struct xt_option_call * cb)337 static void conntrack_parse(struct xt_option_call *cb)
338 {
339 struct xt_conntrack_info *sinfo = cb->data;
340
341 xtables_option_parse(cb);
342 switch (cb->entry->id) {
343 case O_CTSTATE:
344 parse_states(cb->arg, sinfo);
345 if (cb->invert)
346 sinfo->invflags |= XT_CONNTRACK_STATE;
347 break;
348 case O_CTPROTO:
349 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = cb->val.protocol;
350 if (cb->invert)
351 sinfo->invflags |= XT_CONNTRACK_PROTO;
352 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0
353 && (sinfo->invflags & XT_INV_PROTO))
354 xtables_error(PARAMETER_PROBLEM,
355 "rule would never match protocol");
356
357 sinfo->flags |= XT_CONNTRACK_PROTO;
358 break;
359 case O_CTORIGSRC:
360 if (cb->invert)
361 sinfo->invflags |= XT_CONNTRACK_ORIGSRC;
362 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = cb->val.haddr.ip;
363 sinfo->flags |= XT_CONNTRACK_ORIGSRC;
364 break;
365 case O_CTORIGDST:
366 if (cb->invert)
367 sinfo->invflags |= XT_CONNTRACK_ORIGDST;
368 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = cb->val.haddr.ip;
369 sinfo->flags |= XT_CONNTRACK_ORIGDST;
370 break;
371 case O_CTREPLSRC:
372 if (cb->invert)
373 sinfo->invflags |= XT_CONNTRACK_REPLSRC;
374 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = cb->val.haddr.ip;
375 sinfo->flags |= XT_CONNTRACK_REPLSRC;
376 break;
377 case O_CTREPLDST:
378 if (cb->invert)
379 sinfo->invflags |= XT_CONNTRACK_REPLDST;
380 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = cb->val.haddr.ip;
381 sinfo->flags |= XT_CONNTRACK_REPLDST;
382 break;
383 case O_CTSTATUS:
384 parse_statuses(cb->arg, sinfo);
385 if (cb->invert)
386 sinfo->invflags |= XT_CONNTRACK_STATUS;
387 sinfo->flags |= XT_CONNTRACK_STATUS;
388 break;
389 case O_CTEXPIRE:
390 sinfo->expires_min = cb->val.u32_range[0];
391 sinfo->expires_max = cb->val.u32_range[0];
392 if (cb->nvals >= 2)
393 sinfo->expires_max = cb->val.u32_range[1];
394 if (cb->invert)
395 sinfo->invflags |= XT_CONNTRACK_EXPIRES;
396 sinfo->flags |= XT_CONNTRACK_EXPIRES;
397 break;
398 }
399 }
400
conntrack_mt_parse(struct xt_option_call * cb,uint8_t rev)401 static void conntrack_mt_parse(struct xt_option_call *cb, uint8_t rev)
402 {
403 struct xt_conntrack_mtinfo3 *info = cb->data;
404
405 xtables_option_parse(cb);
406 switch (cb->entry->id) {
407 case O_CTSTATE:
408 conntrack_ps_states(info, cb->arg);
409 info->match_flags |= XT_CONNTRACK_STATE;
410 if (cb->invert)
411 info->invert_flags |= XT_CONNTRACK_STATE;
412 break;
413 case O_CTPROTO:
414 info->l4proto = cb->val.protocol;
415 if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO))
416 xtables_error(PARAMETER_PROBLEM, "conntrack: rule would "
417 "never match protocol");
418
419 info->match_flags |= XT_CONNTRACK_PROTO;
420 if (cb->invert)
421 info->invert_flags |= XT_CONNTRACK_PROTO;
422 break;
423 case O_CTORIGSRC:
424 info->origsrc_addr = cb->val.haddr;
425 info->origsrc_mask = cb->val.hmask;
426 info->match_flags |= XT_CONNTRACK_ORIGSRC;
427 if (cb->invert)
428 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
429 break;
430 case O_CTORIGDST:
431 info->origdst_addr = cb->val.haddr;
432 info->origdst_mask = cb->val.hmask;
433 info->match_flags |= XT_CONNTRACK_ORIGDST;
434 if (cb->invert)
435 info->invert_flags |= XT_CONNTRACK_ORIGDST;
436 break;
437 case O_CTREPLSRC:
438 info->replsrc_addr = cb->val.haddr;
439 info->replsrc_mask = cb->val.hmask;
440 info->match_flags |= XT_CONNTRACK_REPLSRC;
441 if (cb->invert)
442 info->invert_flags |= XT_CONNTRACK_REPLSRC;
443 break;
444 case O_CTREPLDST:
445 info->repldst_addr = cb->val.haddr;
446 info->repldst_mask = cb->val.hmask;
447 info->match_flags |= XT_CONNTRACK_REPLDST;
448 if (cb->invert)
449 info->invert_flags |= XT_CONNTRACK_REPLDST;
450 break;
451 case O_CTSTATUS:
452 conntrack_ps_statuses(info, cb->arg);
453 info->match_flags |= XT_CONNTRACK_STATUS;
454 if (cb->invert)
455 info->invert_flags |= XT_CONNTRACK_STATUS;
456 break;
457 case O_CTEXPIRE:
458 info->expires_min = cb->val.u32_range[0];
459 info->expires_max = cb->val.u32_range[0];
460 if (cb->nvals >= 2)
461 info->expires_max = cb->val.u32_range[1];
462 info->match_flags |= XT_CONNTRACK_EXPIRES;
463 if (cb->invert)
464 info->invert_flags |= XT_CONNTRACK_EXPIRES;
465 break;
466 case O_CTORIGSRCPORT:
467 info->origsrc_port = cb->val.port_range[0];
468 info->origsrc_port_high = cb->val.port_range[cb->nvals >= 2];
469 info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT;
470 if (cb->invert)
471 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT;
472 break;
473 case O_CTORIGDSTPORT:
474 info->origdst_port = cb->val.port_range[0];
475 info->origdst_port_high = cb->val.port_range[cb->nvals >= 2];
476 info->match_flags |= XT_CONNTRACK_ORIGDST_PORT;
477 if (cb->invert)
478 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT;
479 break;
480 case O_CTREPLSRCPORT:
481 info->replsrc_port = cb->val.port_range[0];
482 info->replsrc_port_high = cb->val.port_range[cb->nvals >= 2];
483 info->match_flags |= XT_CONNTRACK_REPLSRC_PORT;
484 if (cb->invert)
485 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT;
486 break;
487 case O_CTREPLDSTPORT:
488 info->repldst_port = cb->val.port_range[0];
489 info->repldst_port_high = cb->val.port_range[cb->nvals >= 2];
490 info->match_flags |= XT_CONNTRACK_REPLDST_PORT;
491 if (cb->invert)
492 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT;
493 break;
494 case O_CTDIR:
495 if (strcasecmp(cb->arg, "ORIGINAL") == 0) {
496 info->match_flags |= XT_CONNTRACK_DIRECTION;
497 info->invert_flags &= ~XT_CONNTRACK_DIRECTION;
498 } else if (strcasecmp(cb->arg, "REPLY") == 0) {
499 info->match_flags |= XT_CONNTRACK_DIRECTION;
500 info->invert_flags |= XT_CONNTRACK_DIRECTION;
501 } else {
502 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", cb->arg);
503 }
504 break;
505 }
506 }
507
508 #define cinfo_transform(r, l) \
509 do { \
510 memcpy((r), (l), offsetof(typeof(*(l)), state_mask)); \
511 (r)->state_mask = (l)->state_mask; \
512 (r)->status_mask = (l)->status_mask; \
513 } while (false);
514
conntrack1_mt_parse(struct xt_option_call * cb)515 static void conntrack1_mt_parse(struct xt_option_call *cb)
516 {
517 struct xt_conntrack_mtinfo1 *info = cb->data;
518 struct xt_conntrack_mtinfo3 up;
519
520 memset(&up, 0, sizeof(up));
521 cinfo_transform(&up, info);
522 up.origsrc_port_high = up.origsrc_port;
523 up.origdst_port_high = up.origdst_port;
524 up.replsrc_port_high = up.replsrc_port;
525 up.repldst_port_high = up.repldst_port;
526 cb->data = &up;
527 conntrack_mt_parse(cb, 3);
528 if (up.origsrc_port != up.origsrc_port_high ||
529 up.origdst_port != up.origdst_port_high ||
530 up.replsrc_port != up.replsrc_port_high ||
531 up.repldst_port != up.repldst_port_high)
532 xtables_error(PARAMETER_PROBLEM,
533 "conntrack rev 1 does not support port ranges");
534 cinfo_transform(info, &up);
535 cb->data = info;
536 }
537
conntrack2_mt_parse(struct xt_option_call * cb)538 static void conntrack2_mt_parse(struct xt_option_call *cb)
539 {
540 #define cinfo2_transform(r, l) \
541 memcpy((r), (l), offsetof(typeof(*(l)), sizeof(*info));
542
543 struct xt_conntrack_mtinfo2 *info = cb->data;
544 struct xt_conntrack_mtinfo3 up;
545
546 memset(&up, 0, sizeof(up));
547 memcpy(&up, info, sizeof(*info));
548 up.origsrc_port_high = up.origsrc_port;
549 up.origdst_port_high = up.origdst_port;
550 up.replsrc_port_high = up.replsrc_port;
551 up.repldst_port_high = up.repldst_port;
552 cb->data = &up;
553 conntrack_mt_parse(cb, 3);
554 if (up.origsrc_port != up.origsrc_port_high ||
555 up.origdst_port != up.origdst_port_high ||
556 up.replsrc_port != up.replsrc_port_high ||
557 up.repldst_port != up.repldst_port_high)
558 xtables_error(PARAMETER_PROBLEM,
559 "conntrack rev 2 does not support port ranges");
560 memcpy(info, &up, sizeof(*info));
561 cb->data = info;
562 #undef cinfo2_transform
563 }
564
conntrack3_mt_parse(struct xt_option_call * cb)565 static void conntrack3_mt_parse(struct xt_option_call *cb)
566 {
567 conntrack_mt_parse(cb, 3);
568 }
569
conntrack_mt_check(struct xt_fcheck_call * cb)570 static void conntrack_mt_check(struct xt_fcheck_call *cb)
571 {
572 if (cb->xflags == 0)
573 xtables_error(PARAMETER_PROBLEM, "conntrack: At least one option "
574 "is required");
575 }
576
577 static void
print_state(unsigned int statemask)578 print_state(unsigned int statemask)
579 {
580 const char *sep = " ";
581
582 if (statemask & XT_CONNTRACK_STATE_INVALID) {
583 printf("%sINVALID", sep);
584 sep = ",";
585 }
586 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
587 printf("%sNEW", sep);
588 sep = ",";
589 }
590 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
591 printf("%sRELATED", sep);
592 sep = ",";
593 }
594 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
595 printf("%sESTABLISHED", sep);
596 sep = ",";
597 }
598 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
599 printf("%sUNTRACKED", sep);
600 sep = ",";
601 }
602 if (statemask & XT_CONNTRACK_STATE_SNAT) {
603 printf("%sSNAT", sep);
604 sep = ",";
605 }
606 if (statemask & XT_CONNTRACK_STATE_DNAT) {
607 printf("%sDNAT", sep);
608 sep = ",";
609 }
610 }
611
612 static void
print_status(unsigned int statusmask)613 print_status(unsigned int statusmask)
614 {
615 const char *sep = " ";
616
617 if (statusmask & IPS_EXPECTED) {
618 printf("%sEXPECTED", sep);
619 sep = ",";
620 }
621 if (statusmask & IPS_SEEN_REPLY) {
622 printf("%sSEEN_REPLY", sep);
623 sep = ",";
624 }
625 if (statusmask & IPS_ASSURED) {
626 printf("%sASSURED", sep);
627 sep = ",";
628 }
629 if (statusmask & IPS_CONFIRMED) {
630 printf("%sCONFIRMED", sep);
631 sep = ",";
632 }
633 if (statusmask == 0)
634 printf("%sNONE", sep);
635 }
636
637 static void
conntrack_dump_addr(const union nf_inet_addr * addr,const union nf_inet_addr * mask,unsigned int family,bool numeric)638 conntrack_dump_addr(const union nf_inet_addr *addr,
639 const union nf_inet_addr *mask,
640 unsigned int family, bool numeric)
641 {
642 if (family == NFPROTO_IPV4) {
643 if (!numeric && addr->ip == 0) {
644 printf(" anywhere");
645 return;
646 }
647 if (numeric)
648 printf(" %s%s",
649 xtables_ipaddr_to_numeric(&addr->in),
650 xtables_ipmask_to_numeric(&mask->in));
651 else
652 printf(" %s%s",
653 xtables_ipaddr_to_anyname(&addr->in),
654 xtables_ipmask_to_numeric(&mask->in));
655 } else if (family == NFPROTO_IPV6) {
656 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 &&
657 addr->ip6[2] == 0 && addr->ip6[3] == 0) {
658 printf(" anywhere");
659 return;
660 }
661 if (numeric)
662 printf(" %s%s",
663 xtables_ip6addr_to_numeric(&addr->in6),
664 xtables_ip6mask_to_numeric(&mask->in6));
665 else
666 printf(" %s%s",
667 xtables_ip6addr_to_anyname(&addr->in6),
668 xtables_ip6mask_to_numeric(&mask->in6));
669 }
670 }
671
672 static void
print_addr(const struct in_addr * addr,const struct in_addr * mask,int inv,int numeric)673 print_addr(const struct in_addr *addr, const struct in_addr *mask,
674 int inv, int numeric)
675 {
676 char buf[BUFSIZ];
677
678 if (inv)
679 printf(" !");
680
681 if (mask->s_addr == 0L && !numeric)
682 printf(" %s", "anywhere");
683 else {
684 if (numeric)
685 strcpy(buf, xtables_ipaddr_to_numeric(addr));
686 else
687 strcpy(buf, xtables_ipaddr_to_anyname(addr));
688 strcat(buf, xtables_ipmask_to_numeric(mask));
689 printf(" %s", buf);
690 }
691 }
692
693 static void
matchinfo_print(const void * ip,const struct xt_entry_match * match,int numeric,const char * optpfx)694 matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx)
695 {
696 const struct xt_conntrack_info *sinfo = (const void *)match->data;
697
698 if(sinfo->flags & XT_CONNTRACK_STATE) {
699 if (sinfo->invflags & XT_CONNTRACK_STATE)
700 printf(" !");
701 printf(" %sctstate", optpfx);
702 print_state(sinfo->statemask);
703 }
704
705 if(sinfo->flags & XT_CONNTRACK_PROTO) {
706 if (sinfo->invflags & XT_CONNTRACK_PROTO)
707 printf(" !");
708 printf(" %sctproto", optpfx);
709 printf(" %u", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum);
710 }
711
712 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
713 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC)
714 printf(" !");
715 printf(" %sctorigsrc", optpfx);
716
717 print_addr(
718 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
719 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
720 false,
721 numeric);
722 }
723
724 if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
725 if (sinfo->invflags & XT_CONNTRACK_ORIGDST)
726 printf(" !");
727 printf(" %sctorigdst", optpfx);
728
729 print_addr(
730 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
731 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
732 false,
733 numeric);
734 }
735
736 if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
737 if (sinfo->invflags & XT_CONNTRACK_REPLSRC)
738 printf(" !");
739 printf(" %sctreplsrc", optpfx);
740
741 print_addr(
742 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
743 &sinfo->sipmsk[IP_CT_DIR_REPLY],
744 false,
745 numeric);
746 }
747
748 if(sinfo->flags & XT_CONNTRACK_REPLDST) {
749 if (sinfo->invflags & XT_CONNTRACK_REPLDST)
750 printf(" !");
751 printf(" %sctrepldst", optpfx);
752
753 print_addr(
754 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
755 &sinfo->dipmsk[IP_CT_DIR_REPLY],
756 false,
757 numeric);
758 }
759
760 if(sinfo->flags & XT_CONNTRACK_STATUS) {
761 if (sinfo->invflags & XT_CONNTRACK_STATUS)
762 printf(" !");
763 printf(" %sctstatus", optpfx);
764 print_status(sinfo->statusmask);
765 }
766
767 if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
768 if (sinfo->invflags & XT_CONNTRACK_EXPIRES)
769 printf(" !");
770 printf(" %sctexpire ", optpfx);
771
772 if (sinfo->expires_max == sinfo->expires_min)
773 printf("%lu", sinfo->expires_min);
774 else
775 printf("%lu:%lu", sinfo->expires_min, sinfo->expires_max);
776 }
777
778 if (sinfo->flags & XT_CONNTRACK_DIRECTION) {
779 if (sinfo->invflags & XT_CONNTRACK_DIRECTION)
780 printf(" %sctdir REPLY", optpfx);
781 else
782 printf(" %sctdir ORIGINAL", optpfx);
783 }
784
785 }
786
787 static void
conntrack_dump_ports(const char * prefix,const char * opt,u_int16_t port_low,u_int16_t port_high)788 conntrack_dump_ports(const char *prefix, const char *opt,
789 u_int16_t port_low, u_int16_t port_high)
790 {
791 if (port_high == 0 || port_low == port_high)
792 printf(" %s%s %u", prefix, opt, port_low);
793 else
794 printf(" %s%s %u:%u", prefix, opt, port_low, port_high);
795 }
796
797 static void
conntrack_dump(const struct xt_conntrack_mtinfo3 * info,const char * prefix,unsigned int family,bool numeric,bool v3)798 conntrack_dump(const struct xt_conntrack_mtinfo3 *info, const char *prefix,
799 unsigned int family, bool numeric, bool v3)
800 {
801 if (info->match_flags & XT_CONNTRACK_STATE) {
802 if (info->invert_flags & XT_CONNTRACK_STATE)
803 printf(" !");
804 printf(" %s%s", prefix,
805 info->match_flags & XT_CONNTRACK_STATE_ALIAS
806 ? "state" : "ctstate");
807 print_state(info->state_mask);
808 }
809
810 if (info->match_flags & XT_CONNTRACK_PROTO) {
811 if (info->invert_flags & XT_CONNTRACK_PROTO)
812 printf(" !");
813 printf(" %sctproto %u", prefix, info->l4proto);
814 }
815
816 if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
817 if (info->invert_flags & XT_CONNTRACK_ORIGSRC)
818 printf(" !");
819 printf(" %sctorigsrc", prefix);
820 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask,
821 family, numeric);
822 }
823
824 if (info->match_flags & XT_CONNTRACK_ORIGDST) {
825 if (info->invert_flags & XT_CONNTRACK_ORIGDST)
826 printf(" !");
827 printf(" %sctorigdst", prefix);
828 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask,
829 family, numeric);
830 }
831
832 if (info->match_flags & XT_CONNTRACK_REPLSRC) {
833 if (info->invert_flags & XT_CONNTRACK_REPLSRC)
834 printf(" !");
835 printf(" %sctreplsrc", prefix);
836 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask,
837 family, numeric);
838 }
839
840 if (info->match_flags & XT_CONNTRACK_REPLDST) {
841 if (info->invert_flags & XT_CONNTRACK_REPLDST)
842 printf(" !");
843 printf(" %sctrepldst", prefix);
844 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask,
845 family, numeric);
846 }
847
848 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
849 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)
850 printf(" !");
851 conntrack_dump_ports(prefix, "ctorigsrcport",
852 v3 ? info->origsrc_port : ntohs(info->origsrc_port),
853 v3 ? info->origsrc_port_high : 0);
854 }
855
856 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
857 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT)
858 printf(" !");
859 conntrack_dump_ports(prefix, "ctorigdstport",
860 v3 ? info->origdst_port : ntohs(info->origdst_port),
861 v3 ? info->origdst_port_high : 0);
862 }
863
864 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
865 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT)
866 printf(" !");
867 conntrack_dump_ports(prefix, "ctreplsrcport",
868 v3 ? info->replsrc_port : ntohs(info->replsrc_port),
869 v3 ? info->replsrc_port_high : 0);
870 }
871
872 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) {
873 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT)
874 printf(" !");
875 conntrack_dump_ports(prefix, "ctrepldstport",
876 v3 ? info->repldst_port : ntohs(info->repldst_port),
877 v3 ? info->repldst_port_high : 0);
878 }
879
880 if (info->match_flags & XT_CONNTRACK_STATUS) {
881 if (info->invert_flags & XT_CONNTRACK_STATUS)
882 printf(" !");
883 printf(" %sctstatus", prefix);
884 print_status(info->status_mask);
885 }
886
887 if (info->match_flags & XT_CONNTRACK_EXPIRES) {
888 if (info->invert_flags & XT_CONNTRACK_EXPIRES)
889 printf(" !");
890 printf(" %sctexpire ", prefix);
891
892 if (info->expires_max == info->expires_min)
893 printf("%u", (unsigned int)info->expires_min);
894 else
895 printf("%u:%u", (unsigned int)info->expires_min,
896 (unsigned int)info->expires_max);
897 }
898
899 if (info->match_flags & XT_CONNTRACK_DIRECTION) {
900 if (info->invert_flags & XT_CONNTRACK_DIRECTION)
901 printf(" %sctdir REPLY", prefix);
902 else
903 printf(" %sctdir ORIGINAL", prefix);
904 }
905 }
906
907 static const char *
conntrack_print_name_alias(const struct xt_entry_match * match)908 conntrack_print_name_alias(const struct xt_entry_match *match)
909 {
910 struct xt_conntrack_mtinfo1 *info = (void *)match->data;
911
912 return info->match_flags & XT_CONNTRACK_STATE_ALIAS
913 ? "state" : "conntrack";
914 }
915
conntrack_print(const void * ip,const struct xt_entry_match * match,int numeric)916 static void conntrack_print(const void *ip, const struct xt_entry_match *match,
917 int numeric)
918 {
919 matchinfo_print(ip, match, numeric, "");
920 }
921
922 static void
conntrack1_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)923 conntrack1_mt4_print(const void *ip, const struct xt_entry_match *match,
924 int numeric)
925 {
926 const struct xt_conntrack_mtinfo1 *info = (void *)match->data;
927 struct xt_conntrack_mtinfo3 up;
928
929 cinfo_transform(&up, info);
930 conntrack_dump(&up, "", NFPROTO_IPV4, numeric, false);
931 }
932
933 static void
conntrack1_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)934 conntrack1_mt6_print(const void *ip, const struct xt_entry_match *match,
935 int numeric)
936 {
937 const struct xt_conntrack_mtinfo1 *info = (void *)match->data;
938 struct xt_conntrack_mtinfo3 up;
939
940 cinfo_transform(&up, info);
941 conntrack_dump(&up, "", NFPROTO_IPV6, numeric, false);
942 }
943
944 static void
conntrack2_mt_print(const void * ip,const struct xt_entry_match * match,int numeric)945 conntrack2_mt_print(const void *ip, const struct xt_entry_match *match,
946 int numeric)
947 {
948 conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric, false);
949 }
950
951 static void
conntrack2_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)952 conntrack2_mt6_print(const void *ip, const struct xt_entry_match *match,
953 int numeric)
954 {
955 conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric, false);
956 }
957
958 static void
conntrack3_mt_print(const void * ip,const struct xt_entry_match * match,int numeric)959 conntrack3_mt_print(const void *ip, const struct xt_entry_match *match,
960 int numeric)
961 {
962 conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric, true);
963 }
964
965 static void
conntrack3_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)966 conntrack3_mt6_print(const void *ip, const struct xt_entry_match *match,
967 int numeric)
968 {
969 conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric, true);
970 }
971
conntrack_save(const void * ip,const struct xt_entry_match * match)972 static void conntrack_save(const void *ip, const struct xt_entry_match *match)
973 {
974 matchinfo_print(ip, match, 1, "--");
975 }
976
conntrack3_mt_save(const void * ip,const struct xt_entry_match * match)977 static void conntrack3_mt_save(const void *ip,
978 const struct xt_entry_match *match)
979 {
980 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true, true);
981 }
982
conntrack3_mt6_save(const void * ip,const struct xt_entry_match * match)983 static void conntrack3_mt6_save(const void *ip,
984 const struct xt_entry_match *match)
985 {
986 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true, true);
987 }
988
conntrack2_mt_save(const void * ip,const struct xt_entry_match * match)989 static void conntrack2_mt_save(const void *ip,
990 const struct xt_entry_match *match)
991 {
992 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true, false);
993 }
994
conntrack2_mt6_save(const void * ip,const struct xt_entry_match * match)995 static void conntrack2_mt6_save(const void *ip,
996 const struct xt_entry_match *match)
997 {
998 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true, false);
999 }
1000
1001 static void
conntrack1_mt4_save(const void * ip,const struct xt_entry_match * match)1002 conntrack1_mt4_save(const void *ip, const struct xt_entry_match *match)
1003 {
1004 const struct xt_conntrack_mtinfo1 *info = (void *)match->data;
1005 struct xt_conntrack_mtinfo3 up;
1006
1007 cinfo_transform(&up, info);
1008 conntrack_dump(&up, "--", NFPROTO_IPV4, true, false);
1009 }
1010
1011 static void
conntrack1_mt6_save(const void * ip,const struct xt_entry_match * match)1012 conntrack1_mt6_save(const void *ip, const struct xt_entry_match *match)
1013 {
1014 const struct xt_conntrack_mtinfo1 *info = (void *)match->data;
1015 struct xt_conntrack_mtinfo3 up;
1016
1017 cinfo_transform(&up, info);
1018 conntrack_dump(&up, "--", NFPROTO_IPV6, true, false);
1019 }
1020
1021 static void
state_help(void)1022 state_help(void)
1023 {
1024 printf(
1025 "state match options:\n"
1026 " [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n"
1027 " State(s) to match\n");
1028 }
1029
1030 static const struct xt_option_entry state_opts[] = {
1031 {.name = "state", .id = O_CTSTATE, .type = XTTYPE_STRING,
1032 .flags = XTOPT_MAND | XTOPT_INVERT},
1033 XTOPT_TABLEEND,
1034 };
1035
1036 static unsigned int
state_parse_state(const char * state,size_t len)1037 state_parse_state(const char *state, size_t len)
1038 {
1039 if (strncasecmp(state, "INVALID", len) == 0)
1040 return XT_CONNTRACK_STATE_INVALID;
1041 else if (strncasecmp(state, "NEW", len) == 0)
1042 return XT_CONNTRACK_STATE_BIT(IP_CT_NEW);
1043 else if (strncasecmp(state, "ESTABLISHED", len) == 0)
1044 return XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED);
1045 else if (strncasecmp(state, "RELATED", len) == 0)
1046 return XT_CONNTRACK_STATE_BIT(IP_CT_RELATED);
1047 else if (strncasecmp(state, "UNTRACKED", len) == 0)
1048 return XT_CONNTRACK_STATE_UNTRACKED;
1049 return 0;
1050 }
1051
1052 static unsigned int
state_parse_states(const char * arg)1053 state_parse_states(const char *arg)
1054 {
1055 const char *comma;
1056 unsigned int mask = 0, flag;
1057
1058 while ((comma = strchr(arg, ',')) != NULL) {
1059 if (comma == arg)
1060 goto badstate;
1061 flag = state_parse_state(arg, comma-arg);
1062 if (flag == 0)
1063 goto badstate;
1064 mask |= flag;
1065 arg = comma+1;
1066 }
1067 if (!*arg)
1068 xtables_error(PARAMETER_PROBLEM, "\"--state\" requires a list of "
1069 "states with no spaces, e.g. "
1070 "ESTABLISHED,RELATED");
1071 if (strlen(arg) == 0)
1072 goto badstate;
1073 flag = state_parse_state(arg, strlen(arg));
1074 if (flag == 0)
1075 goto badstate;
1076 mask |= flag;
1077 return mask;
1078 badstate:
1079 xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg);
1080 }
1081
state_parse(struct xt_option_call * cb)1082 static void state_parse(struct xt_option_call *cb)
1083 {
1084 struct xt_state_info *sinfo = cb->data;
1085
1086 xtables_option_parse(cb);
1087 sinfo->statemask = state_parse_states(cb->arg);
1088 if (cb->invert)
1089 sinfo->statemask = ~sinfo->statemask;
1090 }
1091
state_ct1_parse(struct xt_option_call * cb)1092 static void state_ct1_parse(struct xt_option_call *cb)
1093 {
1094 struct xt_conntrack_mtinfo1 *sinfo = cb->data;
1095
1096 xtables_option_parse(cb);
1097 sinfo->match_flags = XT_CONNTRACK_STATE | XT_CONNTRACK_STATE_ALIAS;
1098 sinfo->state_mask = state_parse_states(cb->arg);
1099 if (cb->invert)
1100 sinfo->invert_flags |= XT_CONNTRACK_STATE;
1101 }
1102
state_ct23_parse(struct xt_option_call * cb)1103 static void state_ct23_parse(struct xt_option_call *cb)
1104 {
1105 struct xt_conntrack_mtinfo3 *sinfo = cb->data;
1106
1107 xtables_option_parse(cb);
1108 sinfo->match_flags = XT_CONNTRACK_STATE | XT_CONNTRACK_STATE_ALIAS;
1109 sinfo->state_mask = state_parse_states(cb->arg);
1110 if (cb->invert)
1111 sinfo->invert_flags |= XT_CONNTRACK_STATE;
1112 }
1113
state_print_state(unsigned int statemask)1114 static void state_print_state(unsigned int statemask)
1115 {
1116 const char *sep = "";
1117
1118 if (statemask & XT_CONNTRACK_STATE_INVALID) {
1119 printf("%sINVALID", sep);
1120 sep = ",";
1121 }
1122 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
1123 printf("%sNEW", sep);
1124 sep = ",";
1125 }
1126 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
1127 printf("%sRELATED", sep);
1128 sep = ",";
1129 }
1130 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
1131 printf("%sESTABLISHED", sep);
1132 sep = ",";
1133 }
1134 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
1135 printf("%sUNTRACKED", sep);
1136 sep = ",";
1137 }
1138 }
1139
1140 static void
state_print(const void * ip,const struct xt_entry_match * match,int numeric)1141 state_print(const void *ip,
1142 const struct xt_entry_match *match,
1143 int numeric)
1144 {
1145 const struct xt_state_info *sinfo = (const void *)match->data;
1146
1147 printf(" state ");
1148 state_print_state(sinfo->statemask);
1149 }
1150
state_save(const void * ip,const struct xt_entry_match * match)1151 static void state_save(const void *ip, const struct xt_entry_match *match)
1152 {
1153 const struct xt_state_info *sinfo = (const void *)match->data;
1154
1155 printf(" --state ");
1156 state_print_state(sinfo->statemask);
1157 }
1158
state_xlate_print(struct xt_xlate * xl,unsigned int statemask)1159 static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask)
1160 {
1161 const char *sep = "";
1162
1163 if (statemask & XT_CONNTRACK_STATE_INVALID) {
1164 xt_xlate_add(xl, "%s%s", sep, "invalid");
1165 sep = ",";
1166 }
1167 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
1168 xt_xlate_add(xl, "%s%s", sep, "new");
1169 sep = ",";
1170 }
1171 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
1172 xt_xlate_add(xl, "%s%s", sep, "related");
1173 sep = ",";
1174 }
1175 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
1176 xt_xlate_add(xl, "%s%s", sep, "established");
1177 sep = ",";
1178 }
1179 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
1180 xt_xlate_add(xl, "%s%s", sep, "untracked");
1181 sep = ",";
1182 }
1183 }
1184
state_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1185 static int state_xlate(struct xt_xlate *xl,
1186 const struct xt_xlate_mt_params *params)
1187 {
1188 const struct xt_conntrack_mtinfo3 *sinfo =
1189 (const void *)params->match->data;
1190
1191 xt_xlate_add(xl, "ct state %s", sinfo->invert_flags & XT_CONNTRACK_STATE ?
1192 "!= " : "");
1193 state_xlate_print(xl, sinfo->state_mask);
1194 xt_xlate_add(xl, " ");
1195 return 1;
1196 }
1197
status_xlate_print(struct xt_xlate * xl,unsigned int statusmask)1198 static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask)
1199 {
1200 const char *sep = "";
1201
1202 if (statusmask & IPS_EXPECTED) {
1203 xt_xlate_add(xl, "%s%s", sep, "expected");
1204 sep = ",";
1205 }
1206 if (statusmask & IPS_SEEN_REPLY) {
1207 xt_xlate_add(xl, "%s%s", sep, "seen-reply");
1208 sep = ",";
1209 }
1210 if (statusmask & IPS_ASSURED) {
1211 xt_xlate_add(xl, "%s%s", sep, "assured");
1212 sep = ",";
1213 }
1214 if (statusmask & IPS_CONFIRMED) {
1215 xt_xlate_add(xl, "%s%s", sep, "confirmed");
1216 sep = ",";
1217 }
1218 }
1219
addr_xlate_print(struct xt_xlate * xl,const union nf_inet_addr * addr,const union nf_inet_addr * mask,unsigned int family)1220 static void addr_xlate_print(struct xt_xlate *xl,
1221 const union nf_inet_addr *addr,
1222 const union nf_inet_addr *mask,
1223 unsigned int family)
1224 {
1225 if (family == NFPROTO_IPV4) {
1226 xt_xlate_add(xl, "%s%s", xtables_ipaddr_to_numeric(&addr->in),
1227 xtables_ipmask_to_numeric(&mask->in));
1228 } else if (family == NFPROTO_IPV6) {
1229 xt_xlate_add(xl, "%s%s", xtables_ip6addr_to_numeric(&addr->in6),
1230 xtables_ip6mask_to_numeric(&mask->in6));
1231 }
1232 }
1233
_conntrack3_mt_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params,int family)1234 static int _conntrack3_mt_xlate(struct xt_xlate *xl,
1235 const struct xt_xlate_mt_params *params,
1236 int family)
1237 {
1238 const struct xt_conntrack_mtinfo3 *sinfo =
1239 (const void *)params->match->data;
1240 char *space = "";
1241
1242 if (sinfo->match_flags & XT_CONNTRACK_DIRECTION) {
1243 xt_xlate_add(xl, "ct direction %s",
1244 sinfo->invert_flags & XT_CONNTRACK_DIRECTION ?
1245 "reply" : "original");
1246 space = " ";
1247 }
1248
1249 if (sinfo->match_flags & XT_CONNTRACK_PROTO) {
1250 xt_xlate_add(xl, "%sct %s protocol %s%u", space,
1251 sinfo->invert_flags & XT_CONNTRACK_DIRECTION ?
1252 "reply" : "original",
1253 sinfo->invert_flags & XT_CONNTRACK_PROTO ?
1254 "!= " : "",
1255 sinfo->l4proto);
1256 space = " ";
1257 }
1258
1259 if (sinfo->match_flags & XT_CONNTRACK_STATE) {
1260 xt_xlate_add(xl, "%sct state %s", space,
1261 sinfo->invert_flags & XT_CONNTRACK_STATE ?
1262 "!= " : "");
1263 state_xlate_print(xl, sinfo->state_mask);
1264 space = " ";
1265 }
1266
1267 if (sinfo->match_flags & XT_CONNTRACK_STATUS) {
1268 if (sinfo->status_mask == 1)
1269 return 0;
1270 xt_xlate_add(xl, "%sct status %s", space,
1271 sinfo->invert_flags & XT_CONNTRACK_STATUS ?
1272 "!= " : "");
1273 status_xlate_print(xl, sinfo->status_mask);
1274 space = " ";
1275 }
1276
1277 if (sinfo->match_flags & XT_CONNTRACK_EXPIRES) {
1278 xt_xlate_add(xl, "%sct expiration %s", space,
1279 sinfo->invert_flags & XT_CONNTRACK_EXPIRES ?
1280 "!= " : "");
1281 if (sinfo->expires_max == sinfo->expires_min)
1282 xt_xlate_add(xl, "%lu", sinfo->expires_min);
1283 else
1284 xt_xlate_add(xl, "%lu-%lu", sinfo->expires_min,
1285 sinfo->expires_max);
1286 space = " ";
1287 }
1288
1289 if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC) {
1290 if (&sinfo->origsrc_addr == 0L)
1291 return 0;
1292
1293 xt_xlate_add(xl, "%sct original saddr %s", space,
1294 sinfo->invert_flags & XT_CONNTRACK_ORIGSRC ?
1295 "!= " : "");
1296 addr_xlate_print(xl, &sinfo->origsrc_addr,
1297 &sinfo->origsrc_mask, family);
1298 space = " ";
1299 }
1300
1301 if (sinfo->match_flags & XT_CONNTRACK_ORIGDST) {
1302 if (&sinfo->origdst_addr == 0L)
1303 return 0;
1304
1305 xt_xlate_add(xl, "%sct original daddr %s", space,
1306 sinfo->invert_flags & XT_CONNTRACK_ORIGDST ?
1307 "!= " : "");
1308 addr_xlate_print(xl, &sinfo->origdst_addr,
1309 &sinfo->origdst_mask, family);
1310 space = " ";
1311 }
1312
1313 if (sinfo->match_flags & XT_CONNTRACK_REPLSRC) {
1314 if (&sinfo->replsrc_addr == 0L)
1315 return 0;
1316
1317 xt_xlate_add(xl, "%sct reply saddr %s", space,
1318 sinfo->invert_flags & XT_CONNTRACK_REPLSRC ?
1319 "!= " : "");
1320 addr_xlate_print(xl, &sinfo->replsrc_addr,
1321 &sinfo->replsrc_mask, family);
1322 space = " ";
1323 }
1324
1325 if (sinfo->match_flags & XT_CONNTRACK_REPLDST) {
1326 if (&sinfo->repldst_addr == 0L)
1327 return 0;
1328
1329 xt_xlate_add(xl, "%sct reply daddr %s", space,
1330 sinfo->invert_flags & XT_CONNTRACK_REPLDST ?
1331 "!= " : "");
1332 addr_xlate_print(xl, &sinfo->repldst_addr,
1333 &sinfo->repldst_mask, family);
1334 space = " ";
1335 }
1336
1337 if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
1338 xt_xlate_add(xl, "%sct original proto-src %s", space,
1339 sinfo->invert_flags & XT_CONNTRACK_ORIGSRC_PORT ?
1340 "!= " : "");
1341 if (sinfo->origsrc_port == sinfo->origsrc_port_high)
1342 xt_xlate_add(xl, "%u", sinfo->origsrc_port);
1343 else
1344 xt_xlate_add(xl, "%u-%u", sinfo->origsrc_port,
1345 sinfo->origsrc_port_high);
1346 space = " ";
1347 }
1348
1349 if (sinfo->match_flags & XT_CONNTRACK_ORIGDST_PORT) {
1350 xt_xlate_add(xl, "%sct original proto-dst %s", space,
1351 sinfo->invert_flags & XT_CONNTRACK_ORIGDST_PORT ?
1352 "!= " : "");
1353 if (sinfo->origdst_port == sinfo->origdst_port_high)
1354 xt_xlate_add(xl, "%u", sinfo->origdst_port);
1355 else
1356 xt_xlate_add(xl, "%u-%u", sinfo->origdst_port,
1357 sinfo->origdst_port_high);
1358 space = " ";
1359 }
1360
1361 if (sinfo->match_flags & XT_CONNTRACK_REPLSRC_PORT) {
1362 xt_xlate_add(xl, "%sct reply proto-src %s", space,
1363 sinfo->invert_flags & XT_CONNTRACK_REPLSRC_PORT ?
1364 "!= " : "");
1365 if (sinfo->replsrc_port == sinfo->replsrc_port_high)
1366 xt_xlate_add(xl, "%u", sinfo->replsrc_port);
1367 else
1368 xt_xlate_add(xl, "%u-%u", sinfo->replsrc_port,
1369 sinfo->replsrc_port_high);
1370 space = " ";
1371 }
1372
1373 if (sinfo->match_flags & XT_CONNTRACK_REPLDST_PORT) {
1374 xt_xlate_add(xl, "%sct reply proto-dst %s", space,
1375 sinfo->invert_flags & XT_CONNTRACK_REPLDST_PORT ?
1376 "!= " : "", sinfo->repldst_port);
1377 if (sinfo->repldst_port == sinfo->repldst_port_high)
1378 xt_xlate_add(xl, "%u", sinfo->repldst_port);
1379 else
1380 xt_xlate_add(xl, "%u-%u", sinfo->repldst_port,
1381 sinfo->repldst_port_high);
1382 }
1383
1384 return 1;
1385 }
1386
conntrack3_mt4_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1387 static int conntrack3_mt4_xlate(struct xt_xlate *xl,
1388 const struct xt_xlate_mt_params *params)
1389 {
1390 return _conntrack3_mt_xlate(xl, params, NFPROTO_IPV4);
1391 }
1392
conntrack3_mt6_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1393 static int conntrack3_mt6_xlate(struct xt_xlate *xl,
1394 const struct xt_xlate_mt_params *params)
1395 {
1396 return _conntrack3_mt_xlate(xl, params, NFPROTO_IPV6);
1397 }
1398
1399 static struct xtables_match conntrack_mt_reg[] = {
1400 {
1401 .version = XTABLES_VERSION,
1402 .name = "conntrack",
1403 .revision = 0,
1404 .family = NFPROTO_IPV4,
1405 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)),
1406 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)),
1407 .help = conntrack_mt_help,
1408 .x6_parse = conntrack_parse,
1409 .x6_fcheck = conntrack_mt_check,
1410 .print = conntrack_print,
1411 .save = conntrack_save,
1412 .alias = conntrack_print_name_alias,
1413 .x6_options = conntrack_mt_opts_v0,
1414 },
1415 {
1416 .version = XTABLES_VERSION,
1417 .name = "conntrack",
1418 .revision = 1,
1419 .family = NFPROTO_IPV4,
1420 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1421 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1422 .help = conntrack_mt_help,
1423 .x6_parse = conntrack1_mt_parse,
1424 .x6_fcheck = conntrack_mt_check,
1425 .print = conntrack1_mt4_print,
1426 .save = conntrack1_mt4_save,
1427 .alias = conntrack_print_name_alias,
1428 .x6_options = conntrack2_mt_opts,
1429 },
1430 {
1431 .version = XTABLES_VERSION,
1432 .name = "conntrack",
1433 .revision = 1,
1434 .family = NFPROTO_IPV6,
1435 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1436 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1437 .help = conntrack_mt_help,
1438 .x6_parse = conntrack1_mt_parse,
1439 .x6_fcheck = conntrack_mt_check,
1440 .print = conntrack1_mt6_print,
1441 .save = conntrack1_mt6_save,
1442 .alias = conntrack_print_name_alias,
1443 .x6_options = conntrack2_mt_opts,
1444 },
1445 {
1446 .version = XTABLES_VERSION,
1447 .name = "conntrack",
1448 .revision = 2,
1449 .family = NFPROTO_IPV4,
1450 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
1451 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
1452 .help = conntrack_mt_help,
1453 .x6_parse = conntrack2_mt_parse,
1454 .x6_fcheck = conntrack_mt_check,
1455 .print = conntrack2_mt_print,
1456 .save = conntrack2_mt_save,
1457 .alias = conntrack_print_name_alias,
1458 .x6_options = conntrack2_mt_opts,
1459 },
1460 {
1461 .version = XTABLES_VERSION,
1462 .name = "conntrack",
1463 .revision = 2,
1464 .family = NFPROTO_IPV6,
1465 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
1466 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
1467 .help = conntrack_mt_help,
1468 .x6_parse = conntrack2_mt_parse,
1469 .x6_fcheck = conntrack_mt_check,
1470 .print = conntrack2_mt6_print,
1471 .save = conntrack2_mt6_save,
1472 .alias = conntrack_print_name_alias,
1473 .x6_options = conntrack2_mt_opts,
1474 },
1475 {
1476 .version = XTABLES_VERSION,
1477 .name = "conntrack",
1478 .revision = 3,
1479 .family = NFPROTO_IPV4,
1480 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)),
1481 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)),
1482 .help = conntrack_mt_help,
1483 .x6_parse = conntrack3_mt_parse,
1484 .x6_fcheck = conntrack_mt_check,
1485 .print = conntrack3_mt_print,
1486 .save = conntrack3_mt_save,
1487 .alias = conntrack_print_name_alias,
1488 .x6_options = conntrack3_mt_opts,
1489 .xlate = conntrack3_mt4_xlate,
1490 },
1491 {
1492 .version = XTABLES_VERSION,
1493 .name = "conntrack",
1494 .revision = 3,
1495 .family = NFPROTO_IPV6,
1496 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)),
1497 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)),
1498 .help = conntrack_mt_help,
1499 .x6_parse = conntrack3_mt_parse,
1500 .x6_fcheck = conntrack_mt_check,
1501 .print = conntrack3_mt6_print,
1502 .save = conntrack3_mt6_save,
1503 .alias = conntrack_print_name_alias,
1504 .x6_options = conntrack3_mt_opts,
1505 .xlate = conntrack3_mt6_xlate,
1506 },
1507 {
1508 .family = NFPROTO_UNSPEC,
1509 .name = "state",
1510 .real_name = "conntrack",
1511 .revision = 1,
1512 .ext_flags = XTABLES_EXT_ALIAS,
1513 .version = XTABLES_VERSION,
1514 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1515 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)),
1516 .help = state_help,
1517 .print = state_print,
1518 .save = state_save,
1519 .x6_parse = state_ct1_parse,
1520 .x6_options = state_opts,
1521 },
1522 {
1523 .family = NFPROTO_UNSPEC,
1524 .name = "state",
1525 .real_name = "conntrack",
1526 .revision = 2,
1527 .ext_flags = XTABLES_EXT_ALIAS,
1528 .version = XTABLES_VERSION,
1529 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
1530 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)),
1531 .help = state_help,
1532 .print = state_print,
1533 .save = state_save,
1534 .x6_parse = state_ct23_parse,
1535 .x6_options = state_opts,
1536 },
1537 {
1538 .family = NFPROTO_UNSPEC,
1539 .name = "state",
1540 .real_name = "conntrack",
1541 .revision = 3,
1542 .ext_flags = XTABLES_EXT_ALIAS,
1543 .version = XTABLES_VERSION,
1544 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)),
1545 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)),
1546 .help = state_help,
1547 .print = state_print,
1548 .save = state_save,
1549 .x6_parse = state_ct23_parse,
1550 .x6_options = state_opts,
1551 .xlate = state_xlate,
1552 },
1553 {
1554 .family = NFPROTO_UNSPEC,
1555 .name = "state",
1556 .revision = 0,
1557 .version = XTABLES_VERSION,
1558 .size = XT_ALIGN(sizeof(struct xt_state_info)),
1559 .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)),
1560 .help = state_help,
1561 .print = state_print,
1562 .save = state_save,
1563 .x6_parse = state_parse,
1564 .x6_options = state_opts,
1565 },
1566 };
1567
_init(void)1568 void _init(void)
1569 {
1570 xtables_register_matches(conntrack_mt_reg, ARRAY_SIZE(conntrack_mt_reg));
1571 }
1572