• 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 *arp_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[22];
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 		snprintf(buf, sizeof(buf), "/%s", addr_to_dotted(mask));
113 
114 	return buf;
115 }
116 
need_devaddr(struct arpt_devaddr_info * info)117 static bool need_devaddr(struct arpt_devaddr_info *info)
118 {
119 	int i;
120 
121 	for (i = 0; i < ETH_ALEN; i++) {
122 		if (info->addr[i] || info->mask[i])
123 			return true;
124 	}
125 
126 	return false;
127 }
128 
nft_arp_add(struct nft_handle * h,struct nftnl_rule * r,void * data)129 static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
130 {
131 	struct iptables_command_state *cs = data;
132 	struct arpt_entry *fw = &cs->arp;
133 	uint32_t op;
134 	int ret = 0;
135 
136 	if (fw->arp.iniface[0] != '\0') {
137 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
138 		add_iniface(r, fw->arp.iniface, op);
139 	}
140 
141 	if (fw->arp.outiface[0] != '\0') {
142 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
143 		add_outiface(r, fw->arp.outiface, op);
144 	}
145 
146 	if (fw->arp.arhrd != 0 ||
147 	    fw->arp.invflags & IPT_INV_ARPHRD) {
148 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
149 		add_payload(r, offsetof(struct arphdr, ar_hrd), 2,
150 			    NFT_PAYLOAD_NETWORK_HEADER);
151 		add_cmp_u16(r, fw->arp.arhrd, op);
152 	}
153 
154 	if (fw->arp.arpro != 0 ||
155 	    fw->arp.invflags & IPT_INV_PROTO) {
156 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
157 	        add_payload(r, offsetof(struct arphdr, ar_pro), 2,
158 			    NFT_PAYLOAD_NETWORK_HEADER);
159 		add_cmp_u16(r, fw->arp.arpro, op);
160 	}
161 
162 	if (fw->arp.arhln != 0 ||
163 	    fw->arp.invflags & IPT_INV_ARPHLN) {
164 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
165 		add_proto(r, offsetof(struct arphdr, ar_hln), 1,
166 			  fw->arp.arhln, op);
167 	}
168 
169 	add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
170 
171 	if (fw->arp.arpop != 0 ||
172 	    fw->arp.invflags & IPT_INV_ARPOP) {
173 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
174 		add_payload(r, offsetof(struct arphdr, ar_op), 2,
175 			    NFT_PAYLOAD_NETWORK_HEADER);
176 		add_cmp_u16(r, fw->arp.arpop, op);
177 	}
178 
179 	if (need_devaddr(&fw->arp.src_devaddr)) {
180 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
181 		add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
182 			 sizeof(struct arphdr),
183 			 &fw->arp.src_devaddr.addr,
184 			 &fw->arp.src_devaddr.mask,
185 			 fw->arp.arhln, op);
186 
187 	}
188 
189 	if (fw->arp.src.s_addr != 0 ||
190 	    fw->arp.smsk.s_addr != 0 ||
191 	    fw->arp.invflags & IPT_INV_SRCIP) {
192 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
193 		add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
194 			 sizeof(struct arphdr) + fw->arp.arhln,
195 			 &fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
196 			 sizeof(struct in_addr), op);
197 	}
198 
199 
200 	if (need_devaddr(&fw->arp.tgt_devaddr)) {
201 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
202 		add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
203 			 sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
204 			 &fw->arp.tgt_devaddr.addr,
205 			 &fw->arp.tgt_devaddr.mask,
206 			 fw->arp.arhln, op);
207 	}
208 
209 	if (fw->arp.tgt.s_addr != 0 ||
210 	    fw->arp.tmsk.s_addr != 0 ||
211 	    fw->arp.invflags & IPT_INV_DSTIP) {
212 		op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
213 		add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
214 			 sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
215 			 &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
216 			 sizeof(struct in_addr), op);
217 	}
218 
219 	/* Counters need to me added before the target, otherwise they are
220 	 * increased for each rule because of the way nf_tables works.
221 	 */
222 	if (add_counters(r, fw->counters.pcnt, fw->counters.bcnt) < 0)
223 		return -1;
224 
225 	if (cs->target != NULL) {
226 		/* Standard target? */
227 		if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
228 			ret = add_verdict(r, NF_ACCEPT);
229 		else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
230 			ret = add_verdict(r, NF_DROP);
231 		else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
232 			ret = add_verdict(r, NFT_RETURN);
233 		else
234 			ret = add_target(r, cs->target->t);
235 	} else if (strlen(cs->jumpto) > 0) {
236 		/* No goto in arptables */
237 		ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
238 	}
239 
240 	return ret;
241 }
242 
nft_arp_parse_meta(struct nft_xt_ctx * ctx,struct nftnl_expr * e,void * data)243 static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
244 			       void *data)
245 {
246 	struct iptables_command_state *cs = data;
247 	struct arpt_entry *fw = &cs->arp;
248 	uint8_t flags = 0;
249 
250 	parse_meta(e, ctx->meta.key, fw->arp.iniface, fw->arp.iniface_mask,
251 		   fw->arp.outiface, fw->arp.outiface_mask,
252 		   &flags);
253 
254 	fw->arp.invflags |= flags;
255 }
256 
nft_arp_parse_immediate(const char * jumpto,bool nft_goto,void * data)257 static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
258 				    void *data)
259 {
260 	struct iptables_command_state *cs = data;
261 
262 	cs->jumpto = jumpto;
263 }
264 
parse_mask_ipv4(struct nft_xt_ctx * ctx,struct in_addr * mask)265 static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
266 {
267 	mask->s_addr = ctx->bitwise.mask[0];
268 }
269 
nft_arp_parse_devaddr(struct nft_xt_ctx * ctx,struct nftnl_expr * e,struct arpt_devaddr_info * info)270 static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx,
271 				  struct nftnl_expr *e,
272 				  struct arpt_devaddr_info *info)
273 {
274 	uint32_t hlen;
275 	bool inv;
276 
277 	nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen);
278 
279 	if (hlen != ETH_ALEN)
280 		return false;
281 
282 	get_cmp_data(e, info->addr, ETH_ALEN, &inv);
283 
284 	if (ctx->flags & NFT_XT_CTX_BITWISE) {
285 		memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN);
286 		ctx->flags &= ~NFT_XT_CTX_BITWISE;
287 	} else {
288 		memset(info->mask, 0xff,
289 		       min(ctx->payload.len, ETH_ALEN));
290 	}
291 
292 	return inv;
293 }
294 
nft_arp_parse_payload(struct nft_xt_ctx * ctx,struct nftnl_expr * e,void * data)295 static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
296 				  struct nftnl_expr *e, void *data)
297 {
298 	struct iptables_command_state *cs = data;
299 	struct arpt_entry *fw = &cs->arp;
300 	struct in_addr addr;
301 	uint16_t ar_hrd, ar_pro, ar_op;
302 	uint8_t ar_hln;
303 	bool inv;
304 
305 	switch (ctx->payload.offset) {
306 	case offsetof(struct arphdr, ar_hrd):
307 		get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv);
308 		fw->arp.arhrd = ar_hrd;
309 		fw->arp.arhrd_mask = 0xffff;
310 		if (inv)
311 			fw->arp.invflags |= IPT_INV_ARPHRD;
312 		break;
313 	case offsetof(struct arphdr, ar_pro):
314 		get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv);
315 		fw->arp.arpro = ar_pro;
316 		fw->arp.arpro_mask = 0xffff;
317 		if (inv)
318 			fw->arp.invflags |= IPT_INV_PROTO;
319 		break;
320 	case offsetof(struct arphdr, ar_op):
321 		get_cmp_data(e, &ar_op, sizeof(ar_op), &inv);
322 		fw->arp.arpop = ar_op;
323 		fw->arp.arpop_mask = 0xffff;
324 		if (inv)
325 			fw->arp.invflags |= IPT_INV_ARPOP;
326 		break;
327 	case offsetof(struct arphdr, ar_hln):
328 		get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv);
329 		fw->arp.arhln = ar_hln;
330 		fw->arp.arhln_mask = 0xff;
331 		if (inv)
332 			fw->arp.invflags |= IPT_INV_ARPOP;
333 		break;
334 	default:
335 		if (ctx->payload.offset == sizeof(struct arphdr)) {
336 			if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr))
337 				fw->arp.invflags |= IPT_INV_SRCDEVADDR;
338 		} else if (ctx->payload.offset == sizeof(struct arphdr) +
339 					   fw->arp.arhln) {
340 			get_cmp_data(e, &addr, sizeof(addr), &inv);
341 			fw->arp.src.s_addr = addr.s_addr;
342 			if (ctx->flags & NFT_XT_CTX_BITWISE) {
343 				parse_mask_ipv4(ctx, &fw->arp.smsk);
344 				ctx->flags &= ~NFT_XT_CTX_BITWISE;
345 			} else {
346 				memset(&fw->arp.smsk, 0xff,
347 				       min(ctx->payload.len,
348 					   sizeof(struct in_addr)));
349 			}
350 
351 			if (inv)
352 				fw->arp.invflags |= IPT_INV_SRCIP;
353 		} else if (ctx->payload.offset == sizeof(struct arphdr) +
354 						  fw->arp.arhln +
355 						  sizeof(struct in_addr)) {
356 			if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr))
357 				fw->arp.invflags |= IPT_INV_TGTDEVADDR;
358 		} else if (ctx->payload.offset == sizeof(struct arphdr) +
359 						  fw->arp.arhln +
360 						  sizeof(struct in_addr) +
361 						  fw->arp.arhln) {
362 			get_cmp_data(e, &addr, sizeof(addr), &inv);
363 			fw->arp.tgt.s_addr = addr.s_addr;
364 			if (ctx->flags & NFT_XT_CTX_BITWISE) {
365 				parse_mask_ipv4(ctx, &fw->arp.tmsk);
366 				ctx->flags &= ~NFT_XT_CTX_BITWISE;
367 			} else {
368 				memset(&fw->arp.tmsk, 0xff,
369 				       min(ctx->payload.len,
370 					   sizeof(struct in_addr)));
371 			}
372 
373 			if (inv)
374 				fw->arp.invflags |= IPT_INV_DSTIP;
375 		}
376 		break;
377 	}
378 }
379 
nft_arp_print_header(unsigned int format,const char * chain,const char * pol,const struct xt_counters * counters,bool basechain,uint32_t refs,uint32_t entries)380 static void nft_arp_print_header(unsigned int format, const char *chain,
381 				 const char *pol,
382 				 const struct xt_counters *counters,
383 				 bool basechain, uint32_t refs,
384 				 uint32_t entries)
385 {
386 	printf("Chain %s", chain);
387 	if (basechain && pol) {
388 		printf(" (policy %s", pol);
389 		if (!(format & FMT_NOCOUNTS)) {
390 			fputc(' ', stdout);
391 			xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
392 			fputs("packets, ", stdout);
393 			xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
394 			fputs("bytes", stdout);
395 		}
396 		printf(")\n");
397 	} else {
398 		printf(" (%u references)\n", refs);
399 	}
400 }
401 
nft_arp_print_rule_details(const struct iptables_command_state * cs,unsigned int format)402 static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
403 				       unsigned int format)
404 {
405 	const struct arpt_entry *fw = &cs->arp;
406 	char buf[BUFSIZ];
407 	char iface[IFNAMSIZ+2];
408 	const char *sep = "";
409 	int print_iface = 0;
410 	int i;
411 
412 	if (strlen(cs->jumpto)) {
413 		printf("%s-j %s", sep, cs->jumpto);
414 		sep = " ";
415 	}
416 
417 	iface[0] = '\0';
418 
419 	if (fw->arp.iniface[0] != '\0') {
420 		strcat(iface, fw->arp.iniface);
421 		print_iface = 1;
422 	}
423 	else if (format & FMT_VIA) {
424 		print_iface = 1;
425 		if (format & FMT_NUMERIC) strcat(iface, "*");
426 		else strcat(iface, "any");
427 	}
428 	if (print_iface) {
429 		printf("%s%s-i %s", sep, fw->arp.invflags & IPT_INV_VIA_IN ?
430 				   "! " : "", iface);
431 		sep = " ";
432 	}
433 
434 	print_iface = 0;
435 	iface[0] = '\0';
436 
437 	if (fw->arp.outiface[0] != '\0') {
438 		strcat(iface, fw->arp.outiface);
439 		print_iface = 1;
440 	}
441 	else if (format & FMT_VIA) {
442 		print_iface = 1;
443 		if (format & FMT_NUMERIC) strcat(iface, "*");
444 		else strcat(iface, "any");
445 	}
446 	if (print_iface) {
447 		printf("%s%s-o %s", sep, fw->arp.invflags & IPT_INV_VIA_OUT ?
448 				   "! " : "", iface);
449 		sep = " ";
450 	}
451 
452 	if (fw->arp.smsk.s_addr != 0L) {
453 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCIP
454 			? "! " : "");
455 		if (format & FMT_NUMERIC)
456 			sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
457 		else
458 			sprintf(buf, "%s", addr_to_anyname(&(fw->arp.src)));
459 		strncat(buf, mask_to_dotted(&(fw->arp.smsk)),
460 			sizeof(buf) - strlen(buf) - 1);
461 		printf("-s %s", buf);
462 		sep = " ";
463 	}
464 
465 	for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++)
466 		if (fw->arp.src_devaddr.mask[i] != 0)
467 			break;
468 	if (i == ARPT_DEV_ADDR_LEN_MAX)
469 		goto after_devsrc;
470 	printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCDEVADDR
471 		? "! " : "");
472 	printf("--src-mac ");
473 	xtables_print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
474 				   (unsigned char *)fw->arp.src_devaddr.mask);
475 	sep = " ";
476 after_devsrc:
477 
478 	if (fw->arp.tmsk.s_addr != 0L) {
479 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_DSTIP
480 			? "! " : "");
481 		if (format & FMT_NUMERIC)
482 			sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
483 		else
484 			sprintf(buf, "%s", addr_to_anyname(&(fw->arp.tgt)));
485 		strncat(buf, mask_to_dotted(&(fw->arp.tmsk)),
486 			sizeof(buf) - strlen(buf) - 1);
487 		printf("-d %s", buf);
488 		sep = " ";
489 	}
490 
491 	for (i = 0; i <ARPT_DEV_ADDR_LEN_MAX; i++)
492 		if (fw->arp.tgt_devaddr.mask[i] != 0)
493 			break;
494 	if (i == ARPT_DEV_ADDR_LEN_MAX)
495 		goto after_devdst;
496 	printf("%s%s", sep, fw->arp.invflags & IPT_INV_TGTDEVADDR
497 		? "! " : "");
498 	printf("--dst-mac ");
499 	xtables_print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
500 				   (unsigned char *)fw->arp.tgt_devaddr.mask);
501 	sep = " ";
502 
503 after_devdst:
504 
505 	if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) {
506 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN
507 			? "! " : "");
508 		printf("--h-length %d", fw->arp.arhln);
509 		if (fw->arp.arhln_mask != 255)
510 			printf("/%d", fw->arp.arhln_mask);
511 		sep = " ";
512 	}
513 
514 	if (fw->arp.arpop_mask != 0) {
515 		int tmp = ntohs(fw->arp.arpop);
516 
517 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP
518 			? "! " : "");
519 		if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC))
520 			printf("--opcode %s", arp_opcodes[tmp-1]);
521 		else
522 			printf("--opcode %d", tmp);
523 
524 		if (fw->arp.arpop_mask != 65535)
525 			printf("/%d", ntohs(fw->arp.arpop_mask));
526 		sep = " ";
527 	}
528 
529 	if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) {
530 		uint16_t tmp = ntohs(fw->arp.arhrd);
531 
532 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD
533 			? "! " : "");
534 		if (tmp == 1 && !(format & FMT_NUMERIC))
535 			printf("--h-type %s", "Ethernet");
536 		else
537 			printf("--h-type %u", tmp);
538 		if (fw->arp.arhrd_mask != 65535)
539 			printf("/%d", ntohs(fw->arp.arhrd_mask));
540 		sep = " ";
541 	}
542 
543 	if (fw->arp.arpro_mask != 0) {
544 		int tmp = ntohs(fw->arp.arpro);
545 
546 		printf("%s%s", sep, fw->arp.invflags & IPT_INV_PROTO
547 			? "! " : "");
548 		if (tmp == 0x0800 && !(format & FMT_NUMERIC))
549 			printf("--proto-type %s", "IPv4");
550 		else
551 			printf("--proto-type 0x%x", tmp);
552 		if (fw->arp.arpro_mask != 65535)
553 			printf("/%x", ntohs(fw->arp.arpro_mask));
554 		sep = " ";
555 	}
556 }
557 
558 static void
nft_arp_save_rule(const void * data,unsigned int format)559 nft_arp_save_rule(const void *data, unsigned int format)
560 {
561 	const struct iptables_command_state *cs = data;
562 
563 	format |= FMT_NUMERIC;
564 
565 	nft_arp_print_rule_details(cs, format);
566 	if (cs->target && cs->target->save)
567 		cs->target->save(&cs->fw, cs->target->t);
568 	printf("\n");
569 }
570 
571 static void
nft_arp_print_rule(struct nft_handle * h,struct nftnl_rule * r,unsigned int num,unsigned int format)572 nft_arp_print_rule(struct nft_handle *h, struct nftnl_rule *r,
573 		   unsigned int num, unsigned int format)
574 {
575 	struct iptables_command_state cs = {};
576 
577 	if (format & FMT_LINENUMBERS)
578 		printf("%u ", num);
579 
580 	nft_rule_to_iptables_command_state(h, r, &cs);
581 
582 	nft_arp_print_rule_details(&cs, format);
583 	print_matches_and_target(&cs, format);
584 
585 	if (!(format & FMT_NOCOUNTS)) {
586 		printf(" , pcnt=");
587 		xtables_print_num(cs.counters.pcnt, format | FMT_NOTABLE);
588 		printf("-- bcnt=");
589 		xtables_print_num(cs.counters.bcnt, format | FMT_NOTABLE);
590 	}
591 
592 	if (!(format & FMT_NONEWLINE))
593 		fputc('\n', stdout);
594 
595 	nft_clear_iptables_command_state(&cs);
596 }
597 
nft_arp_is_same(const void * data_a,const void * data_b)598 static bool nft_arp_is_same(const void *data_a,
599 			    const void *data_b)
600 {
601 	const struct arpt_entry *a = data_a;
602 	const struct arpt_entry *b = data_b;
603 
604 	if (a->arp.src.s_addr != b->arp.src.s_addr
605 	    || a->arp.tgt.s_addr != b->arp.tgt.s_addr
606 	    || a->arp.smsk.s_addr != b->arp.smsk.s_addr
607 	    || a->arp.tmsk.s_addr != b->arp.tmsk.s_addr
608 	    || a->arp.arpro != b->arp.arpro
609 	    || a->arp.flags != b->arp.flags
610 	    || a->arp.invflags != b->arp.invflags) {
611 		DEBUGP("different src/dst/proto/flags/invflags\n");
612 		return false;
613 	}
614 
615 	return is_same_interfaces(a->arp.iniface,
616 				  a->arp.outiface,
617 				  (unsigned char *)a->arp.iniface_mask,
618 				  (unsigned char *)a->arp.outiface_mask,
619 				  b->arp.iniface,
620 				  b->arp.outiface,
621 				  (unsigned char *)b->arp.iniface_mask,
622 				  (unsigned char *)b->arp.outiface_mask);
623 }
624 
nft_arp_save_chain(const struct nftnl_chain * c,const char * policy)625 static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
626 {
627 	const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
628 
629 	printf(":%s %s\n", chain, policy ?: "-");
630 }
631 
632 struct nft_family_ops nft_family_ops_arp = {
633 	.add			= nft_arp_add,
634 	.is_same		= nft_arp_is_same,
635 	.print_payload		= NULL,
636 	.parse_meta		= nft_arp_parse_meta,
637 	.parse_payload		= nft_arp_parse_payload,
638 	.parse_immediate	= nft_arp_parse_immediate,
639 	.print_header		= nft_arp_print_header,
640 	.print_rule		= nft_arp_print_rule,
641 	.save_rule		= nft_arp_save_rule,
642 	.save_chain		= nft_arp_save_chain,
643 	.post_parse		= NULL,
644 	.rule_to_cs		= nft_rule_to_iptables_command_state,
645 	.clear_cs		= nft_clear_iptables_command_state,
646 	.parse_target		= nft_ipv46_parse_target,
647 };
648