configure: Avoid addition assignment operators
[iptables-mirror.git] / iptables / nft-ruleparse-arp.c
blobb0671cb0dfe8fa9ceb37195777ea76d3e1c95ad8
1 /*
2 * (C) 2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3 * (C) 2013 by Giuseppe Longo <giuseppelng@gmail.com>
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.
10 * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
13 #include <stddef.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <netdb.h>
18 #include <net/if.h>
19 #include <net/if_arp.h>
20 #include <netinet/if_ether.h>
22 #include <libnftnl/rule.h>
23 #include <libnftnl/expr.h>
25 #include "nft-shared.h"
26 #include "nft-ruleparse.h"
27 #include "xshared.h"
29 static void nft_arp_parse_meta(struct nft_xt_ctx *ctx,
30 const struct nft_xt_ctx_reg *reg,
31 struct nftnl_expr *e,
32 struct iptables_command_state *cs)
34 struct arpt_entry *fw = &cs->arp;
35 uint8_t flags = 0;
37 if (parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface,
38 fw->arp.outiface, &flags) == 0) {
39 fw->arp.invflags |= flags;
40 return;
43 ctx->errmsg = "Unknown arp meta key";
46 static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask)
48 mask->s_addr = reg->bitwise.mask[0];
51 static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg,
52 struct nftnl_expr *e,
53 struct arpt_devaddr_info *info)
55 uint32_t hlen;
56 bool inv;
58 nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen);
60 if (hlen != ETH_ALEN)
61 return false;
63 get_cmp_data(e, info->addr, ETH_ALEN, &inv);
65 if (reg->bitwise.set)
66 memcpy(info->mask, reg->bitwise.mask, ETH_ALEN);
67 else
68 memset(info->mask, 0xff,
69 min(reg->payload.len, ETH_ALEN));
71 return inv;
74 static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
75 const struct nft_xt_ctx_reg *reg,
76 struct nftnl_expr *e,
77 struct iptables_command_state *cs)
79 struct arpt_entry *fw = &cs->arp;
80 struct in_addr addr;
81 uint16_t ar_hrd, ar_pro, ar_op;
82 uint8_t ar_hln, ar_pln;
83 bool inv;
85 switch (reg->payload.offset) {
86 case offsetof(struct arphdr, ar_hrd):
87 get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv);
88 fw->arp.arhrd = ar_hrd;
89 fw->arp.arhrd_mask = 0xffff;
90 if (inv)
91 fw->arp.invflags |= IPT_INV_ARPHRD;
92 if (reg->bitwise.set)
93 fw->arp.arhrd_mask = reg->bitwise.mask[0];
94 break;
95 case offsetof(struct arphdr, ar_pro):
96 get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv);
97 fw->arp.arpro = ar_pro;
98 fw->arp.arpro_mask = 0xffff;
99 if (inv)
100 fw->arp.invflags |= IPT_INV_PROTO;
101 if (reg->bitwise.set)
102 fw->arp.arpro_mask = reg->bitwise.mask[0];
103 break;
104 case offsetof(struct arphdr, ar_op):
105 get_cmp_data(e, &ar_op, sizeof(ar_op), &inv);
106 fw->arp.arpop = ar_op;
107 fw->arp.arpop_mask = 0xffff;
108 if (inv)
109 fw->arp.invflags |= IPT_INV_ARPOP;
110 if (reg->bitwise.set)
111 fw->arp.arpop_mask = reg->bitwise.mask[0];
112 break;
113 case offsetof(struct arphdr, ar_hln):
114 get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv);
115 fw->arp.arhln = ar_hln;
116 fw->arp.arhln_mask = 0xff;
117 if (inv)
118 fw->arp.invflags |= IPT_INV_ARPHLN;
119 if (reg->bitwise.set)
120 fw->arp.arhln_mask = reg->bitwise.mask[0];
121 break;
122 case offsetof(struct arphdr, ar_pln):
123 get_cmp_data(e, &ar_pln, sizeof(ar_pln), &inv);
124 if (ar_pln != 4 || inv)
125 ctx->errmsg = "unexpected ARP protocol length match";
126 break;
127 default:
128 if (reg->payload.offset == sizeof(struct arphdr)) {
129 if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr))
130 fw->arp.invflags |= IPT_INV_SRCDEVADDR;
131 } else if (reg->payload.offset == sizeof(struct arphdr) +
132 fw->arp.arhln) {
133 get_cmp_data(e, &addr, sizeof(addr), &inv);
134 fw->arp.src.s_addr = addr.s_addr;
135 if (reg->bitwise.set)
136 parse_mask_ipv4(reg, &fw->arp.smsk);
137 else
138 memset(&fw->arp.smsk, 0xff,
139 min(reg->payload.len,
140 sizeof(struct in_addr)));
142 if (inv)
143 fw->arp.invflags |= IPT_INV_SRCIP;
144 } else if (reg->payload.offset == sizeof(struct arphdr) +
145 fw->arp.arhln +
146 sizeof(struct in_addr)) {
147 if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr))
148 fw->arp.invflags |= IPT_INV_TGTDEVADDR;
149 } else if (reg->payload.offset == sizeof(struct arphdr) +
150 fw->arp.arhln +
151 sizeof(struct in_addr) +
152 fw->arp.arhln) {
153 get_cmp_data(e, &addr, sizeof(addr), &inv);
154 fw->arp.tgt.s_addr = addr.s_addr;
155 if (reg->bitwise.set)
156 parse_mask_ipv4(reg, &fw->arp.tmsk);
157 else
158 memset(&fw->arp.tmsk, 0xff,
159 min(reg->payload.len,
160 sizeof(struct in_addr)));
162 if (inv)
163 fw->arp.invflags |= IPT_INV_DSTIP;
164 } else {
165 ctx->errmsg = "unknown payload offset";
167 break;
171 struct nft_ruleparse_ops nft_ruleparse_ops_arp = {
172 .meta = nft_arp_parse_meta,
173 .payload = nft_arp_parse_payload,