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