• 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 <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-arp.h"
29 #include "nft.h"
30 
31 /* a few names */
32 char *opcodes[] =
33 {
34 	"Request",
35 	"Reply",
36 	"Request_Reverse",
37 	"Reply_Reverse",
38 	"DRARP_Request",
39 	"DRARP_Reply",
40 	"DRARP_Error",
41 	"InARP_Request",
42 	"ARP_NAK",
43 };
44 
45 static char *
addr_to_dotted(const struct in_addr * addrp)46 addr_to_dotted(const struct in_addr *addrp)
47 {
48 	static char buf[20];
49 	const unsigned char *bytep;
50 
51 	bytep = (const unsigned char *) &(addrp->s_addr);
52 	sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
53 	return buf;
54 }
55 
56 static char *
addr_to_host(const struct in_addr * addr)57 addr_to_host(const struct in_addr *addr)
58 {
59 	struct hostent *host;
60 
61 	if ((host = gethostbyaddr((char *) addr,
62 					sizeof(struct in_addr), AF_INET)) != NULL)
63 		return (char *) host->h_name;
64 
65 	return (char *) NULL;
66 }
67 
68 static char *
addr_to_network(const struct in_addr * addr)69 addr_to_network(const struct in_addr *addr)
70 {
71 	struct netent *net;
72 
73 	if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
74 		return (char *) net->n_name;
75 
76 	return (char *) NULL;
77 }
78 
79 static char *
addr_to_anyname(const struct in_addr * addr)80 addr_to_anyname(const struct in_addr *addr)
81 {
82 	char *name;
83 
84 	if ((name = addr_to_host(addr)) != NULL ||
85 		(name = addr_to_network(addr)) != NULL)
86 		return name;
87 
88 	return addr_to_dotted(addr);
89 }
90 
91 static char *
mask_to_dotted(const struct in_addr * mask)92 mask_to_dotted(const struct in_addr *mask)
93 {
94 	int i;
95 	static char buf[20];
96 	u_int32_t maskaddr, bits;
97 
98 	maskaddr = ntohl(mask->s_addr);
99 
100 	if (maskaddr == 0xFFFFFFFFL)
101 		/* we don't want to see "/32" */
102 		return "";
103 
104 	i = 32;
105 	bits = 0xFFFFFFFEL;
106 	while (--i >= 0 && maskaddr != bits)
107 		bits <<= 1;
108 	if (i >= 0)
109 		sprintf(buf, "/%d", i);
110 	else
111 		/* mask was not a decent combination of 1's and 0's */
112 		sprintf(buf, "/%s", addr_to_dotted(mask));
113 
114 	return buf;
115 }
116 
print_mac(const unsigned char * mac,int l)117 static void print_mac(const unsigned char *mac, int l)
118 {
119 	int j;
120 
121 	for (j = 0; j < l; j++)
122 		printf("%02x%s", mac[j],
123 			(j==l-1) ? "" : ":");
124 }
125 
print_mac_and_mask(const unsigned char * mac,const unsigned char * mask,int l)126 static void print_mac_and_mask(const unsigned char *mac, const unsigned char *mask, int l)
127 {
128 	int i;
129 
130 	print_mac(mac, l);
131 	for (i = 0; i < l ; i++)
132 		if (mask[i] != 255)
133 			break;
134 	if (i == l)
135 		return;
136 	printf("/");
137 	print_mac(mask, l);
138 }
139 
nft_arp_add(struct nftnl_rule * r,void * data)140 static int nft_arp_add(struct nftnl_rule *r, void *data)
141 {
142 	struct arptables_command_state *cs = data;
143 	struct arpt_entry *fw = &cs->fw;
144 	uint32_t op;
145 	int ret = 0;
146 
147 	if (fw->arp.iniface[0] != '\0') {
148 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_IN);
149 		add_iniface(r, fw->arp.iniface, op);
150 	}
151 
152 	if (fw->arp.outiface[0] != '\0') {
153 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_OUT);
154 		add_outiface(r, fw->arp.outiface, op);
155 	}
156 
157 	if (fw->arp.arhrd != 0) {
158 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHRD);
159 		add_payload(r, offsetof(struct arphdr, ar_hrd), 2,
160 			    NFT_PAYLOAD_NETWORK_HEADER);
161 		add_cmp_u16(r, fw->arp.arhrd, op);
162 	}
163 
164 	if (fw->arp.arpro != 0) {
165 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPPRO);
166 	        add_payload(r, offsetof(struct arphdr, ar_pro), 2,
167 			    NFT_PAYLOAD_NETWORK_HEADER);
168 		add_cmp_u16(r, fw->arp.arpro, op);
169 	}
170 
171 	if (fw->arp.arhln != 0) {
172 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHLN);
173 		add_proto(r, offsetof(struct arphdr, ar_hln), 1,
174 			  fw->arp.arhln, op);
175 	}
176 
177 	add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
178 
179 	if (fw->arp.arpop != 0) {
180 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPOP);
181 		add_payload(r, offsetof(struct arphdr, ar_op), 2,
182 			    NFT_PAYLOAD_NETWORK_HEADER);
183 		add_cmp_u16(r, fw->arp.arpop, op);
184 	}
185 
186 	if (fw->arp.src_devaddr.addr[0] != '\0') {
187 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCDEVADDR);
188 		add_payload(r, sizeof(struct arphdr), fw->arp.arhln,
189 			    NFT_PAYLOAD_NETWORK_HEADER);
190 		add_cmp_ptr(r, op, fw->arp.src_devaddr.addr, fw->arp.arhln);
191 	}
192 
193 	if (fw->arp.src.s_addr != 0) {
194 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCIP);
195 		add_addr(r, sizeof(struct arphdr) + fw->arp.arhln,
196 			 &fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
197 			 sizeof(struct in_addr), op);
198 	}
199 
200 	if (fw->arp.tgt_devaddr.addr[0] != '\0') {
201 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTDEVADDR);
202 		add_payload(r, sizeof(struct arphdr) + fw->arp.arhln + 4,
203 			    fw->arp.arhln, NFT_PAYLOAD_NETWORK_HEADER);
204 		add_cmp_ptr(r, op, fw->arp.tgt_devaddr.addr, fw->arp.arhln);
205 	}
206 
207 	if (fw->arp.tgt.s_addr != 0) {
208 		op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTIP);
209 		add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
210 			 &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
211 			 sizeof(struct in_addr), op);
212 	}
213 
214 	/* Counters need to me added before the target, otherwise they are
215 	 * increased for each rule because of the way nf_tables works.
216 	 */
217 	if (add_counters(r, fw->counters.pcnt, fw->counters.bcnt) < 0)
218 		return -1;
219 
220 	if (cs->target != NULL) {
221 		/* Standard target? */
222 		if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
223 			ret = add_verdict(r, NF_ACCEPT);
224 		else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
225 			ret = add_verdict(r, NF_DROP);
226 		else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
227 			ret = add_verdict(r, NFT_RETURN);
228 		else
229 			ret = add_target(r, cs->target->t);
230 	} else if (strlen(cs->jumpto) > 0) {
231 		/* No goto in arptables */
232 		ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
233 	}
234 
235 	return ret;
236 }
237 
ipt_to_arpt_flags(uint8_t invflags)238 static uint16_t ipt_to_arpt_flags(uint8_t invflags)
239 {
240 	uint16_t result = 0;
241 
242 	if (invflags & IPT_INV_VIA_IN)
243 		result |= ARPT_INV_VIA_IN;
244 
245 	if (invflags & IPT_INV_VIA_OUT)
246 		result |= ARPT_INV_VIA_OUT;
247 
248 	if (invflags & IPT_INV_SRCIP)
249 		result |= ARPT_INV_SRCIP;
250 
251 	if (invflags & IPT_INV_DSTIP)
252 		result |= ARPT_INV_TGTIP;
253 
254 	if (invflags & IPT_INV_PROTO)
255 		result |= ARPT_INV_ARPPRO;
256 
257 	return result;
258 }
259 
nft_arp_parse_meta(struct nft_xt_ctx * ctx,struct nftnl_expr * e,void * data)260 static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
261 			       void *data)
262 {
263 	struct arptables_command_state *cs = data;
264 	struct arpt_entry *fw = &cs->fw;
265 	uint8_t flags = 0;
266 
267 	parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask,
268 		   fw->arp.outiface, fw->arp.outiface_mask,
269 		   &flags);
270 
271 	fw->arp.invflags |= ipt_to_arpt_flags(flags);
272 }
273 
nft_arp_parse_target(struct xtables_target * target,void * data)274 static void nft_arp_parse_target(struct xtables_target *target, void *data)
275 {
276 	struct arptables_command_state *cs = data;
277 
278 	cs->target = target;
279 }
280 
nft_arp_parse_immediate(const char * jumpto,bool nft_goto,void * data)281 static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
282 				    void *data)
283 {
284 	struct arptables_command_state *cs = data;
285 
286 	cs->jumpto = jumpto;
287 }
288 
parse_mask_ipv4(struct nft_xt_ctx * ctx,struct in_addr * mask)289 static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
290 {
291 	mask->s_addr = ctx->bitwise.mask[0];
292 }
293 
nft_arp_parse_payload(struct nft_xt_ctx * ctx,struct nftnl_expr * e,void * data)294 static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
295 				  struct nftnl_expr *e, void *data)
296 {
297 	struct arptables_command_state *cs = data;
298 	struct arpt_entry *fw = &cs->fw;
299 	struct in_addr addr;
300 	unsigned short int ar_hrd, ar_pro, ar_op, ar_hln;
301 	bool inv;
302 
303 	switch (ctx->payload.offset) {
304 	case offsetof(struct arphdr, ar_hrd):
305 		get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv);
306 		fw->arp.arhrd = ar_hrd;
307 		fw->arp.arhrd_mask = 0xffff;
308 		if (inv)
309 			fw->arp.invflags |= ARPT_INV_ARPHRD;
310 		break;
311 	case offsetof(struct arphdr, ar_pro):
312 		get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv);
313 		fw->arp.arpro = ar_pro;
314 		fw->arp.arpro_mask = 0xffff;
315 		if (inv)
316 			fw->arp.invflags |= ARPT_INV_ARPPRO;
317 		break;
318 	case offsetof(struct arphdr, ar_op):
319 		get_cmp_data(e, &ar_op, sizeof(ar_op), &inv);
320 		fw->arp.arpop = ar_op;
321 		fw->arp.arpop_mask = 0xffff;
322 		if (inv)
323 			fw->arp.invflags |= ARPT_INV_ARPOP;
324 		break;
325 	case offsetof(struct arphdr, ar_hln):
326 		get_cmp_data(e, &ar_hln, sizeof(ar_op), &inv);
327 		fw->arp.arhln = ar_hln;
328 		fw->arp.arhln_mask = 0xff;
329 		if (inv)
330 			fw->arp.invflags |= ARPT_INV_ARPOP;
331 		break;
332 	default:
333 		if (fw->arp.arhln < 0)
334 			break;
335 
336 		if (ctx->payload.offset == sizeof(struct arphdr) +
337 					   fw->arp.arhln) {
338 			get_cmp_data(e, &addr, sizeof(addr), &inv);
339 			fw->arp.src.s_addr = addr.s_addr;
340 			if (ctx->flags & NFT_XT_CTX_BITWISE) {
341 				parse_mask_ipv4(ctx, &fw->arp.smsk);
342 				ctx->flags &= ~NFT_XT_CTX_BITWISE;
343 			} else {
344 				fw->arp.smsk.s_addr = 0xffffffff;
345 			}
346 
347 			if (inv)
348 				fw->arp.invflags |= ARPT_INV_SRCIP;
349 		} else if (ctx->payload.offset == sizeof(struct arphdr) +
350 						  fw->arp.arhln +
351 						  sizeof(struct in_addr)) {
352 			get_cmp_data(e, &addr, sizeof(addr), &inv);
353 			fw->arp.tgt.s_addr = addr.s_addr;
354 			if (ctx->flags & NFT_XT_CTX_BITWISE) {
355 				parse_mask_ipv4(ctx, &fw->arp.tmsk);
356 				ctx->flags &= ~NFT_XT_CTX_BITWISE;
357 			} else {
358 				fw->arp.tmsk.s_addr = 0xffffffff;
359 			}
360 
361 			if (inv)
362 				fw->arp.invflags |= ARPT_INV_TGTIP;
363 		}
364 		break;
365 	}
366 }
367 
nft_rule_to_arptables_command_state(struct nftnl_rule * r,struct arptables_command_state * cs)368 void nft_rule_to_arptables_command_state(struct nftnl_rule *r,
369 					 struct arptables_command_state *cs)
370 {
371 	struct nftnl_expr_iter *iter;
372 	struct nftnl_expr *expr;
373 	int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY);
374 	struct nft_xt_ctx ctx = {
375 		.state.cs_arp = cs,
376 		.family = family,
377 	};
378 
379 	iter = nftnl_expr_iter_create(r);
380 	if (iter == NULL)
381 		return;
382 
383 	ctx.iter = iter;
384 	expr = nftnl_expr_iter_next(iter);
385 	while (expr != NULL) {
386 		const char *name =
387 			nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
388 
389 		if (strcmp(name, "counter") == 0)
390 			nft_parse_counter(expr, &ctx.state.cs_arp->fw.counters);
391 		else if (strcmp(name, "payload") == 0)
392 			nft_parse_payload(&ctx, expr);
393 		else if (strcmp(name, "meta") == 0)
394 			nft_parse_meta(&ctx, expr);
395 		else if (strcmp(name, "bitwise") == 0)
396 			nft_parse_bitwise(&ctx, expr);
397 		else if (strcmp(name, "cmp") == 0)
398 			nft_parse_cmp(&ctx, expr);
399 		else if (strcmp(name, "immediate") == 0)
400 			nft_parse_immediate(&ctx, expr);
401 		else if (strcmp(name, "target") == 0)
402 			nft_parse_target(&ctx, expr);
403 
404 		expr = nftnl_expr_iter_next(iter);
405 	}
406 
407 	nftnl_expr_iter_destroy(iter);
408 
409 	if (cs->jumpto != NULL)
410 		return;
411 
412 	if (cs->target != NULL && cs->target->name != NULL)
413 		cs->target = xtables_find_target(cs->target->name, XTF_TRY_LOAD);
414 	else
415 		cs->jumpto = "";
416 }
417 
nft_arp_print_header(unsigned int format,const char * chain,const char * pol,const struct xt_counters * counters,bool basechain,uint32_t refs)418 static void nft_arp_print_header(unsigned int format, const char *chain,
419 				 const char *pol,
420 				 const struct xt_counters *counters,
421 				 bool basechain, uint32_t refs)
422 {
423 	printf("Chain %s", chain);
424 	if (pol) {
425 		printf(" (policy %s", pol);
426 		if (!(format & FMT_NOCOUNTS)) {
427 			fputc(' ', stdout);
428 			xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
429 			fputs("packets, ", stdout);
430 			xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
431 			fputs("bytes", stdout);
432 		}
433 		printf(")\n");
434 	} else {
435 		printf(" (%u references)\n", refs);
436 	}
437 }
438 
print_fw_details(struct arpt_entry * fw,unsigned int format)439 static void print_fw_details(struct arpt_entry *fw, unsigned int format)
440 {
441 	char buf[BUFSIZ];
442 	char iface[IFNAMSIZ+2];
443 	int print_iface = 0;
444 	int i;
445 
446 	iface[0] = '\0';
447 
448 	if (fw->arp.iniface[0] != '\0') {
449 		strcat(iface, fw->arp.iniface);
450 		print_iface = 1;
451 	}
452 	else if (format & FMT_VIA) {
453 		print_iface = 1;
454 		if (format & FMT_NUMERIC) strcat(iface, "*");
455 		else strcat(iface, "any");
456 	}
457 	if (print_iface)
458 		printf("%s-i %s ", fw->arp.invflags & ARPT_INV_VIA_IN ?
459 				   "! " : "", iface);
460 
461 	print_iface = 0;
462 	iface[0] = '\0';
463 
464 	if (fw->arp.outiface[0] != '\0') {
465 		strcat(iface, fw->arp.outiface);
466 		print_iface = 1;
467 	}
468 	else if (format & FMT_VIA) {
469 		print_iface = 1;
470 		if (format & FMT_NUMERIC) strcat(iface, "*");
471 		else strcat(iface, "any");
472 	}
473 	if (print_iface)
474 		printf("%s-o %s ", fw->arp.invflags & ARPT_INV_VIA_OUT ?
475 				   "! " : "", iface);
476 
477 	if (fw->arp.smsk.s_addr != 0L) {
478 		printf("%s", fw->arp.invflags & ARPT_INV_SRCIP
479 			? "! " : "");
480 		if (format & FMT_NUMERIC)
481 			sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
482 		else
483 			sprintf(buf, "%s", addr_to_anyname(&(fw->arp.src)));
484 		strncat(buf, mask_to_dotted(&(fw->arp.smsk)),
485 			sizeof(buf) - strlen(buf) - 1);
486 		printf("-s %s ", buf);
487 	}
488 
489 	for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++)
490 		if (fw->arp.src_devaddr.mask[i] != 0)
491 			break;
492 	if (i == ARPT_DEV_ADDR_LEN_MAX)
493 		goto after_devsrc;
494 	printf("%s", fw->arp.invflags & ARPT_INV_SRCDEVADDR
495 		? "! " : "");
496 	printf("--src-mac ");
497 	print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
498 		(unsigned char *)fw->arp.src_devaddr.mask, ETH_ALEN);
499 	printf(" ");
500 after_devsrc:
501 
502 	if (fw->arp.tmsk.s_addr != 0L) {
503 		printf("%s", fw->arp.invflags & ARPT_INV_TGTIP
504 			? "! " : "");
505 		if (format & FMT_NUMERIC)
506 			sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
507 		else
508 			sprintf(buf, "%s", addr_to_anyname(&(fw->arp.tgt)));
509 		strncat(buf, mask_to_dotted(&(fw->arp.tmsk)),
510 			sizeof(buf) - strlen(buf) - 1);
511 		printf("-d %s ", buf);
512 	}
513 
514 	for (i = 0; i <ARPT_DEV_ADDR_LEN_MAX; i++)
515 		if (fw->arp.tgt_devaddr.mask[i] != 0)
516 			break;
517 	if (i == ARPT_DEV_ADDR_LEN_MAX)
518 		goto after_devdst;
519 	printf("%s", fw->arp.invflags & ARPT_INV_TGTDEVADDR
520 		? "! " : "");
521 	printf("--dst-mac ");
522 	print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
523 		(unsigned char *)fw->arp.tgt_devaddr.mask, ETH_ALEN);
524 	printf(" ");
525 
526 after_devdst:
527 
528 	if (fw->arp.arhln_mask != 0) {
529 		printf("%s", fw->arp.invflags & ARPT_INV_ARPHLN
530 			? "! " : "");
531 		printf("--h-length %d", fw->arp.arhln);
532 		if (fw->arp.arhln_mask != 255)
533 			printf("/%d", fw->arp.arhln_mask);
534 		printf(" ");
535 	}
536 
537 	if (fw->arp.arpop_mask != 0) {
538 		int tmp = ntohs(fw->arp.arpop);
539 
540 		printf("%s", fw->arp.invflags & ARPT_INV_ARPOP
541 			? "! " : "");
542 		if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC))
543 			printf("--opcode %s", opcodes[tmp-1]);
544 		else
545 
546 		if (fw->arp.arpop_mask != 65535)
547 			printf("/%d", ntohs(fw->arp.arpop_mask));
548 		printf(" ");
549 	}
550 
551 	if (fw->arp.arhrd_mask != 0) {
552 		uint16_t tmp = ntohs(fw->arp.arhrd);
553 
554 		printf("%s", fw->arp.invflags & ARPT_INV_ARPHRD
555 			? "! " : "");
556 		if (tmp == 1 && !(format & FMT_NUMERIC))
557 			printf("--h-type %s", "Ethernet");
558 		else
559 			printf("--h-type %u", tmp);
560 		if (fw->arp.arhrd_mask != 65535)
561 			printf("/%d", ntohs(fw->arp.arhrd_mask));
562 		printf(" ");
563 	}
564 
565 	if (fw->arp.arpro_mask != 0) {
566 		int tmp = ntohs(fw->arp.arpro);
567 
568 		printf("%s", fw->arp.invflags & ARPT_INV_ARPPRO
569 			? "! " : "");
570 		if (tmp == 0x0800 && !(format & FMT_NUMERIC))
571 			printf("--proto-type %s", "IPv4");
572 		else
573 			printf("--proto-type 0x%x", tmp);
574 		if (fw->arp.arpro_mask != 65535)
575 			printf("/%x", ntohs(fw->arp.arpro_mask));
576 		printf(" ");
577 	}
578 }
579 
580 static void
nft_arp_print_firewall(struct nftnl_rule * r,unsigned int num,unsigned int format)581 nft_arp_print_firewall(struct nftnl_rule *r, unsigned int num,
582 		       unsigned int format)
583 {
584 	struct arptables_command_state cs = {};
585 
586 	nft_rule_to_arptables_command_state(r, &cs);
587 
588 	if (format & FMT_LINENUMBERS)
589 		printf("%u ", num);
590 
591 	print_fw_details(&cs.fw, format);
592 
593 	if (cs.jumpto != NULL && strcmp(cs.jumpto, "") != 0) {
594 		printf("-j %s", cs.jumpto);
595 	} else if (cs.target) {
596 		printf("-j %s", cs.target->name);
597 		cs.target->print(&cs.fw, cs.target->t, format & FMT_NUMERIC);
598 	}
599 
600 	if (!(format & FMT_NOCOUNTS)) {
601 		printf(", pcnt=");
602 		xtables_print_num(cs.fw.counters.pcnt, format);
603 		printf("-- bcnt=");
604 		xtables_print_num(cs.fw.counters.bcnt, format);
605 	}
606 
607 	if (!(format & FMT_NONEWLINE))
608 		fputc('\n', stdout);
609 }
610 
nft_arp_is_same(const void * data_a,const void * data_b)611 static bool nft_arp_is_same(const void *data_a,
612 			    const void *data_b)
613 {
614 	const struct arpt_entry *a = data_a;
615 	const struct arpt_entry *b = data_b;
616 
617 	if (a->arp.src.s_addr != b->arp.src.s_addr
618 	    || a->arp.tgt.s_addr != b->arp.tgt.s_addr
619 	    || a->arp.smsk.s_addr != b->arp.tmsk.s_addr
620 	    || a->arp.arpro != b->arp.arpro
621 	    || a->arp.flags != b->arp.flags
622 	    || a->arp.invflags != b->arp.invflags) {
623 		DEBUGP("different src/dst/proto/flags/invflags\n");
624 		return false;
625 	}
626 
627 	return is_same_interfaces(a->arp.iniface,
628 				  a->arp.outiface,
629 				  (unsigned char *)a->arp.iniface_mask,
630 				  (unsigned char *)a->arp.outiface_mask,
631 				  b->arp.iniface,
632 				  b->arp.outiface,
633 				  (unsigned char *)b->arp.iniface_mask,
634 				  (unsigned char *)b->arp.outiface_mask);
635 }
636 
nft_arp_rule_find(struct nft_family_ops * ops,struct nftnl_rule * r,void * data)637 static bool nft_arp_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r,
638 			      void *data)
639 {
640 	const struct arptables_command_state *cs = data;
641 	struct arptables_command_state this = {};
642 
643 	/* Delete by matching rule case */
644 	nft_rule_to_arptables_command_state(r, &this);
645 
646 	if (!nft_arp_is_same(cs, &this))
647 		return false;
648 
649 	if (!compare_targets(cs->target, this.target))
650 		return false;
651 
652 	if (strcmp(cs->jumpto, this.jumpto) != 0)
653 		return false;
654 
655 	return true;
656 }
657 
658 struct nft_family_ops nft_family_ops_arp = {
659 	.add			= nft_arp_add,
660 	.is_same		= nft_arp_is_same,
661 	.print_payload		= NULL,
662 	.parse_meta		= nft_arp_parse_meta,
663 	.parse_payload		= nft_arp_parse_payload,
664 	.parse_immediate	= nft_arp_parse_immediate,
665 	.print_header		= nft_arp_print_header,
666 	.print_firewall		= nft_arp_print_firewall,
667 	.save_firewall		= NULL,
668 	.save_counters		= NULL,
669 	.post_parse		= NULL,
670 	.rule_find		= nft_arp_rule_find,
671 	.parse_target		= nft_arp_parse_target,
672 };
673