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 <arpa/inet.h>
22 #include <net/if_arp.h>
23 #include <netinet/if_ether.h>
24
25 #include <linux/netfilter_arp/arp_tables.h>
26 #include <linux/netfilter/nf_tables.h>
27
28 #include "nft-shared.h"
29 #include "nft.h"
30 #include "xshared.h"
31
need_devaddr(struct arpt_devaddr_info * info)32 static bool need_devaddr(struct arpt_devaddr_info *info)
33 {
34 int i;
35
36 for (i = 0; i < ETH_ALEN; i++) {
37 if (info->addr[i] || info->mask[i])
38 return true;
39 }
40
41 return false;
42 }
43
nft_arp_add(struct nft_handle * h,struct nft_rule_ctx * ctx,struct nftnl_rule * r,struct iptables_command_state * cs)44 static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
45 struct nftnl_rule *r, struct iptables_command_state *cs)
46 {
47 struct arpt_entry *fw = &cs->arp;
48 uint32_t op;
49 int ret = 0;
50
51 if (fw->arp.iniface[0] != '\0') {
52 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
53 add_iface(h, r, fw->arp.iniface, NFT_META_IIFNAME, op);
54 }
55
56 if (fw->arp.outiface[0] != '\0') {
57 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
58 add_iface(h, r, fw->arp.outiface, NFT_META_OIFNAME, op);
59 }
60
61 if (fw->arp.arhrd != 0 ||
62 fw->arp.arhrd_mask != 0xffff ||
63 fw->arp.invflags & IPT_INV_ARPHRD) {
64 uint8_t reg;
65
66 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
67 add_payload(h, r, offsetof(struct arphdr, ar_hrd), 2,
68 NFT_PAYLOAD_NETWORK_HEADER, ®);
69 if (fw->arp.arhrd_mask != 0xffff)
70 add_bitwise_u16(h, r, fw->arp.arhrd_mask, 0, reg, ®);
71 add_cmp_u16(r, fw->arp.arhrd, op, reg);
72 }
73
74 if (fw->arp.arpro != 0 ||
75 fw->arp.arpro_mask != 0xffff ||
76 fw->arp.invflags & IPT_INV_PROTO) {
77 uint8_t reg;
78
79 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
80 add_payload(h, r, offsetof(struct arphdr, ar_pro), 2,
81 NFT_PAYLOAD_NETWORK_HEADER, ®);
82 if (fw->arp.arpro_mask != 0xffff)
83 add_bitwise_u16(h, r, fw->arp.arpro_mask, 0, reg, ®);
84 add_cmp_u16(r, fw->arp.arpro, op, reg);
85 }
86
87 if (fw->arp.arhln != 0 ||
88 fw->arp.arhln_mask != 255 ||
89 fw->arp.invflags & IPT_INV_ARPHLN) {
90 uint8_t reg;
91
92 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
93 add_payload(h, r, offsetof(struct arphdr, ar_hln), 1,
94 NFT_PAYLOAD_NETWORK_HEADER, ®);
95 if (fw->arp.arhln_mask != 255)
96 add_bitwise(h, r, &fw->arp.arhln_mask, 1, reg, ®);
97 add_cmp_u8(r, fw->arp.arhln, op, reg);
98 }
99
100 add_proto(h, r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
101
102 if (fw->arp.arpop != 0 ||
103 fw->arp.arpop_mask != 0xffff ||
104 fw->arp.invflags & IPT_INV_ARPOP) {
105 uint8_t reg;
106
107 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
108 add_payload(h, r, offsetof(struct arphdr, ar_op), 2,
109 NFT_PAYLOAD_NETWORK_HEADER, ®);
110 if (fw->arp.arpop_mask != 0xffff)
111 add_bitwise_u16(h, r, fw->arp.arpop_mask, 0, reg, ®);
112 add_cmp_u16(r, fw->arp.arpop, op, reg);
113 }
114
115 if (need_devaddr(&fw->arp.src_devaddr)) {
116 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
117 add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
118 sizeof(struct arphdr),
119 &fw->arp.src_devaddr.addr,
120 &fw->arp.src_devaddr.mask,
121 fw->arp.arhln, op);
122
123 }
124
125 if (fw->arp.src.s_addr != 0 ||
126 fw->arp.smsk.s_addr != 0 ||
127 fw->arp.invflags & IPT_INV_SRCIP) {
128 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
129 add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
130 sizeof(struct arphdr) + fw->arp.arhln,
131 &fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
132 sizeof(struct in_addr), op);
133 }
134
135
136 if (need_devaddr(&fw->arp.tgt_devaddr)) {
137 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
138 add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
139 sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
140 &fw->arp.tgt_devaddr.addr,
141 &fw->arp.tgt_devaddr.mask,
142 fw->arp.arhln, op);
143 }
144
145 if (fw->arp.tgt.s_addr != 0 ||
146 fw->arp.tmsk.s_addr != 0 ||
147 fw->arp.invflags & IPT_INV_DSTIP) {
148 op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
149 add_addr(h, r, NFT_PAYLOAD_NETWORK_HEADER,
150 sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
151 &fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
152 sizeof(struct in_addr), op);
153 }
154
155 /* Counters need to me added before the target, otherwise they are
156 * increased for each rule because of the way nf_tables works.
157 */
158 if (add_counters(r, fw->counters.pcnt, fw->counters.bcnt) < 0)
159 return -1;
160
161 if (cs->target != NULL) {
162 /* Standard target? */
163 if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
164 ret = add_verdict(r, NF_ACCEPT);
165 else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
166 ret = add_verdict(r, NF_DROP);
167 else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
168 ret = add_verdict(r, NFT_RETURN);
169 else
170 ret = add_target(r, cs->target->t);
171 } else if (strlen(cs->jumpto) > 0) {
172 /* No goto in arptables */
173 ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
174 }
175
176 return ret;
177 }
178
nft_arp_print_header(unsigned int format,const char * chain,const char * pol,const struct xt_counters * counters,int refs,uint32_t entries)179 static void nft_arp_print_header(unsigned int format, const char *chain,
180 const char *pol,
181 const struct xt_counters *counters,
182 int refs, uint32_t entries)
183 {
184 printf("Chain %s", chain);
185 if (pol) {
186 printf(" (policy %s", pol);
187 if (!(format & FMT_NOCOUNTS)) {
188 fputc(' ', stdout);
189 xtables_print_num(counters->pcnt, (format|FMT_NOTABLE));
190 fputs("packets, ", stdout);
191 xtables_print_num(counters->bcnt, (format|FMT_NOTABLE));
192 fputs("bytes", stdout);
193 }
194 printf(")\n");
195 } else {
196 printf(" (%d references)\n", refs);
197 }
198 }
199
print_iface(char letter,const char * iface,unsigned int format,bool invert,const char ** sep)200 static void print_iface(char letter, const char *iface,
201 unsigned int format, bool invert, const char **sep)
202 {
203 if (iface[0] == '\0' || (!strcmp(iface, "+") && !invert)) {
204 if (!(format & FMT_VIA))
205 return;
206 iface = (format & FMT_NUMERIC) ? "*" : "any";
207 }
208 printf("%s%s-%c %s", *sep, invert ? "! " : "", letter, iface);
209 *sep = " ";
210 }
211
nft_arp_print_rule_details(const struct iptables_command_state * cs,unsigned int format)212 static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
213 unsigned int format)
214 {
215 const struct arpt_entry *fw = &cs->arp;
216 const char *sep = "";
217 int i;
218
219 if (strlen(cs->jumpto)) {
220 printf("%s-j %s", sep, cs->jumpto);
221 sep = " ";
222 }
223
224 print_iface('i', fw->arp.iniface, format,
225 fw->arp.invflags & IPT_INV_VIA_IN, &sep);
226 print_iface('o', fw->arp.outiface, format,
227 fw->arp.invflags & IPT_INV_VIA_OUT, &sep);
228
229 if (fw->arp.smsk.s_addr != 0L) {
230 printf("%s%s-s %s", sep,
231 fw->arp.invflags & IPT_INV_SRCIP ? "! " : "",
232 ipv4_addr_to_string(&fw->arp.src,
233 &fw->arp.smsk, format));
234 sep = " ";
235 }
236
237 for (i = 0; i < ARPT_DEV_ADDR_LEN_MAX; i++)
238 if (fw->arp.src_devaddr.mask[i] != 0)
239 break;
240 if (i == ARPT_DEV_ADDR_LEN_MAX)
241 goto after_devsrc;
242 printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCDEVADDR
243 ? "! " : "");
244 printf("--src-mac ");
245 xtables_print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
246 (unsigned char *)fw->arp.src_devaddr.mask);
247 sep = " ";
248 after_devsrc:
249
250 if (fw->arp.tmsk.s_addr != 0L) {
251 printf("%s%s-d %s", sep,
252 fw->arp.invflags & IPT_INV_DSTIP ? "! " : "",
253 ipv4_addr_to_string(&fw->arp.tgt,
254 &fw->arp.tmsk, format));
255 sep = " ";
256 }
257
258 for (i = 0; i <ARPT_DEV_ADDR_LEN_MAX; i++)
259 if (fw->arp.tgt_devaddr.mask[i] != 0)
260 break;
261 if (i == ARPT_DEV_ADDR_LEN_MAX)
262 goto after_devdst;
263 printf("%s%s", sep, fw->arp.invflags & IPT_INV_TGTDEVADDR
264 ? "! " : "");
265 printf("--dst-mac ");
266 xtables_print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
267 (unsigned char *)fw->arp.tgt_devaddr.mask);
268 sep = " ";
269
270 after_devdst:
271
272 if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6 ||
273 fw->arp.invflags & IPT_INV_ARPHLN) {
274 printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN
275 ? "! " : "");
276 printf("--h-length %d", fw->arp.arhln);
277 if (fw->arp.arhln_mask != 255)
278 printf("/%d", fw->arp.arhln_mask);
279 sep = " ";
280 }
281
282 if (fw->arp.arpop_mask != 65535 || fw->arp.arpop != 0 ||
283 fw->arp.invflags & IPT_INV_ARPOP) {
284 int tmp = ntohs(fw->arp.arpop);
285
286 printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP
287 ? "! " : "");
288 if (tmp <= ARP_NUMOPCODES && !(format & FMT_NUMERIC))
289 printf("--opcode %s", arp_opcodes[tmp-1]);
290 else
291 printf("--opcode %d", tmp);
292
293 if (fw->arp.arpop_mask != 65535)
294 printf("/%d", ntohs(fw->arp.arpop_mask));
295 sep = " ";
296 }
297
298 if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1) ||
299 fw->arp.invflags & IPT_INV_ARPHRD) {
300 uint16_t tmp = ntohs(fw->arp.arhrd);
301
302 printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD
303 ? "! " : "");
304 if (tmp == 1 && !(format & FMT_NUMERIC))
305 printf("--h-type %s", "Ethernet");
306 else
307 printf("--h-type 0x%x", tmp);
308 if (fw->arp.arhrd_mask != 65535)
309 printf("/0x%x", ntohs(fw->arp.arhrd_mask));
310 sep = " ";
311 }
312
313 if (fw->arp.arpro_mask != 65535 || fw->arp.arpro != 0 ||
314 fw->arp.invflags & IPT_INV_PROTO) {
315 int tmp = ntohs(fw->arp.arpro);
316
317 printf("%s%s", sep, fw->arp.invflags & IPT_INV_PROTO
318 ? "! " : "");
319 if (tmp == 0x0800 && !(format & FMT_NUMERIC))
320 printf("--proto-type %s", "IPv4");
321 else
322 printf("--proto-type 0x%x", tmp);
323 if (fw->arp.arpro_mask != 65535)
324 printf("/0x%x", ntohs(fw->arp.arpro_mask));
325 sep = " ";
326 }
327 }
328
329 static void
nft_arp_save_rule(const struct iptables_command_state * cs,unsigned int format)330 nft_arp_save_rule(const struct iptables_command_state *cs, unsigned int format)
331 {
332 format |= FMT_NUMERIC;
333
334 printf(" ");
335 nft_arp_print_rule_details(cs, format);
336 if (cs->target && cs->target->save)
337 cs->target->save(&cs->fw, cs->target->t);
338 printf("\n");
339 }
340
341 static void nft_arp_init_cs(struct iptables_command_state *cs);
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_arp_init_cs(&cs);
353 nft_rule_to_iptables_command_state(h, r, &cs);
354
355 nft_arp_print_rule_details(&cs, format);
356 print_matches_and_target(&cs, format);
357
358 if (!(format & FMT_NOCOUNTS)) {
359 printf(" , pcnt=");
360 xtables_print_num(cs.counters.pcnt, format | FMT_NOTABLE);
361 printf("-- bcnt=");
362 xtables_print_num(cs.counters.bcnt, format | FMT_NOTABLE);
363 }
364
365 if (!(format & FMT_NONEWLINE))
366 fputc('\n', stdout);
367
368 xtables_clear_iptables_command_state(&cs);
369 }
370
nft_arp_is_same(const struct iptables_command_state * cs_a,const struct iptables_command_state * cs_b)371 static bool nft_arp_is_same(const struct iptables_command_state *cs_a,
372 const struct iptables_command_state *cs_b)
373 {
374 const struct arpt_entry *a = &cs_a->arp;
375 const struct arpt_entry *b = &cs_b->arp;
376
377 if (a->arp.src.s_addr != b->arp.src.s_addr
378 || a->arp.tgt.s_addr != b->arp.tgt.s_addr
379 || a->arp.smsk.s_addr != b->arp.smsk.s_addr
380 || a->arp.tmsk.s_addr != b->arp.tmsk.s_addr
381 || a->arp.arpro != b->arp.arpro
382 || a->arp.flags != b->arp.flags
383 || a->arp.invflags != b->arp.invflags) {
384 DEBUGP("different src/dst/proto/flags/invflags\n");
385 return false;
386 }
387
388 return is_same_interfaces(a->arp.iniface,
389 a->arp.outiface,
390 (unsigned char *)a->arp.iniface_mask,
391 (unsigned char *)a->arp.outiface_mask,
392 b->arp.iniface,
393 b->arp.outiface,
394 (unsigned char *)b->arp.iniface_mask,
395 (unsigned char *)b->arp.outiface_mask);
396 }
397
nft_arp_save_chain(const struct nftnl_chain * c,const char * policy)398 static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
399 {
400 const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
401
402 printf(":%s %s\n", chain, policy ?: "-");
403 }
404
getlength_and_mask(const char * from,uint8_t * to,uint8_t * mask)405 static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask)
406 {
407 char *dup = strdup(from);
408 char *p, *buffer;
409 int i, ret = -1;
410
411 if (!dup)
412 return -1;
413
414 if ( (p = strrchr(dup, '/')) != NULL) {
415 *p = '\0';
416 i = strtol(p+1, &buffer, 10);
417 if (*buffer != '\0' || i < 0 || i > 255)
418 goto out_err;
419 *mask = (uint8_t)i;
420 } else
421 *mask = 255;
422 i = strtol(dup, &buffer, 10);
423 if (*buffer != '\0' || i < 0 || i > 255)
424 goto out_err;
425 *to = (uint8_t)i;
426 ret = 0;
427 out_err:
428 free(dup);
429 return ret;
430
431 }
432
get16_and_mask(const char * from,uint16_t * to,uint16_t * mask,int base)433 static int get16_and_mask(const char *from, uint16_t *to,
434 uint16_t *mask, int base)
435 {
436 char *dup = strdup(from);
437 char *p, *buffer;
438 int i, ret = -1;
439
440 if (!dup)
441 return -1;
442
443 if ( (p = strrchr(dup, '/')) != NULL) {
444 *p = '\0';
445 i = strtol(p+1, &buffer, base);
446 if (*buffer != '\0' || i < 0 || i > 65535)
447 goto out_err;
448 *mask = htons((uint16_t)i);
449 } else
450 *mask = 65535;
451 i = strtol(dup, &buffer, base);
452 if (*buffer != '\0' || i < 0 || i > 65535)
453 goto out_err;
454 *to = htons((uint16_t)i);
455 ret = 0;
456 out_err:
457 free(dup);
458 return ret;
459 }
460
nft_arp_post_parse(int command,struct iptables_command_state * cs,struct xtables_args * args)461 static void nft_arp_post_parse(int command,
462 struct iptables_command_state *cs,
463 struct xtables_args *args)
464 {
465 cs->arp.arp.invflags = args->invflags;
466
467 memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ);
468 memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ);
469
470 memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ);
471 memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ);
472
473 cs->arp.counters.pcnt = args->pcnt_cnt;
474 cs->arp.counters.bcnt = args->bcnt_cnt;
475
476 if (command & (CMD_REPLACE | CMD_INSERT |
477 CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
478 if (!(cs->options & OPT_DESTINATION))
479 args->dhostnetworkmask = "0.0.0.0/0";
480 if (!(cs->options & OPT_SOURCE))
481 args->shostnetworkmask = "0.0.0.0/0";
482 }
483
484 if (args->shostnetworkmask)
485 xtables_ipparse_multiple(args->shostnetworkmask,
486 &args->s.addr.v4, &args->s.mask.v4,
487 &args->s.naddrs);
488 if (args->dhostnetworkmask)
489 xtables_ipparse_multiple(args->dhostnetworkmask,
490 &args->d.addr.v4, &args->d.mask.v4,
491 &args->d.naddrs);
492
493 if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
494 (cs->arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
495 xtables_error(PARAMETER_PROBLEM,
496 "! not allowed with multiple"
497 " source or destination IP addresses");
498
499 if (args->src_mac &&
500 xtables_parse_mac_and_mask(args->src_mac,
501 cs->arp.arp.src_devaddr.addr,
502 cs->arp.arp.src_devaddr.mask))
503 xtables_error(PARAMETER_PROBLEM,
504 "Problem with specified source mac");
505 if (args->dst_mac &&
506 xtables_parse_mac_and_mask(args->dst_mac,
507 cs->arp.arp.tgt_devaddr.addr,
508 cs->arp.arp.tgt_devaddr.mask))
509 xtables_error(PARAMETER_PROBLEM,
510 "Problem with specified destination mac");
511 if (args->arp_hlen) {
512 getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln,
513 &cs->arp.arp.arhln_mask);
514
515 if (cs->arp.arp.arhln != 6)
516 xtables_error(PARAMETER_PROBLEM,
517 "Only hardware address length of 6 is supported currently.");
518 }
519 if (args->arp_opcode) {
520 if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop,
521 &cs->arp.arp.arpop_mask, 10)) {
522 int i;
523
524 for (i = 0; i < ARP_NUMOPCODES; i++)
525 if (!strcasecmp(arp_opcodes[i],
526 args->arp_opcode))
527 break;
528 if (i == ARP_NUMOPCODES)
529 xtables_error(PARAMETER_PROBLEM,
530 "Problem with specified opcode");
531 cs->arp.arp.arpop = htons(i+1);
532 }
533 }
534 if (args->arp_htype) {
535 if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd,
536 &cs->arp.arp.arhrd_mask, 16)) {
537 if (strcasecmp(args->arp_htype, "Ethernet"))
538 xtables_error(PARAMETER_PROBLEM,
539 "Problem with specified hardware type");
540 cs->arp.arp.arhrd = htons(1);
541 }
542 }
543 if (args->arp_ptype) {
544 if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro,
545 &cs->arp.arp.arpro_mask, 0)) {
546 if (strcasecmp(args->arp_ptype, "ipv4"))
547 xtables_error(PARAMETER_PROBLEM,
548 "Problem with specified protocol type");
549 cs->arp.arp.arpro = htons(0x800);
550 }
551 }
552 }
553
nft_arp_init_cs(struct iptables_command_state * cs)554 static void nft_arp_init_cs(struct iptables_command_state *cs)
555 {
556 cs->arp.arp.arhln = 6;
557 cs->arp.arp.arhln_mask = 255;
558 cs->arp.arp.arhrd = htons(ARPHRD_ETHER);
559 cs->arp.arp.arhrd_mask = 65535;
560 cs->arp.arp.arpop_mask = 65535;
561 cs->arp.arp.arpro_mask = 65535;
562 }
563
564 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)565 nft_arp_add_entry(struct nft_handle *h,
566 const char *chain, const char *table,
567 struct iptables_command_state *cs,
568 struct xtables_args *args, bool verbose,
569 bool append, int rulenum)
570 {
571 unsigned int i, j;
572 int ret = 1;
573
574 for (i = 0; i < args->s.naddrs; i++) {
575 cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
576 cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
577 for (j = 0; j < args->d.naddrs; j++) {
578 cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
579 cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
580 if (append) {
581 ret = nft_cmd_rule_append(h, chain, table, cs,
582 verbose);
583 } else {
584 ret = nft_cmd_rule_insert(h, chain, table, cs,
585 rulenum, verbose);
586 }
587 }
588 }
589
590 return ret;
591 }
592
593 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)594 nft_arp_delete_entry(struct nft_handle *h,
595 const char *chain, const char *table,
596 struct iptables_command_state *cs,
597 struct xtables_args *args, bool verbose)
598 {
599 unsigned int i, j;
600 int ret = 1;
601
602 for (i = 0; i < args->s.naddrs; i++) {
603 cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
604 cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
605 for (j = 0; j < args->d.naddrs; j++) {
606 cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
607 cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
608 ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
609 }
610 }
611
612 return ret;
613 }
614
615 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)616 nft_arp_check_entry(struct nft_handle *h,
617 const char *chain, const char *table,
618 struct iptables_command_state *cs,
619 struct xtables_args *args, bool verbose)
620 {
621 unsigned int i, j;
622 int ret = 1;
623
624 for (i = 0; i < args->s.naddrs; i++) {
625 cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
626 cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
627 for (j = 0; j < args->d.naddrs; j++) {
628 cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
629 cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
630 ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
631 }
632 }
633
634 return ret;
635 }
636
637 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)638 nft_arp_replace_entry(struct nft_handle *h,
639 const char *chain, const char *table,
640 struct iptables_command_state *cs,
641 struct xtables_args *args, bool verbose,
642 int rulenum)
643 {
644 cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr;
645 cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr;
646 cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr;
647 cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr;
648
649 return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
650 }
651
nft_arp_xlate_mac_and_mask(const struct arpt_devaddr_info * devaddr,const char * addr,bool invert,struct xt_xlate * xl)652 static void nft_arp_xlate_mac_and_mask(const struct arpt_devaddr_info *devaddr,
653 const char *addr,
654 bool invert,
655 struct xt_xlate *xl)
656 {
657 unsigned int i;
658
659 for (i = 0; i < 6; ++i) {
660 if (devaddr->mask[i])
661 break;
662 }
663
664 if (i == 6)
665 return;
666
667 xt_xlate_add(xl, "arp %s ether ", addr);
668 if (invert)
669 xt_xlate_add(xl, "!= ");
670
671 xt_xlate_add(xl, "%02x", (uint8_t)devaddr->addr[0]);
672 for (i = 1; i < 6; ++i)
673 xt_xlate_add(xl, ":%02x", (uint8_t)devaddr->addr[i]);
674
675 for (i = 0; i < 6; ++i) {
676 int j;
677
678 if ((uint8_t)devaddr->mask[i] == 0xff)
679 continue;
680
681 xt_xlate_add(xl, "/%02x", (uint8_t)devaddr->mask[0]);
682
683 for (j = 1; j < 6; ++j)
684 xt_xlate_add(xl, ":%02x", (uint8_t)devaddr->mask[j]);
685 return;
686 }
687 }
688
nft_arp_xlate16(uint16_t v,uint16_t m,const char * what,bool hex,bool inverse,struct xt_xlate * xl)689 static void nft_arp_xlate16(uint16_t v, uint16_t m, const char *what,
690 bool hex, bool inverse,
691 struct xt_xlate *xl)
692 {
693 const char *fmt = hex ? "0x%x " : "%d ";
694
695 if (m) {
696 xt_xlate_add(xl, "arp %s ", what);
697 if (inverse)
698 xt_xlate_add(xl, " !=");
699 if (m != 0xffff) {
700 xt_xlate_add(xl, "& ");
701 xt_xlate_add(xl, fmt, ntohs(m));;
702
703 }
704 xt_xlate_add(xl, fmt, ntohs(v));
705 }
706 }
707
nft_arp_xlate_ipv4_addr(const char * what,const struct in_addr * addr,const struct in_addr * mask,bool inv,struct xt_xlate * xl)708 static void nft_arp_xlate_ipv4_addr(const char *what, const struct in_addr *addr,
709 const struct in_addr *mask,
710 bool inv, struct xt_xlate *xl)
711 {
712 char mbuf[INET_ADDRSTRLEN], abuf[INET_ADDRSTRLEN];
713 const char *op = inv ? "!= " : "";
714 int cidr;
715
716 if (!inv && !addr->s_addr && !mask->s_addr)
717 return;
718
719 inet_ntop(AF_INET, addr, abuf, sizeof(abuf));
720
721 cidr = xtables_ipmask_to_cidr(mask);
722 switch (cidr) {
723 case -1:
724 xt_xlate_add(xl, "arp %s ip & %s %s %s ", what,
725 inet_ntop(AF_INET, mask, mbuf, sizeof(mbuf)),
726 inv ? "!=" : "==", abuf);
727 break;
728 case 32:
729 xt_xlate_add(xl, "arp %s ip %s%s ", what, op, abuf);
730 break;
731 default:
732 xt_xlate_add(xl, "arp %s ip %s%s/%d ", what, op, abuf, cidr);
733 }
734 }
735
nft_arp_xlate(const struct iptables_command_state * cs,struct xt_xlate * xl)736 static int nft_arp_xlate(const struct iptables_command_state *cs,
737 struct xt_xlate *xl)
738 {
739 const struct arpt_entry *fw = &cs->arp;
740 int ret;
741
742 xlate_ifname(xl, "iifname", fw->arp.iniface,
743 fw->arp.invflags & IPT_INV_VIA_IN);
744 xlate_ifname(xl, "oifname", fw->arp.outiface,
745 fw->arp.invflags & IPT_INV_VIA_OUT);
746
747 if (fw->arp.arhrd ||
748 fw->arp.arhrd_mask != 0xffff ||
749 fw->arp.invflags & IPT_INV_ARPHRD)
750 nft_arp_xlate16(fw->arp.arhrd, fw->arp.arhrd_mask,
751 "htype", false,
752 fw->arp.invflags & IPT_INV_ARPHRD, xl);
753
754 if (fw->arp.arhln_mask != 255 || fw->arp.arhln ||
755 fw->arp.invflags & IPT_INV_ARPHLN) {
756 xt_xlate_add(xl, "arp hlen ");
757 if (fw->arp.invflags & IPT_INV_ARPHLN)
758 xt_xlate_add(xl, " !=");
759 if (fw->arp.arhln_mask != 255)
760 xt_xlate_add(xl, "& %d ", fw->arp.arhln_mask);
761 xt_xlate_add(xl, "%d ", fw->arp.arhln);
762 }
763
764 /* added implicitly by arptables-nft */
765 xt_xlate_add(xl, "arp plen %d", 4);
766
767 if (fw->arp.arpop_mask != 65535 ||
768 fw->arp.arpop != 0 ||
769 fw->arp.invflags & IPT_INV_ARPOP)
770 nft_arp_xlate16(fw->arp.arpop, fw->arp.arpop_mask,
771 "operation", false,
772 fw->arp.invflags & IPT_INV_ARPOP, xl);
773
774 if (fw->arp.arpro_mask != 65535 ||
775 fw->arp.invflags & IPT_INV_PROTO ||
776 fw->arp.arpro)
777 nft_arp_xlate16(fw->arp.arpro, fw->arp.arpro_mask,
778 "ptype", true,
779 fw->arp.invflags & IPT_INV_PROTO, xl);
780
781 if (fw->arp.smsk.s_addr != 0L)
782 nft_arp_xlate_ipv4_addr("saddr", &fw->arp.src, &fw->arp.smsk,
783 fw->arp.invflags & IPT_INV_SRCIP, xl);
784
785 if (fw->arp.tmsk.s_addr != 0L)
786 nft_arp_xlate_ipv4_addr("daddr", &fw->arp.tgt, &fw->arp.tmsk,
787 fw->arp.invflags & IPT_INV_DSTIP, xl);
788
789 nft_arp_xlate_mac_and_mask(&fw->arp.src_devaddr, "saddr",
790 fw->arp.invflags & IPT_INV_SRCDEVADDR, xl);
791 nft_arp_xlate_mac_and_mask(&fw->arp.tgt_devaddr, "daddr",
792 fw->arp.invflags & IPT_INV_TGTDEVADDR, xl);
793
794 ret = xlate_matches(cs, xl);
795 if (!ret)
796 return ret;
797
798 /* Always add counters per rule, as in iptables */
799 xt_xlate_add(xl, "counter");
800 return xlate_action(cs, false, xl);
801 }
802
nft_arp_option_name(int option)803 static const char *nft_arp_option_name(int option)
804 {
805 switch (option) {
806 default: return ip46t_option_name(option);
807 /* different name than iptables */
808 case OPT_SOURCE: return "--source-ip";
809 case OPT_DESTINATION: return "--destination-ip";
810 /* arptables specific ones */
811 case OPT_S_MAC: return "--source-mac";
812 case OPT_D_MAC: return "--destination-mac";
813 case OPT_H_LENGTH: return "--h-length";
814 case OPT_OPCODE: return "--opcode";
815 case OPT_H_TYPE: return "--h-type";
816 case OPT_P_TYPE: return "--proto-type";
817 }
818 }
819
nft_arp_option_invert(int option)820 static int nft_arp_option_invert(int option)
821 {
822 switch (option) {
823 case OPT_S_MAC: return IPT_INV_SRCDEVADDR;
824 case OPT_D_MAC: return IPT_INV_TGTDEVADDR;
825 case OPT_H_LENGTH: return IPT_INV_ARPHLN;
826 case OPT_OPCODE: return IPT_INV_ARPOP;
827 case OPT_H_TYPE: return IPT_INV_ARPHRD;
828 case OPT_P_TYPE: return IPT_INV_PROTO;
829 default: return ip46t_option_invert(option);
830 }
831 }
832
833 struct nft_family_ops nft_family_ops_arp = {
834 .add = nft_arp_add,
835 .is_same = nft_arp_is_same,
836 .print_payload = NULL,
837 .print_header = nft_arp_print_header,
838 .print_rule = nft_arp_print_rule,
839 .save_rule = nft_arp_save_rule,
840 .save_chain = nft_arp_save_chain,
841 .rule_parse = &nft_ruleparse_ops_arp,
842 .cmd_parse = {
843 .post_parse = nft_arp_post_parse,
844 .option_name = nft_arp_option_name,
845 .option_invert = nft_arp_option_invert,
846 .command_default = command_default,
847 .print_help = xtables_printhelp,
848 },
849 .rule_to_cs = nft_rule_to_iptables_command_state,
850 .init_cs = nft_arp_init_cs,
851 .clear_cs = xtables_clear_iptables_command_state,
852 .xlate = nft_arp_xlate,
853 .add_entry = nft_arp_add_entry,
854 .delete_entry = nft_arp_delete_entry,
855 .check_entry = nft_arp_check_entry,
856 .replace_entry = nft_arp_replace_entry,
857 };
858