• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2012-2014 by Pablo Neira Ayuso <pablo@netfilter.org>
3  * (C) 2013 by Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
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.outiface, &cs->fw6.ipv6.invflags) == 0)
46 		return;
47 
48 	ctx->errmsg = "unknown ipv6 meta key";
49 }
50 
parse_mask_ipv6(const struct nft_xt_ctx_reg * reg,struct in6_addr * mask)51 static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg,
52 			    struct in6_addr *mask)
53 {
54 	memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr));
55 }
56 
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)57 static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
58 				   const struct nft_xt_ctx_reg *reg,
59 				   struct nftnl_expr *e,
60 				   struct iptables_command_state *cs)
61 {
62 	struct in6_addr addr;
63 	uint8_t proto;
64 	bool inv;
65 
66 	switch (reg->payload.offset) {
67 	case offsetof(struct ip6_hdr, ip6_src):
68 		get_cmp_data(e, &addr, sizeof(addr), &inv);
69 		memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr));
70 		if (reg->bitwise.set)
71 			parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk);
72 		else
73 			memset(&cs->fw6.ipv6.smsk, 0xff,
74 			       min(reg->payload.len, sizeof(struct in6_addr)));
75 
76 		if (inv)
77 			cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP;
78 		break;
79 	case offsetof(struct ip6_hdr, ip6_dst):
80 		get_cmp_data(e, &addr, sizeof(addr), &inv);
81 		memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr));
82 		if (reg->bitwise.set)
83 			parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk);
84 		else
85 			memset(&cs->fw6.ipv6.dmsk, 0xff,
86 			       min(reg->payload.len, sizeof(struct in6_addr)));
87 
88 		if (inv)
89 			cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP;
90 		break;
91 	case offsetof(struct ip6_hdr, ip6_nxt):
92 		get_cmp_data(e, &proto, sizeof(proto), &inv);
93 		cs->fw6.ipv6.proto = proto;
94 		if (inv)
95 			cs->fw6.ipv6.invflags |= IP6T_INV_PROTO;
96 	case offsetof(struct ip6_hdr, ip6_hlim):
97 		if (nft_parse_hl(ctx, e, cs) < 0)
98 			ctx->errmsg = "invalid ttl field match";
99 		break;
100 	default:
101 		DEBUGP("unknown payload offset %d\n", reg->payload.offset);
102 		ctx->errmsg = "unknown payload offset";
103 		break;
104 	}
105 }
106 
107 struct nft_ruleparse_ops nft_ruleparse_ops_ipv6 = {
108 	.meta		= nft_ipv6_parse_meta,
109 	.payload	= nft_ipv6_parse_payload,
110 };
111