• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  * (C) 2013 by Giuseppe Longo <giuseppelng@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
11  */
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <netdb.h>
17 #include <net/if_arp.h>
18 
19 #include <xtables.h>
20 #include <libiptc/libxtc.h>
21 #include <arpa/inet.h>
22 #include <net/if_arp.h>
23 #include <netinet/if_ether.h>
24 
25 #include <linux/netfilter_arp/arp_tables.h>
26 #include <linux/netfilter/nf_tables.h>
27 
28 #include "nft-shared.h"
29 #include "nft.h"
30 #include "xshared.h"
31 
need_devaddr(struct arpt_devaddr_info * info)32 static bool need_devaddr(struct arpt_devaddr_info *info)
33 {
34 	int i;
35 
36 	for (i = 0; i < ETH_ALEN; i++) {
37 		if (info->addr[i] || info->mask[i])
38 			return true;
39 	}
40 
41 	return false;
42 }
43 
nft_arp_add(struct nft_handle * h,struct nft_rule_ctx * ctx,struct nftnl_rule * r,struct iptables_command_state * cs)44 static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
45 		       struct nftnl_rule *r, struct iptables_command_state *cs)
46 {
47 	struct arpt_entry *fw = &cs->arp;
48 	uint32_t op;
49 	int ret = 0;
50 
51 	if (fw->arp.iniface[0] != '\0') {
52 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
53 		add_iface(h, r, fw->arp.iniface, NFT_META_IIFNAME, op);
54 	}
55 
56 	if (fw->arp.outiface[0] != '\0') {
57 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
58 		add_iface(h, r, fw->arp.outiface, NFT_META_OIFNAME, op);
59 	}
60 
61 	if (fw->arp.arhrd != 0 ||
62 	    fw->arp.arhrd_mask != 0xffff ||
63 	    fw->arp.invflags & IPT_INV_ARPHRD) {
64 		uint8_t reg;
65 
66 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
67 		add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2,
68 			    NFT_PAYLOAD_NETWORK_HEADER, &reg);
69 		if (fw->arp.arhrd_mask != 0xffff)
70 			add_bitwise_u16(h, r, fw->arp.arhrd_mask, 0, reg, &reg);
71 		add_cmp_u16(r, fw->arp.arhrd, op, reg);
72 	}
73 
74 	if (fw->arp.arpro != 0 ||
75 	    fw->arp.arpro_mask != 0xffff ||
76 	    fw->arp.invflags & IPT_INV_PROTO) {
77 		uint8_t reg;
78 
79 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
80 	        add_payload(h, r, offsetof(struct arphdr, ar_pro), 2,
81 			    NFT_PAYLOAD_NETWORK_HEADER, &reg);
82 		if (fw->arp.arpro_mask != 0xffff)
83 			add_bitwise_u16(h, r, fw->arp.arpro_mask, 0, reg, &reg);
84 		add_cmp_u16(r, fw->arp.arpro, op, reg);
85 	}
86 
87 	if (fw->arp.arhln != 0 ||
88 	    fw->arp.arhln_mask != 255 ||
89 	    fw->arp.invflags & IPT_INV_ARPHLN) {
90 		uint8_t reg;
91 
92 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
93 		add_payload(h, r, offsetof(struct arphdr, ar_hln), 1,
94 			    NFT_PAYLOAD_NETWORK_HEADER, &reg);
95 		if (fw->arp.arhln_mask != 255)
96 			add_bitwise(h, r, &fw->arp.arhln_mask, 1, reg, &reg);
97 		add_cmp_u8(r, fw->arp.arhln, op, reg);
98 	}
99 
100 	add_proto(h, r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
101 
102 	if (fw->arp.arpop != 0 ||
103 	    fw->arp.arpop_mask != 0xffff ||
104 	    fw->arp.invflags & IPT_INV_ARPOP) {
105 		uint8_t reg;
106 
107 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
108 		add_payload(h, r, offsetof(struct arphdr, ar_op), 2,
109 			    NFT_PAYLOAD_NETWORK_HEADER, &reg);
110 		if (fw->arp.arpop_mask != 0xffff)
111 			add_bitwise_u16(h, r, fw->arp.arpop_mask, 0, reg, &reg);
112 		add_cmp_u16(r, fw->arp.arpop, op, reg);
113 	}
114 
115 	if (need_devaddr(&fw->arp.src_devaddr)) {
116 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
117 		add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
118 			 sizeof(struct arphdr),
119 			 &fw->arp.src_devaddr.addr,
120 			 &fw->arp.src_devaddr.mask,
121 			 fw->arp.arhln, op);
122 
123 	}
124 
125 	if (fw->arp.src.s_addr != 0 ||
126 	    fw->arp.smsk.s_addr != 0 ||
127 	    fw->arp.invflags & IPT_INV_SRCIP) {
128 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
129 		add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
130 			 sizeof(struct arphdr) + fw->arp.arhln,
131 			 &fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
132 			 sizeof(struct in_addr), op);
133 	}
134 
135 
136 	if (need_devaddr(&fw->arp.tgt_devaddr)) {
137 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
138 		add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
139 			 sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
140 			 &fw->arp.tgt_devaddr.addr,
141 			 &fw->arp.tgt_devaddr.mask,
142 			 fw->arp.arhln, op);
143 	}
144 
145 	if (fw->arp.tgt.s_addr != 0 ||
146 	    fw->arp.tmsk.s_addr != 0 ||
147 	    fw->arp.invflags & IPT_INV_DSTIP) {
148 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
149 		add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
150 			 sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
151 			 &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
152 			 sizeof(struct in_addr), op);
153 	}
154 
155 	/* Counters need to me added before the target, otherwise they are
156 	 * increased for each rule because of the way nf_tables works.
157 	 */
158 	if (add_counters(r, fw->counters.pcnt, fw->counters.bcnt) < 0)
159 		return -1;
160 
161 	if (cs->target != NULL) {
162 		/* Standard target? */
163 		if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
164 			ret = add_verdict(r, NF_ACCEPT);
165 		else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
166 			ret = add_verdict(r, NF_DROP);
167 		else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
168 			ret = add_verdict(r, NFT_RETURN);
169 		else
170 			ret = add_target(r, cs->target->t);
171 	} else if (strlen(cs->jumpto) > 0) {
172 		/* No goto in arptables */
173 		ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
174 	}
175 
176 	return ret;
177 }
178 
nft_arp_print_header(unsigned int format,const char * chain,const char * pol,const struct xt_counters * counters,int refs,uint32_t entries)179 static void nft_arp_print_header(unsigned int format, const char *chain,
180 				 const char *pol,
181 				 const struct xt_counters *counters,
182 				 int refs, uint32_t entries)
183 {
184 	printf("Chain %s", chain);
185 	if (pol) {
186 		printf(" (policy %s", pol);
187 		if (!(format & FMT_NOCOUNTS)) {
188 			fputc(' ', stdout);
189 			xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
190 			fputs("packets, ", stdout);
191 			xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
192 			fputs("bytes", stdout);
193 		}
194 		printf(")\n");
195 	} else {
196 		printf(" (%d references)\n", refs);
197 	}
198 }
199 
print_iface(char letter,const char * iface,unsigned int format,bool invert,const char ** sep)200 static void print_iface(char letter, const char *iface,
201 			unsigned int format, bool invert, const char **sep)
202 {
203 	if (iface[0] == '\0' || (!strcmp(iface, "+") && !invert)) {
204 		if (!(format & FMT_VIA))
205 			return;
206 		iface = (format & FMT_NUMERIC) ? "*" : "any";
207 	}
208 	printf("%s%s-%c %s", *sep, invert ? "! " : "", letter, iface);
209 	*sep = " ";
210 }
211 
nft_arp_print_rule_details(const struct iptables_command_state * cs,unsigned int format)212 static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
213 				       unsigned int format)
214 {
215 	const struct arpt_entry *fw = &cs->arp;
216 	const char *sep = "";
217 	int i;
218 
219 	if (strlen(cs->jumpto)) {
220 		printf("%s-j %s", sep, cs->jumpto);
221 		sep = " ";
222 	}
223 
224 	print_iface('i', fw->arp.iniface, format,
225 		    fw->arp.invflags & IPT_INV_VIA_IN, &sep);
226 	print_iface('o', fw->arp.outiface, format,
227 		    fw->arp.invflags & IPT_INV_VIA_OUT, &sep);
228 
229 	if (fw->arp.smsk.s_addr != 0L) {
230 		printf("%s%s-s %s", sep,
231 		       fw->arp.invflags & IPT_INV_SRCIP ? "! " : "",
232 		       ipv4_addr_to_string(&fw->arp.src,
233 					   &fw->arp.smsk, format));
234 		sep = " ";
235 	}
236 
237 	for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++)
238 		if (fw->arp.src_devaddr.mask[i] != 0)
239 			break;
240 	if (i == ARPT_DEV_ADDR_LEN_MAX)
241 		goto after_devsrc;
242 	printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCDEVADDR
243 		? "! " : "");
244 	printf("--src-mac ");
245 	xtables_print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
246 				   (unsigned char *)fw->arp.src_devaddr.mask);
247 	sep = " ";
248 after_devsrc:
249 
250 	if (fw->arp.tmsk.s_addr != 0L) {
251 		printf("%s%s-d %s", sep,
252 		       fw->arp.invflags & IPT_INV_DSTIP ? "! " : "",
253 		       ipv4_addr_to_string(&fw->arp.tgt,
254 					   &fw->arp.tmsk, format));
255 		sep = " ";
256 	}
257 
258 	for (i = 0; i <ARPT_DEV_ADDR_LEN_MAX; i++)
259 		if (fw->arp.tgt_devaddr.mask[i] != 0)
260 			break;
261 	if (i == ARPT_DEV_ADDR_LEN_MAX)
262 		goto after_devdst;
263 	printf("%s%s", sep, fw->arp.invflags & IPT_INV_TGTDEVADDR
264 		? "! " : "");
265 	printf("--dst-mac ");
266 	xtables_print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
267 				   (unsigned char *)fw->arp.tgt_devaddr.mask);
268 	sep = " ";
269 
270 after_devdst:
271 
272 	if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6 ||
273 	    fw->arp.invflags & IPT_INV_ARPHLN) {
274 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN
275 			? "! " : "");
276 		printf("--h-length %d", fw->arp.arhln);
277 		if (fw->arp.arhln_mask != 255)
278 			printf("/%d", fw->arp.arhln_mask);
279 		sep = " ";
280 	}
281 
282 	if (fw->arp.arpop_mask != 65535 || fw->arp.arpop != 0 ||
283 	    fw->arp.invflags & IPT_INV_ARPOP) {
284 		int tmp = ntohs(fw->arp.arpop);
285 
286 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP
287 			? "! " : "");
288 		if (tmp <= ARP_NUMOPCODES && !(format & FMT_NUMERIC))
289 			printf("--opcode %s", arp_opcodes[tmp-1]);
290 		else
291 			printf("--opcode %d", tmp);
292 
293 		if (fw->arp.arpop_mask != 65535)
294 			printf("/%d", ntohs(fw->arp.arpop_mask));
295 		sep = " ";
296 	}
297 
298 	if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1) ||
299 	    fw->arp.invflags & IPT_INV_ARPHRD) {
300 		uint16_t tmp = ntohs(fw->arp.arhrd);
301 
302 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD
303 			? "! " : "");
304 		if (tmp == 1 && !(format & FMT_NUMERIC))
305 			printf("--h-type %s", "Ethernet");
306 		else
307 			printf("--h-type 0x%x", tmp);
308 		if (fw->arp.arhrd_mask != 65535)
309 			printf("/0x%x", ntohs(fw->arp.arhrd_mask));
310 		sep = " ";
311 	}
312 
313 	if (fw->arp.arpro_mask != 65535 || fw->arp.arpro != 0 ||
314 	    fw->arp.invflags & IPT_INV_PROTO) {
315 		int tmp = ntohs(fw->arp.arpro);
316 
317 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_PROTO
318 			? "! " : "");
319 		if (tmp == 0x0800 && !(format & FMT_NUMERIC))
320 			printf("--proto-type %s", "IPv4");
321 		else
322 			printf("--proto-type 0x%x", tmp);
323 		if (fw->arp.arpro_mask != 65535)
324 			printf("/0x%x", ntohs(fw->arp.arpro_mask));
325 		sep = " ";
326 	}
327 }
328 
329 static void
nft_arp_save_rule(const struct iptables_command_state * cs,unsigned int format)330 nft_arp_save_rule(const struct iptables_command_state *cs, unsigned int format)
331 {
332 	format |= FMT_NUMERIC;
333 
334 	printf(" ");
335 	nft_arp_print_rule_details(cs, format);
336 	if (cs->target && cs->target->save)
337 		cs->target->save(&cs->fw, cs->target->t);
338 	printf("\n");
339 }
340 
341 static void nft_arp_init_cs(struct iptables_command_state *cs);
342 
343 static void
nft_arp_print_rule(struct nft_handle * h,struct nftnl_rule * r,unsigned int num,unsigned int format)344 nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r,
345 		   unsigned int num, unsigned int format)
346 {
347 	struct iptables_command_state cs = {};
348 
349 	if (format & FMT_LINENUMBERS)
350 		printf("%u ", num);
351 
352 	nft_arp_init_cs(&cs);
353 	nft_rule_to_iptables_command_state(h, r, &cs);
354 
355 	nft_arp_print_rule_details(&cs, format);
356 	print_matches_and_target(&cs, format);
357 
358 	if (!(format & FMT_NOCOUNTS)) {
359 		printf(" , pcnt=");
360 		xtables_print_num(cs.counters.pcnt, format | FMT_NOTABLE);
361 		printf("-- bcnt=");
362 		xtables_print_num(cs.counters.bcnt, format | FMT_NOTABLE);
363 	}
364 
365 	if (!(format & FMT_NONEWLINE))
366 		fputc('\n', stdout);
367 
368 	xtables_clear_iptables_command_state(&cs);
369 }
370 
nft_arp_is_same(const struct iptables_command_state * cs_a,const struct iptables_command_state * cs_b)371 static bool nft_arp_is_same(const struct iptables_command_state *cs_a,
372 			    const struct iptables_command_state *cs_b)
373 {
374 	const struct arpt_entry *a = &cs_a->arp;
375 	const struct arpt_entry *b = &cs_b->arp;
376 
377 	if (a->arp.src.s_addr != b->arp.src.s_addr
378 	    || a->arp.tgt.s_addr != b->arp.tgt.s_addr
379 	    || a->arp.smsk.s_addr != b->arp.smsk.s_addr
380 	    || a->arp.tmsk.s_addr != b->arp.tmsk.s_addr
381 	    || a->arp.arpro != b->arp.arpro
382 	    || a->arp.flags != b->arp.flags
383 	    || a->arp.invflags != b->arp.invflags) {
384 		DEBUGP("different src/dst/proto/flags/invflags\n");
385 		return false;
386 	}
387 
388 	return is_same_interfaces(a->arp.iniface,
389 				  a->arp.outiface,
390 				  (unsigned char *)a->arp.iniface_mask,
391 				  (unsigned char *)a->arp.outiface_mask,
392 				  b->arp.iniface,
393 				  b->arp.outiface,
394 				  (unsigned char *)b->arp.iniface_mask,
395 				  (unsigned char *)b->arp.outiface_mask);
396 }
397 
nft_arp_save_chain(const struct nftnl_chain * c,const char * policy)398 static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
399 {
400 	const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
401 
402 	printf(":%s %s\n", chain, policy ?: "-");
403 }
404 
getlength_and_mask(const char * from,uint8_t * to,uint8_t * mask)405 static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask)
406 {
407 	char *dup = strdup(from);
408 	char *p, *buffer;
409 	int i, ret = -1;
410 
411 	if (!dup)
412 		return -1;
413 
414 	if ( (p = strrchr(dup, '/')) != NULL) {
415 		*p = '\0';
416 		i = strtol(p+1, &buffer, 10);
417 		if (*buffer != '\0' || i < 0 || i > 255)
418 			goto out_err;
419 		*mask = (uint8_t)i;
420 	} else
421 		*mask = 255;
422 	i = strtol(dup, &buffer, 10);
423 	if (*buffer != '\0' || i < 0 || i > 255)
424 		goto out_err;
425 	*to = (uint8_t)i;
426 	ret = 0;
427 out_err:
428 	free(dup);
429 	return ret;
430 
431 }
432 
get16_and_mask(const char * from,uint16_t * to,uint16_t * mask,int base)433 static int get16_and_mask(const char *from, uint16_t *to,
434 			  uint16_t *mask, int base)
435 {
436 	char *dup = strdup(from);
437 	char *p, *buffer;
438 	int i, ret = -1;
439 
440 	if (!dup)
441 		return -1;
442 
443 	if ( (p = strrchr(dup, '/')) != NULL) {
444 		*p = '\0';
445 		i = strtol(p+1, &buffer, base);
446 		if (*buffer != '\0' || i < 0 || i > 65535)
447 			goto out_err;
448 		*mask = htons((uint16_t)i);
449 	} else
450 		*mask = 65535;
451 	i = strtol(dup, &buffer, base);
452 	if (*buffer != '\0' || i < 0 || i > 65535)
453 		goto out_err;
454 	*to = htons((uint16_t)i);
455 	ret = 0;
456 out_err:
457 	free(dup);
458 	return ret;
459 }
460 
nft_arp_post_parse(int command,struct iptables_command_state * cs,struct xtables_args * args)461 static void nft_arp_post_parse(int command,
462 			       struct iptables_command_state *cs,
463 			       struct xtables_args *args)
464 {
465 	cs->arp.arp.invflags = args->invflags;
466 
467 	memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ);
468 	memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ);
469 
470 	memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ);
471 	memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ);
472 
473 	cs->arp.counters.pcnt = args->pcnt_cnt;
474 	cs->arp.counters.bcnt = args->bcnt_cnt;
475 
476 	if (command & (CMD_REPLACE | CMD_INSERT |
477 			CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
478 		if (!(cs->options & OPT_DESTINATION))
479 			args->dhostnetworkmask = "0.0.0.0/0";
480 		if (!(cs->options & OPT_SOURCE))
481 			args->shostnetworkmask = "0.0.0.0/0";
482 	}
483 
484 	if (args->shostnetworkmask)
485 		xtables_ipparse_multiple(args->shostnetworkmask,
486 					 &args->s.addr.v4, &args->s.mask.v4,
487 					 &args->s.naddrs);
488 	if (args->dhostnetworkmask)
489 		xtables_ipparse_multiple(args->dhostnetworkmask,
490 					 &args->d.addr.v4, &args->d.mask.v4,
491 					 &args->d.naddrs);
492 
493 	if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
494 	    (cs->arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
495 		xtables_error(PARAMETER_PROBLEM,
496 			      "! not allowed with multiple"
497 			      " source or destination IP addresses");
498 
499 	if (args->src_mac &&
500 	    xtables_parse_mac_and_mask(args->src_mac,
501 				       cs->arp.arp.src_devaddr.addr,
502 				       cs->arp.arp.src_devaddr.mask))
503 		xtables_error(PARAMETER_PROBLEM,
504 			      "Problem with specified source mac");
505 	if (args->dst_mac &&
506 	    xtables_parse_mac_and_mask(args->dst_mac,
507 				       cs->arp.arp.tgt_devaddr.addr,
508 				       cs->arp.arp.tgt_devaddr.mask))
509 		xtables_error(PARAMETER_PROBLEM,
510 			      "Problem with specified destination mac");
511 	if (args->arp_hlen) {
512 		getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln,
513 				   &cs->arp.arp.arhln_mask);
514 
515 		if (cs->arp.arp.arhln != 6)
516 			xtables_error(PARAMETER_PROBLEM,
517 				      "Only hardware address length of 6 is supported currently.");
518 	}
519 	if (args->arp_opcode) {
520 		if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop,
521 				   &cs->arp.arp.arpop_mask, 10)) {
522 			int i;
523 
524 			for (i = 0; i < ARP_NUMOPCODES; i++)
525 				if (!strcasecmp(arp_opcodes[i],
526 						args->arp_opcode))
527 					break;
528 			if (i == ARP_NUMOPCODES)
529 				xtables_error(PARAMETER_PROBLEM,
530 					      "Problem with specified opcode");
531 			cs->arp.arp.arpop = htons(i+1);
532 		}
533 	}
534 	if (args->arp_htype) {
535 		if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd,
536 				   &cs->arp.arp.arhrd_mask, 16)) {
537 			if (strcasecmp(args->arp_htype, "Ethernet"))
538 				xtables_error(PARAMETER_PROBLEM,
539 					      "Problem with specified hardware type");
540 			cs->arp.arp.arhrd = htons(1);
541 		}
542 	}
543 	if (args->arp_ptype) {
544 		if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro,
545 				   &cs->arp.arp.arpro_mask, 0)) {
546 			if (strcasecmp(args->arp_ptype, "ipv4"))
547 				xtables_error(PARAMETER_PROBLEM,
548 					      "Problem with specified protocol type");
549 			cs->arp.arp.arpro = htons(0x800);
550 		}
551 	}
552 }
553 
nft_arp_init_cs(struct iptables_command_state * cs)554 static void nft_arp_init_cs(struct iptables_command_state *cs)
555 {
556 	cs->arp.arp.arhln = 6;
557 	cs->arp.arp.arhln_mask = 255;
558 	cs->arp.arp.arhrd = htons(ARPHRD_ETHER);
559 	cs->arp.arp.arhrd_mask = 65535;
560 	cs->arp.arp.arpop_mask = 65535;
561 	cs->arp.arp.arpro_mask = 65535;
562 }
563 
564 static int
nft_arp_add_entry(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,struct xtables_args * args,bool verbose,bool append,int rulenum)565 nft_arp_add_entry(struct nft_handle *h,
566 		  const char *chain, const char *table,
567 		  struct iptables_command_state *cs,
568 		  struct xtables_args *args, bool verbose,
569 		  bool append, int rulenum)
570 {
571 	unsigned int i, j;
572 	int ret = 1;
573 
574 	for (i = 0; i < args->s.naddrs; i++) {
575 		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
576 		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
577 		for (j = 0; j < args->d.naddrs; j++) {
578 			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
579 			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
580 			if (append) {
581 				ret = nft_cmd_rule_append(h, chain, table, cs,
582 						          verbose);
583 			} else {
584 				ret = nft_cmd_rule_insert(h, chain, table, cs,
585 						          rulenum, verbose);
586 			}
587 		}
588 	}
589 
590 	return ret;
591 }
592 
593 static int
nft_arp_delete_entry(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,struct xtables_args * args,bool verbose)594 nft_arp_delete_entry(struct nft_handle *h,
595 		     const char *chain, const char *table,
596 		     struct iptables_command_state *cs,
597 		     struct xtables_args *args, bool verbose)
598 {
599 	unsigned int i, j;
600 	int ret = 1;
601 
602 	for (i = 0; i < args->s.naddrs; i++) {
603 		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
604 		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
605 		for (j = 0; j < args->d.naddrs; j++) {
606 			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
607 			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
608 			ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
609 		}
610 	}
611 
612 	return ret;
613 }
614 
615 static int
nft_arp_check_entry(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,struct xtables_args * args,bool verbose)616 nft_arp_check_entry(struct nft_handle *h,
617 		    const char *chain, const char *table,
618 		    struct iptables_command_state *cs,
619 		    struct xtables_args *args, bool verbose)
620 {
621 	unsigned int i, j;
622 	int ret = 1;
623 
624 	for (i = 0; i < args->s.naddrs; i++) {
625 		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
626 		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
627 		for (j = 0; j < args->d.naddrs; j++) {
628 			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
629 			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
630 			ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
631 		}
632 	}
633 
634 	return ret;
635 }
636 
637 static int
nft_arp_replace_entry(struct nft_handle * h,const char * chain,const char * table,struct iptables_command_state * cs,struct xtables_args * args,bool verbose,int rulenum)638 nft_arp_replace_entry(struct nft_handle *h,
639 		      const char *chain, const char *table,
640 		      struct iptables_command_state *cs,
641 		      struct xtables_args *args, bool verbose,
642 		      int rulenum)
643 {
644 	cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr;
645 	cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr;
646 	cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr;
647 	cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr;
648 
649 	return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
650 }
651 
nft_arp_xlate_mac_and_mask(const struct arpt_devaddr_info * devaddr,const char * addr,bool invert,struct xt_xlate * xl)652 static void nft_arp_xlate_mac_and_mask(const struct arpt_devaddr_info *devaddr,
653 				       const char *addr,
654 				       bool invert,
655 				       struct xt_xlate *xl)
656 {
657 	unsigned int i;
658 
659 	for (i = 0; i < 6; ++i) {
660 		if (devaddr->mask[i])
661 			break;
662 	}
663 
664 	if (i == 6)
665 		return;
666 
667 	xt_xlate_add(xl, "arp %s ether ", addr);
668 	if (invert)
669 		xt_xlate_add(xl, "!= ");
670 
671 	xt_xlate_add(xl, "%02x", (uint8_t)devaddr->addr[0]);
672 	for (i = 1; i < 6; ++i)
673 		xt_xlate_add(xl, ":%02x", (uint8_t)devaddr->addr[i]);
674 
675 	for (i = 0; i < 6; ++i) {
676 		int j;
677 
678 		if ((uint8_t)devaddr->mask[i] == 0xff)
679 			continue;
680 
681 		xt_xlate_add(xl, "/%02x", (uint8_t)devaddr->mask[0]);
682 
683 		for (j = 1; j < 6; ++j)
684 			xt_xlate_add(xl, ":%02x", (uint8_t)devaddr->mask[j]);
685 		return;
686 	}
687 }
688 
nft_arp_xlate16(uint16_t v,uint16_t m,const char * what,bool hex,bool inverse,struct xt_xlate * xl)689 static void nft_arp_xlate16(uint16_t v, uint16_t m, const char *what,
690 			    bool hex, bool inverse,
691 			    struct xt_xlate *xl)
692 {
693 	const char *fmt = hex ? "0x%x " : "%d ";
694 
695 	if (m) {
696 		xt_xlate_add(xl, "arp %s ", what);
697 		if (inverse)
698 			xt_xlate_add(xl, " !=");
699 		if (m != 0xffff) {
700 			xt_xlate_add(xl, "& ");
701 			xt_xlate_add(xl, fmt, ntohs(m));;
702 
703 		}
704 		xt_xlate_add(xl, fmt, ntohs(v));
705 	}
706 }
707 
nft_arp_xlate_ipv4_addr(const char * what,const struct in_addr * addr,const struct in_addr * mask,bool inv,struct xt_xlate * xl)708 static void nft_arp_xlate_ipv4_addr(const char *what, const struct in_addr *addr,
709 				    const struct in_addr *mask,
710 				    bool inv, struct xt_xlate *xl)
711 {
712 	char mbuf[INET_ADDRSTRLEN], abuf[INET_ADDRSTRLEN];
713 	const char *op = inv ? "!= " : "";
714 	int cidr;
715 
716 	if (!inv && !addr->s_addr && !mask->s_addr)
717 		return;
718 
719 	inet_ntop(AF_INET, addr, abuf, sizeof(abuf));
720 
721 	cidr = xtables_ipmask_to_cidr(mask);
722 	switch (cidr) {
723 	case -1:
724 		xt_xlate_add(xl, "arp %s ip & %s %s %s ", what,
725 			     inet_ntop(AF_INET, mask, mbuf, sizeof(mbuf)),
726 			     inv ? "!=" : "==", abuf);
727 		break;
728 	case 32:
729 		xt_xlate_add(xl, "arp %s ip %s%s ", what, op, abuf);
730 		break;
731 	default:
732 		xt_xlate_add(xl, "arp %s ip %s%s/%d ", what, op, abuf, cidr);
733 	}
734 }
735 
nft_arp_xlate(const struct iptables_command_state * cs,struct xt_xlate * xl)736 static int nft_arp_xlate(const struct iptables_command_state *cs,
737 			 struct xt_xlate *xl)
738 {
739 	const struct arpt_entry *fw = &cs->arp;
740 	int ret;
741 
742 	xlate_ifname(xl, "iifname", fw->arp.iniface,
743 		     fw->arp.invflags & IPT_INV_VIA_IN);
744 	xlate_ifname(xl, "oifname", fw->arp.outiface,
745 		     fw->arp.invflags & IPT_INV_VIA_OUT);
746 
747 	if (fw->arp.arhrd ||
748 	    fw->arp.arhrd_mask != 0xffff ||
749 	    fw->arp.invflags & IPT_INV_ARPHRD)
750 		nft_arp_xlate16(fw->arp.arhrd, fw->arp.arhrd_mask,
751 				"htype", false,
752 				 fw->arp.invflags & IPT_INV_ARPHRD, xl);
753 
754 	if (fw->arp.arhln_mask != 255 || fw->arp.arhln ||
755 	    fw->arp.invflags & IPT_INV_ARPHLN) {
756 		xt_xlate_add(xl, "arp hlen ");
757 		if (fw->arp.invflags & IPT_INV_ARPHLN)
758 			xt_xlate_add(xl, " !=");
759 		if (fw->arp.arhln_mask != 255)
760 			xt_xlate_add(xl, "& %d ", fw->arp.arhln_mask);
761 		xt_xlate_add(xl, "%d ", fw->arp.arhln);
762 	}
763 
764 	/* added implicitly by arptables-nft */
765 	xt_xlate_add(xl, "arp plen %d", 4);
766 
767 	if (fw->arp.arpop_mask != 65535 ||
768 	    fw->arp.arpop != 0 ||
769 	    fw->arp.invflags & IPT_INV_ARPOP)
770 		nft_arp_xlate16(fw->arp.arpop, fw->arp.arpop_mask,
771 				"operation", false,
772 				fw->arp.invflags & IPT_INV_ARPOP, xl);
773 
774 	if (fw->arp.arpro_mask != 65535 ||
775 	    fw->arp.invflags & IPT_INV_PROTO ||
776 	    fw->arp.arpro)
777 		nft_arp_xlate16(fw->arp.arpro, fw->arp.arpro_mask,
778 				"ptype", true,
779 				fw->arp.invflags & IPT_INV_PROTO, xl);
780 
781 	if (fw->arp.smsk.s_addr != 0L)
782 		nft_arp_xlate_ipv4_addr("saddr", &fw->arp.src, &fw->arp.smsk,
783 					fw->arp.invflags & IPT_INV_SRCIP, xl);
784 
785 	if (fw->arp.tmsk.s_addr != 0L)
786 		nft_arp_xlate_ipv4_addr("daddr", &fw->arp.tgt, &fw->arp.tmsk,
787 					fw->arp.invflags & IPT_INV_DSTIP, xl);
788 
789 	nft_arp_xlate_mac_and_mask(&fw->arp.src_devaddr, "saddr",
790 				   fw->arp.invflags & IPT_INV_SRCDEVADDR, xl);
791 	nft_arp_xlate_mac_and_mask(&fw->arp.tgt_devaddr, "daddr",
792 				   fw->arp.invflags & IPT_INV_TGTDEVADDR, xl);
793 
794 	ret = xlate_matches(cs, xl);
795 	if (!ret)
796 		return ret;
797 
798 	/* Always add counters per rule, as in iptables */
799 	xt_xlate_add(xl, "counter");
800 	return xlate_action(cs, false, xl);
801 }
802 
nft_arp_option_name(int option)803 static const char *nft_arp_option_name(int option)
804 {
805 	switch (option) {
806 	default:		return ip46t_option_name(option);
807 	/* different name than iptables */
808 	case OPT_SOURCE:	return "--source-ip";
809 	case OPT_DESTINATION:	return "--destination-ip";
810 	/* arptables specific ones */
811 	case OPT_S_MAC:		return "--source-mac";
812 	case OPT_D_MAC:		return "--destination-mac";
813 	case OPT_H_LENGTH:	return "--h-length";
814 	case OPT_OPCODE:	return "--opcode";
815 	case OPT_H_TYPE:	return "--h-type";
816 	case OPT_P_TYPE:	return "--proto-type";
817 	}
818 }
819 
nft_arp_option_invert(int option)820 static int nft_arp_option_invert(int option)
821 {
822 	switch (option) {
823 	case OPT_S_MAC:		return IPT_INV_SRCDEVADDR;
824 	case OPT_D_MAC:		return IPT_INV_TGTDEVADDR;
825 	case OPT_H_LENGTH:	return IPT_INV_ARPHLN;
826 	case OPT_OPCODE:	return IPT_INV_ARPOP;
827 	case OPT_H_TYPE:	return IPT_INV_ARPHRD;
828 	case OPT_P_TYPE:	return IPT_INV_PROTO;
829 	default:		return ip46t_option_invert(option);
830 	}
831 }
832 
833 struct nft_family_ops nft_family_ops_arp = {
834 	.add			= nft_arp_add,
835 	.is_same		= nft_arp_is_same,
836 	.print_payload		= NULL,
837 	.print_header		= nft_arp_print_header,
838 	.print_rule		= nft_arp_print_rule,
839 	.save_rule		= nft_arp_save_rule,
840 	.save_chain		= nft_arp_save_chain,
841 	.rule_parse		= &nft_ruleparse_ops_arp,
842 	.cmd_parse		= {
843 		.post_parse	= nft_arp_post_parse,
844 		.option_name	= nft_arp_option_name,
845 		.option_invert	= nft_arp_option_invert,
846 		.command_default = command_default,
847 		.print_help	= xtables_printhelp,
848 	},
849 	.rule_to_cs		= nft_rule_to_iptables_command_state,
850 	.init_cs		= nft_arp_init_cs,
851 	.clear_cs		= xtables_clear_iptables_command_state,
852 	.xlate			= nft_arp_xlate,
853 	.add_entry		= nft_arp_add_entry,
854 	.delete_entry		= nft_arp_delete_entry,
855 	.check_entry		= nft_arp_check_entry,
856 	.replace_entry		= nft_arp_replace_entry,
857 };
858