Home | History | Annotate | Download | only in extensions
      1 /* 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 <iptables.h>
      9 #include <linux/netfilter_ipv4/ipt_iprange.h>
     10 
     11 /* Function which prints out usage message. */
     12 static void
     13 help(void)
     14 {
     15 	printf(
     16 "iprange match v%s options:\n"
     17 "[!] --src-range ip-ip        Match source IP in the specified range\n"
     18 "[!] --dst-range ip-ip        Match destination IP in the specified range\n"
     19 "\n",
     20 IPTABLES_VERSION);
     21 }
     22 
     23 static struct option opts[] = {
     24 	{ "src-range", 1, 0, '1' },
     25 	{ "dst-range", 1, 0, '2' },
     26 	{0}
     27 };
     28 
     29 static void
     30 parse_iprange(char *arg, struct ipt_iprange *range)
     31 {
     32 	char *dash;
     33 	struct in_addr *ip;
     34 
     35 	dash = strchr(arg, '-');
     36 	if (dash)
     37 		*dash = '\0';
     38 
     39 	ip = dotted_to_addr(arg);
     40 	if (!ip)
     41 		exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n",
     42 			   arg);
     43 	range->min_ip = ip->s_addr;
     44 
     45 	if (dash) {
     46 		ip = dotted_to_addr(dash+1);
     47 		if (!ip)
     48 			exit_error(PARAMETER_PROBLEM, "iprange match: Bad IP address `%s'\n",
     49 				   dash+1);
     50 		range->max_ip = ip->s_addr;
     51 	} else
     52 		range->max_ip = range->min_ip;
     53 }
     54 
     55 /* Function which parses command options; returns true if it
     56    ate an option */
     57 static int
     58 parse(int c, char **argv, int invert, unsigned int *flags,
     59       const struct ipt_entry *entry,
     60       unsigned int *nfcache,
     61       struct ipt_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 			exit_error(PARAMETER_PROBLEM,
     69 				   "iprange match: Only use --src-range ONCE!");
     70 		*flags |= IPRANGE_SRC;
     71 
     72 		info->flags |= IPRANGE_SRC;
     73 		check_inverse(optarg, &invert, &optind, 0);
     74 		if (invert) {
     75 			info->flags |= IPRANGE_SRC_INV;
     76 		}
     77 		parse_iprange(optarg, &info->src);
     78 
     79 		break;
     80 
     81 	case '2':
     82 		if (*flags & IPRANGE_DST)
     83 			exit_error(PARAMETER_PROBLEM,
     84 				   "iprange match: Only use --dst-range ONCE!");
     85 		*flags |= IPRANGE_DST;
     86 
     87 		info->flags |= IPRANGE_DST;
     88 		check_inverse(optarg, &invert, &optind, 0);
     89 		if (invert)
     90 			info->flags |= IPRANGE_DST_INV;
     91 
     92 		parse_iprange(optarg, &info->dst);
     93 
     94 		break;
     95 
     96 	default:
     97 		return 0;
     98 	}
     99 	return 1;
    100 }
    101 
    102 /* Final check; must have specified --src-range or --dst-range. */
    103 static void
    104 final_check(unsigned int flags)
    105 {
    106 	if (!flags)
    107 		exit_error(PARAMETER_PROBLEM,
    108 			   "iprange match: You must specify `--src-range' or `--dst-range'");
    109 }
    110 
    111 static void
    112 print_iprange(const struct ipt_iprange *range)
    113 {
    114 	const unsigned char *byte_min, *byte_max;
    115 
    116 	byte_min = (const unsigned char *) &(range->min_ip);
    117 	byte_max = (const unsigned char *) &(range->max_ip);
    118 	printf("%d.%d.%d.%d-%d.%d.%d.%d ",
    119 		byte_min[0], byte_min[1], byte_min[2], byte_min[3],
    120 		byte_max[0], byte_max[1], byte_max[2], byte_max[3]);
    121 }
    122 
    123 /* Prints out the info. */
    124 static void
    125 print(const struct ipt_ip *ip,
    126       const struct ipt_entry_match *match,
    127       int numeric)
    128 {
    129 	struct ipt_iprange_info *info = (struct ipt_iprange_info *)match->data;
    130 
    131 	if (info->flags & IPRANGE_SRC) {
    132 		printf("source IP range ");
    133 		if (info->flags & IPRANGE_SRC_INV)
    134 			printf("! ");
    135 		print_iprange(&info->src);
    136 	}
    137 	if (info->flags & IPRANGE_DST) {
    138 		printf("destination IP range ");
    139 		if (info->flags & IPRANGE_DST_INV)
    140 			printf("! ");
    141 		print_iprange(&info->dst);
    142 	}
    143 }
    144 
    145 /* Saves the union ipt_info in parsable form to stdout. */
    146 static void
    147 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
    148 {
    149 	struct ipt_iprange_info *info = (struct ipt_iprange_info *)match->data;
    150 
    151 	if (info->flags & IPRANGE_SRC) {
    152 		if (info->flags & IPRANGE_SRC_INV)
    153 			printf("! ");
    154 		printf("--src-range ");
    155 		print_iprange(&info->src);
    156 		if (info->flags & IPRANGE_DST)
    157 			fputc(' ', stdout);
    158 	}
    159 	if (info->flags & IPRANGE_DST) {
    160 		if (info->flags & IPRANGE_DST_INV)
    161 			printf("! ");
    162 		printf("--dst-range ");
    163 		print_iprange(&info->dst);
    164 	}
    165 }
    166 
    167 static struct iptables_match iprange = {
    168 	.next		= NULL,
    169 	.name		= "iprange",
    170 	.version	= IPTABLES_VERSION,
    171 	.size		= IPT_ALIGN(sizeof(struct ipt_iprange_info)),
    172 	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_iprange_info)),
    173 	.help		= &help,
    174 	.parse		= &parse,
    175 	.final_check	= &final_check,
    176 	.print		= &print,
    177 	.save		= &save,
    178 	.extra_opts	= opts
    179 };
    180 
    181 void ipt_iprange_init(void)
    182 {
    183 	register_match(&iprange);
    184 }
    185