1 /*
2  * Copyright (c) 2021 BayLibre SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(npf_base, CONFIG_NET_PKT_FILTER_LOG_LEVEL);
9 
10 #include <zephyr/net/net_core.h>
11 #include <zephyr/net/net_pkt_filter.h>
12 #include <zephyr/spinlock.h>
13 
14 /*
15  * Our actual rule lists for supported test points
16  */
17 
18 struct npf_rule_list npf_send_rules = {
19 	.rule_head = SYS_SLIST_STATIC_INIT(&send_rules.rule_head),
20 	.lock = { },
21 };
22 
23 struct npf_rule_list npf_recv_rules = {
24 	.rule_head = SYS_SLIST_STATIC_INIT(&recv_rules.rule_head),
25 	.lock = { },
26 };
27 
28 #ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK
29 struct npf_rule_list npf_local_in_recv_rules = {
30 	.rule_head = SYS_SLIST_STATIC_INIT(&local_in_recv_rules.rule_head),
31 	.lock = { },
32 };
33 #endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */
34 
35 #ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK
36 struct npf_rule_list npf_ipv4_recv_rules = {
37 	.rule_head = SYS_SLIST_STATIC_INIT(&ipv4_recv_rules.rule_head),
38 	.lock = { },
39 };
40 #endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK */
41 
42 #ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK
43 struct npf_rule_list npf_ipv6_recv_rules = {
44 	.rule_head = SYS_SLIST_STATIC_INIT(&ipv6_recv_rules.rule_head),
45 	.lock = { },
46 };
47 #endif /* CONFIG_NET_PKT_FILTER_IPV6_HOOK */
48 
49 /*
50  * Helper function
51  */
get_ip_rules(uint8_t pf)52 static struct npf_rule_list *get_ip_rules(uint8_t pf)
53 {
54 	switch (pf) {
55 	case PF_INET:
56 #ifdef CONFIG_NET_PKT_FILTER_IPV4_HOOK
57 		return &npf_ipv4_recv_rules;
58 #endif
59 		break;
60 	case PF_INET6:
61 #ifdef CONFIG_NET_PKT_FILTER_IPV6_HOOK
62 		return &npf_ipv6_recv_rules;
63 #endif
64 		break;
65 	default:
66 		return NULL;
67 	}
68 
69 	return NULL;
70 }
71 
72 /*
73  * Rule application
74  */
75 
76 /*
77  * All tests must be true to return true.
78  * If no tests then it is true.
79  */
apply_tests(struct npf_rule * rule,struct net_pkt * pkt)80 static bool apply_tests(struct npf_rule *rule, struct net_pkt *pkt)
81 {
82 	struct npf_test *test;
83 	unsigned int i;
84 	bool result;
85 
86 	for (i = 0; i < rule->nb_tests; i++) {
87 		test = rule->tests[i];
88 		result = test->fn(test, pkt);
89 		NET_DBG("test %p result %d", test, result);
90 		if (result == false) {
91 			return false;
92 		}
93 	}
94 
95 	return true;
96 }
97 
98 /*
99  * We return the specified result for the first rule whose tests are all true.
100  */
evaluate(sys_slist_t * rule_head,struct net_pkt * pkt)101 static enum net_verdict evaluate(sys_slist_t *rule_head, struct net_pkt *pkt)
102 {
103 	struct npf_rule *rule;
104 
105 	NET_DBG("rule_head %p on pkt %p", rule_head, pkt);
106 
107 	if (sys_slist_is_empty(rule_head)) {
108 		NET_DBG("no rules");
109 		return NET_OK;
110 	}
111 
112 	SYS_SLIST_FOR_EACH_CONTAINER(rule_head, rule, node) {
113 		if (apply_tests(rule, pkt) == true) {
114 			return rule->result;
115 		}
116 	}
117 
118 	NET_DBG("no matching rules from rule_head %p", rule_head);
119 	return NET_DROP;
120 }
121 
lock_evaluate(struct npf_rule_list * rules,struct net_pkt * pkt)122 static enum net_verdict lock_evaluate(struct npf_rule_list *rules, struct net_pkt *pkt)
123 {
124 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
125 	enum net_verdict result = evaluate(&rules->rule_head, pkt);
126 
127 	k_spin_unlock(&rules->lock, key);
128 	return result;
129 }
130 
net_pkt_filter_send_ok(struct net_pkt * pkt)131 bool net_pkt_filter_send_ok(struct net_pkt *pkt)
132 {
133 	enum net_verdict result = lock_evaluate(&npf_send_rules, pkt);
134 
135 	return result == NET_OK;
136 }
137 
net_pkt_filter_recv_ok(struct net_pkt * pkt)138 bool net_pkt_filter_recv_ok(struct net_pkt *pkt)
139 {
140 	enum net_verdict result = lock_evaluate(&npf_recv_rules, pkt);
141 
142 	return result == NET_OK;
143 }
144 
145 #ifdef CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK
net_pkt_filter_local_in_recv_ok(struct net_pkt * pkt)146 bool net_pkt_filter_local_in_recv_ok(struct net_pkt *pkt)
147 {
148 	enum net_verdict result = lock_evaluate(&npf_local_in_recv_rules, pkt);
149 
150 	return result == NET_OK;
151 }
152 #endif /* CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK */
153 
154 #if defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) || defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK)
net_pkt_filter_ip_recv_ok(struct net_pkt * pkt)155 bool net_pkt_filter_ip_recv_ok(struct net_pkt *pkt)
156 {
157 	struct npf_rule_list *rules = get_ip_rules(net_pkt_family(pkt));
158 
159 	if (!rules) {
160 		NET_DBG("no rules");
161 		return true;
162 	}
163 
164 	enum net_verdict result = lock_evaluate(rules, pkt);
165 
166 	return result == NET_OK;
167 }
168 #endif /* CONFIG_NET_PKT_FILTER_IPV4_HOOK || CONFIG_NET_PKT_FILTER_IPV6_HOOK */
169 
170 /*
171  * Rule management
172  */
173 
npf_insert_rule(struct npf_rule_list * rules,struct npf_rule * rule)174 void npf_insert_rule(struct npf_rule_list *rules, struct npf_rule *rule)
175 {
176 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
177 
178 	NET_DBG("inserting rule %p into %p", rule, rules);
179 	sys_slist_prepend(&rules->rule_head, &rule->node);
180 
181 	k_spin_unlock(&rules->lock, key);
182 }
183 
npf_append_rule(struct npf_rule_list * rules,struct npf_rule * rule)184 void npf_append_rule(struct npf_rule_list *rules, struct npf_rule *rule)
185 {
186 	__ASSERT(sys_slist_peek_tail(&rules->rule_head) != &npf_default_ok.node, "");
187 	__ASSERT(sys_slist_peek_tail(&rules->rule_head) != &npf_default_drop.node, "");
188 
189 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
190 
191 	NET_DBG("appending rule %p into %p", rule, rules);
192 	sys_slist_append(&rules->rule_head, &rule->node);
193 
194 	k_spin_unlock(&rules->lock, key);
195 }
196 
npf_remove_rule(struct npf_rule_list * rules,struct npf_rule * rule)197 bool npf_remove_rule(struct npf_rule_list *rules, struct npf_rule *rule)
198 {
199 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
200 	bool result = sys_slist_find_and_remove(&rules->rule_head, &rule->node);
201 
202 	k_spin_unlock(&rules->lock, key);
203 	NET_DBG("removing rule %p from %p: %d", rule, rules, result);
204 	return result;
205 }
206 
npf_remove_all_rules(struct npf_rule_list * rules)207 bool npf_remove_all_rules(struct npf_rule_list *rules)
208 {
209 	k_spinlock_key_t key = k_spin_lock(&rules->lock);
210 	bool result = !sys_slist_is_empty(&rules->rule_head);
211 
212 	if (result) {
213 		sys_slist_init(&rules->rule_head);
214 		NET_DBG("removing all rules from %p", rules);
215 	}
216 
217 	k_spin_unlock(&rules->lock, key);
218 	return result;
219 }
220 
221 /*
222  * Default rule list terminations.
223  */
224 
225 struct npf_rule npf_default_ok = {
226 	.result = NET_OK,
227 };
228 
229 struct npf_rule npf_default_drop = {
230 	.result = NET_DROP,
231 };
232 
233 /*
234  * Some simple generic conditions
235  */
236 
npf_iface_match(struct npf_test * test,struct net_pkt * pkt)237 bool npf_iface_match(struct npf_test *test, struct net_pkt *pkt)
238 {
239 	struct npf_test_iface *test_iface =
240 			CONTAINER_OF(test, struct npf_test_iface, test);
241 
242 	return test_iface->iface == net_pkt_iface(pkt);
243 }
244 
npf_iface_unmatch(struct npf_test * test,struct net_pkt * pkt)245 bool npf_iface_unmatch(struct npf_test *test, struct net_pkt *pkt)
246 {
247 	return !npf_iface_match(test, pkt);
248 }
249 
npf_orig_iface_match(struct npf_test * test,struct net_pkt * pkt)250 bool npf_orig_iface_match(struct npf_test *test, struct net_pkt *pkt)
251 {
252 	struct npf_test_iface *test_iface =
253 			CONTAINER_OF(test, struct npf_test_iface, test);
254 
255 	return test_iface->iface == net_pkt_orig_iface(pkt);
256 }
257 
npf_orig_iface_unmatch(struct npf_test * test,struct net_pkt * pkt)258 bool npf_orig_iface_unmatch(struct npf_test *test, struct net_pkt *pkt)
259 {
260 	return !npf_orig_iface_match(test, pkt);
261 }
262 
npf_size_inbounds(struct npf_test * test,struct net_pkt * pkt)263 bool npf_size_inbounds(struct npf_test *test, struct net_pkt *pkt)
264 {
265 	struct npf_test_size_bounds *bounds =
266 			CONTAINER_OF(test, struct npf_test_size_bounds, test);
267 	size_t pkt_size = net_pkt_get_len(pkt);
268 
269 	return pkt_size >= bounds->min && pkt_size <= bounds->max;
270 }
271 
npf_ip_src_addr_match(struct npf_test * test,struct net_pkt * pkt)272 bool npf_ip_src_addr_match(struct npf_test *test, struct net_pkt *pkt)
273 {
274 	struct npf_test_ip *test_ip =
275 			CONTAINER_OF(test, struct npf_test_ip, test);
276 	uint8_t pkt_family = net_pkt_family(pkt);
277 
278 	for (uint32_t ip_it = 0; ip_it < test_ip->ipaddr_num; ip_it++) {
279 		if (IS_ENABLED(CONFIG_NET_IPV4) && pkt_family == AF_INET) {
280 			struct in_addr *addr = (struct in_addr *)NET_IPV4_HDR(pkt)->src;
281 
282 			if (net_ipv4_addr_cmp(addr, &((struct in_addr *)test_ip->ipaddr)[ip_it])) {
283 				return true;
284 			}
285 		} else if (IS_ENABLED(CONFIG_NET_IPV6) && pkt_family == AF_INET6) {
286 			struct in6_addr *addr = (struct in6_addr *)NET_IPV6_HDR(pkt)->src;
287 
288 			if (net_ipv6_addr_cmp(addr, &((struct in6_addr *)test_ip->ipaddr)[ip_it])) {
289 				return true;
290 			}
291 		}
292 	}
293 	return false;
294 }
295 
npf_ip_src_addr_unmatch(struct npf_test * test,struct net_pkt * pkt)296 bool npf_ip_src_addr_unmatch(struct npf_test *test, struct net_pkt *pkt)
297 {
298 	return !npf_ip_src_addr_match(test, pkt);
299 }
300