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, ®);
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, ®);
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, ®);
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