• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
help(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
parse_iprange(char * arg,struct ipt_iprange * range)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
parse(int c,char ** argv,int invert,unsigned int * flags,const struct ipt_entry * entry,unsigned int * nfcache,struct ipt_entry_match ** match)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
final_check(unsigned int flags)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
print_iprange(const struct ipt_iprange * range)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
print(const struct ipt_ip * ip,const struct ipt_entry_match * match,int numeric)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
save(const struct ipt_ip * ip,const struct ipt_entry_match * match)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 
ipt_iprange_init(void)181 void ipt_iprange_init(void)
182 {
183 	register_match(&iprange);
184 }
185