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