From 4c923250269f9ef4a7b4235f4dc127b04932a8eb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Apr 2023 15:52:14 +0200 Subject: nft: ruleparse: Create family-specific source files Extract the remaining nftnl rule parsing code from nft-.c sources into dedicated ones to complete the separation. Signed-off-by: Phil Sutter --- iptables/nft-ruleparse-arp.c | 168 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 iptables/nft-ruleparse-arp.c (limited to 'iptables/nft-ruleparse-arp.c') diff --git a/iptables/nft-ruleparse-arp.c b/iptables/nft-ruleparse-arp.c new file mode 100644 index 00000000..b68fb06d --- /dev/null +++ b/iptables/nft-ruleparse-arp.c @@ -0,0 +1,168 @@ +/* + * (C) 2013 by Pablo Neira Ayuso + * (C) 2013 by Giuseppe Longo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This code has been sponsored by Sophos Astaro + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "nft-shared.h" +#include "nft-ruleparse.h" +#include "xshared.h" + +static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct arpt_entry *fw = &cs->arp; + uint8_t flags = 0; + + if (parse_meta(ctx, e, reg->meta_dreg.key, fw->arp.iniface, fw->arp.iniface_mask, + fw->arp.outiface, fw->arp.outiface_mask, + &flags) == 0) { + fw->arp.invflags |= flags; + return; + } + + ctx->errmsg = "Unknown arp meta key"; +} + +static void parse_mask_ipv4(const struct nft_xt_ctx_reg *reg, struct in_addr *mask) +{ + mask->s_addr = reg->bitwise.mask[0]; +} + +static bool nft_arp_parse_devaddr(const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct arpt_devaddr_info *info) +{ + uint32_t hlen; + bool inv; + + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &hlen); + + if (hlen != ETH_ALEN) + return false; + + get_cmp_data(e, info->addr, ETH_ALEN, &inv); + + if (reg->bitwise.set) + memcpy(info->mask, reg->bitwise.mask, ETH_ALEN); + else + memset(info->mask, 0xff, + min(reg->payload.len, ETH_ALEN)); + + return inv; +} + +static void nft_arp_parse_payload(struct nft_xt_ctx *ctx, + const struct nft_xt_ctx_reg *reg, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct arpt_entry *fw = &cs->arp; + struct in_addr addr; + uint16_t ar_hrd, ar_pro, ar_op; + uint8_t ar_hln, ar_pln; + bool inv; + + switch (reg->payload.offset) { + case offsetof(struct arphdr, ar_hrd): + get_cmp_data(e, &ar_hrd, sizeof(ar_hrd), &inv); + fw->arp.arhrd = ar_hrd; + fw->arp.arhrd_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPHRD; + break; + case offsetof(struct arphdr, ar_pro): + get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv); + fw->arp.arpro = ar_pro; + fw->arp.arpro_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_PROTO; + break; + case offsetof(struct arphdr, ar_op): + get_cmp_data(e, &ar_op, sizeof(ar_op), &inv); + fw->arp.arpop = ar_op; + fw->arp.arpop_mask = 0xffff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPOP; + break; + case offsetof(struct arphdr, ar_hln): + get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv); + fw->arp.arhln = ar_hln; + fw->arp.arhln_mask = 0xff; + if (inv) + fw->arp.invflags |= IPT_INV_ARPHLN; + break; + case offsetof(struct arphdr, ar_pln): + get_cmp_data(e, &ar_pln, sizeof(ar_pln), &inv); + if (ar_pln != 4 || inv) + ctx->errmsg = "unexpected ARP protocol length match"; + break; + default: + if (reg->payload.offset == sizeof(struct arphdr)) { + if (nft_arp_parse_devaddr(reg, e, &fw->arp.src_devaddr)) + fw->arp.invflags |= IPT_INV_SRCDEVADDR; + } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln) { + get_cmp_data(e, &addr, sizeof(addr), &inv); + fw->arp.src.s_addr = addr.s_addr; + if (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.smsk); + else + memset(&fw->arp.smsk, 0xff, + min(reg->payload.len, + sizeof(struct in_addr))); + + if (inv) + fw->arp.invflags |= IPT_INV_SRCIP; + } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln + + sizeof(struct in_addr)) { + if (nft_arp_parse_devaddr(reg, e, &fw->arp.tgt_devaddr)) + fw->arp.invflags |= IPT_INV_TGTDEVADDR; + } else if (reg->payload.offset == sizeof(struct arphdr) + + fw->arp.arhln + + sizeof(struct in_addr) + + fw->arp.arhln) { + get_cmp_data(e, &addr, sizeof(addr), &inv); + fw->arp.tgt.s_addr = addr.s_addr; + if (reg->bitwise.set) + parse_mask_ipv4(reg, &fw->arp.tmsk); + else + memset(&fw->arp.tmsk, 0xff, + min(reg->payload.len, + sizeof(struct in_addr))); + + if (inv) + fw->arp.invflags |= IPT_INV_DSTIP; + } else { + ctx->errmsg = "unknown payload offset"; + } + break; + } +} + +struct nft_ruleparse_ops nft_ruleparse_ops_arp = { + .meta = nft_arp_parse_meta, + .payload = nft_arp_parse_payload, + .target = nft_ipv46_parse_target, +}; -- cgit v1.2.1