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