1 #include <stdio.h>
2 #include <string.h>
3 #include <xtables.h>
4 #include <linux/netfilter/nf_conntrack_common.h>
5 #include <linux/netfilter/xt_state.h>
6
7 #ifndef XT_STATE_UNTRACKED
8 #define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
9 #endif
10
11 enum {
12 O_STATE = 0,
13 };
14
15 static void
state_help(void)16 state_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
24 static const struct xt_option_entry state_opts[] = {
25 {.name = "state", .id = O_STATE, .type = XTTYPE_STRING,
26 .flags = XTOPT_MAND},
27 XTOPT_TABLEEND,
28 };
29
30 static int
state_parse_state(const char * state,size_t len,struct xt_state_info * sinfo)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
state_parse_states(const char * arg,struct xt_state_info * sinfo)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 xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg);
56 arg = comma+1;
57 }
58 if (!*arg)
59 xtables_error(PARAMETER_PROBLEM, "\"--state\" requires a list of "
60 "states with no spaces, e.g. "
61 "ESTABLISHED,RELATED");
62 if (strlen(arg) == 0 || !state_parse_state(arg, strlen(arg), sinfo))
63 xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg);
64 }
65
state_parse(struct xt_option_call * cb)66 static void state_parse(struct xt_option_call *cb)
67 {
68 struct xt_state_info *sinfo = cb->data;
69
70 xtables_option_parse(cb);
71 state_parse_states(cb->arg, sinfo);
72 if (cb->invert)
73 sinfo->statemask = ~sinfo->statemask;
74 }
75
state_print_state(unsigned int statemask)76 static void state_print_state(unsigned int statemask)
77 {
78 const char *sep = "";
79
80 if (statemask & XT_STATE_INVALID) {
81 printf("%sINVALID", sep);
82 sep = ",";
83 }
84 if (statemask & XT_STATE_BIT(IP_CT_NEW)) {
85 printf("%sNEW", sep);
86 sep = ",";
87 }
88 if (statemask & XT_STATE_BIT(IP_CT_RELATED)) {
89 printf("%sRELATED", sep);
90 sep = ",";
91 }
92 if (statemask & XT_STATE_BIT(IP_CT_ESTABLISHED)) {
93 printf("%sESTABLISHED", sep);
94 sep = ",";
95 }
96 if (statemask & XT_STATE_UNTRACKED) {
97 printf("%sUNTRACKED", sep);
98 sep = ",";
99 }
100 }
101
102 static void
state_print(const void * ip,const struct xt_entry_match * match,int numeric)103 state_print(const void *ip,
104 const struct xt_entry_match *match,
105 int numeric)
106 {
107 const struct xt_state_info *sinfo = (const void *)match->data;
108
109 printf(" state ");
110 state_print_state(sinfo->statemask);
111 }
112
state_save(const void * ip,const struct xt_entry_match * match)113 static void state_save(const void *ip, const struct xt_entry_match *match)
114 {
115 const struct xt_state_info *sinfo = (const void *)match->data;
116
117 printf(" --state ");
118 state_print_state(sinfo->statemask);
119 }
120
121 static struct xtables_match state_match = {
122 .family = NFPROTO_UNSPEC,
123 .name = "state",
124 .version = XTABLES_VERSION,
125 .size = XT_ALIGN(sizeof(struct xt_state_info)),
126 .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)),
127 .help = state_help,
128 .print = state_print,
129 .save = state_save,
130 .x6_parse = state_parse,
131 .x6_options = state_opts,
132 };
133
_init(void)134 void _init(void)
135 {
136 xtables_register_match(&state_match);
137 }
138