1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
/*
* (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org>
* (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
*
* 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 <http://www.sophos.com>
*/
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <netinet/ip6.h>
#include <libnftnl/rule.h>
#include <libnftnl/expr.h>
#include "nft-shared.h"
#include "nft-ruleparse.h"
#include "xshared.h"
static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx,
const struct nft_xt_ctx_reg *reg,
struct nftnl_expr *e,
struct iptables_command_state *cs)
{
switch (reg->meta_dreg.key) {
case NFT_META_L4PROTO:
cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA);
if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ)
cs->fw6.ipv6.invflags |= XT_INV_PROTO;
return;
default:
break;
}
if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface,
cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface,
cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags) == 0)
return;
ctx->errmsg = "unknown ipv6 meta key";
}
static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg,
struct in6_addr *mask)
{
memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr));
}
static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
const struct nft_xt_ctx_reg *reg,
struct nftnl_expr *e,
struct iptables_command_state *cs)
{
struct in6_addr addr;
uint8_t proto;
bool inv;
switch (reg->payload.offset) {
case offsetof(struct ip6_hdr, ip6_src):
get_cmp_data(e, &addr, sizeof(addr), &inv);
memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr));
if (reg->bitwise.set)
parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk);
else
memset(&cs->fw6.ipv6.smsk, 0xff,
min(reg->payload.len, sizeof(struct in6_addr)));
if (inv)
cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP;
break;
case offsetof(struct ip6_hdr, ip6_dst):
get_cmp_data(e, &addr, sizeof(addr), &inv);
memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr));
if (reg->bitwise.set)
parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk);
else
memset(&cs->fw6.ipv6.dmsk, 0xff,
min(reg->payload.len, sizeof(struct in6_addr)));
if (inv)
cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP;
break;
case offsetof(struct ip6_hdr, ip6_nxt):
get_cmp_data(e, &proto, sizeof(proto), &inv);
cs->fw6.ipv6.proto = proto;
if (inv)
cs->fw6.ipv6.invflags |= IP6T_INV_PROTO;
case offsetof(struct ip6_hdr, ip6_hlim):
if (nft_parse_hl(ctx, e, cs) < 0)
ctx->errmsg = "invalid ttl field match";
break;
default:
DEBUGP("unknown payload offset %d\n", reg->payload.offset);
ctx->errmsg = "unknown payload offset";
break;
}
}
struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = {
.meta = nft_ipv6_parse_meta,
.payload = nft_ipv6_parse_payload,
};
|