xref: /aosp_15_r20/external/iptables/iptables/nft-arp.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 /*
2  * (C) 2013 by Pablo Neira Ayuso <[email protected]>
3  * (C) 2013 by Giuseppe Longo <[email protected]>
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 <net/if_arp.h>
22 #include <netinet/if_ether.h>
23 
24 #include <linux/netfilter_arp/arp_tables.h>
25 #include <linux/netfilter/nf_tables.h>
26 
27 #include "nft-shared.h"
28 #include "nft.h"
29 #include "xshared.h"
30 
need_devaddr(struct arpt_devaddr_info * info)31 static bool need_devaddr(struct arpt_devaddr_info *info)
32 {
33 	int i;
34 
35 	for (i = 0; i < ETH_ALEN; i++) {
36 		if (info->addr[i] || info->mask[i])
37 			return true;
38 	}
39 
40 	return false;
41 }
42 
nft_arp_add(struct nft_handle * h,struct nft_rule_ctx * ctx,struct nftnl_rule * r,struct iptables_command_state * cs)43 static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
44 		       struct nftnl_rule *r, struct iptables_command_state *cs)
45 {
46 	struct arpt_entry *fw = &cs->arp;
47 	uint32_t op;
48 	int ret = 0;
49 
50 	if (fw->arp.iniface[0] != '\0') {
51 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
52 		add_iface(h, r, fw->arp.iniface, NFT_META_IIFNAME, op);
53 	}
54 
55 	if (fw->arp.outiface[0] != '\0') {
56 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
57 		add_iface(h, r, fw->arp.outiface, NFT_META_OIFNAME, op);
58 	}
59 
60 	if (fw->arp.arhrd != 0 ||
61 	    fw->arp.invflags & IPT_INV_ARPHRD) {
62 		uint8_t reg;
63 
64 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
65 		add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2,
66 			    NFT_PAYLOAD_NETWORK_HEADER, &reg);
67 		add_cmp_u16(r, fw->arp.arhrd, op, reg);
68 	}
69 
70 	if (fw->arp.arpro != 0 ||
71 	    fw->arp.invflags & IPT_INV_PROTO) {
72 		uint8_t reg;
73 
74 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
75 	        add_payload(h, r, offsetof(struct arphdr, ar_pro), 2,
76 			    NFT_PAYLOAD_NETWORK_HEADER, &reg);
77 		add_cmp_u16(r, fw->arp.arpro, op, reg);
78 	}
79 
80 	if (fw->arp.arhln != 0 ||
81 	    fw->arp.invflags & IPT_INV_ARPHLN) {
82 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
83 		add_proto(h, r, offsetof(struct arphdr, ar_hln), 1,
84 			  fw->arp.arhln, op);
85 	}
86 
87 	add_proto(h, r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
88 
89 	if (fw->arp.arpop != 0 ||
90 	    fw->arp.invflags & IPT_INV_ARPOP) {
91 		uint8_t reg;
92 
93 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
94 		add_payload(h, r, offsetof(struct arphdr, ar_op), 2,
95 			    NFT_PAYLOAD_NETWORK_HEADER, &reg);
96 		add_cmp_u16(r, fw->arp.arpop, op, reg);
97 	}
98 
99 	if (need_devaddr(&fw->arp.src_devaddr)) {
100 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
101 		add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
102 			 sizeof(struct arphdr),
103 			 &fw->arp.src_devaddr.addr,
104 			 &fw->arp.src_devaddr.mask,
105 			 fw->arp.arhln, op);
106 
107 	}
108 
109 	if (fw->arp.src.s_addr != 0 ||
110 	    fw->arp.smsk.s_addr != 0 ||
111 	    fw->arp.invflags & IPT_INV_SRCIP) {
112 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
113 		add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
114 			 sizeof(struct arphdr) + fw->arp.arhln,
115 			 &fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
116 			 sizeof(struct in_addr), op);
117 	}
118 
119 
120 	if (need_devaddr(&fw->arp.tgt_devaddr)) {
121 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
122 		add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
123 			 sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
124 			 &fw->arp.tgt_devaddr.addr,
125 			 &fw->arp.tgt_devaddr.mask,
126 			 fw->arp.arhln, op);
127 	}
128 
129 	if (fw->arp.tgt.s_addr != 0 ||
130 	    fw->arp.tmsk.s_addr != 0 ||
131 	    fw->arp.invflags & IPT_INV_DSTIP) {
132 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
133 		add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
134 			 sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
135 			 &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
136 			 sizeof(struct in_addr), op);
137 	}
138 
139 	/* Counters need to me added before the target, otherwise they are
140 	 * increased for each rule because of the way nf_tables works.
141 	 */
142 	if (add_counters(r, fw->counters.pcnt, fw->counters.bcnt) < 0)
143 		return -1;
144 
145 	if (cs->target != NULL) {
146 		/* Standard target? */
147 		if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
148 			ret = add_verdict(r, NF_ACCEPT);
149 		else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
150 			ret = add_verdict(r, NF_DROP);
151 		else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
152 			ret = add_verdict(r, NFT_RETURN);
153 		else
154 			ret = add_target(r, cs->target->t);
155 	} else if (strlen(cs->jumpto) > 0) {
156 		/* No goto in arptables */
157 		ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
158 	}
159 
160 	return ret;
161 }
162 
nft_arp_print_header(unsigned int format,const char * chain,const char * pol,const struct xt_counters * counters,int refs,uint32_t entries)163 static void nft_arp_print_header(unsigned int format, const char *chain,
164 				 const char *pol,
165 				 const struct xt_counters *counters,
166 				 int refs, uint32_t entries)
167 {
168 	printf("Chain %s", chain);
169 	if (pol) {
170 		printf(" (policy %s", pol);
171 		if (!(format & FMT_NOCOUNTS)) {
172 			fputc(' ', stdout);
173 			xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
174 			fputs("packets, ", stdout);
175 			xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
176 			fputs("bytes", stdout);
177 		}
178 		printf(")\n");
179 	} else {
180 		printf(" (%d references)\n", refs);
181 	}
182 }
183 
nft_arp_print_rule_details(const struct iptables_command_state * cs,unsigned int format)184 static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
185 				       unsigned int format)
186 {
187 	const struct arpt_entry *fw = &cs->arp;
188 	char iface[IFNAMSIZ+2];
189 	const char *sep = "";
190 	int print_iface = 0;
191 	int i;
192 
193 	if (strlen(cs->jumpto)) {
194 		printf("%s-j %s", sep, cs->jumpto);
195 		sep = " ";
196 	}
197 
198 	iface[0] = '\0';
199 
200 	if (fw->arp.iniface[0] != '\0') {
201 		strcat(iface, fw->arp.iniface);
202 		print_iface = 1;
203 	}
204 	else if (format & FMT_VIA) {
205 		print_iface = 1;
206 		if (format & FMT_NUMERIC) strcat(iface, "*");
207 		else strcat(iface, "any");
208 	}
209 	if (print_iface) {
210 		printf("%s%s-i %s", sep, fw->arp.invflags & IPT_INV_VIA_IN ?
211 				   "! " : "", iface);
212 		sep = " ";
213 	}
214 
215 	print_iface = 0;
216 	iface[0] = '\0';
217 
218 	if (fw->arp.outiface[0] != '\0') {
219 		strcat(iface, fw->arp.outiface);
220 		print_iface = 1;
221 	}
222 	else if (format & FMT_VIA) {
223 		print_iface = 1;
224 		if (format & FMT_NUMERIC) strcat(iface, "*");
225 		else strcat(iface, "any");
226 	}
227 	if (print_iface) {
228 		printf("%s%s-o %s", sep, fw->arp.invflags & IPT_INV_VIA_OUT ?
229 				   "! " : "", iface);
230 		sep = " ";
231 	}
232 
233 	if (fw->arp.smsk.s_addr != 0L) {
234 		printf("%s%s-s %s", sep,
235 		       fw->arp.invflags & IPT_INV_SRCIP ? "! " : "",
236 		       ipv4_addr_to_string(&fw->arp.src,
237 					   &fw->arp.smsk, format));
238 		sep = " ";
239 	}
240 
241 	for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++)
242 		if (fw->arp.src_devaddr.mask[i] != 0)
243 			break;
244 	if (i == ARPT_DEV_ADDR_LEN_MAX)
245 		goto after_devsrc;
246 	printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCDEVADDR
247 		? "! " : "");
248 	printf("--src-mac ");
249 	xtables_print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
250 				   (unsigned char *)fw->arp.src_devaddr.mask);
251 	sep = " ";
252 after_devsrc:
253 
254 	if (fw->arp.tmsk.s_addr != 0L) {
255 		printf("%s%s-d %s", sep,
256 		       fw->arp.invflags & IPT_INV_DSTIP ? "! " : "",
257 		       ipv4_addr_to_string(&fw->arp.tgt,
258 					   &fw->arp.tmsk, format));
259 		sep = " ";
260 	}
261 
262 	for (i = 0; i <ARPT_DEV_ADDR_LEN_MAX; i++)
263 		if (fw->arp.tgt_devaddr.mask[i] != 0)
264 			break;
265 	if (i == ARPT_DEV_ADDR_LEN_MAX)
266 		goto after_devdst;
267 	printf("%s%s", sep, fw->arp.invflags & IPT_INV_TGTDEVADDR
268 		? "! " : "");
269 	printf("--dst-mac ");
270 	xtables_print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
271 				   (unsigned char *)fw->arp.tgt_devaddr.mask);
272 	sep = " ";
273 
274 after_devdst:
275 
276 	if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6 ||
277 	    fw->arp.invflags & IPT_INV_ARPHLN) {
278 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN
279 			? "! " : "");
280 		printf("--h-length %d", fw->arp.arhln);
281 		if (fw->arp.arhln_mask != 255)
282 			printf("/%d", fw->arp.arhln_mask);
283 		sep = " ";
284 	}
285 
286 	if (fw->arp.arpop_mask != 0) {
287 		int tmp = ntohs(fw->arp.arpop);
288 
289 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP
290 			? "! " : "");
291 		if (tmp <= ARP_NUMOPCODES && !(format & FMT_NUMERIC))
292 			printf("--opcode %s", arp_opcodes[tmp-1]);
293 		else
294 			printf("--opcode %d", tmp);
295 
296 		if (fw->arp.arpop_mask != 65535)
297 			printf("/%d", ntohs(fw->arp.arpop_mask));
298 		sep = " ";
299 	}
300 
301 	if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1) ||
302 	    fw->arp.invflags & IPT_INV_ARPHRD) {
303 		uint16_t tmp = ntohs(fw->arp.arhrd);
304 
305 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD
306 			? "! " : "");
307 		if (tmp == 1 && !(format & FMT_NUMERIC))
308 			printf("--h-type %s", "Ethernet");
309 		else
310 			printf("--h-type %u", tmp);
311 		if (fw->arp.arhrd_mask != 65535)
312 			printf("/%d", ntohs(fw->arp.arhrd_mask));
313 		sep = " ";
314 	}
315 
316 	if (fw->arp.arpro_mask != 0) {
317 		int tmp = ntohs(fw->arp.arpro);
318 
319 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_PROTO
320 			? "! " : "");
321 		if (tmp == 0x0800 && !(format & FMT_NUMERIC))
322 			printf("--proto-type %s", "IPv4");
323 		else
324 			printf("--proto-type 0x%x", tmp);
325 		if (fw->arp.arpro_mask != 65535)
326 			printf("/%x", ntohs(fw->arp.arpro_mask));
327 		sep = " ";
328 	}
329 }
330 
331 static void
nft_arp_save_rule(const struct iptables_command_state * cs,unsigned int format)332 nft_arp_save_rule(const struct iptables_command_state *cs, unsigned int format)
333 {
334 	format |= FMT_NUMERIC;
335 
336 	printf(" ");
337 	nft_arp_print_rule_details(cs, format);
338 	if (cs->target && cs->target->save)
339 		cs->target->save(&cs->fw, cs->target->t);
340 	printf("\n");
341 }
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_rule_to_iptables_command_state(h, r, &cs);
353 
354 	nft_arp_print_rule_details(&cs, format);
355 	print_matches_and_target(&cs, format);
356 
357 	if (!(format & FMT_NOCOUNTS)) {
358 		printf(" , pcnt=");
359 		xtables_print_num(cs.counters.pcnt, format | FMT_NOTABLE);
360 		printf("-- bcnt=");
361 		xtables_print_num(cs.counters.bcnt, format | FMT_NOTABLE);
362 	}
363 
364 	if (!(format & FMT_NONEWLINE))
365 		fputc('\n', stdout);
366 
367 	xtables_clear_iptables_command_state(&cs);
368 }
369 
nft_arp_is_same(const struct iptables_command_state * cs_a,const struct iptables_command_state * cs_b)370 static bool nft_arp_is_same(const struct iptables_command_state *cs_a,
371 			    const struct iptables_command_state *cs_b)
372 {
373 	const struct arpt_entry *a = &cs_a->arp;
374 	const struct arpt_entry *b = &cs_b->arp;
375 
376 	if (a->arp.src.s_addr != b->arp.src.s_addr
377 	    || a->arp.tgt.s_addr != b->arp.tgt.s_addr
378 	    || a->arp.smsk.s_addr != b->arp.smsk.s_addr
379 	    || a->arp.tmsk.s_addr != b->arp.tmsk.s_addr
380 	    || a->arp.arpro != b->arp.arpro
381 	    || a->arp.flags != b->arp.flags
382 	    || a->arp.invflags != b->arp.invflags) {
383 		DEBUGP("different src/dst/proto/flags/invflags\n");
384 		return false;
385 	}
386 
387 	return is_same_interfaces(a->arp.iniface,
388 				  a->arp.outiface,
389 				  (unsigned char *)a->arp.iniface_mask,
390 				  (unsigned char *)a->arp.outiface_mask,
391 				  b->arp.iniface,
392 				  b->arp.outiface,
393 				  (unsigned char *)b->arp.iniface_mask,
394 				  (unsigned char *)b->arp.outiface_mask);
395 }
396 
nft_arp_save_chain(const struct nftnl_chain * c,const char * policy)397 static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
398 {
399 	const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
400 
401 	printf(":%s %s\n", chain, policy ?: "-");
402 }
403 
getlength_and_mask(const char * from,uint8_t * to,uint8_t * mask)404 static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask)
405 {
406 	char *dup = strdup(from);
407 	char *p, *buffer;
408 	int i, ret = -1;
409 
410 	if (!dup)
411 		return -1;
412 
413 	if ( (p = strrchr(dup, '/')) != NULL) {
414 		*p = '\0';
415 		i = strtol(p+1, &buffer, 10);
416 		if (*buffer != '\0' || i < 0 || i > 255)
417 			goto out_err;
418 		*mask = (uint8_t)i;
419 	} else
420 		*mask = 255;
421 	i = strtol(dup, &buffer, 10);
422 	if (*buffer != '\0' || i < 0 || i > 255)
423 		goto out_err;
424 	*to = (uint8_t)i;
425 	ret = 0;
426 out_err:
427 	free(dup);
428 	return ret;
429 
430 }
431 
get16_and_mask(const char * from,uint16_t * to,uint16_t * mask,int base)432 static int get16_and_mask(const char *from, uint16_t *to,
433 			  uint16_t *mask, int base)
434 {
435 	char *dup = strdup(from);
436 	char *p, *buffer;
437 	int i, ret = -1;
438 
439 	if (!dup)
440 		return -1;
441 
442 	if ( (p = strrchr(dup, '/')) != NULL) {
443 		*p = '\0';
444 		i = strtol(p+1, &buffer, base);
445 		if (*buffer != '\0' || i < 0 || i > 65535)
446 			goto out_err;
447 		*mask = htons((uint16_t)i);
448 	} else
449 		*mask = 65535;
450 	i = strtol(dup, &buffer, base);
451 	if (*buffer != '\0' || i < 0 || i > 65535)
452 		goto out_err;
453 	*to = htons((uint16_t)i);
454 	ret = 0;
455 out_err:
456 	free(dup);
457 	return ret;
458 }
459 
nft_arp_post_parse(int command,struct iptables_command_state * cs,struct xtables_args * args)460 static void nft_arp_post_parse(int command,
461 			       struct iptables_command_state *cs,
462 			       struct xtables_args *args)
463 {
464 	cs->arp.arp.invflags = args->invflags;
465 
466 	memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ);
467 	memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ);
468 
469 	memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ);
470 	memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ);
471 
472 	cs->arp.counters.pcnt = args->pcnt_cnt;
473 	cs->arp.counters.bcnt = args->bcnt_cnt;
474 
475 	if (command & (CMD_REPLACE | CMD_INSERT |
476 			CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
477 		if (!(cs->options & OPT_DESTINATION))
478 			args->dhostnetworkmask = "0.0.0.0/0";
479 		if (!(cs->options & OPT_SOURCE))
480 			args->shostnetworkmask = "0.0.0.0/0";
481 	}
482 
483 	if (args->shostnetworkmask)
484 		xtables_ipparse_multiple(args->shostnetworkmask,
485 					 &args->s.addr.v4, &args->s.mask.v4,
486 					 &args->s.naddrs);
487 	if (args->dhostnetworkmask)
488 		xtables_ipparse_multiple(args->dhostnetworkmask,
489 					 &args->d.addr.v4, &args->d.mask.v4,
490 					 &args->d.naddrs);
491 
492 	if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
493 	    (cs->arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
494 		xtables_error(PARAMETER_PROBLEM,
495 			      "! not allowed with multiple"
496 			      " source or destination IP addresses");
497 
498 	if (args->src_mac &&
499 	    xtables_parse_mac_and_mask(args->src_mac,
500 				       cs->arp.arp.src_devaddr.addr,
501 				       cs->arp.arp.src_devaddr.mask))
502 		xtables_error(PARAMETER_PROBLEM,
503 			      "Problem with specified source mac");
504 	if (args->dst_mac &&
505 	    xtables_parse_mac_and_mask(args->dst_mac,
506 				       cs->arp.arp.tgt_devaddr.addr,
507 				       cs->arp.arp.tgt_devaddr.mask))
508 		xtables_error(PARAMETER_PROBLEM,
509 			      "Problem with specified destination mac");
510 	if (args->arp_hlen) {
511 		getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln,
512 				   &cs->arp.arp.arhln_mask);
513 
514 		if (cs->arp.arp.arhln != 6)
515 			xtables_error(PARAMETER_PROBLEM,
516 				      "Only harware address length of 6 is supported currently.");
517 	}
518 	if (args->arp_opcode) {
519 		if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop,
520 				   &cs->arp.arp.arpop_mask, 10)) {
521 			int i;
522 
523 			for (i = 0; i < ARP_NUMOPCODES; i++)
524 				if (!strcasecmp(arp_opcodes[i],
525 						args->arp_opcode))
526 					break;
527 			if (i == ARP_NUMOPCODES)
528 				xtables_error(PARAMETER_PROBLEM,
529 					      "Problem with specified opcode");
530 			cs->arp.arp.arpop = htons(i+1);
531 		}
532 	}
533 	if (args->arp_htype) {
534 		if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd,
535 				   &cs->arp.arp.arhrd_mask, 16)) {
536 			if (strcasecmp(args->arp_htype, "Ethernet"))
537 				xtables_error(PARAMETER_PROBLEM,
538 					      "Problem with specified hardware type");
539 			cs->arp.arp.arhrd = htons(1);
540 		}
541 	}
542 	if (args->arp_ptype) {
543 		if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro,
544 				   &cs->arp.arp.arpro_mask, 0)) {
545 			if (strcasecmp(args->arp_ptype, "ipv4"))
546 				xtables_error(PARAMETER_PROBLEM,
547 					      "Problem with specified protocol type");
548 			cs->arp.arp.arpro = htons(0x800);
549 		}
550 	}
551 }
552 
nft_arp_init_cs(struct iptables_command_state * cs)553 static void nft_arp_init_cs(struct iptables_command_state *cs)
554 {
555 	cs->arp.arp.arhln = 6;
556 	cs->arp.arp.arhln_mask = 255;
557 	cs->arp.arp.arhrd = htons(ARPHRD_ETHER);
558 	cs->arp.arp.arhrd_mask = 65535;
559 }
560 
561 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)562 nft_arp_add_entry(struct nft_handle *h,
563 		  const char *chain, const char *table,
564 		  struct iptables_command_state *cs,
565 		  struct xtables_args *args, bool verbose,
566 		  bool append, int rulenum)
567 {
568 	unsigned int i, j;
569 	int ret = 1;
570 
571 	for (i = 0; i < args->s.naddrs; i++) {
572 		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
573 		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
574 		for (j = 0; j < args->d.naddrs; j++) {
575 			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
576 			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
577 			if (append) {
578 				ret = nft_cmd_rule_append(h, chain, table, cs,
579 						          verbose);
580 			} else {
581 				ret = nft_cmd_rule_insert(h, chain, table, cs,
582 						          rulenum, verbose);
583 			}
584 		}
585 	}
586 
587 	return ret;
588 }
589 
590 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)591 nft_arp_delete_entry(struct nft_handle *h,
592 		     const char *chain, const char *table,
593 		     struct iptables_command_state *cs,
594 		     struct xtables_args *args, bool verbose)
595 {
596 	unsigned int i, j;
597 	int ret = 1;
598 
599 	for (i = 0; i < args->s.naddrs; i++) {
600 		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
601 		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
602 		for (j = 0; j < args->d.naddrs; j++) {
603 			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
604 			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
605 			ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
606 		}
607 	}
608 
609 	return ret;
610 }
611 
612 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)613 nft_arp_check_entry(struct nft_handle *h,
614 		    const char *chain, const char *table,
615 		    struct iptables_command_state *cs,
616 		    struct xtables_args *args, bool verbose)
617 {
618 	unsigned int i, j;
619 	int ret = 1;
620 
621 	for (i = 0; i < args->s.naddrs; i++) {
622 		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
623 		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
624 		for (j = 0; j < args->d.naddrs; j++) {
625 			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
626 			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
627 			ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
628 		}
629 	}
630 
631 	return ret;
632 }
633 
634 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)635 nft_arp_replace_entry(struct nft_handle *h,
636 		      const char *chain, const char *table,
637 		      struct iptables_command_state *cs,
638 		      struct xtables_args *args, bool verbose,
639 		      int rulenum)
640 {
641 	cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr;
642 	cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr;
643 	cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr;
644 	cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr;
645 
646 	return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
647 }
648 
649 struct nft_family_ops nft_family_ops_arp = {
650 	.add			= nft_arp_add,
651 	.is_same		= nft_arp_is_same,
652 	.print_payload		= NULL,
653 	.print_header		= nft_arp_print_header,
654 	.print_rule		= nft_arp_print_rule,
655 	.save_rule		= nft_arp_save_rule,
656 	.save_chain		= nft_arp_save_chain,
657 	.rule_parse		= &nft_ruleparse_ops_arp,
658 	.cmd_parse		= {
659 		.post_parse	= nft_arp_post_parse,
660 	},
661 	.rule_to_cs		= nft_rule_to_iptables_command_state,
662 	.init_cs		= nft_arp_init_cs,
663 	.clear_cs		= xtables_clear_iptables_command_state,
664 	.add_entry		= nft_arp_add_entry,
665 	.delete_entry		= nft_arp_delete_entry,
666 	.check_entry		= nft_arp_check_entry,
667 	.replace_entry		= nft_arp_replace_entry,
668 };
669