1 /* Shared library add-on to iptables to add IP range matching support. */
8 #include <netinet/in.h>
10 #include <linux/netfilter.h>
11 #include <linux/netfilter/xt_iprange.h>
14 /* Inclusive: network order. */
15 __be32 min_ip, max_ip;
18 struct ipt_iprange_info {
19 struct ipt_iprange src;
20 struct ipt_iprange dst;
22 /* Flags from above */
31 static void iprange_mt_help(void)
34 "iprange match options:\n"
35 "[!] --src-range ip[-ip] Match source IP in the specified range\n"
36 "[!] --dst-range ip[-ip] Match destination IP in the specified range\n");
39 static const struct option iprange_mt_opts[] = {
40 {.name = "src-range", .has_arg = true, .val = '1'},
41 {.name = "dst-range", .has_arg = true, .val = '2'},
46 iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range,
47 uint8_t family, const char *optname)
49 const char *spec[2] = {from, to};
54 memset(range, 0, sizeof(union nf_inet_addr) * 2);
56 if (family == NFPROTO_IPV6) {
57 for (i = 0; i < ARRAY_SIZE(spec); ++i) {
58 ia6 = xtables_numeric_to_ip6addr(spec[i]);
60 xtables_param_act(XTF_BAD_VALUE, "iprange",
65 for (i = 0; i < ARRAY_SIZE(spec); ++i) {
66 ia4 = xtables_numeric_to_ipaddr(spec[i]);
68 xtables_param_act(XTF_BAD_VALUE, "iprange",
75 static void iprange_parse_range(char *arg, union nf_inet_addr *range,
76 u_int8_t family, const char *optname)
80 dash = strchr(arg, '-');
82 iprange_parse_spec(arg, arg, range, family, optname);
87 iprange_parse_spec(arg, dash + 1, range, family, optname);
88 if (memcmp(&range[0], &range[1], sizeof(*range)) > 0)
89 fprintf(stderr, "xt_iprange: range %s-%s is reversed and "
90 "will never match\n", arg, dash + 1);
93 static int iprange_parse(int c, char **argv, int invert, unsigned int *flags,
94 const void *entry, struct xt_entry_match **match)
96 struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data;
97 union nf_inet_addr range[2];
101 if (*flags & IPRANGE_SRC)
102 xtables_error(PARAMETER_PROBLEM,
103 "iprange match: Only use --src-range ONCE!");
104 *flags |= IPRANGE_SRC;
106 info->flags |= IPRANGE_SRC;
107 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
109 info->flags |= IPRANGE_SRC_INV;
110 iprange_parse_range(optarg, range, NFPROTO_IPV4, "--src-range");
111 info->src.min_ip = range[0].ip;
112 info->src.max_ip = range[1].ip;
116 if (*flags & IPRANGE_DST)
117 xtables_error(PARAMETER_PROBLEM,
118 "iprange match: Only use --dst-range ONCE!");
119 *flags |= IPRANGE_DST;
121 info->flags |= IPRANGE_DST;
122 xtables_check_inverse(optarg, &invert, &optind, 0, argv);
124 info->flags |= IPRANGE_DST_INV;
126 iprange_parse_range(optarg, range, NFPROTO_IPV4, "--dst-range");
127 info->dst.min_ip = range[0].ip;
128 info->dst.max_ip = range[1].ip;
138 iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
139 const void *entry, struct xt_entry_match **match)
141 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
144 case '1': /* --src-range */
145 iprange_parse_range(optarg, &info->src_min, NFPROTO_IPV4,
147 info->flags |= IPRANGE_SRC;
149 info->flags |= IPRANGE_SRC_INV;
153 case '2': /* --dst-range */
154 iprange_parse_range(optarg, &info->dst_min, NFPROTO_IPV4,
156 info->flags |= IPRANGE_DST;
158 info->flags |= IPRANGE_DST_INV;
166 iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
167 const void *entry, struct xt_entry_match **match)
169 struct xt_iprange_mtinfo *info = (void *)(*match)->data;
172 case '1': /* --src-range */
173 iprange_parse_range(optarg, &info->src_min, NFPROTO_IPV6,
175 info->flags |= IPRANGE_SRC;
177 info->flags |= IPRANGE_SRC_INV;
181 case '2': /* --dst-range */
182 iprange_parse_range(optarg, &info->dst_min, NFPROTO_IPV6,
184 info->flags |= IPRANGE_DST;
186 info->flags |= IPRANGE_DST_INV;
193 static void iprange_mt_check(unsigned int flags)
196 xtables_error(PARAMETER_PROBLEM,
197 "iprange match: You must specify `--src-range' or `--dst-range'");
201 print_iprange(const struct ipt_iprange *range)
203 const unsigned char *byte_min, *byte_max;
205 byte_min = (const unsigned char *)&range->min_ip;
206 byte_max = (const unsigned char *)&range->max_ip;
207 printf("%u.%u.%u.%u-%u.%u.%u.%u ",
208 byte_min[0], byte_min[1], byte_min[2], byte_min[3],
209 byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
212 static void iprange_print(const void *ip, const struct xt_entry_match *match,
215 const struct ipt_iprange_info *info = (const void *)match->data;
217 if (info->flags & IPRANGE_SRC) {
218 printf("source IP range ");
219 if (info->flags & IPRANGE_SRC_INV)
221 print_iprange(&info->src);
223 if (info->flags & IPRANGE_DST) {
224 printf("destination IP range ");
225 if (info->flags & IPRANGE_DST_INV)
227 print_iprange(&info->dst);
232 iprange_mt4_print(const void *ip, const struct xt_entry_match *match,
235 const struct xt_iprange_mtinfo *info = (const void *)match->data;
237 if (info->flags & IPRANGE_SRC) {
238 printf("source IP range ");
239 if (info->flags & IPRANGE_SRC_INV)
242 * ipaddr_to_numeric() uses a static buffer, so cannot
243 * combine the printf() calls.
245 printf("%s", xtables_ipaddr_to_numeric(&info->src_min.in));
246 printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in));
248 if (info->flags & IPRANGE_DST) {
249 printf("destination IP range ");
250 if (info->flags & IPRANGE_DST_INV)
252 printf("%s", xtables_ipaddr_to_numeric(&info->dst_min.in));
253 printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in));
258 iprange_mt6_print(const void *ip, const struct xt_entry_match *match,
261 const struct xt_iprange_mtinfo *info = (const void *)match->data;
263 if (info->flags & IPRANGE_SRC) {
264 printf("source IP range ");
265 if (info->flags & IPRANGE_SRC_INV)
268 * ipaddr_to_numeric() uses a static buffer, so cannot
269 * combine the printf() calls.
271 printf("%s", xtables_ip6addr_to_numeric(&info->src_min.in6));
272 printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6));
274 if (info->flags & IPRANGE_DST) {
275 printf("destination IP range ");
276 if (info->flags & IPRANGE_DST_INV)
278 printf("%s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
279 printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6));
283 static void iprange_save(const void *ip, const struct xt_entry_match *match)
285 const struct ipt_iprange_info *info = (const void *)match->data;
287 if (info->flags & IPRANGE_SRC) {
288 if (info->flags & IPRANGE_SRC_INV)
290 printf("--src-range ");
291 print_iprange(&info->src);
292 if (info->flags & IPRANGE_DST)
295 if (info->flags & IPRANGE_DST) {
296 if (info->flags & IPRANGE_DST_INV)
298 printf("--dst-range ");
299 print_iprange(&info->dst);
303 static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match)
305 const struct xt_iprange_mtinfo *info = (const void *)match->data;
307 if (info->flags & IPRANGE_SRC) {
308 if (info->flags & IPRANGE_SRC_INV)
310 printf("--src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in));
311 printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in));
313 if (info->flags & IPRANGE_DST) {
314 if (info->flags & IPRANGE_DST_INV)
316 printf("--dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in));
317 printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in));
321 static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match)
323 const struct xt_iprange_mtinfo *info = (const void *)match->data;
325 if (info->flags & IPRANGE_SRC) {
326 if (info->flags & IPRANGE_SRC_INV)
328 printf("--src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6));
329 printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6));
331 if (info->flags & IPRANGE_DST) {
332 if (info->flags & IPRANGE_DST_INV)
334 printf("--dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6));
335 printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6));
339 static struct xtables_match iprange_mt_reg[] = {
341 .version = XTABLES_VERSION,
344 .family = NFPROTO_IPV4,
345 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)),
346 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)),
347 .help = iprange_mt_help,
348 .parse = iprange_parse,
349 .final_check = iprange_mt_check,
350 .print = iprange_print,
351 .save = iprange_save,
352 .extra_opts = iprange_mt_opts,
355 .version = XTABLES_VERSION,
358 .family = NFPROTO_IPV4,
359 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
360 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
361 .help = iprange_mt_help,
362 .parse = iprange_mt4_parse,
363 .final_check = iprange_mt_check,
364 .print = iprange_mt4_print,
365 .save = iprange_mt4_save,
366 .extra_opts = iprange_mt_opts,
369 .version = XTABLES_VERSION,
372 .family = NFPROTO_IPV6,
373 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
374 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)),
375 .help = iprange_mt_help,
376 .parse = iprange_mt6_parse,
377 .final_check = iprange_mt_check,
378 .print = iprange_mt6_print,
379 .save = iprange_mt6_save,
380 .extra_opts = iprange_mt_opts,
386 xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));