• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ebt_arp
2  *
3  * Authors:
4  * Bart De Schuymer <bdschuym@pandora.be>
5  * Tim Gardner <timg@tpi.com>
6  *
7  * April, 2002
8  */
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <getopt.h>
14 #include <xtables.h>
15 #include <netinet/ether.h>
16 
17 #include <xtables.h>
18 #include <net/if_arp.h>
19 #include <linux/netfilter_bridge/ebt_arp.h>
20 #include "iptables/nft.h"
21 #include "iptables/nft-bridge.h"
22 
23 #define ARP_OPCODE '1'
24 #define ARP_HTYPE  '2'
25 #define ARP_PTYPE  '3'
26 #define ARP_IP_S   '4'
27 #define ARP_IP_D   '5'
28 #define ARP_MAC_S  '6'
29 #define ARP_MAC_D  '7'
30 #define ARP_GRAT   '8'
31 
32 static const struct option brarp_opts[] = {
33 	{ "arp-opcode"    , required_argument, 0, ARP_OPCODE },
34 	{ "arp-op"        , required_argument, 0, ARP_OPCODE },
35 	{ "arp-htype"     , required_argument, 0, ARP_HTYPE  },
36 	{ "arp-ptype"     , required_argument, 0, ARP_PTYPE  },
37 	{ "arp-ip-src"    , required_argument, 0, ARP_IP_S   },
38 	{ "arp-ip-dst"    , required_argument, 0, ARP_IP_D   },
39 	{ "arp-mac-src"   , required_argument, 0, ARP_MAC_S  },
40 	{ "arp-mac-dst"   , required_argument, 0, ARP_MAC_D  },
41 	{ "arp-gratuitous",       no_argument, 0, ARP_GRAT   },
42 	XT_GETOPT_TABLEEND,
43 };
44 
45 /* a few names */
46 static char *opcodes[] =
47 {
48 	"Request",
49 	"Reply",
50 	"Request_Reverse",
51 	"Reply_Reverse",
52 	"DRARP_Request",
53 	"DRARP_Reply",
54 	"DRARP_Error",
55 	"InARP_Request",
56 	"ARP_NAK",
57 };
58 
brarp_print_help(void)59 static void brarp_print_help(void)
60 {
61 	int i;
62 
63 	printf(
64 "arp options:\n"
65 "--arp-opcode  [!] opcode        : ARP opcode (integer or string)\n"
66 "--arp-htype   [!] type          : ARP hardware type (integer or string)\n"
67 "--arp-ptype   [!] type          : ARP protocol type (hexadecimal or string)\n"
68 "--arp-ip-src  [!] address[/mask]: ARP IP source specification\n"
69 "--arp-ip-dst  [!] address[/mask]: ARP IP target specification\n"
70 "--arp-mac-src [!] address[/mask]: ARP MAC source specification\n"
71 "--arp-mac-dst [!] address[/mask]: ARP MAC target specification\n"
72 "[!] --arp-gratuitous            : ARP gratuitous packet\n"
73 " opcode strings: \n");
74 	for (i = 0; i < ARRAY_SIZE(opcodes); i++)
75 		printf(" %d = %s\n", i + 1, opcodes[i]);
76 	printf(
77 " hardware type string: 1 = Ethernet\n"
78 " protocol type string: see "XT_PATH_ETHERTYPES"\n");
79 }
80 
81 #define OPT_OPCODE 0x01
82 #define OPT_HTYPE  0x02
83 #define OPT_PTYPE  0x04
84 #define OPT_IP_S   0x08
85 #define OPT_IP_D   0x10
86 #define OPT_MAC_S  0x20
87 #define OPT_MAC_D  0x40
88 #define OPT_GRAT   0x80
89 
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 
brarp_get_mac_and_mask(const char * from,unsigned char * to,unsigned char * mask)164 static int brarp_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask)
165 {
166 	char *p;
167 	int i;
168 	struct ether_addr *addr = NULL;
169 
170 	static const unsigned char mac_type_unicast[ETH_ALEN];
171 	static const unsigned char msk_type_unicast[ETH_ALEN] =   {1,0,0,0,0,0};
172 	static const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
173 	static const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
174 	static const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
175 	static const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
176 
177 	if (strcasecmp(from, "Unicast") == 0) {
178 		memcpy(to, mac_type_unicast, ETH_ALEN);
179 		memcpy(mask, msk_type_unicast, ETH_ALEN);
180 		return 0;
181 	}
182 	if (strcasecmp(from, "Multicast") == 0) {
183 		memcpy(to, mac_type_multicast, ETH_ALEN);
184 		memcpy(mask, mac_type_multicast, ETH_ALEN);
185 		return 0;
186 	}
187 	if (strcasecmp(from, "Broadcast") == 0) {
188 		memcpy(to, mac_type_broadcast, ETH_ALEN);
189 		memcpy(mask, mac_type_broadcast, ETH_ALEN);
190 		return 0;
191 	}
192 	if (strcasecmp(from, "BGA") == 0) {
193 		memcpy(to, mac_type_bridge_group, ETH_ALEN);
194 		memcpy(mask, msk_type_bridge_group, ETH_ALEN);
195 		return 0;
196 	}
197 	if ( (p = strrchr(from, '/')) != NULL) {
198 		*p = '\0';
199 		if (!(addr = ether_aton(p + 1)))
200 			return -1;
201 		memcpy(mask, addr, ETH_ALEN);
202 	} else
203 		memset(mask, 0xff, ETH_ALEN);
204 	if (!(addr = ether_aton(from)))
205 		return -1;
206 	memcpy(to, addr, ETH_ALEN);
207 	for (i = 0; i < ETH_ALEN; i++)
208 		to[i] &= mask[i];
209 	return 0;
210 }
211 
212 static int
brarp_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_match ** match)213 brarp_parse(int c, char **argv, int invert, unsigned int *flags,
214 	    const void *entry, struct xt_entry_match **match)
215 {
216 	struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data;
217 	long int i;
218 	char *end;
219 	uint32_t *addr;
220 	uint32_t *mask;
221 	unsigned char *maddr;
222 	unsigned char *mmask;
223 
224 	switch (c) {
225 	case ARP_OPCODE:
226 		EBT_CHECK_OPTION(flags, OPT_OPCODE);
227 		if (invert)
228 			arpinfo->invflags |= EBT_ARP_OPCODE;
229 		i = strtol(optarg, &end, 10);
230 		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
231 			for (i = 0; i < ARRAY_SIZE(opcodes); i++)
232 				if (!strcasecmp(opcodes[i], optarg))
233 					break;
234 			if (i == ARRAY_SIZE(opcodes))
235 				xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP opcode");
236 			i++;
237 		}
238 		arpinfo->opcode = htons(i);
239 		arpinfo->bitmask |= EBT_ARP_OPCODE;
240 		break;
241 
242 	case ARP_HTYPE:
243 		EBT_CHECK_OPTION(flags, OPT_HTYPE);
244 		if (invert)
245 			arpinfo->invflags |= EBT_ARP_HTYPE;
246 		i = strtol(optarg, &end, 10);
247 		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
248 			if (!strcasecmp("Ethernet", argv[optind - 1]))
249 				i = 1;
250 			else
251 				xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP hardware type");
252 		}
253 		arpinfo->htype = htons(i);
254 		arpinfo->bitmask |= EBT_ARP_HTYPE;
255 		break;
256 	case ARP_PTYPE: {
257 		uint16_t proto;
258 
259 		EBT_CHECK_OPTION(flags, OPT_PTYPE);
260 		if (invert)
261 			arpinfo->invflags |= EBT_ARP_PTYPE;
262 
263 		i = strtol(optarg, &end, 16);
264 		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
265 			struct xt_ethertypeent *ent;
266 
267 			ent = xtables_getethertypebyname(argv[optind - 1]);
268 			if (!ent)
269 				xtables_error(PARAMETER_PROBLEM, "Problem with specified ARP "
270 								 "protocol type");
271 			proto = ent->e_ethertype;
272 
273 		} else
274 			proto = i;
275 		arpinfo->ptype = htons(proto);
276 		arpinfo->bitmask |= EBT_ARP_PTYPE;
277 		break;
278 	}
279 
280 	case ARP_IP_S:
281 	case ARP_IP_D:
282 		if (c == ARP_IP_S) {
283 			EBT_CHECK_OPTION(flags, OPT_IP_S);
284 			addr = &arpinfo->saddr;
285 			mask = &arpinfo->smsk;
286 			arpinfo->bitmask |= EBT_ARP_SRC_IP;
287 		} else {
288 			EBT_CHECK_OPTION(flags, OPT_IP_D);
289 			addr = &arpinfo->daddr;
290 			mask = &arpinfo->dmsk;
291 			arpinfo->bitmask |= EBT_ARP_DST_IP;
292 		}
293 		if (invert) {
294 			if (c == ARP_IP_S)
295 				arpinfo->invflags |= EBT_ARP_SRC_IP;
296 			else
297 				arpinfo->invflags |= EBT_ARP_DST_IP;
298 		}
299 		ebt_parse_ip_address(optarg, addr, mask);
300 		break;
301 	case ARP_MAC_S:
302 	case ARP_MAC_D:
303 		if (c == ARP_MAC_S) {
304 			EBT_CHECK_OPTION(flags, OPT_MAC_S);
305 			maddr = arpinfo->smaddr;
306 			mmask = arpinfo->smmsk;
307 			arpinfo->bitmask |= EBT_ARP_SRC_MAC;
308 		} else {
309 			EBT_CHECK_OPTION(flags, OPT_MAC_D);
310 			maddr = arpinfo->dmaddr;
311 			mmask = arpinfo->dmmsk;
312 			arpinfo->bitmask |= EBT_ARP_DST_MAC;
313 		}
314 		if (invert) {
315 			if (c == ARP_MAC_S)
316 				arpinfo->invflags |= EBT_ARP_SRC_MAC;
317 			else
318 				arpinfo->invflags |= EBT_ARP_DST_MAC;
319 		}
320 		if (brarp_get_mac_and_mask(optarg, maddr, mmask))
321 			xtables_error(PARAMETER_PROBLEM, "Problem with ARP MAC address argument");
322 		break;
323 	case ARP_GRAT:
324 		EBT_CHECK_OPTION(flags, OPT_GRAT);
325 		arpinfo->bitmask |= EBT_ARP_GRAT;
326 		if (invert)
327 			arpinfo->invflags |= EBT_ARP_GRAT;
328 		break;
329 	default:
330 		return 0;
331 	}
332 	return 1;
333 }
334 
brarp_print(const void * ip,const struct xt_entry_match * match,int numeric)335 static void brarp_print(const void *ip, const struct xt_entry_match *match, int numeric)
336 {
337 	const struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)match->data;
338 
339 	if (arpinfo->bitmask & EBT_ARP_OPCODE) {
340 		int opcode = ntohs(arpinfo->opcode);
341 		printf("--arp-op ");
342 		if (arpinfo->invflags & EBT_ARP_OPCODE)
343 			printf("! ");
344 		if (opcode > 0 && opcode <= ARRAY_SIZE(opcodes))
345 			printf("%s ", opcodes[opcode - 1]);
346 		else
347 			printf("%d ", opcode);
348 	}
349 	if (arpinfo->bitmask & EBT_ARP_HTYPE) {
350 		printf("--arp-htype ");
351 		if (arpinfo->invflags & EBT_ARP_HTYPE)
352 			printf("! ");
353 		printf("%d ", ntohs(arpinfo->htype));
354 	}
355 	if (arpinfo->bitmask & EBT_ARP_PTYPE) {
356 		printf("--arp-ptype ");
357 		if (arpinfo->invflags & EBT_ARP_PTYPE)
358 			printf("! ");
359 		printf("0x%x ", ntohs(arpinfo->ptype));
360 	}
361 	if (arpinfo->bitmask & EBT_ARP_SRC_IP) {
362 		printf("--arp-ip-src ");
363 		if (arpinfo->invflags & EBT_ARP_SRC_IP)
364 			printf("! ");
365 		printf("%s%s ", xtables_ipaddr_to_numeric((const struct in_addr*) &arpinfo->saddr),
366 		       xtables_ipmask_to_numeric((const struct in_addr*)&arpinfo->smsk));
367 	}
368 	if (arpinfo->bitmask & EBT_ARP_DST_IP) {
369 		printf("--arp-ip-dst ");
370 		if (arpinfo->invflags & EBT_ARP_DST_IP)
371 			printf("! ");
372 		printf("%s%s ", xtables_ipaddr_to_numeric((const struct in_addr*) &arpinfo->daddr),
373 		       xtables_ipmask_to_numeric((const struct in_addr*)&arpinfo->dmsk));
374 	}
375 	if (arpinfo->bitmask & EBT_ARP_SRC_MAC) {
376 		printf("--arp-mac-src ");
377 		if (arpinfo->invflags & EBT_ARP_SRC_MAC)
378 			printf("! ");
379 		xtables_print_mac_and_mask(arpinfo->smaddr, arpinfo->smmsk);
380 		printf(" ");
381 	}
382 	if (arpinfo->bitmask & EBT_ARP_DST_MAC) {
383 		printf("--arp-mac-dst ");
384 		if (arpinfo->invflags & EBT_ARP_DST_MAC)
385 			printf("! ");
386 		xtables_print_mac_and_mask(arpinfo->dmaddr, arpinfo->dmmsk);
387 		printf(" ");
388 	}
389 	if (arpinfo->bitmask & EBT_ARP_GRAT) {
390 		if (arpinfo->invflags & EBT_ARP_GRAT)
391 			printf("! ");
392 		printf("--arp-gratuitous ");
393 	}
394 }
395 
396 static struct xtables_match brarp_match = {
397 	.name		= "arp",
398 	.version	= XTABLES_VERSION,
399 	.family		= NFPROTO_BRIDGE,
400 	.size		= XT_ALIGN(sizeof(struct ebt_arp_info)),
401 	.userspacesize	= XT_ALIGN(sizeof(struct ebt_arp_info)),
402 	.help		= brarp_print_help,
403 	.parse		= brarp_parse,
404 	.print		= brarp_print,
405 	.extra_opts	= brarp_opts,
406 };
407 
_init(void)408 void _init(void)
409 {
410 	xtables_register_match(&brarp_match);
411 }
412