10
#include <mem/misc/pool.h>
11
#include <framework/mod/options.h>
13
#include <net/netfilter.h>
14
#include <net/skbuff.h>
15
#include <net/l3/ipv4/ip.h>
19
#include <net/l4/udp.h>
20
#include <net/l4/tcp.h>
22
#define MODOPS_NETFILTER_AMOUNT_RULES OPTION_GET(NUMBER, amount_rules)
25
* Storage of nf_rule structure
27
POOL_DEF(nf_rule_pool, struct nf_rule, MODOPS_NETFILTER_AMOUNT_RULES);
30
* Default chains of rules
32
DLIST_DEFINE(nf_input_rules);
33
DLIST_DEFINE(nf_forward_rules);
34
DLIST_DEFINE(nf_output_rules);
37
* Default policy for chains
39
static enum nf_target nf_input_default_target = NF_TARGET_ACCEPT;
40
static enum nf_target nf_forward_default_target = NF_TARGET_ACCEPT;
41
static enum nf_target nf_output_default_target = NF_TARGET_ACCEPT;
43
static void free_rule(struct nf_rule *r) {
45
dlist_del_init(&r->lnk);
46
pool_free(&nf_rule_pool, r);
49
int nf_chain_get_by_name(const char *chain_name) {
50
if (chain_name == NULL) {
51
return NF_CHAIN_UNKNOWN;
53
else if (0 == strcmp(chain_name, "INPUT")) {
54
return NF_CHAIN_INPUT;
56
else if (0 == strcmp(chain_name, "FORWARD")) {
57
return NF_CHAIN_FORWARD;
59
else if (0 == strcmp(chain_name, "OUTPUT")) {
60
return NF_CHAIN_OUTPUT;
63
return NF_CHAIN_UNKNOWN;
67
const char *nf_chain_to_str(int chain) {
70
case NF_CHAIN_INPUT: return "INPUT";
71
case NF_CHAIN_FORWARD: return "FORWARD";
72
case NF_CHAIN_OUTPUT: return "OUTPUT";
76
enum nf_target nf_target_get_by_name(const char *target_name) {
77
if (target_name == NULL) {
78
return NF_TARGET_UNKNOWN;
80
else if (0 == strcmp(target_name, "DROP")) {
81
return NF_TARGET_DROP;
83
else if (0 == strcmp(target_name, "ACCEPT")) {
84
return NF_TARGET_ACCEPT;
87
return NF_TARGET_UNKNOWN;
91
const char *nf_target_to_str(enum nf_target target) {
94
case NF_TARGET_DROP: return "DROP";
95
case NF_TARGET_ACCEPT: return "ACCEPT";
99
enum nf_proto nf_proto_get_by_name(const char *proto_name) {
100
if (proto_name == NULL) {
101
return NF_PROTO_UNKNOWN;
103
else if (0 == strcmp(proto_name, "all")) {
106
else if (0 == strcmp(proto_name, "icmp")) {
107
return NF_PROTO_ICMP;
109
else if (0 == strcmp(proto_name, "tcp")) {
112
else if (0 == strcmp(proto_name, "udp")) {
116
return NF_PROTO_UNKNOWN;
120
const char *nf_proto_to_str(enum nf_proto proto) {
122
default: return NULL;
123
case NF_PROTO_ALL: return "all";
124
case NF_PROTO_ICMP: return "icmp";
125
case NF_PROTO_TCP: return "tcp";
126
case NF_PROTO_UDP: return "udp";
130
struct dlist_head *nf_get_chain(int chain) {
132
default: return NULL;
133
case NF_CHAIN_INPUT: return &nf_input_rules;
134
case NF_CHAIN_FORWARD: return &nf_forward_rules;
135
case NF_CHAIN_OUTPUT: return &nf_output_rules;
139
enum nf_target nf_get_chain_target(int chain) {
141
default: return NF_TARGET_UNKNOWN;
142
case NF_CHAIN_INPUT: return nf_input_default_target;
143
case NF_CHAIN_FORWARD: return nf_forward_default_target;
144
case NF_CHAIN_OUTPUT: return nf_output_default_target;
148
int nf_set_chain_target(int chain, enum nf_target target) {
149
if (target == NF_TARGET_UNKNOWN) {
154
default: return -EINVAL;
156
nf_input_default_target = target;
158
case NF_CHAIN_FORWARD:
159
nf_forward_default_target = target;
161
case NF_CHAIN_OUTPUT:
162
nf_output_default_target = target;
169
struct nf_rule *nf_get_rule_by_num(int chain, size_t r_num) {
170
struct dlist_head *rules;
174
rules = nf_get_chain(chain);
180
dlist_foreach_entry(r, rules, lnk) {
190
int nf_rule_init(struct nf_rule *r) {
195
memset(r, 0, sizeof *r);
196
dlist_head_init(&r->lnk);
201
int nf_rule_copy(struct nf_rule *r_dst,
202
const struct nf_rule *r_src) {
203
struct dlist_head dst_link;
205
if ((r_dst == NULL) || (r_src == NULL)) {
209
memcpy(&dst_link, &r_dst->lnk, sizeof dst_link);
210
memcpy(r_dst, r_src, sizeof *r_dst);
211
memcpy(&r_dst->lnk, &dst_link, sizeof r_dst->lnk);
216
static int nf_chain_rule_prepare(int chain, const struct nf_rule *r,
217
struct dlist_head **rules_p, struct nf_rule **new_r_p) {
218
struct dlist_head *rules;
219
struct nf_rule *new_r;
221
rules = nf_get_chain(chain);
230
new_r = pool_alloc(&nf_rule_pool);
236
nf_rule_copy(new_r, r);
245
int nf_add_rule(int chain, const struct nf_rule *r) {
246
struct dlist_head *rules;
247
struct nf_rule *new_r;
250
res = nf_chain_rule_prepare(chain, r, &rules, &new_r);
255
dlist_add_prev(&new_r->lnk, rules);
260
int nf_insert_rule(int chain, const struct nf_rule *r, size_t num) {
261
struct dlist_head *rules;
262
struct nf_rule *new_r, *old_r;
265
res = nf_chain_rule_prepare(chain, r, &rules, &new_r);
270
old_r = nf_get_rule_by_num(chain, num);
272
dlist_add_prev(&new_r->lnk, rules);
274
dlist_add_prev(&new_r->lnk, &old_r->lnk);
280
int nf_set_rule(int chain, const struct nf_rule *r, size_t r_num) {
281
struct nf_rule *new_r;
287
new_r = nf_get_rule_by_num(chain, r_num);
292
nf_rule_copy(new_r, r);
297
int nf_del_rule(int chain, size_t r_num) {
300
r = nf_get_rule_by_num(chain, r_num);
310
int nf_clear(int chain) {
311
struct dlist_head *rules;
312
struct nf_rule *r = NULL;
314
rules = nf_get_chain(chain);
319
dlist_foreach_entry(r, rules, lnk) {
326
#define NF_TEST_NOT_FIELD(test_r, r, field) \
327
(!r->set_##field ? 1 : !test_r->set_##field ? 0 \
328
: (assert(!test_r->not_##field), \
329
(0 == memcmp(&test_r->field, &r->field, \
330
sizeof test_r->field)) \
331
!= !!r->not_##field))
333
int nf_test_rule(int chain, const struct nf_rule *test_r) {
334
struct dlist_head *rules;
337
rules = nf_get_chain(chain);
342
if (test_r == NULL) {
346
dlist_foreach_entry(r, rules, lnk) {
347
if ((r->target != NF_TARGET_UNKNOWN)
348
&& NF_TEST_NOT_FIELD(test_r, r, hwaddr_src)
349
&& NF_TEST_NOT_FIELD(test_r, r, hwaddr_dst)
350
&& NF_TEST_NOT_FIELD(test_r, r, saddr)
351
&& NF_TEST_NOT_FIELD(test_r, r, daddr)
352
&& (((test_r->proto != NF_PROTO_ALL)
353
&& (r->proto != NF_PROTO_ALL)
354
&& NF_TEST_NOT_FIELD(test_r, r, proto))
355
|| ((test_r->proto == NF_PROTO_ALL) && !test_r->not_proto
356
&& (r->proto == NF_PROTO_ALL) && !r->not_proto)
357
|| ((test_r->proto != NF_PROTO_ALL)
358
&& ((r->proto == NF_PROTO_ALL) && !r->not_proto)))
359
&& NF_TEST_NOT_FIELD(test_r, r, sport)
360
&& NF_TEST_NOT_FIELD(test_r, r, dport)
361
&& (!r->test_hnd ? 1 : r->test_hnd(test_r, r->test_hnd_data))) {
363
return test_r->target != r->target;
367
return test_r->target != nf_get_chain_target(chain);
370
int nf_test_skb(int chain, enum nf_target target,
371
const struct sk_buff *test_skb) {
374
if (test_skb == NULL) {
379
rule.target = target;
380
NF_SET_NOT_FIELD_PTR(&rule, saddr, 0, &test_skb->nh.iph->saddr,
381
sizeof test_skb->nh.iph->saddr);
382
NF_SET_NOT_FIELD_PTR(&rule, daddr, 0, &test_skb->nh.iph->daddr,
383
sizeof test_skb->nh.iph->daddr);
384
switch (test_skb->nh.iph->proto) {
386
NF_SET_NOT_FIELD(&rule, proto, 0, NF_PROTO_ICMP);
389
NF_SET_NOT_FIELD(&rule, proto, 0, NF_PROTO_TCP);
390
NF_SET_NOT_FIELD(&rule, sport, 0, test_skb->h.th->source);
391
NF_SET_NOT_FIELD(&rule, dport, 0, test_skb->h.th->dest);
394
NF_SET_NOT_FIELD(&rule, proto, 0, NF_PROTO_UDP);
395
NF_SET_NOT_FIELD(&rule, sport, 0, test_skb->h.uh->source);
396
NF_SET_NOT_FIELD(&rule, dport, 0, test_skb->h.uh->dest);
400
return nf_test_rule(chain, &rule);
403
int nf_test_raw(int chain, enum nf_target target, const void *hwaddr_dst,
404
const void *hwaddr_src, size_t hwaddr_len) {
410
rule.target = target;
411
NF_SET_NOT_FIELD_PTR(&rule, hwaddr_src, 0, hwaddr_src,
413
NF_SET_NOT_FIELD_PTR(&rule, hwaddr_dst, 0, hwaddr_dst,
416
return nf_test_rule(chain, &rule);