blob: 0f2644392a6cc55e3113227e994bf3167fb453f8 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* 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 struct xt_state_info *sinfo = (struct xt_state_info *)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 struct xt_state_info *sinfo = (struct xt_state_info *)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}