1 /* ebt_ip
2 *
3 * Authors:
4 * Bart De Schuymer <bdschuym@pandora.be>
5 *
6 * Changes:
7 * added ip-sport and ip-dport; parsing of port arguments is
8 * based on code from iptables-1.2.7a
9 * Innominate Security Technologies AG <mhopf@innominate.com>
10 * September, 2002
11 *
12 * Adapted by Arturo Borrero Gonzalez <arturo@debian.org>
13 * to use libxtables for ebtables-compat in 2015.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <getopt.h>
20 #include <netdb.h>
21 #include <xtables.h>
22 #include <linux/netfilter_bridge/ebt_ip.h>
23
24 #define IP_SOURCE '1'
25 #define IP_DEST '2'
26 #define IP_EBT_TOS '3' /* include/bits/in.h seems to already define IP_TOS */
27 #define IP_PROTO '4'
28 #define IP_SPORT '5'
29 #define IP_DPORT '6'
30
31 static const struct option brip_opts[] = {
32 { .name = "ip-source", .has_arg = true, .val = IP_SOURCE },
33 { .name = "ip-src", .has_arg = true, .val = IP_SOURCE },
34 { .name = "ip-destination", .has_arg = true, .val = IP_DEST },
35 { .name = "ip-dst", .has_arg = true, .val = IP_DEST },
36 { .name = "ip-tos", .has_arg = true, .val = IP_EBT_TOS },
37 { .name = "ip-protocol", .has_arg = true, .val = IP_PROTO },
38 { .name = "ip-proto", .has_arg = true, .val = IP_PROTO },
39 { .name = "ip-source-port", .has_arg = true, .val = IP_SPORT },
40 { .name = "ip-sport", .has_arg = true, .val = IP_SPORT },
41 { .name = "ip-destination-port",.has_arg = true, .val = IP_DPORT },
42 { .name = "ip-dport", .has_arg = true, .val = IP_DPORT },
43 XT_GETOPT_TABLEEND,
44 };
45
brip_print_help(void)46 static void brip_print_help(void)
47 {
48 printf(
49 "ip options:\n"
50 "--ip-src [!] address[/mask]: ip source specification\n"
51 "--ip-dst [!] address[/mask]: ip destination specification\n"
52 "--ip-tos [!] tos : ip tos specification\n"
53 "--ip-proto [!] protocol : ip protocol specification\n"
54 "--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
55 "--ip-dport [!] port[:port] : tcp/udp destination port or port range\n");
56 }
57
brip_init(struct xt_entry_match * match)58 static void brip_init(struct xt_entry_match *match)
59 {
60 struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
61
62 info->invflags = 0;
63 info->bitmask = 0;
64 }
65
66 static void
parse_port_range(const char * protocol,const char * portstring,uint16_t * ports)67 parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
68 {
69 char *buffer;
70 char *cp;
71
72 buffer = strdup(portstring);
73 if ((cp = strchr(buffer, ':')) == NULL)
74 ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
75 else {
76 *cp = '\0';
77 cp++;
78
79 ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0;
80 ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF;
81
82 if (ports[0] > ports[1])
83 xtables_error(PARAMETER_PROBLEM,
84 "invalid portrange (min > max)");
85 }
86 free(buffer);
87 }
88
89 /* original code from ebtables: useful_functions.c */
undot_ip(char * ip,unsigned char * ip2)90 static int undot_ip(char *ip, unsigned char *ip2)
91 {
92 char *p, *q, *end;
93 long int onebyte;
94 int i;
95 char buf[20];
96
97 strncpy(buf, ip, sizeof(buf) - 1);
98
99 p = buf;
100 for (i = 0; i < 3; i++) {
101 if ((q = strchr(p, '.')) == NULL)
102 return -1;
103 *q = '\0';
104 onebyte = strtol(p, &end, 10);
105 if (*end != '\0' || onebyte > 255 || onebyte < 0)
106 return -1;
107 ip2[i] = (unsigned char)onebyte;
108 p = q + 1;
109 }
110
111 onebyte = strtol(p, &end, 10);
112 if (*end != '\0' || onebyte > 255 || onebyte < 0)
113 return -1;
114 ip2[3] = (unsigned char)onebyte;
115
116 return 0;
117 }
118
ip_mask(char * mask,unsigned char * mask2)119 static int ip_mask(char *mask, unsigned char *mask2)
120 {
121 char *end;
122 long int bits;
123 uint32_t mask22;
124
125 if (undot_ip(mask, mask2)) {
126 /* not the /a.b.c.e format, maybe the /x format */
127 bits = strtol(mask, &end, 10);
128 if (*end != '\0' || bits > 32 || bits < 0)
129 return -1;
130 if (bits != 0) {
131 mask22 = htonl(0xFFFFFFFF << (32 - bits));
132 memcpy(mask2, &mask22, 4);
133 } else {
134 mask22 = 0xFFFFFFFF;
135 memcpy(mask2, &mask22, 4);
136 }
137 }
138 return 0;
139 }
140
ebt_parse_ip_address(char * address,uint32_t * addr,uint32_t * msk)141 static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
142 {
143 char *p;
144
145 /* first the mask */
146 if ((p = strrchr(address, '/')) != NULL) {
147 *p = '\0';
148 if (ip_mask(p + 1, (unsigned char *)msk)) {
149 xtables_error(PARAMETER_PROBLEM,
150 "Problem with the IP mask '%s'", p + 1);
151 return;
152 }
153 } else
154 *msk = 0xFFFFFFFF;
155
156 if (undot_ip(address, (unsigned char *)addr)) {
157 xtables_error(PARAMETER_PROBLEM,
158 "Problem with the IP address '%s'", address);
159 return;
160 }
161 *addr = *addr & *msk;
162 }
163
164 static int
brip_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_match ** match)165 brip_parse(int c, char **argv, int invert, unsigned int *flags,
166 const void *entry, struct xt_entry_match **match)
167 {
168 struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data;
169
170 switch (c) {
171 case IP_SOURCE:
172 if (invert)
173 info->invflags |= EBT_IP_SOURCE;
174 ebt_parse_ip_address(optarg, &info->saddr, &info->smsk);
175 info->bitmask |= EBT_IP_SOURCE;
176 break;
177 case IP_DEST:
178 if (invert)
179 info->invflags |= EBT_IP_DEST;
180 ebt_parse_ip_address(optarg, &info->daddr, &info->dmsk);
181 info->bitmask |= EBT_IP_DEST;
182 break;
183 case IP_SPORT:
184 if (invert)
185 info->invflags |= EBT_IP_SPORT;
186 parse_port_range(NULL, optarg, info->sport);
187 info->bitmask |= EBT_IP_SPORT;
188 break;
189 case IP_DPORT:
190 if (invert)
191 info->invflags |= EBT_IP_DPORT;
192 parse_port_range(NULL, optarg, info->dport);
193 info->bitmask |= EBT_IP_DPORT;
194 break;
195 case IP_EBT_TOS:
196 if (invert)
197 info->invflags |= EBT_IP_TOS;
198 if (!xtables_strtoul(optarg, NULL, (uintmax_t *)&info->tos,
199 0, 255))
200 xtables_error(PARAMETER_PROBLEM,
201 "Problem with specified IP tos");
202 info->bitmask |= EBT_IP_TOS;
203 break;
204 case IP_PROTO:
205 if (invert)
206 info->invflags |= EBT_IP_PROTO;
207 info->protocol = xtables_parse_protocol(optarg);
208 if (info->protocol == -1)
209 xtables_error(PARAMETER_PROBLEM,
210 "Unknown specified IP protocol - %s",
211 optarg);
212 info->bitmask |= EBT_IP_PROTO;
213 break;
214 default:
215 return 0;
216 }
217
218 *flags |= info->bitmask;
219 return 1;
220 }
221
brip_final_check(unsigned int flags)222 static void brip_final_check(unsigned int flags)
223 {
224 if (!flags)
225 xtables_error(PARAMETER_PROBLEM,
226 "You must specify proper arguments");
227 }
228
print_port_range(uint16_t * ports)229 static void print_port_range(uint16_t *ports)
230 {
231 if (ports[0] == ports[1])
232 printf("%d ", ports[0]);
233 else
234 printf("%d:%d ", ports[0], ports[1]);
235 }
236
brip_print(const void * ip,const struct xt_entry_match * match,int numeric)237 static void brip_print(const void *ip, const struct xt_entry_match *match,
238 int numeric)
239 {
240 struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
241 struct in_addr *addrp, *maskp;
242
243 if (info->bitmask & EBT_IP_SOURCE) {
244 printf("--ip-src ");
245 if (info->invflags & EBT_IP_SOURCE)
246 printf("! ");
247 addrp = (struct in_addr *)&info->saddr;
248 maskp = (struct in_addr *)&info->smsk;
249 printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
250 xtables_ipmask_to_numeric(maskp));
251 }
252 if (info->bitmask & EBT_IP_DEST) {
253 printf("--ip-dst ");
254 if (info->invflags & EBT_IP_DEST)
255 printf("! ");
256 addrp = (struct in_addr *)&info->daddr;
257 maskp = (struct in_addr *)&info->dmsk;
258 printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
259 xtables_ipmask_to_numeric(maskp));
260 }
261 if (info->bitmask & EBT_IP_TOS) {
262 printf("--ip-tos ");
263 if (info->invflags & EBT_IP_TOS)
264 printf("! ");
265 printf("0x%02X ", info->tos);
266 }
267 if (info->bitmask & EBT_IP_PROTO) {
268 struct protoent *pe;
269
270 printf("--ip-proto ");
271 if (info->invflags & EBT_IP_PROTO)
272 printf("! ");
273 pe = getprotobynumber(info->protocol);
274 if (pe == NULL) {
275 printf("%d ", info->protocol);
276 } else {
277 printf("%s ", pe->p_name);
278 }
279 }
280 if (info->bitmask & EBT_IP_SPORT) {
281 printf("--ip-sport ");
282 if (info->invflags & EBT_IP_SPORT)
283 printf("! ");
284 print_port_range(info->sport);
285 }
286 if (info->bitmask & EBT_IP_DPORT) {
287 printf("--ip-dport ");
288 if (info->invflags & EBT_IP_DPORT)
289 printf("! ");
290 print_port_range(info->dport);
291 }
292 }
293
294 static struct xtables_match brip_match = {
295 .name = "ip",
296 .revision = 0,
297 .version = XTABLES_VERSION,
298 .family = NFPROTO_BRIDGE,
299 .size = XT_ALIGN(sizeof(struct ebt_ip_info)),
300 .userspacesize = XT_ALIGN(sizeof(struct ebt_ip_info)),
301 .init = brip_init,
302 .help = brip_print_help,
303 .parse = brip_parse,
304 .final_check = brip_final_check,
305 .print = brip_print,
306 .extra_opts = brip_opts,
307 };
308
_init(void)309 void _init(void)
310 {
311 xtables_register_match(&brip_match);
312 }
313