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