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 "../include/ebtables_u.h"
15#include "../include/ethernetdb.h"
16#include <linux/if_ether.h>
17#include <linux/netfilter_bridge/ebt_arp.h>
18
19#define ARP_OPCODE '1'
20#define ARP_HTYPE  '2'
21#define ARP_PTYPE  '3'
22#define ARP_IP_S   '4'
23#define ARP_IP_D   '5'
24#define ARP_MAC_S  '6'
25#define ARP_MAC_D  '7'
26#define ARP_GRAT   '8'
27static struct option opts[] =
28{
29	{ "arp-opcode"    , required_argument, 0, ARP_OPCODE },
30	{ "arp-op"        , required_argument, 0, ARP_OPCODE },
31	{ "arp-htype"     , required_argument, 0, ARP_HTYPE  },
32	{ "arp-ptype"     , required_argument, 0, ARP_PTYPE  },
33	{ "arp-ip-src"    , required_argument, 0, ARP_IP_S   },
34	{ "arp-ip-dst"    , required_argument, 0, ARP_IP_D   },
35	{ "arp-mac-src"   , required_argument, 0, ARP_MAC_S  },
36	{ "arp-mac-dst"   , required_argument, 0, ARP_MAC_D  },
37	{ "arp-gratuitous",       no_argument, 0, ARP_GRAT   },
38	{ 0 }
39};
40
41#define NUMOPCODES 9
42/* a few names */
43static char *opcodes[] =
44{
45	"Request",
46	"Reply",
47	"Request_Reverse",
48	"Reply_Reverse",
49	"DRARP_Request",
50	"DRARP_Reply",
51	"DRARP_Error",
52	"InARP_Request",
53	"ARP_NAK",
54};
55
56static void print_help()
57{
58	int i;
59
60	printf(
61"arp options:\n"
62"--arp-opcode  [!] opcode        : ARP opcode (integer or string)\n"
63"--arp-htype   [!] type          : ARP hardware type (integer or string)\n"
64"--arp-ptype   [!] type          : ARP protocol type (hexadecimal or string)\n"
65"--arp-ip-src  [!] address[/mask]: ARP IP source specification\n"
66"--arp-ip-dst  [!] address[/mask]: ARP IP target specification\n"
67"--arp-mac-src [!] address[/mask]: ARP MAC source specification\n"
68"--arp-mac-dst [!] address[/mask]: ARP MAC target specification\n"
69"[!] --arp-gratuitous            : ARP gratuitous packet\n"
70" opcode strings: \n");
71	for (i = 0; i < NUMOPCODES; i++)
72		printf(" %d = %s\n", i + 1, opcodes[i]);
73	printf(
74" hardware type string: 1 = Ethernet\n"
75" protocol type string: see "_PATH_ETHERTYPES"\n");
76}
77
78static void init(struct ebt_entry_match *match)
79{
80	struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)match->data;
81
82	arpinfo->invflags = 0;
83	arpinfo->bitmask = 0;
84}
85
86
87#define OPT_OPCODE 0x01
88#define OPT_HTYPE  0x02
89#define OPT_PTYPE  0x04
90#define OPT_IP_S   0x08
91#define OPT_IP_D   0x10
92#define OPT_MAC_S  0x20
93#define OPT_MAC_D  0x40
94#define OPT_GRAT   0x80
95static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
96   unsigned int *flags, struct ebt_entry_match **match)
97{
98	struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)(*match)->data;
99	long int i;
100	char *end;
101	uint32_t *addr;
102	uint32_t *mask;
103	unsigned char *maddr;
104	unsigned char *mmask;
105
106	switch (c) {
107	case ARP_OPCODE:
108		ebt_check_option2(flags, OPT_OPCODE);
109		if (ebt_check_inverse2(optarg))
110			arpinfo->invflags |= EBT_ARP_OPCODE;
111		i = strtol(optarg, &end, 10);
112		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
113			for (i = 0; i < NUMOPCODES; i++)
114				if (!strcasecmp(opcodes[i], optarg))
115					break;
116			if (i == NUMOPCODES)
117				ebt_print_error2("Problem with specified ARP opcode");
118			i++;
119		}
120		arpinfo->opcode = htons(i);
121		arpinfo->bitmask |= EBT_ARP_OPCODE;
122		break;
123
124	case ARP_HTYPE:
125		ebt_check_option2(flags, OPT_HTYPE);
126		if (ebt_check_inverse2(optarg))
127			arpinfo->invflags |= EBT_ARP_HTYPE;
128		i = strtol(optarg, &end, 10);
129		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
130			if (!strcasecmp("Ethernet", argv[optind - 1]))
131				i = 1;
132			else
133				ebt_print_error2("Problem with specified ARP hardware type");
134		}
135		arpinfo->htype = htons(i);
136		arpinfo->bitmask |= EBT_ARP_HTYPE;
137		break;
138
139	case ARP_PTYPE:
140	{
141		uint16_t proto;
142
143		ebt_check_option2(flags, OPT_PTYPE);
144		if (ebt_check_inverse2(optarg))
145			arpinfo->invflags |= EBT_ARP_PTYPE;
146
147		i = strtol(optarg, &end, 16);
148		if (i < 0 || i >= (0x1 << 16) || *end !='\0') {
149			struct ethertypeent *ent;
150
151			ent = getethertypebyname(argv[optind - 1]);
152			if (!ent)
153				ebt_print_error2("Problem with specified ARP "
154						"protocol type");
155			proto = ent->e_ethertype;
156
157		} else
158			proto = i;
159		arpinfo->ptype = htons(proto);
160		arpinfo->bitmask |= EBT_ARP_PTYPE;
161		break;
162	}
163
164	case ARP_IP_S:
165	case ARP_IP_D:
166		if (c == ARP_IP_S) {
167			ebt_check_option2(flags, OPT_IP_S);
168			addr = &arpinfo->saddr;
169			mask = &arpinfo->smsk;
170			arpinfo->bitmask |= EBT_ARP_SRC_IP;
171		} else {
172			ebt_check_option2(flags, OPT_IP_D);
173			addr = &arpinfo->daddr;
174			mask = &arpinfo->dmsk;
175			arpinfo->bitmask |= EBT_ARP_DST_IP;
176		}
177		if (ebt_check_inverse2(optarg)) {
178			if (c == ARP_IP_S)
179				arpinfo->invflags |= EBT_ARP_SRC_IP;
180			else
181				arpinfo->invflags |= EBT_ARP_DST_IP;
182		}
183		ebt_parse_ip_address(optarg, addr, mask);
184		break;
185
186	case ARP_MAC_S:
187	case ARP_MAC_D:
188		if (c == ARP_MAC_S) {
189			ebt_check_option2(flags, OPT_MAC_S);
190			maddr = arpinfo->smaddr;
191			mmask = arpinfo->smmsk;
192			arpinfo->bitmask |= EBT_ARP_SRC_MAC;
193		} else {
194			ebt_check_option2(flags, OPT_MAC_D);
195			maddr = arpinfo->dmaddr;
196			mmask = arpinfo->dmmsk;
197			arpinfo->bitmask |= EBT_ARP_DST_MAC;
198		}
199		if (ebt_check_inverse2(optarg)) {
200			if (c == ARP_MAC_S)
201				arpinfo->invflags |= EBT_ARP_SRC_MAC;
202			else
203				arpinfo->invflags |= EBT_ARP_DST_MAC;
204		}
205		if (ebt_get_mac_and_mask(optarg, maddr, mmask))
206			ebt_print_error2("Problem with ARP MAC address argument");
207		break;
208	case ARP_GRAT:
209		ebt_check_option2(flags, OPT_GRAT);
210		arpinfo->bitmask |= EBT_ARP_GRAT;
211		if (ebt_invert)
212			arpinfo->invflags |= EBT_ARP_GRAT;
213		break;
214
215	default:
216		return 0;
217	}
218	return 1;
219}
220
221static void final_check(const struct ebt_u_entry *entry,
222   const struct ebt_entry_match *match, const char *name,
223   unsigned int hookmask, unsigned int time)
224{
225	if ((entry->ethproto != ETH_P_ARP && entry->ethproto != ETH_P_RARP) ||
226	    entry->invflags & EBT_IPROTO)
227		ebt_print_error("For (R)ARP filtering the protocol must be specified as ARP or RARP");
228}
229
230static void print(const struct ebt_u_entry *entry,
231   const struct ebt_entry_match *match)
232{
233	struct ebt_arp_info *arpinfo = (struct ebt_arp_info *)match->data;
234	int i;
235
236	if (arpinfo->bitmask & EBT_ARP_OPCODE) {
237		int opcode = ntohs(arpinfo->opcode);
238		printf("--arp-op ");
239		if (arpinfo->invflags & EBT_ARP_OPCODE)
240			printf("! ");
241		if (opcode > 0 && opcode <= NUMOPCODES)
242			printf("%s ", opcodes[opcode - 1]);
243		else
244			printf("%d ", opcode);
245	}
246	if (arpinfo->bitmask & EBT_ARP_HTYPE) {
247		printf("--arp-htype ");
248		if (arpinfo->invflags & EBT_ARP_HTYPE)
249			printf("! ");
250		printf("%d ", ntohs(arpinfo->htype));
251	}
252	if (arpinfo->bitmask & EBT_ARP_PTYPE) {
253		struct ethertypeent *ent;
254
255		printf("--arp-ptype ");
256		if (arpinfo->invflags & EBT_ARP_PTYPE)
257			printf("! ");
258		ent = getethertypebynumber(ntohs(arpinfo->ptype));
259		if (!ent)
260			printf("0x%x ", ntohs(arpinfo->ptype));
261		else
262			printf("%s ", ent->e_name);
263	}
264	if (arpinfo->bitmask & EBT_ARP_SRC_IP) {
265		printf("--arp-ip-src ");
266		if (arpinfo->invflags & EBT_ARP_SRC_IP)
267			printf("! ");
268		for (i = 0; i < 4; i++)
269			printf("%d%s", ((unsigned char *)&arpinfo->saddr)[i],
270			   (i == 3) ? "" : ".");
271		printf("%s ", ebt_mask_to_dotted(arpinfo->smsk));
272	}
273	if (arpinfo->bitmask & EBT_ARP_DST_IP) {
274		printf("--arp-ip-dst ");
275		if (arpinfo->invflags & EBT_ARP_DST_IP)
276			printf("! ");
277		for (i = 0; i < 4; i++)
278			printf("%d%s", ((unsigned char *)&arpinfo->daddr)[i],
279			   (i == 3) ? "" : ".");
280		printf("%s ", ebt_mask_to_dotted(arpinfo->dmsk));
281	}
282	if (arpinfo->bitmask & EBT_ARP_SRC_MAC) {
283		printf("--arp-mac-src ");
284		if (arpinfo->invflags & EBT_ARP_SRC_MAC)
285			printf("! ");
286		ebt_print_mac_and_mask(arpinfo->smaddr, arpinfo->smmsk);
287		printf(" ");
288	}
289	if (arpinfo->bitmask & EBT_ARP_DST_MAC) {
290		printf("--arp-mac-dst ");
291		if (arpinfo->invflags & EBT_ARP_DST_MAC)
292			printf("! ");
293		ebt_print_mac_and_mask(arpinfo->dmaddr, arpinfo->dmmsk);
294		printf(" ");
295	}
296	if (arpinfo->bitmask & EBT_ARP_GRAT) {
297		if (arpinfo->invflags & EBT_ARP_GRAT)
298			printf("! ");
299		printf("--arp-gratuitous ");
300	}
301}
302
303static int compare(const struct ebt_entry_match *m1,
304   const struct ebt_entry_match *m2)
305{
306	struct ebt_arp_info *arpinfo1 = (struct ebt_arp_info *)m1->data;
307	struct ebt_arp_info *arpinfo2 = (struct ebt_arp_info *)m2->data;
308
309	if (arpinfo1->bitmask != arpinfo2->bitmask)
310		return 0;
311	if (arpinfo1->invflags != arpinfo2->invflags)
312		return 0;
313	if (arpinfo1->bitmask & EBT_ARP_OPCODE) {
314		if (arpinfo1->opcode != arpinfo2->opcode)
315			return 0;
316	}
317	if (arpinfo1->bitmask & EBT_ARP_HTYPE) {
318		if (arpinfo1->htype != arpinfo2->htype)
319			return 0;
320	}
321	if (arpinfo1->bitmask & EBT_ARP_PTYPE) {
322		if (arpinfo1->ptype != arpinfo2->ptype)
323			return 0;
324	}
325	if (arpinfo1->bitmask & EBT_ARP_SRC_IP) {
326		if (arpinfo1->saddr != arpinfo2->saddr)
327			return 0;
328		if (arpinfo1->smsk != arpinfo2->smsk)
329			return 0;
330	}
331	if (arpinfo1->bitmask & EBT_ARP_DST_IP) {
332		if (arpinfo1->daddr != arpinfo2->daddr)
333			return 0;
334		if (arpinfo1->dmsk != arpinfo2->dmsk)
335			return 0;
336	}
337	if (arpinfo1->bitmask & EBT_ARP_SRC_MAC) {
338		if (memcmp(arpinfo1->smaddr, arpinfo2->smaddr, ETH_ALEN))
339			return 0;
340		if (memcmp(arpinfo1->smmsk, arpinfo2->smmsk, ETH_ALEN))
341			return 0;
342	}
343	if (arpinfo1->bitmask & EBT_ARP_DST_MAC) {
344		if (memcmp(arpinfo1->dmaddr, arpinfo2->dmaddr, ETH_ALEN))
345			return 0;
346		if (memcmp(arpinfo1->dmmsk, arpinfo2->dmmsk, ETH_ALEN))
347			return 0;
348	}
349	return 1;
350}
351
352static struct ebt_u_match arp_match =
353{
354	.name		= "arp",
355	.size		= sizeof(struct ebt_arp_info),
356	.help		= print_help,
357	.init		= init,
358	.parse		= parse,
359	.final_check	= final_check,
360	.print		= print,
361	.compare	= compare,
362	.extra_ops	= opts,
363};
364
365void _init(void)
366{
367	ebt_register_match(&arp_match);
368}
369