libxt_state.c revision 69f564e3890976461de0016cd81171ff8bfa8353
1/* Shared library add-on to iptables to add state tracking support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <xtables.h>
8#include <linux/netfilter/nf_conntrack_common.h>
9#include <linux/netfilter/xt_state.h>
10
11#ifndef XT_STATE_UNTRACKED
12#define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
13#endif
14
15static void
16state_help(void)
17{
18	printf(
19"state match options:\n"
20" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n"
21"				State(s) to match\n");
22}
23
24static const struct option state_opts[] = {
25	{ "state", 1, NULL, '1' },
26	{ .name = NULL }
27};
28
29static int
30state_parse_state(const char *state, size_t len, struct xt_state_info *sinfo)
31{
32	if (strncasecmp(state, "INVALID", len) == 0)
33		sinfo->statemask |= XT_STATE_INVALID;
34	else if (strncasecmp(state, "NEW", len) == 0)
35		sinfo->statemask |= XT_STATE_BIT(IP_CT_NEW);
36	else if (strncasecmp(state, "ESTABLISHED", len) == 0)
37		sinfo->statemask |= XT_STATE_BIT(IP_CT_ESTABLISHED);
38	else if (strncasecmp(state, "RELATED", len) == 0)
39		sinfo->statemask |= XT_STATE_BIT(IP_CT_RELATED);
40	else if (strncasecmp(state, "UNTRACKED", len) == 0)
41		sinfo->statemask |= XT_STATE_UNTRACKED;
42	else
43		return 0;
44	return 1;
45}
46
47static void
48state_parse_states(const char *arg, struct xt_state_info *sinfo)
49{
50	const char *comma;
51
52	while ((comma = strchr(arg, ',')) != NULL) {
53		if (comma == arg || !state_parse_state(arg, comma-arg, sinfo))
54			xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg);
55		arg = comma+1;
56	}
57	if (!*arg)
58		xtables_error(PARAMETER_PROBLEM, "\"--state\" requires a list of "
59					      "states with no spaces, e.g. "
60					      "ESTABLISHED,RELATED");
61	if (strlen(arg) == 0 || !state_parse_state(arg, strlen(arg), sinfo))
62		xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg);
63}
64
65static int
66state_parse(int c, char **argv, int invert, unsigned int *flags,
67      const void *entry,
68      struct xt_entry_match **match)
69{
70	struct xt_state_info *sinfo = (struct xt_state_info *)(*match)->data;
71
72	switch (c) {
73	case '1':
74		xtables_check_inverse(optarg, &invert, &optind, 0);
75
76		state_parse_states(argv[optind-1], sinfo);
77		if (invert)
78			sinfo->statemask = ~sinfo->statemask;
79		*flags = 1;
80		break;
81
82	default:
83		return 0;
84	}
85
86	return 1;
87}
88
89static void state_final_check(unsigned int flags)
90{
91	if (!flags)
92		xtables_error(PARAMETER_PROBLEM, "You must specify \"--state\"");
93}
94
95static void state_print_state(unsigned int statemask)
96{
97	const char *sep = "";
98
99	if (statemask & XT_STATE_INVALID) {
100		printf("%sINVALID", sep);
101		sep = ",";
102	}
103	if (statemask & XT_STATE_BIT(IP_CT_NEW)) {
104		printf("%sNEW", sep);
105		sep = ",";
106	}
107	if (statemask & XT_STATE_BIT(IP_CT_RELATED)) {
108		printf("%sRELATED", sep);
109		sep = ",";
110	}
111	if (statemask & XT_STATE_BIT(IP_CT_ESTABLISHED)) {
112		printf("%sESTABLISHED", sep);
113		sep = ",";
114	}
115	if (statemask & XT_STATE_UNTRACKED) {
116		printf("%sUNTRACKED", sep);
117		sep = ",";
118	}
119	printf(" ");
120}
121
122static void
123state_print(const void *ip,
124      const struct xt_entry_match *match,
125      int numeric)
126{
127	const struct xt_state_info *sinfo = (const void *)match->data;
128
129	printf("state ");
130	state_print_state(sinfo->statemask);
131}
132
133static void state_save(const void *ip, const struct xt_entry_match *match)
134{
135	const struct xt_state_info *sinfo = (const void *)match->data;
136
137	printf("--state ");
138	state_print_state(sinfo->statemask);
139}
140
141static struct xtables_match state_match = {
142	.family		= NFPROTO_IPV4,
143	.name		= "state",
144	.version	= XTABLES_VERSION,
145	.size		= XT_ALIGN(sizeof(struct xt_state_info)),
146	.userspacesize	= XT_ALIGN(sizeof(struct xt_state_info)),
147	.help		= state_help,
148	.parse		= state_parse,
149	.final_check	= state_final_check,
150	.print		= state_print,
151	.save		= state_save,
152	.extra_opts	= state_opts,
153};
154
155static struct xtables_match state_match6 = {
156	.family		= NFPROTO_IPV6,
157	.name		= "state",
158	.version	= XTABLES_VERSION,
159	.size		= XT_ALIGN(sizeof(struct xt_state_info)),
160	.userspacesize	= XT_ALIGN(sizeof(struct xt_state_info)),
161	.help		= state_help,
162	.parse		= state_parse,
163	.final_check	= state_final_check,
164	.print		= state_print,
165	.save		= state_save,
166	.extra_opts	= state_opts,
167};
168
169void _init(void)
170{
171	xtables_register_match(&state_match);
172	xtables_register_match(&state_match6);
173}
174