• 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/ip.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_ipv4_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_ipv4_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->fw.ip.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->fw.ip.invflags |= XT_INV_PROTO;
39 		return;
40 	default:
41 		break;
42 	}
43 
44 	if (parse_meta(ctx, e, reg->meta_dreg.key, cs->fw.ip.iniface,
45 		       cs->fw.ip.outiface, &cs->fw.ip.invflags) == 0)
46 		return;
47 
48 	ctx->errmsg = "unknown ipv4 meta key";
49 }
50 
parse_mask_ipv4(const struct nft_xt_ctx_reg * sreg,struct in_addr * mask)51 static void parse_mask_ipv4(const struct nft_xt_ctx_reg *sreg, struct in_addr *mask)
52 {
53 	mask->s_addr = sreg->bitwise.mask[0];
54 }
55 
get_frag(const struct nft_xt_ctx_reg * reg,struct nftnl_expr * e)56 static bool get_frag(const struct nft_xt_ctx_reg *reg, struct nftnl_expr *e)
57 {
58 	uint8_t op;
59 
60 	/* we assume correct mask and xor */
61 	if (!reg->bitwise.set)
62 		return false;
63 
64 	/* we assume correct data */
65 	op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
66 	if (op == NFT_CMP_EQ)
67 		return true;
68 
69 	return false;
70 }
71 
nft_ipv4_parse_payload(struct nft_xt_ctx * ctx,const struct nft_xt_ctx_reg * sreg,struct nftnl_expr * e,struct iptables_command_state * cs)72 static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
73 				   const struct nft_xt_ctx_reg *sreg,
74 				   struct nftnl_expr *e,
75 				   struct iptables_command_state *cs)
76 {
77 	struct in_addr addr;
78 	uint8_t proto;
79 	bool inv;
80 
81 	switch (sreg->payload.offset) {
82 	case offsetof(struct iphdr, saddr):
83 		get_cmp_data(e, &addr, sizeof(addr), &inv);
84 		cs->fw.ip.src.s_addr = addr.s_addr;
85 		if (sreg->bitwise.set) {
86 			parse_mask_ipv4(sreg, &cs->fw.ip.smsk);
87 		} else {
88 			memset(&cs->fw.ip.smsk, 0xff,
89 			       min(sreg->payload.len, sizeof(struct in_addr)));
90 		}
91 
92 		if (inv)
93 			cs->fw.ip.invflags |= IPT_INV_SRCIP;
94 		break;
95 	case offsetof(struct iphdr, daddr):
96 		get_cmp_data(e, &addr, sizeof(addr), &inv);
97 		cs->fw.ip.dst.s_addr = addr.s_addr;
98 		if (sreg->bitwise.set)
99 			parse_mask_ipv4(sreg, &cs->fw.ip.dmsk);
100 		else
101 			memset(&cs->fw.ip.dmsk, 0xff,
102 			       min(sreg->payload.len, sizeof(struct in_addr)));
103 
104 		if (inv)
105 			cs->fw.ip.invflags |= IPT_INV_DSTIP;
106 		break;
107 	case offsetof(struct iphdr, protocol):
108 		get_cmp_data(e, &proto, sizeof(proto), &inv);
109 		cs->fw.ip.proto = proto;
110 		if (inv)
111 			cs->fw.ip.invflags |= IPT_INV_PROTO;
112 		break;
113 	case offsetof(struct iphdr, frag_off):
114 		cs->fw.ip.flags |= IPT_F_FRAG;
115 		inv = get_frag(sreg, e);
116 		if (inv)
117 			cs->fw.ip.invflags |= IPT_INV_FRAG;
118 		break;
119 	case offsetof(struct iphdr, ttl):
120 		if (nft_parse_hl(ctx, e, cs) < 0)
121 			ctx->errmsg = "invalid ttl field match";
122 		break;
123 	default:
124 		DEBUGP("unknown payload offset %d\n", sreg->payload.offset);
125 		ctx->errmsg = "unknown payload offset";
126 		break;
127 	}
128 }
129 
130 struct nft_ruleparse_ops nft_ruleparse_ops_ipv4 = {
131 	.meta		= nft_ipv4_parse_meta,
132 	.payload	= nft_ipv4_parse_payload,
133 };
134