diff options
Diffstat (limited to 'iptables/nft-shared.c')
-rw-r--r-- | iptables/nft-shared.c | 817 |
1 files changed, 134 insertions, 683 deletions
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 10553ab2..6775578b 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -10,6 +10,7 @@ * This code has been sponsored by Sophos Astaro <http://www.sophos.com> */ +#include <assert.h> #include <string.h> #include <stdio.h> #include <stdlib.h> @@ -20,9 +21,6 @@ #include <xtables.h> -#include <linux/netfilter/xt_comment.h> -#include <linux/netfilter/xt_limit.h> - #include <libmnl/libmnl.h> #include <libnftnl/rule.h> #include <libnftnl/expr.h> @@ -37,136 +35,151 @@ extern struct nft_family_ops nft_family_ops_ipv6; extern struct nft_family_ops nft_family_ops_arp; extern struct nft_family_ops nft_family_ops_bridge; -void add_meta(struct nftnl_rule *r, uint32_t key) +static struct nftnl_expr *xt_nftnl_expr_alloc(const char *name) +{ + struct nftnl_expr *expr = nftnl_expr_alloc(name); + + if (expr) + return expr; + + xtables_error(RESOURCE_PROBLEM, + "Failed to allocate nftnl expression '%s'", name); +} + +void add_meta(struct nft_handle *h, struct nftnl_rule *r, uint32_t key, + uint8_t *dreg) { struct nftnl_expr *expr; + uint8_t reg; - expr = nftnl_expr_alloc("meta"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("meta"); + reg = NFT_REG_1; nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, key); - nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, NFT_REG_1); - + nftnl_expr_set_u32(expr, NFTNL_EXPR_META_DREG, reg); nftnl_rule_add_expr(r, expr); + + *dreg = reg; } -void add_payload(struct nftnl_rule *r, int offset, int len, uint32_t base) +void add_payload(struct nft_handle *h, struct nftnl_rule *r, + int offset, int len, uint32_t base, uint8_t *dreg) { struct nftnl_expr *expr; + uint8_t reg; - expr = nftnl_expr_alloc("payload"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("payload"); + reg = NFT_REG_1; nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_BASE, base); - nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1); + nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_DREG, reg); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_OFFSET, offset); nftnl_expr_set_u32(expr, NFTNL_EXPR_PAYLOAD_LEN, len); - nftnl_rule_add_expr(r, expr); + + *dreg = reg; } /* bitwise operation is = sreg & mask ^ xor */ -void add_bitwise_u16(struct nftnl_rule *r, uint16_t mask, uint16_t xor) +void add_bitwise_u16(struct nft_handle *h, struct nftnl_rule *r, + uint16_t mask, uint16_t xor, uint8_t sreg, uint8_t *dreg) { struct nftnl_expr *expr; + uint8_t reg; - expr = nftnl_expr_alloc("bitwise"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("bitwise"); - nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1); - nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1); + reg = NFT_REG_1; + nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg); + nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, sizeof(uint16_t)); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, &mask, sizeof(uint16_t)); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, sizeof(uint16_t)); - nftnl_rule_add_expr(r, expr); + + *dreg = reg; } -void add_bitwise(struct nftnl_rule *r, uint8_t *mask, size_t len) +void add_bitwise(struct nft_handle *h, struct nftnl_rule *r, + uint8_t *mask, size_t len, uint8_t sreg, uint8_t *dreg) { struct nftnl_expr *expr; uint32_t xor[4] = { 0 }; + uint8_t reg = *dreg; - expr = nftnl_expr_alloc("bitwise"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("bitwise"); - nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, NFT_REG_1); - nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, NFT_REG_1); + nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_SREG, sreg); + nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_DREG, reg); nftnl_expr_set_u32(expr, NFTNL_EXPR_BITWISE_LEN, len); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_MASK, mask, len); nftnl_expr_set(expr, NFTNL_EXPR_BITWISE_XOR, &xor, len); - nftnl_rule_add_expr(r, expr); + + *dreg = reg; } -void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len) +void add_cmp_ptr(struct nftnl_rule *r, uint32_t op, void *data, size_t len, + uint8_t sreg) { struct nftnl_expr *expr; - expr = nftnl_expr_alloc("cmp"); - if (expr == NULL) - return; + expr = xt_nftnl_expr_alloc("cmp"); - nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, NFT_REG_1); + nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_SREG, sreg); nftnl_expr_set_u32(expr, NFTNL_EXPR_CMP_OP, op); nftnl_expr_set(expr, NFTNL_EXPR_CMP_DATA, data, len); - nftnl_rule_add_expr(r, expr); } -void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op) +void add_cmp_u8(struct nftnl_rule *r, uint8_t val, uint32_t op, uint8_t sreg) { - add_cmp_ptr(r, op, &val, sizeof(val)); + add_cmp_ptr(r, op, &val, sizeof(val), sreg); } -void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op) +void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op, uint8_t sreg) { - add_cmp_ptr(r, op, &val, sizeof(val)); + add_cmp_ptr(r, op, &val, sizeof(val), sreg); } -void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op) +void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op, uint8_t sreg) { - add_cmp_ptr(r, op, &val, sizeof(val)); + add_cmp_ptr(r, op, &val, sizeof(val), sreg); } -void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op) +void add_iface(struct nft_handle *h, struct nftnl_rule *r, + char *iface, uint32_t key, uint32_t op) { - int iface_len; + int iface_len = strlen(iface); + uint8_t reg; - iface_len = strlen(iface); - add_meta(r, NFT_META_IIFNAME); if (iface[iface_len - 1] == '+') { - if (iface_len > 1) - add_cmp_ptr(r, op, iface, iface_len - 1); - } else - add_cmp_ptr(r, op, iface, iface_len + 1); -} - -void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op) -{ - int iface_len; - - iface_len = strlen(iface); + if (iface_len > 1) { + iface_len -= 1; + } else if (op != NFT_CMP_EQ) { + op = NFT_CMP_EQ; + iface = "INVAL/D"; + iface_len = strlen(iface) + 1; + } else { + return; /* -o + */ + } + } else { + iface_len += 1; + } - add_meta(r, NFT_META_OIFNAME); - if (iface[iface_len - 1] == '+') { - if (iface_len > 1) - add_cmp_ptr(r, op, iface, iface_len - 1); - } else - add_cmp_ptr(r, op, iface, iface_len + 1); + add_meta(h, r, key, ®); + add_cmp_ptr(r, op, iface, iface_len, reg); } -void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset, +void add_addr(struct nft_handle *h, struct nftnl_rule *r, + enum nft_payload_bases base, int offset, void *data, void *mask, size_t len, uint32_t op) { const unsigned char *m = mask; bool bitwise = false; - int i; + uint8_t reg; + int i, j; for (i = 0; i < len; i++) { if (m[i] != 0xff) { @@ -174,29 +187,36 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset, break; } } + for (j = i + 1; !bitwise && j < len; j++) + bitwise = !!m[j]; if (!bitwise) len = i; - add_payload(r, offset, len, base); + add_payload(h, r, offset, len, base, ®); if (bitwise) - add_bitwise(r, mask, len); + add_bitwise(h, r, mask, len, reg, ®); - add_cmp_ptr(r, op, data, len); + add_cmp_ptr(r, op, data, len, reg); } -void add_proto(struct nftnl_rule *r, int offset, size_t len, - uint8_t proto, uint32_t op) +void add_proto(struct nft_handle *h, struct nftnl_rule *r, + int offset, size_t len, uint8_t proto, uint32_t op) { - add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER); - add_cmp_u8(r, proto, op); + uint8_t reg; + + add_payload(h, r, offset, len, NFT_PAYLOAD_NETWORK_HEADER, ®); + add_cmp_u8(r, proto, op, reg); } -void add_l4proto(struct nftnl_rule *r, uint8_t proto, uint32_t op) +void add_l4proto(struct nft_handle *h, struct nftnl_rule *r, + uint8_t proto, uint32_t op) { - add_meta(r, NFT_META_L4PROTO); - add_cmp_u8(r, proto, op); + uint8_t reg; + + add_meta(h, r, NFT_META_L4PROTO, ®); + add_cmp_u8(r, proto, op, reg); } bool is_same_interfaces(const char *a_iniface, const char *a_outiface, @@ -233,607 +253,20 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface, return true; } -static void parse_ifname(const char *name, unsigned int len, char *dst, unsigned char *mask) +void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op) { - if (len == 0) - return; - - memcpy(dst, name, len); - if (name[len - 1] == '\0') { - if (mask) - memset(mask, 0xff, len); - return; - } - - if (len >= IFNAMSIZ) - return; - - /* wildcard */ - dst[len++] = '+'; - if (len >= IFNAMSIZ) - return; - dst[len++] = 0; - if (mask) - memset(mask, 0xff, len - 2); -} - -int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface, - unsigned char *iniface_mask, char *outiface, - unsigned char *outiface_mask, uint8_t *invflags) -{ - uint32_t value; - const void *ifname; uint32_t len; - switch(key) { - case NFT_META_IIF: - value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_IN; - - if_indextoname(value, iniface); - - memset(iniface_mask, 0xff, strlen(iniface)+1); - break; - case NFT_META_OIF: - value = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_OUT; - - if_indextoname(value, outiface); - - memset(outiface_mask, 0xff, strlen(outiface)+1); - break; - case NFT_META_BRI_IIFNAME: - case NFT_META_IIFNAME: - ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_IN; - - parse_ifname(ifname, len, iniface, iniface_mask); - break; - case NFT_META_BRI_OIFNAME: - case NFT_META_OIFNAME: - ifname = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - *invflags |= IPT_INV_VIA_OUT; - - parse_ifname(ifname, len, outiface, outiface_mask); - break; - default: - return -1; - } - - return 0; -} - -static void nft_parse_target(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - uint32_t tg_len; - const char *targname = nftnl_expr_get_str(e, NFTNL_EXPR_TG_NAME); - const void *targinfo = nftnl_expr_get(e, NFTNL_EXPR_TG_INFO, &tg_len); - struct xtables_target *target; - struct xt_entry_target *t; - size_t size; - void *data = ctx->cs; - - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len; - - t = xtables_calloc(1, size); - memcpy(&t->data, targinfo, tg_len); - t->u.target_size = size; - t->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); - strcpy(t->u.user.name, target->name); - - target->t = t; - - ctx->h->ops->parse_target(target, data); -} - -static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - uint32_t mt_len; - const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME); - const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len); - struct xtables_match *match; - struct xtables_rule_match **matches; - struct xt_entry_match *m; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - case NFPROTO_IPV6: - case NFPROTO_BRIDGE: - matches = &ctx->cs->matches; - break; - default: - fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", - ctx->h->family); - exit(EXIT_FAILURE); - } - - match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); - if (match == NULL) - return; - - m = xtables_calloc(1, sizeof(struct xt_entry_match) + mt_len); - memcpy(&m->data, mt_info, mt_len); - m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match)); - m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); - strcpy(m->u.user.name, match->name); - - match->m = m; - - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); -} - -void print_proto(uint16_t proto, int invert) -{ - const struct protoent *pent = getprotobynumber(proto); - - if (invert) - printf("! "); - - if (pent) { - printf("-p %s ", pent->p_name); - return; - } - - printf("-p %u ", proto); + memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen); + *op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); } void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv) { - uint32_t len; uint8_t op; - memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen); - op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); - if (op == NFT_CMP_NEQ) - *inv = true; - else - *inv = false; -} - -static void nft_meta_set_to_target(struct nft_xt_ctx *ctx) -{ - struct xtables_target *target; - struct xt_entry_target *t; - unsigned int size; - const char *targname; - - switch (ctx->meta.key) { - case NFT_META_NFTRACE: - if (ctx->immediate.data[0] == 0) - return; - targname = "TRACE"; - break; - default: - return; - } - - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target == NULL) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; - - t = xtables_calloc(1, size); - t->u.target_size = size; - t->u.user.revision = target->revision; - strcpy(t->u.user.name, targname); - - target->t = t; - - ctx->h->ops->parse_target(target, ctx->cs); -} - -static void nft_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - ctx->meta.key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); - - if (nftnl_expr_is_set(e, NFTNL_EXPR_META_SREG) && - (ctx->flags & NFT_XT_CTX_IMMEDIATE) && - nftnl_expr_get_u32(e, NFTNL_EXPR_META_SREG) == ctx->immediate.reg) { - ctx->flags &= ~NFT_XT_CTX_IMMEDIATE; - nft_meta_set_to_target(ctx); - return; - } - - ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); - ctx->flags |= NFT_XT_CTX_META; -} - -static void nft_parse_payload(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - memcpy(&ctx->prev_payload, &ctx->payload, - sizeof(ctx->prev_payload)); - ctx->flags |= NFT_XT_CTX_PREV_PAYLOAD; - } - - ctx->reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); - ctx->payload.base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); - ctx->payload.offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); - ctx->payload.len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); - ctx->flags |= NFT_XT_CTX_PAYLOAD; -} - -static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - uint32_t reg, len; - const void *data; - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_SREG); - if (ctx->reg && reg != ctx->reg) - return; - - data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); - memcpy(ctx->bitwise.xor, data, len); - data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len); - memcpy(ctx->bitwise.mask, data, len); - ctx->flags |= NFT_XT_CTX_BITWISE; -} - -static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - void *data = ctx->cs; - uint32_t reg; - - reg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); - if (ctx->reg && reg != ctx->reg) - return; - - if (ctx->flags & NFT_XT_CTX_META) { - ctx->h->ops->parse_meta(ctx, e, data); - ctx->flags &= ~NFT_XT_CTX_META; - } - /* bitwise context is interpreted from payload */ - if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - ctx->h->ops->parse_payload(ctx, e, data); - ctx->flags &= ~NFT_XT_CTX_PAYLOAD; - } -} - -static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters) -{ - counters->pcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS); - counters->bcnt = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES); -} - -static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN); - const char *jumpto = NULL; - bool nft_goto = false; - void *data = ctx->cs; - int verdict; - - if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) { - const void *imm_data; - uint32_t len; - - imm_data = nftnl_expr_get_data(e, NFTNL_EXPR_IMM_DATA, &len); - - if (len > sizeof(ctx->immediate.data)) - return; - - memcpy(ctx->immediate.data, imm_data, len); - ctx->immediate.len = len; - ctx->immediate.reg = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG); - ctx->flags |= NFT_XT_CTX_IMMEDIATE; - return; - } - - verdict = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT); - /* Standard target? */ - switch(verdict) { - case NF_ACCEPT: - jumpto = "ACCEPT"; - break; - case NF_DROP: - jumpto = "DROP"; - break; - case NFT_RETURN: - jumpto = "RETURN"; - break;; - case NFT_GOTO: - nft_goto = true; - /* fall through */ - case NFT_JUMP: - jumpto = chain; - break; - } - - ctx->h->ops->parse_immediate(jumpto, nft_goto, data); -} - -static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e) -{ - __u32 burst = nftnl_expr_get_u32(e, NFTNL_EXPR_LIMIT_BURST); - __u64 unit = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_UNIT); - __u64 rate = nftnl_expr_get_u64(e, NFTNL_EXPR_LIMIT_RATE); - struct xtables_rule_match **matches; - struct xtables_match *match; - struct xt_rateinfo *rinfo; - size_t size; - - switch (ctx->h->family) { - case NFPROTO_IPV4: - case NFPROTO_IPV6: - case NFPROTO_BRIDGE: - matches = &ctx->cs->matches; - break; - default: - fprintf(stderr, "BUG: nft_parse_limit() unknown family %d\n", - ctx->h->family); - exit(EXIT_FAILURE); - } - - match = xtables_find_match("limit", XTF_TRY_LOAD, matches); - if (match == NULL) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; - match->m = xtables_calloc(1, size); - match->m->u.match_size = size; - strcpy(match->m->u.user.name, match->name); - match->m->u.user.revision = match->revision; - xs_init_match(match); - - rinfo = (void *)match->m->data; - rinfo->avg = XT_LIMIT_SCALE * unit / rate; - rinfo->burst = burst; - - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); -} - -static void nft_parse_lookup(struct nft_xt_ctx *ctx, struct nft_handle *h, - struct nftnl_expr *e) -{ - if (ctx->h->ops->parse_lookup) - ctx->h->ops->parse_lookup(ctx, e, NULL); -} - -void nft_rule_to_iptables_command_state(struct nft_handle *h, - const struct nftnl_rule *r, - struct iptables_command_state *cs) -{ - struct nftnl_expr_iter *iter; - struct nftnl_expr *expr; - struct nft_xt_ctx ctx = { - .cs = cs, - .h = h, - .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE), - }; - - iter = nftnl_expr_iter_create(r); - if (iter == NULL) - return; - - ctx.iter = iter; - expr = nftnl_expr_iter_next(iter); - while (expr != NULL) { - const char *name = - nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); - - if (strcmp(name, "counter") == 0) - nft_parse_counter(expr, &ctx.cs->counters); - else if (strcmp(name, "payload") == 0) - nft_parse_payload(&ctx, expr); - else if (strcmp(name, "meta") == 0) - nft_parse_meta(&ctx, expr); - else if (strcmp(name, "bitwise") == 0) - nft_parse_bitwise(&ctx, expr); - else if (strcmp(name, "cmp") == 0) - nft_parse_cmp(&ctx, expr); - else if (strcmp(name, "immediate") == 0) - nft_parse_immediate(&ctx, expr); - else if (strcmp(name, "match") == 0) - nft_parse_match(&ctx, expr); - else if (strcmp(name, "target") == 0) - nft_parse_target(&ctx, expr); - else if (strcmp(name, "limit") == 0) - nft_parse_limit(&ctx, expr); - else if (strcmp(name, "lookup") == 0) - nft_parse_lookup(&ctx, h, expr); - - expr = nftnl_expr_iter_next(iter); - } - - nftnl_expr_iter_destroy(iter); - - if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) { - const void *data; - uint32_t len, size; - const char *comment; - - data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); - comment = get_comment(data, len); - if (comment) { - struct xtables_match *match; - struct xt_entry_match *m; - - match = xtables_find_match("comment", XTF_TRY_LOAD, - &cs->matches); - if (match == NULL) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_match)) - + match->size; - m = xtables_calloc(1, size); - - strncpy((char *)m->data, comment, match->size - 1); - m->u.match_size = size; - m->u.user.revision = 0; - strcpy(m->u.user.name, match->name); - - match->m = m; - } - } - - if (cs->target != NULL) { - cs->jumpto = cs->target->name; - } else if (cs->jumpto != NULL) { - struct xt_entry_target *t; - uint32_t size; - - cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); - if (!cs->target) - return; - - size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size; - t = xtables_calloc(1, size); - t->u.target_size = size; - t->u.user.revision = cs->target->revision; - strcpy(t->u.user.name, cs->jumpto); - cs->target->t = t; - } else { - cs->jumpto = ""; - } -} - -void nft_clear_iptables_command_state(struct iptables_command_state *cs) -{ - xtables_rule_matches_free(&cs->matches); - if (cs->target) { - free(cs->target->t); - cs->target->t = NULL; - - if (cs->target == cs->target->next) { - free(cs->target); - cs->target = NULL; - } - } -} - -void print_header(unsigned int format, const char *chain, const char *pol, - const struct xt_counters *counters, bool basechain, - uint32_t refs, uint32_t entries) -{ - printf("Chain %s", chain); - if (basechain) { - printf(" (policy %s", pol); - if (!(format & FMT_NOCOUNTS)) { - fputc(' ', stdout); - xtables_print_num(counters->pcnt, (format|FMT_NOTABLE)); - fputs("packets, ", stdout); - xtables_print_num(counters->bcnt, (format|FMT_NOTABLE)); - fputs("bytes", stdout); - } - printf(")\n"); - } else { - printf(" (%u references)\n", refs); - } - - if (format & FMT_LINENUMBERS) - printf(FMT("%-4s ", "%s "), "num"); - if (!(format & FMT_NOCOUNTS)) { - if (format & FMT_KILOMEGAGIGA) { - printf(FMT("%5s ","%s "), "pkts"); - printf(FMT("%5s ","%s "), "bytes"); - } else { - printf(FMT("%8s ","%s "), "pkts"); - printf(FMT("%10s ","%s "), "bytes"); - } - } - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ","%s "), "target"); - fputs(" prot ", stdout); - if (format & FMT_OPTIONS) - fputs("opt", stdout); - if (format & FMT_VIA) { - printf(FMT(" %-6s ","%s "), "in"); - printf(FMT("%-6s ","%s "), "out"); - } - printf(FMT(" %-19s ","%s "), "source"); - printf(FMT(" %-19s "," %s "), "destination"); - printf("\n"); -} - -void print_rule_details(const struct iptables_command_state *cs, - const char *targname, uint8_t flags, - uint8_t invflags, uint8_t proto, - unsigned int num, unsigned int format) -{ - if (format & FMT_LINENUMBERS) - printf(FMT("%-4u ", "%u "), num); - - if (!(format & FMT_NOCOUNTS)) { - xtables_print_num(cs->counters.pcnt, format); - xtables_print_num(cs->counters.bcnt, format); - } - - if (!(format & FMT_NOTARGET)) - printf(FMT("%-9s ", "%s "), targname ? targname : ""); - - fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout); - { - const char *pname = - proto_to_name(proto, format&FMT_NUMERIC); - if (pname) - printf(FMT("%-5s", "%s "), pname); - else - printf(FMT("%-5hu", "%hu "), proto); - } -} - -static void -print_iface(char letter, const char *iface, const unsigned char *mask, int inv) -{ - unsigned int i; - - if (mask[0] == 0) - return; - - printf("%s-%c ", inv ? "! " : "", letter); - - for (i = 0; i < IFNAMSIZ; i++) { - if (mask[i] != 0) { - if (iface[i] != '\0') - printf("%c", iface[i]); - } else { - if (iface[i-1] != '\0') - printf("+"); - break; - } - } - - printf(" "); -} - -void save_rule_details(const struct iptables_command_state *cs, - uint8_t invflags, uint16_t proto, - const char *iniface, - unsigned const char *iniface_mask, - const char *outiface, - unsigned const char *outiface_mask) -{ - if (iniface != NULL) { - print_iface('i', iniface, iniface_mask, - invflags & IPT_INV_VIA_IN); - } - if (outiface != NULL) { - print_iface('o', outiface, outiface_mask, - invflags & IPT_INV_VIA_OUT); - } - - if (proto > 0) { - const struct protoent *pent = getprotobynumber(proto); - - if (invflags & XT_INV_PROTO) - printf("! "); - - if (pent) - printf("-p %s ", pent->p_name); - else - printf("-p %u ", proto); - } + __get_cmp_data(e, data, dlen, &op); + *inv = (op == NFT_CMP_NEQ); } void nft_ipv46_save_chain(const struct nftnl_chain *c, const char *policy) @@ -854,33 +287,33 @@ void save_matches_and_target(const struct iptables_command_state *cs, for (matchp = cs->matches; matchp; matchp = matchp->next) { if (matchp->match->alias) { - printf("-m %s", + printf(" -m %s", matchp->match->alias(matchp->match->m)); } else - printf("-m %s", matchp->match->name); + printf(" -m %s", matchp->match->name); if (matchp->match->save != NULL) { /* cs->fw union makes the trick */ matchp->match->save(fw, matchp->match->m); } - printf(" "); } if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS) - printf("-c %llu %llu ", + printf(" -c %llu %llu", (unsigned long long)cs->counters.pcnt, (unsigned long long)cs->counters.bcnt); if (cs->target != NULL) { if (cs->target->alias) { - printf("-j %s", cs->target->alias(cs->target->t)); + printf(" -j %s", cs->target->alias(cs->target->t)); } else - printf("-j %s", cs->jumpto); + printf(" -j %s", cs->jumpto); - if (cs->target->save != NULL) + if (cs->target->save != NULL) { cs->target->save(fw, cs->target->t); + } } else if (strlen(cs->jumpto) > 0) { - printf("-%c %s", goto_flag ? 'g' : 'j', cs->jumpto); + printf(" -%c %s", goto_flag ? 'g' : 'j', cs->jumpto); } printf("\n"); @@ -933,6 +366,7 @@ bool compare_matches(struct xtables_rule_match *mt1, for (mp1 = mt1, mp2 = mt2; mp1 && mp2; mp1 = mp1->next, mp2 = mp2->next) { struct xt_entry_match *m1 = mp1->match->m; struct xt_entry_match *m2 = mp2->match->m; + size_t cmplen = mp1->match->userspacesize; if (strcmp(m1->u.user.name, m2->u.user.name) != 0) { DEBUGP("mismatching match name\n"); @@ -944,9 +378,13 @@ bool compare_matches(struct xtables_rule_match *mt1, return false; } - if (memcmp(m1->data, m2->data, - mp1->match->userspacesize) != 0) { + if (!strcmp(m1->u.user.name, "among")) + cmplen = m1->u.match_size - sizeof(*m1); + + if (memcmp(m1->data, m2->data, cmplen) != 0) { DEBUGP("mismatch match data\n"); + DEBUG_HEXDUMP("m1->data", m1->data, cmplen); + DEBUG_HEXDUMP("m2->data", m2->data, cmplen); return false; } } @@ -979,17 +417,11 @@ bool compare_targets(struct xtables_target *tg1, struct xtables_target *tg2) return true; } -void nft_ipv46_parse_target(struct xtables_target *t, void *data) -{ - struct iptables_command_state *cs = data; - - cs->target = t; -} - void nft_check_xt_legacy(int family, bool is_ipt_save) { static const char tables6[] = "/proc/net/ip6_tables_names"; static const char tables4[] = "/proc/net/ip_tables_names"; + static const char tablesa[] = "/proc/net/arp_tables_names"; const char *prefix = "ip"; FILE *fp = NULL; char buf[1024]; @@ -1002,6 +434,10 @@ void nft_check_xt_legacy(int family, bool is_ipt_save) fp = fopen(tables6, "r"); prefix = "ip6"; break; + case NFPROTO_ARP: + fp = fopen(tablesa, "r"); + prefix = "arp"; + break; default: break; } @@ -1014,3 +450,18 @@ void nft_check_xt_legacy(int family, bool is_ipt_save) prefix, prefix, is_ipt_save ? "-save" : ""); fclose(fp); } + +enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size) +{ + /* convert size to NETLINK_ALIGN-sized chunks */ + size = (size + NETLINK_ALIGN - 1) / NETLINK_ALIGN; + + /* map 16byte reg to 4byte one */ + if (reg < __NFT_REG_MAX) + reg = NFT_REG32_00 + (reg - 1) * NFT_REG_SIZE / NFT_REG32_SIZE; + + reg += size; + assert(reg <= NFT_REG32_15); + + return reg; +} |