1 #include <stdint.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <xtables.h> 6 #include <linux/netfilter.h> 7 #include <linux/netfilter/xt_iprange.h> 8 9 struct ipt_iprange { 10 /* Inclusive: network order. */ 11 __be32 min_ip, max_ip; 12 }; 13 14 struct ipt_iprange_info { 15 struct ipt_iprange src; 16 struct ipt_iprange dst; 17 18 /* Flags from above */ 19 uint8_t flags; 20 }; 21 22 enum { 23 O_SRC_RANGE = 0, 24 O_DST_RANGE, 25 }; 26 27 static void iprange_mt_help(void) 28 { 29 printf( 30 "iprange match options:\n" 31 "[!] --src-range ip[-ip] Match source IP in the specified range\n" 32 "[!] --dst-range ip[-ip] Match destination IP in the specified range\n"); 33 } 34 35 static const struct xt_option_entry iprange_mt_opts[] = { 36 {.name = "src-range", .id = O_SRC_RANGE, .type = XTTYPE_STRING, 37 .flags = XTOPT_INVERT}, 38 {.name = "dst-range", .id = O_DST_RANGE, .type = XTTYPE_STRING, 39 .flags = XTOPT_INVERT}, 40 XTOPT_TABLEEND, 41 }; 42 43 static void 44 iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range, 45 uint8_t family, const char *optname) 46 { 47 const char *spec[2] = {from, to}; 48 struct in6_addr *ia6; 49 struct in_addr *ia4; 50 unsigned int i; 51 52 memset(range, 0, sizeof(union nf_inet_addr) * 2); 53 54 if (family == NFPROTO_IPV6) { 55 for (i = 0; i < ARRAY_SIZE(spec); ++i) { 56 ia6 = xtables_numeric_to_ip6addr(spec[i]); 57 if (ia6 == NULL) 58 xtables_param_act(XTF_BAD_VALUE, "iprange", 59 optname, spec[i]); 60 range[i].in6 = *ia6; 61 } 62 } else { 63 for (i = 0; i < ARRAY_SIZE(spec); ++i) { 64 ia4 = xtables_numeric_to_ipaddr(spec[i]); 65 if (ia4 == NULL) 66 xtables_param_act(XTF_BAD_VALUE, "iprange", 67 optname, spec[i]); 68 range[i].in = *ia4; 69 } 70 } 71 } 72 73 static void iprange_parse_range(const char *oarg, union nf_inet_addr *range, 74 uint8_t family, const char *optname) 75 { 76 char *arg = strdup(oarg); 77 char *dash; 78 79 if (arg == NULL) 80 xtables_error(RESOURCE_PROBLEM, "strdup"); 81 dash = strchr(arg, '-'); 82 if (dash == NULL) { 83 iprange_parse_spec(arg, arg, range, family, optname); 84 free(arg); 85 return; 86 } 87 88 *dash = '\0'; 89 iprange_parse_spec(arg, dash + 1, range, family, optname); 90 if (memcmp(&range[0], &range[1], sizeof(*range)) > 0) 91 fprintf(stderr, "xt_iprange: range %s-%s is reversed and " 92 "will never match\n", arg, dash + 1); 93 free(arg); 94 } 95 96 static void iprange_parse(struct xt_option_call *cb) 97 { 98 struct ipt_iprange_info *info = cb->data; 99 union nf_inet_addr range[2]; 100 101 xtables_option_parse(cb); 102 switch (cb->entry->id) { 103 case O_SRC_RANGE: 104 info->flags |= IPRANGE_SRC; 105 if (cb->invert) 106 info->flags |= IPRANGE_SRC_INV; 107 iprange_parse_range(cb->arg, range, NFPROTO_IPV4, "--src-range"); 108 info->src.min_ip = range[0].ip; 109 info->src.max_ip = range[1].ip; 110 break; 111 case O_DST_RANGE: 112 info->flags |= IPRANGE_DST; 113 if (cb->invert) 114 info->flags |= IPRANGE_DST_INV; 115 iprange_parse_range(cb->arg, range, NFPROTO_IPV4, "--dst-range"); 116 info->dst.min_ip = range[0].ip; 117 info->dst.max_ip = range[1].ip; 118 break; 119 } 120 } 121 122 static void iprange_mt_parse(struct xt_option_call *cb, uint8_t nfproto) 123 { 124 struct xt_iprange_mtinfo *info = cb->data; 125 126 xtables_option_parse(cb); 127 switch (cb->entry->id) { 128 case O_SRC_RANGE: 129 iprange_parse_range(cb->arg, &info->src_min, nfproto, 130 "--src-range"); 131 info->flags |= IPRANGE_SRC; 132 if (cb->invert) 133 info->flags |= IPRANGE_SRC_INV; 134 break; 135 case O_DST_RANGE: 136 iprange_parse_range(cb->arg, &info->dst_min, nfproto, 137 "--dst-range"); 138 info->flags |= IPRANGE_DST; 139 if (cb->invert) 140 info->flags |= IPRANGE_DST_INV; 141 break; 142 } 143 } 144 145 static void iprange_mt4_parse(struct xt_option_call *cb) 146 { 147 iprange_mt_parse(cb, NFPROTO_IPV4); 148 } 149 150 static void iprange_mt6_parse(struct xt_option_call *cb) 151 { 152 iprange_mt_parse(cb, NFPROTO_IPV6); 153 } 154 155 static void iprange_mt_check(struct xt_fcheck_call *cb) 156 { 157 if (cb->xflags == 0) 158 xtables_error(PARAMETER_PROBLEM, 159 "iprange match: You must specify `--src-range' or `--dst-range'"); 160 } 161 162 static void 163 print_iprange(const struct ipt_iprange *range) 164 { 165 const unsigned char *byte_min, *byte_max; 166 167 byte_min = (const unsigned char *)&range->min_ip; 168 byte_max = (const unsigned char *)&range->max_ip; 169 printf(" %u.%u.%u.%u-%u.%u.%u.%u", 170 byte_min[0], byte_min[1], byte_min[2], byte_min[3], 171 byte_max[0], byte_max[1], byte_max[2], byte_max[3]); 172 } 173 174 static void iprange_print(const void *ip, const struct xt_entry_match *match, 175 int numeric) 176 { 177 const struct ipt_iprange_info *info = (const void *)match->data; 178 179 if (info->flags & IPRANGE_SRC) { 180 printf(" source IP range"); 181 if (info->flags & IPRANGE_SRC_INV) 182 printf(" !"); 183 print_iprange(&info->src); 184 } 185 if (info->flags & IPRANGE_DST) { 186 printf(" destination IP range"); 187 if (info->flags & IPRANGE_DST_INV) 188 printf(" !"); 189 print_iprange(&info->dst); 190 } 191 } 192 193 static void 194 iprange_mt4_print(const void *ip, const struct xt_entry_match *match, 195 int numeric) 196 { 197 const struct xt_iprange_mtinfo *info = (const void *)match->data; 198 199 if (info->flags & IPRANGE_SRC) { 200 printf(" source IP range"); 201 if (info->flags & IPRANGE_SRC_INV) 202 printf(" !"); 203 /* 204 * ipaddr_to_numeric() uses a static buffer, so cannot 205 * combine the printf() calls. 206 */ 207 printf(" %s", xtables_ipaddr_to_numeric(&info->src_min.in)); 208 printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in)); 209 } 210 if (info->flags & IPRANGE_DST) { 211 printf(" destination IP range"); 212 if (info->flags & IPRANGE_DST_INV) 213 printf(" !"); 214 printf(" %s", xtables_ipaddr_to_numeric(&info->dst_min.in)); 215 printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in)); 216 } 217 } 218 219 static void 220 iprange_mt6_print(const void *ip, const struct xt_entry_match *match, 221 int numeric) 222 { 223 const struct xt_iprange_mtinfo *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 /* 230 * ipaddr_to_numeric() uses a static buffer, so cannot 231 * combine the printf() calls. 232 */ 233 printf(" %s", xtables_ip6addr_to_numeric(&info->src_min.in6)); 234 printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6)); 235 } 236 if (info->flags & IPRANGE_DST) { 237 printf(" destination IP range"); 238 if (info->flags & IPRANGE_DST_INV) 239 printf(" !"); 240 printf(" %s", xtables_ip6addr_to_numeric(&info->dst_min.in6)); 241 printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6)); 242 } 243 } 244 245 static void iprange_save(const void *ip, const struct xt_entry_match *match) 246 { 247 const struct ipt_iprange_info *info = (const void *)match->data; 248 249 if (info->flags & IPRANGE_SRC) { 250 if (info->flags & IPRANGE_SRC_INV) 251 printf(" !"); 252 printf(" --src-range"); 253 print_iprange(&info->src); 254 } 255 if (info->flags & IPRANGE_DST) { 256 if (info->flags & IPRANGE_DST_INV) 257 printf(" !"); 258 printf(" --dst-range"); 259 print_iprange(&info->dst); 260 } 261 } 262 263 static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match) 264 { 265 const struct xt_iprange_mtinfo *info = (const void *)match->data; 266 267 if (info->flags & IPRANGE_SRC) { 268 if (info->flags & IPRANGE_SRC_INV) 269 printf(" !"); 270 printf(" --src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in)); 271 printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in)); 272 } 273 if (info->flags & IPRANGE_DST) { 274 if (info->flags & IPRANGE_DST_INV) 275 printf(" !"); 276 printf(" --dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in)); 277 printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in)); 278 } 279 } 280 281 static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match) 282 { 283 const struct xt_iprange_mtinfo *info = (const void *)match->data; 284 285 if (info->flags & IPRANGE_SRC) { 286 if (info->flags & IPRANGE_SRC_INV) 287 printf(" !"); 288 printf(" --src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6)); 289 printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6)); 290 } 291 if (info->flags & IPRANGE_DST) { 292 if (info->flags & IPRANGE_DST_INV) 293 printf(" !"); 294 printf(" --dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6)); 295 printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6)); 296 } 297 } 298 299 static struct xtables_match iprange_mt_reg[] = { 300 { 301 .version = XTABLES_VERSION, 302 .name = "iprange", 303 .revision = 0, 304 .family = NFPROTO_IPV4, 305 .size = XT_ALIGN(sizeof(struct ipt_iprange_info)), 306 .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)), 307 .help = iprange_mt_help, 308 .x6_parse = iprange_parse, 309 .x6_fcheck = iprange_mt_check, 310 .print = iprange_print, 311 .save = iprange_save, 312 .x6_options = iprange_mt_opts, 313 }, 314 { 315 .version = XTABLES_VERSION, 316 .name = "iprange", 317 .revision = 1, 318 .family = NFPROTO_IPV4, 319 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 320 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 321 .help = iprange_mt_help, 322 .x6_parse = iprange_mt4_parse, 323 .x6_fcheck = iprange_mt_check, 324 .print = iprange_mt4_print, 325 .save = iprange_mt4_save, 326 .x6_options = iprange_mt_opts, 327 }, 328 { 329 .version = XTABLES_VERSION, 330 .name = "iprange", 331 .revision = 1, 332 .family = NFPROTO_IPV6, 333 .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 334 .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), 335 .help = iprange_mt_help, 336 .x6_parse = iprange_mt6_parse, 337 .x6_fcheck = iprange_mt_check, 338 .print = iprange_mt6_print, 339 .save = iprange_mt6_save, 340 .x6_options = iprange_mt_opts, 341 }, 342 }; 343 344 void _init(void) 345 { 346 xtables_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 347 } 348