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