blob: 8c8521e951dece5cc84658aabddc550d294bd8c8 [file] [log] [blame]
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +00001/* 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
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +00008#include <xtables.h>
9#include <linux/netfilter.h>
10#include <linux/netfilter/xt_iprange.h>
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000011#include <linux/netfilter_ipv4/ipt_iprange.h>
12
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +000013enum {
14 F_SRCIP = 1 << 0,
15 F_DSTIP = 1 << 1,
16};
17
Jan Engelhardt41daaa02008-01-20 13:42:43 +000018static void iprange_mt_help(void)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000019{
20 printf(
Jan Engelhardt41daaa02008-01-20 13:42:43 +000021"iprange match options:\n"
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000022"[!] --src-range ip-ip Match source IP in the specified range\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020023"[!] --dst-range ip-ip Match destination IP in the specified range\n");
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000024}
25
Jan Engelhardt41daaa02008-01-20 13:42:43 +000026static const struct option iprange_mt_opts[] = {
27 {.name = "src-range", .has_arg = true, .val = '1'},
28 {.name = "dst-range", .has_arg = true, .val = '2'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000029 { .name = NULL }
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000030};
31
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000032static void
33parse_iprange(char *arg, struct ipt_iprange *range)
34{
35 char *dash;
Jan Engelhardtbd943842008-01-20 13:38:08 +000036 const struct in_addr *ip;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000037
38 dash = strchr(arg, '-');
Jan Engelhardt41daaa02008-01-20 13:42:43 +000039 if (dash != NULL)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000040 *dash = '\0';
Jan Engelhardt41daaa02008-01-20 13:42:43 +000041
Jan Engelhardtbd943842008-01-20 13:38:08 +000042 ip = numeric_to_ipaddr(arg);
James Kingdbe6c3b2008-04-01 21:17:36 +020043 if (!ip)
Jan Engelhardt41daaa02008-01-20 13:42:43 +000044 exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n",
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000045 arg);
46 range->min_ip = ip->s_addr;
47
Jan Engelhardt41daaa02008-01-20 13:42:43 +000048 if (dash != NULL) {
Jan Engelhardtbd943842008-01-20 13:38:08 +000049 ip = numeric_to_ipaddr(dash+1);
James Kingdbe6c3b2008-04-01 21:17:36 +020050 if (!ip)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000051 exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n",
52 dash+1);
53 range->max_ip = ip->s_addr;
Jan Engelhardt41daaa02008-01-20 13:42:43 +000054 } else {
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000055 range->max_ip = range->min_ip;
Jan Engelhardt41daaa02008-01-20 13:42:43 +000056 }
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000057}
58
Jan Engelhardt59d16402007-10-04 16:28:39 +000059static int iprange_parse(int c, char **argv, int invert, unsigned int *flags,
60 const void *entry, struct xt_entry_match **match)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000061{
62 struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data;
63
64 switch (c) {
65 case '1':
66 if (*flags & IPRANGE_SRC)
67 exit_error(PARAMETER_PROBLEM,
68 "iprange match: Only use --src-range ONCE!");
69 *flags |= IPRANGE_SRC;
70
71 info->flags |= IPRANGE_SRC;
72 check_inverse(optarg, &invert, &optind, 0);
Jan Engelhardt41daaa02008-01-20 13:42:43 +000073 if (invert)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000074 info->flags |= IPRANGE_SRC_INV;
Jan Engelhardt41daaa02008-01-20 13:42:43 +000075 parse_iprange(optarg, &info->src);
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000076
77 break;
78
79 case '2':
80 if (*flags & IPRANGE_DST)
81 exit_error(PARAMETER_PROBLEM,
82 "iprange match: Only use --dst-range ONCE!");
83 *flags |= IPRANGE_DST;
84
85 info->flags |= IPRANGE_DST;
86 check_inverse(optarg, &invert, &optind, 0);
87 if (invert)
88 info->flags |= IPRANGE_DST_INV;
89
Jan Engelhardt41daaa02008-01-20 13:42:43 +000090 parse_iprange(optarg, &info->dst);
Nicolas Boulianeb9c6ec12004-07-12 07:16:54 +000091
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +000092 break;
93
94 default:
95 return 0;
96 }
97 return 1;
98}
99
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000100static int
101iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
102 const void *entry, struct xt_entry_match **match)
103{
104 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
105 const struct in_addr *ia;
106 char *end;
107
108 switch (c) {
109 case '1': /* --src-ip */
110 end = strchr(optarg, '-');
111 if (end == NULL)
112 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
113 *end = '\0';
114 ia = numeric_to_ipaddr(optarg);
115 if (ia == NULL)
116 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
117 memcpy(&info->src_min.in, ia, sizeof(*ia));
118 ia = numeric_to_ipaddr(end+1);
119 if (ia == NULL)
120 param_act(P_BAD_VALUE, "iprange", "--src-ip", end + 1);
121 memcpy(&info->src_max.in, ia, sizeof(*ia));
Jan Engelhardt6a0cd582008-06-13 17:59:29 +0200122 info->flags |= IPRANGE_SRC;
123 if (invert)
124 info->flags |= IPRANGE_SRC_INV;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000125 *flags |= F_SRCIP;
126 return true;
127
128 case '2': /* --dst-ip */
129 end = strchr(optarg, '-');
130 if (end == NULL)
131 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
132 *end = '\0';
133 ia = numeric_to_ipaddr(optarg);
134 if (ia == NULL)
135 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
136 memcpy(&info->dst_min.in, ia, sizeof(*ia));
137 ia = numeric_to_ipaddr(end + 1);
138 if (ia == NULL)
139 param_act(P_BAD_VALUE, "iprange", "--dst-ip", end + 1);
140 memcpy(&info->dst_max.in, ia, sizeof(*ia));
Jan Engelhardt6a0cd582008-06-13 17:59:29 +0200141 info->flags |= IPRANGE_DST;
142 if (invert)
143 info->flags |= IPRANGE_DST_INV;
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000144 *flags |= F_DSTIP;
145 return true;
146 }
147 return false;
148}
149
150static int
151iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
152 const void *entry, struct xt_entry_match **match)
153{
154 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
155 const struct in6_addr *ia;
156 char *end;
157
158 switch (c) {
159 case '1': /* --src-ip */
160 end = strchr(optarg, '-');
161 if (end == NULL)
162 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
163 *end = '\0';
164 ia = numeric_to_ip6addr(optarg);
165 if (ia == NULL)
166 param_act(P_BAD_VALUE, "iprange", "--src-ip", optarg);
167 memcpy(&info->src_min.in, ia, sizeof(*ia));
168 ia = numeric_to_ip6addr(end+1);
169 if (ia == NULL)
170 param_act(P_BAD_VALUE, "iprange", "--src-ip", end + 1);
171 memcpy(&info->src_max.in, ia, sizeof(*ia));
172 info->flags |= IPRANGE_SRC;
173 if (invert)
174 info->flags |= IPRANGE_SRC_INV;
175 *flags |= F_SRCIP;
176 return true;
177
178 case '2': /* --dst-ip */
179 end = strchr(optarg, '-');
180 if (end == NULL)
181 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
182 *end = '\0';
183 ia = numeric_to_ip6addr(optarg);
184 if (ia == NULL)
185 param_act(P_BAD_VALUE, "iprange", "--dst-ip", optarg);
186 memcpy(&info->dst_min.in, ia, sizeof(*ia));
187 ia = numeric_to_ip6addr(end + 1);
188 if (ia == NULL)
189 param_act(P_BAD_VALUE, "iprange", "--dst-ip", end + 1);
190 memcpy(&info->dst_max.in, ia, sizeof(*ia));
191 info->flags |= IPRANGE_DST;
192 if (invert)
193 info->flags |= IPRANGE_DST_INV;
194 *flags |= F_DSTIP;
195 return true;
196 }
197 return false;
198}
199
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000200static void iprange_mt_check(unsigned int flags)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000201{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000202 if (flags == 0)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000203 exit_error(PARAMETER_PROBLEM,
204 "iprange match: You must specify `--src-range' or `--dst-range'");
205}
206
207static void
208print_iprange(const struct ipt_iprange *range)
209{
210 const unsigned char *byte_min, *byte_max;
211
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000212 byte_min = (const unsigned char *)&range->min_ip;
213 byte_max = (const unsigned char *)&range->max_ip;
214 printf("%u.%u.%u.%u-%u.%u.%u.%u ",
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000215 byte_min[0], byte_min[1], byte_min[2], byte_min[3],
216 byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
217}
218
Jan Engelhardt59d16402007-10-04 16:28:39 +0000219static void iprange_print(const void *ip, const struct xt_entry_match *match,
220 int numeric)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000221{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000222 const struct ipt_iprange_info *info = (const void *)match->data;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000223
224 if (info->flags & IPRANGE_SRC) {
225 printf("source IP range ");
226 if (info->flags & IPRANGE_SRC_INV)
227 printf("! ");
228 print_iprange(&info->src);
229 }
230 if (info->flags & IPRANGE_DST) {
231 printf("destination IP range ");
232 if (info->flags & IPRANGE_DST_INV)
233 printf("! ");
234 print_iprange(&info->dst);
235 }
236}
237
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000238static void
239iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
240 int numeric)
241{
242 const struct xt_iprange_mtinfo *info = (const void *)match->data;
243
244 if (info->flags & IPRANGE_SRC) {
245 printf("source IP range ");
246 if (info->flags & IPRANGE_SRC_INV)
247 printf("! ");
248 /*
249 * ipaddr_to_numeric() uses a static buffer, so cannot
250 * combine the printf() calls.
251 */
252 printf("%s", ipaddr_to_numeric(&info->src_min.in));
253 printf("-%s ", ipaddr_to_numeric(&info->src_max.in));
254 }
255 if (info->flags & IPRANGE_DST) {
256 printf("destination IP range ");
257 if (info->flags & IPRANGE_DST_INV)
258 printf("! ");
259 printf("%s", ipaddr_to_numeric(&info->dst_min.in));
260 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in));
261 }
262}
263
264static void
265iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
266 int numeric)
267{
268 const struct xt_iprange_mtinfo *info = (const void *)match->data;
269
270 if (info->flags & IPRANGE_SRC) {
271 printf("source IP range ");
272 if (info->flags & IPRANGE_SRC_INV)
273 printf("! ");
274 /*
275 * ipaddr_to_numeric() uses a static buffer, so cannot
276 * combine the printf() calls.
277 */
278 printf("%s", ip6addr_to_numeric(&info->src_min.in6));
279 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6));
280 }
281 if (info->flags & IPRANGE_DST) {
282 printf("destination IP range ");
283 if (info->flags & IPRANGE_DST_INV)
284 printf("! ");
285 printf("%s", ip6addr_to_numeric(&info->dst_min.in6));
286 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6));
287 }
288}
289
Jan Engelhardt59d16402007-10-04 16:28:39 +0000290static void iprange_save(const void *ip, const struct xt_entry_match *match)
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000291{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000292 const struct ipt_iprange_info *info = (const void *)match->data;
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000293
294 if (info->flags & IPRANGE_SRC) {
295 if (info->flags & IPRANGE_SRC_INV)
296 printf("! ");
297 printf("--src-range ");
298 print_iprange(&info->src);
299 if (info->flags & IPRANGE_DST)
300 fputc(' ', stdout);
301 }
302 if (info->flags & IPRANGE_DST) {
303 if (info->flags & IPRANGE_DST_INV)
304 printf("! ");
305 printf("--dst-range ");
306 print_iprange(&info->dst);
307 }
308}
309
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000310static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
311{
312 const struct xt_iprange_mtinfo *info = (const void *)match->data;
313
314 if (info->flags & IPRANGE_SRC) {
315 if (info->flags & IPRANGE_SRC_INV)
316 printf("! ");
317 printf("--src-range %s", ipaddr_to_numeric(&info->src_min.in));
318 printf("-%s ", ipaddr_to_numeric(&info->src_max.in));
319 }
320 if (info->flags & IPRANGE_DST) {
321 if (info->flags & IPRANGE_DST_INV)
322 printf("! ");
323 printf("--dst-range %s", ipaddr_to_numeric(&info->dst_min.in));
324 printf("-%s ", ipaddr_to_numeric(&info->dst_max.in));
325 }
326}
327
328static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
329{
330 const struct xt_iprange_mtinfo *info = (const void *)match->data;
331
332 if (info->flags & IPRANGE_SRC) {
333 if (info->flags & IPRANGE_SRC_INV)
334 printf("! ");
335 printf("--src-range %s", ip6addr_to_numeric(&info->src_min.in6));
336 printf("-%s ", ip6addr_to_numeric(&info->src_max.in6));
337 }
338 if (info->flags & IPRANGE_DST) {
339 if (info->flags & IPRANGE_DST_INV)
340 printf("! ");
341 printf("--dst-range %s", ip6addr_to_numeric(&info->dst_min.in6));
342 printf("-%s ", ip6addr_to_numeric(&info->dst_max.in6));
343 }
344}
345
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000346static struct xtables_match iprange_match = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200347 .version = XTABLES_VERSION,
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000348 .name = "iprange",
349 .revision = 0,
350 .family = AF_INET,
351 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)),
352 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
353 .help = iprange_mt_help,
354 .parse = iprange_parse,
355 .final_check = iprange_mt_check,
356 .print = iprange_print,
357 .save = iprange_save,
358 .extra_opts = iprange_mt_opts,
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000359};
360
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000361static struct xtables_match iprange_mt_reg = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200362 .version = XTABLES_VERSION,
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000363 .name = "iprange",
364 .revision = 1,
365 .family = AF_INET,
366 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
367 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
368 .help = iprange_mt_help,
369 .parse = iprange_mt4_parse,
370 .final_check = iprange_mt_check,
371 .print = iprange_mt4_print,
372 .save = iprange_mt4_save,
373 .extra_opts = iprange_mt_opts,
374};
375
376static struct xtables_match iprange_mt6_reg = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200377 .version = XTABLES_VERSION,
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000378 .name = "iprange",
379 .revision = 1,
380 .family = AF_INET6,
381 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
382 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
383 .help = iprange_mt_help,
384 .parse = iprange_mt6_parse,
385 .final_check = iprange_mt_check,
386 .print = iprange_mt6_print,
387 .save = iprange_mt6_save,
388 .extra_opts = iprange_mt_opts,
389};
390
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000391void _init(void)
392{
Jan Engelhardt41daaa02008-01-20 13:42:43 +0000393 xtables_register_match(&iprange_match);
Jan Engelhardtfc11b0b2008-01-20 13:43:49 +0000394 xtables_register_match(&iprange_mt_reg);
395 xtables_register_match(&iprange_mt6_reg);
Joszef Kadlecsik9cb66152003-04-23 13:27:09 +0000396}