blob: bc5b2aeb2bd660e89929c3132d6a724a88464736 [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/* Shared library add-on to iptables to add IP range matching support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7
8#include <netinet/in.h>
9#include <xtables.h>
10#include <linux/netfilter.h>
11#include <linux/netfilter/xt_iprange.h>
12#include <linux/netfilter_ipv4/ipt_iprange.h>
13
14enum {
15 F_SRCIP = 1 << 0,
16 F_DSTIP = 1 << 1,
17};
18
19static void iprange_mt_help(void)
20{
21 printf(
22"iprange match options:\n"
23"[!] --src-range ip-ip Match source IP in the specified range\n"
24"[!] --dst-range ip-ip Match destination IP in the specified range\n");
25}
26
27static const struct option iprange_mt_opts[] = {
28 {.name = "src-range", .has_arg = true, .val = '1'},
29 {.name = "dst-range", .has_arg = true, .val = '2'},
30 { .name = NULL }
31};
32
33static void
34parse_iprange(char *arg, struct ipt_iprange *range)
35{
36 char *dash;
37 const struct in_addr *ip;
38
39 dash = strchr(arg, '-');
40 if (dash != NULL)
41 *dash = '\0';
42
43 ip = xtables_numeric_to_ipaddr(arg);
44 if (!ip)
45 xtables_error(PARAMETER_PROBLEM, "iprange match: Bad IP address \"%s\"\n",
46 arg);
47 range->min_ip = ip->s_addr;
48
49 if (dash != NULL) {
50 ip = xtables_numeric_to_ipaddr(dash+1);
51 if (!ip)
52 xtables_error(PARAMETER_PROBLEM, "iprange match: Bad IP address \"%s\"\n",
53 dash+1);
54 range->max_ip = ip->s_addr;
55 } else {
56 range->max_ip = range->min_ip;
57 }
58}
59
60static int iprange_parse(int c, char **argv, int invert, unsigned int *flags,
61 const void *entry, struct xt_entry_match **match)
62{
63 struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data;
64
65 switch (c) {
66 case '1':
67 if (*flags & IPRANGE_SRC)
68 xtables_error(PARAMETER_PROBLEM,
69 "iprange match: Only use --src-range ONCE!");
70 *flags |= IPRANGE_SRC;
71
72 info->flags |= IPRANGE_SRC;
73 xtables_check_inverse(optarg, &invert, &optind, 0);
74 if (invert)
75 info->flags |= IPRANGE_SRC_INV;
76 parse_iprange(optarg, &info->src);
77
78 break;
79
80 case '2':
81 if (*flags & IPRANGE_DST)
82 xtables_error(PARAMETER_PROBLEM,
83 "iprange match: Only use --dst-range ONCE!");
84 *flags |= IPRANGE_DST;
85
86 info->flags |= IPRANGE_DST;
87 xtables_check_inverse(optarg, &invert, &optind, 0);
88 if (invert)
89 info->flags |= IPRANGE_DST_INV;
90
91 parse_iprange(optarg, &info->dst);
92
93 break;
94
95 default:
96 return 0;
97 }
98 return 1;
99}
100
101static int
102iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
103 const void *entry, struct xt_entry_match **match)
104{
105 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
106 const struct in_addr *ia;
107 char *end;
108
109 switch (c) {
110 case '1': /* --src-range */
111 end = strchr(optarg, '-');
112 if (end == NULL)
113 xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", optarg);
114 *end = '\0';
115 ia = xtables_numeric_to_ipaddr(optarg);
116 if (ia == NULL)
117 xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", optarg);
118 memcpy(&info->src_min.in, ia, sizeof(*ia));
119 ia = xtables_numeric_to_ipaddr(end+1);
120 if (ia == NULL)
121 xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", end + 1);
122 memcpy(&info->src_max.in, ia, sizeof(*ia));
123 info->flags |= IPRANGE_SRC;
124 if (invert)
125 info->flags |= IPRANGE_SRC_INV;
126 *flags |= F_SRCIP;
127 return true;
128
129 case '2': /* --dst-range */
130 end = strchr(optarg, '-');
131 if (end == NULL)
132 xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", optarg);
133 *end = '\0';
134 ia = xtables_numeric_to_ipaddr(optarg);
135 if (ia == NULL)
136 xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", optarg);
137 memcpy(&info->dst_min.in, ia, sizeof(*ia));
138 ia = xtables_numeric_to_ipaddr(end + 1);
139 if (ia == NULL)
140 xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", end + 1);
141 memcpy(&info->dst_max.in, ia, sizeof(*ia));
142 info->flags |= IPRANGE_DST;
143 if (invert)
144 info->flags |= IPRANGE_DST_INV;
145 *flags |= F_DSTIP;
146 return true;
147 }
148 return false;
149}
150
151static int
152iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
153 const void *entry, struct xt_entry_match **match)
154{
155 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
156 const struct in6_addr *ia;
157 char *end;
158
159 switch (c) {
160 case '1': /* --src-range */
161 end = strchr(optarg, '-');
162 if (end == NULL)
163 xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", optarg);
164 *end = '\0';
165 ia = xtables_numeric_to_ip6addr(optarg);
166 if (ia == NULL)
167 xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", optarg);
168 memcpy(&info->src_min.in, ia, sizeof(*ia));
169 ia = xtables_numeric_to_ip6addr(end+1);
170 if (ia == NULL)
171 xtables_param_act(XTF_BAD_VALUE, "iprange", "--src-range", end + 1);
172 memcpy(&info->src_max.in, ia, sizeof(*ia));
173 info->flags |= IPRANGE_SRC;
174 if (invert)
175 info->flags |= IPRANGE_SRC_INV;
176 *flags |= F_SRCIP;
177 return true;
178
179 case '2': /* --dst-range */
180 end = strchr(optarg, '-');
181 if (end == NULL)
182 xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", optarg);
183 *end = '\0';
184 ia = xtables_numeric_to_ip6addr(optarg);
185 if (ia == NULL)
186 xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", optarg);
187 memcpy(&info->dst_min.in, ia, sizeof(*ia));
188 ia = xtables_numeric_to_ip6addr(end + 1);
189 if (ia == NULL)
190 xtables_param_act(XTF_BAD_VALUE, "iprange", "--dst-range", end + 1);
191 memcpy(&info->dst_max.in, ia, sizeof(*ia));
192 info->flags |= IPRANGE_DST;
193 if (invert)
194 info->flags |= IPRANGE_DST_INV;
195 *flags |= F_DSTIP;
196 return true;
197 }
198 return false;
199}
200
201static void iprange_mt_check(unsigned int flags)
202{
203 if (flags == 0)
204 xtables_error(PARAMETER_PROBLEM,
205 "iprange match: You must specify `--src-range' or `--dst-range'");
206}
207
208static void
209print_iprange(const struct ipt_iprange *range)
210{
211 const unsigned char *byte_min, *byte_max;
212
213 byte_min = (const unsigned char *)&range->min_ip;
214 byte_max = (const unsigned char *)&range->max_ip;
215 printf("%u.%u.%u.%u-%u.%u.%u.%u ",
216 byte_min[0], byte_min[1], byte_min[2], byte_min[3],
217 byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
218}
219
220static void iprange_print(const void *ip, const struct xt_entry_match *match,
221 int numeric)
222{
223 const struct ipt_iprange_info *info = (const void *)match->data;
224
225 if (info->flags & IPRANGE_SRC) {
226 printf("source IP range ");
227 if (info->flags & IPRANGE_SRC_INV)
228 printf("! ");
229 print_iprange(&info->src);
230 }
231 if (info->flags & IPRANGE_DST) {
232 printf("destination IP range ");
233 if (info->flags & IPRANGE_DST_INV)
234 printf("! ");
235 print_iprange(&info->dst);
236 }
237}
238
239static void
240iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
241 int numeric)
242{
243 const struct xt_iprange_mtinfo *info = (const void *)match->data;
244
245 if (info->flags & IPRANGE_SRC) {
246 printf("source IP range ");
247 if (info->flags & IPRANGE_SRC_INV)
248 printf("! ");
249 /*
250 * ipaddr_to_numeric() uses a static buffer, so cannot
251 * combine the printf() calls.
252 */
253 printf("%s", xtables_ipaddr_to_numeric(&info->src_min.in));
254 printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in));
255 }
256 if (info->flags & IPRANGE_DST) {
257 printf("destination IP range ");
258 if (info->flags & IPRANGE_DST_INV)
259 printf("! ");
260 printf("%s", xtables_ipaddr_to_numeric(&info->dst_min.in));
261 printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in));
262 }
263}
264
265static void
266iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
267 int numeric)
268{
269 const struct xt_iprange_mtinfo *info = (const void *)match->data;
270
271 if (info->flags & IPRANGE_SRC) {
272 printf("source IP range ");
273 if (info->flags & IPRANGE_SRC_INV)
274 printf("! ");
275 /*
276 * ipaddr_to_numeric() uses a static buffer, so cannot
277 * combine the printf() calls.
278 */
279 printf("%s", xtables_ip6addr_to_numeric(&info->src_min.in6));
280 printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6));
281 }
282 if (info->flags & IPRANGE_DST) {
283 printf("destination IP range ");
284 if (info->flags & IPRANGE_DST_INV)
285 printf("! ");
286 printf("%s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
287 printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6));
288 }
289}
290
291static void iprange_save(const void *ip, const struct xt_entry_match *match)
292{
293 const struct ipt_iprange_info *info = (const void *)match->data;
294
295 if (info->flags & IPRANGE_SRC) {
296 if (info->flags & IPRANGE_SRC_INV)
297 printf("! ");
298 printf("--src-range ");
299 print_iprange(&info->src);
300 if (info->flags & IPRANGE_DST)
301 fputc(' ', stdout);
302 }
303 if (info->flags & IPRANGE_DST) {
304 if (info->flags & IPRANGE_DST_INV)
305 printf("! ");
306 printf("--dst-range ");
307 print_iprange(&info->dst);
308 }
309}
310
311static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
312{
313 const struct xt_iprange_mtinfo *info = (const void *)match->data;
314
315 if (info->flags & IPRANGE_SRC) {
316 if (info->flags & IPRANGE_SRC_INV)
317 printf("! ");
318 printf("--src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in));
319 printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in));
320 }
321 if (info->flags & IPRANGE_DST) {
322 if (info->flags & IPRANGE_DST_INV)
323 printf("! ");
324 printf("--dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
325 printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in));
326 }
327}
328
329static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
330{
331 const struct xt_iprange_mtinfo *info = (const void *)match->data;
332
333 if (info->flags & IPRANGE_SRC) {
334 if (info->flags & IPRANGE_SRC_INV)
335 printf("! ");
336 printf("--src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
337 printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6));
338 }
339 if (info->flags & IPRANGE_DST) {
340 if (info->flags & IPRANGE_DST_INV)
341 printf("! ");
342 printf("--dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
343 printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6));
344 }
345}
346
347static struct xtables_match iprange_match = {
348 .version = XTABLES_VERSION,
349 .name = "iprange",
350 .revision = 0,
351 .family = NFPROTO_IPV4,
352 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)),
353 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
354 .help = iprange_mt_help,
355 .parse = iprange_parse,
356 .final_check = iprange_mt_check,
357 .print = iprange_print,
358 .save = iprange_save,
359 .extra_opts = iprange_mt_opts,
360};
361
362static struct xtables_match iprange_mt_reg = {
363 .version = XTABLES_VERSION,
364 .name = "iprange",
365 .revision = 1,
366 .family = NFPROTO_IPV4,
367 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
368 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
369 .help = iprange_mt_help,
370 .parse = iprange_mt4_parse,
371 .final_check = iprange_mt_check,
372 .print = iprange_mt4_print,
373 .save = iprange_mt4_save,
374 .extra_opts = iprange_mt_opts,
375};
376
377static struct xtables_match iprange_mt6_reg = {
378 .version = XTABLES_VERSION,
379 .name = "iprange",
380 .revision = 1,
381 .family = NFPROTO_IPV6,
382 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
383 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
384 .help = iprange_mt_help,
385 .parse = iprange_mt6_parse,
386 .final_check = iprange_mt_check,
387 .print = iprange_mt6_print,
388 .save = iprange_mt6_save,
389 .extra_opts = iprange_mt_opts,
390};
391
392void _init(void)
393{
394 xtables_register_match(&iprange_match);
395 xtables_register_match(&iprange_mt_reg);
396 xtables_register_match(&iprange_mt6_reg);
397}