libxt_state.c revision 9ee386a1b6d7704b259460152c959ab0e79e02aa
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
15/* Function which prints out usage message. */
16static void
17state_help(void)
18{
19	printf(
20"state v%s options:\n"
21" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n"
22"				State(s) to match\n"
23"\n", IPTABLES_VERSION);
24}
25
26static const struct option state_opts[] = {
27	{ "state", 1, NULL, '1' },
28	{ .name = NULL }
29};
30
31static int
32state_parse_state(const char *state, size_t strlen, struct xt_state_info *sinfo)
33{
34	if (strncasecmp(state, "INVALID", strlen) == 0)
35		sinfo->statemask |= XT_STATE_INVALID;
36	else if (strncasecmp(state, "NEW", strlen) == 0)
37		sinfo->statemask |= XT_STATE_BIT(IP_CT_NEW);
38	else if (strncasecmp(state, "ESTABLISHED", strlen) == 0)
39		sinfo->statemask |= XT_STATE_BIT(IP_CT_ESTABLISHED);
40	else if (strncasecmp(state, "RELATED", strlen) == 0)
41		sinfo->statemask |= XT_STATE_BIT(IP_CT_RELATED);
42	else if (strncasecmp(state, "UNTRACKED", strlen) == 0)
43		sinfo->statemask |= XT_STATE_UNTRACKED;
44	else
45		return 0;
46	return 1;
47}
48
49static void
50state_parse_states(const char *arg, struct xt_state_info *sinfo)
51{
52	const char *comma;
53
54	while ((comma = strchr(arg, ',')) != NULL) {
55		if (comma == arg || !state_parse_state(arg, comma-arg, sinfo))
56			exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
57		arg = comma+1;
58	}
59
60	if (strlen(arg) == 0 || !state_parse_state(arg, strlen(arg), sinfo))
61		exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
62}
63
64/* Function which parses command options; returns true if it
65   ate an option */
66static int
67state_parse(int c, char **argv, int invert, unsigned int *flags,
68      const void *entry,
69      struct xt_entry_match **match)
70{
71	struct xt_state_info *sinfo = (struct xt_state_info *)(*match)->data;
72
73	switch (c) {
74	case '1':
75		check_inverse(optarg, &invert, &optind, 0);
76
77		state_parse_states(argv[optind-1], sinfo);
78		if (invert)
79			sinfo->statemask = ~sinfo->statemask;
80		*flags = 1;
81		break;
82
83	default:
84		return 0;
85	}
86
87	return 1;
88}
89
90/* Final check; must have specified --state. */
91static void state_final_check(unsigned int flags)
92{
93	if (!flags)
94		exit_error(PARAMETER_PROBLEM, "You must specify `--state'");
95}
96
97static void state_print_state(unsigned int statemask)
98{
99	const char *sep = "";
100
101	if (statemask & XT_STATE_INVALID) {
102		printf("%sINVALID", sep);
103		sep = ",";
104	}
105	if (statemask & XT_STATE_BIT(IP_CT_NEW)) {
106		printf("%sNEW", sep);
107		sep = ",";
108	}
109	if (statemask & XT_STATE_BIT(IP_CT_RELATED)) {
110		printf("%sRELATED", sep);
111		sep = ",";
112	}
113	if (statemask & XT_STATE_BIT(IP_CT_ESTABLISHED)) {
114		printf("%sESTABLISHED", sep);
115		sep = ",";
116	}
117	if (statemask & XT_STATE_UNTRACKED) {
118		printf("%sUNTRACKED", sep);
119		sep = ",";
120	}
121	printf(" ");
122}
123
124/* Prints out the matchinfo. */
125static void
126state_print(const void *ip,
127      const struct xt_entry_match *match,
128      int numeric)
129{
130	struct xt_state_info *sinfo = (struct xt_state_info *)match->data;
131
132	printf("state ");
133	state_print_state(sinfo->statemask);
134}
135
136/* Saves the matchinfo in parsable form to stdout. */
137static void state_save(const void *ip, const struct xt_entry_match *match)
138{
139	struct xt_state_info *sinfo = (struct xt_state_info *)match->data;
140
141	printf("--state ");
142	state_print_state(sinfo->statemask);
143}
144
145static struct xtables_match state_match = {
146	.family		= AF_INET,
147	.name		= "state",
148	.version	= IPTABLES_VERSION,
149	.size		= XT_ALIGN(sizeof(struct xt_state_info)),
150	.userspacesize	= XT_ALIGN(sizeof(struct xt_state_info)),
151	.help		= state_help,
152	.parse		= state_parse,
153	.final_check	= state_final_check,
154	.print		= state_print,
155	.save		= state_save,
156	.extra_opts	= state_opts,
157};
158
159static struct xtables_match state_match6 = {
160	.family		= AF_INET6,
161	.name		= "state",
162	.version	= IPTABLES_VERSION,
163	.size		= XT_ALIGN(sizeof(struct xt_state_info)),
164	.userspacesize	= XT_ALIGN(sizeof(struct xt_state_info)),
165	.help		= state_help,
166	.parse		= state_parse,
167	.final_check	= state_final_check,
168	.print		= state_print,
169	.save		= state_save,
170	.extra_opts	= state_opts,
171};
172
173void _init(void)
174{
175	xtables_register_match(&state_match);
176	xtables_register_match(&state_match6);
177}
178