1b1b8bc3fSopenharmony_ci/*
2b1b8bc3fSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
3b1b8bc3fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1b8bc3fSopenharmony_ci * you may not use this file except in compliance with the License.
5b1b8bc3fSopenharmony_ci * You may obtain a copy of the License at
6b1b8bc3fSopenharmony_ci *
7b1b8bc3fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1b8bc3fSopenharmony_ci *
9b1b8bc3fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1b8bc3fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1b8bc3fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1b8bc3fSopenharmony_ci * See the License for the specific language governing permissions and
13b1b8bc3fSopenharmony_ci * limitations under the License.
14b1b8bc3fSopenharmony_ci */
15b1b8bc3fSopenharmony_ci#ifndef NET_FIREWALL_H
16b1b8bc3fSopenharmony_ci#define NET_FIREWALL_H
17b1b8bc3fSopenharmony_ci
18b1b8bc3fSopenharmony_ci#include <linux/bpf.h>
19b1b8bc3fSopenharmony_ci
20b1b8bc3fSopenharmony_ci#include "netfirewall_def.h"
21b1b8bc3fSopenharmony_ci#include "netfirewall_match.h"
22b1b8bc3fSopenharmony_ci#include "netfirewall_ct.h"
23b1b8bc3fSopenharmony_ci#include "netfirewall_event.h"
24b1b8bc3fSopenharmony_ci
25b1b8bc3fSopenharmony_ci#define FIREWALL_DNS_QUERY_PORT         53
26b1b8bc3fSopenharmony_ci#define FIREWALL_DNS_OVER_QUERY_PORT    853
27b1b8bc3fSopenharmony_ci
28b1b8bc3fSopenharmony_ci/**
29b1b8bc3fSopenharmony_ci * @brief if tcp socket was intercepted, need send reset packet to peer
30b1b8bc3fSopenharmony_ci *
31b1b8bc3fSopenharmony_ci * @param tuple match tuple of skb meta data
32b1b8bc3fSopenharmony_ci * @param skb struct __sk_buff
33b1b8bc3fSopenharmony_ci * @param dir enum stream_dir
34b1b8bc3fSopenharmony_ci * @return 0 if no error, -1 if an error occurred
35b1b8bc3fSopenharmony_ci */
36b1b8bc3fSopenharmony_cistatic __always_inline int send_sock_tcp_reset(struct match_tuple *tuple, struct __sk_buff *skb, enum stream_dir dir)
37b1b8bc3fSopenharmony_ci{
38b1b8bc3fSopenharmony_ci    if (!skb || !tuple) {
39b1b8bc3fSopenharmony_ci        return -1;
40b1b8bc3fSopenharmony_ci    }
41b1b8bc3fSopenharmony_ci    if (tuple->protocol == IPPROTO_TCP) {
42b1b8bc3fSopenharmony_ci        if (dir == INGRESS) {
43b1b8bc3fSopenharmony_ci            bpf_sock_tcp_send_reset(skb);
44b1b8bc3fSopenharmony_ci        }
45b1b8bc3fSopenharmony_ci        return bpf_sock_destroy(skb);
46b1b8bc3fSopenharmony_ci    }
47b1b8bc3fSopenharmony_ci    return -1;
48b1b8bc3fSopenharmony_ci}
49b1b8bc3fSopenharmony_ci
50b1b8bc3fSopenharmony_ci/**
51b1b8bc3fSopenharmony_ci * @brief Get the packet rst on tuple
52b1b8bc3fSopenharmony_ci *
53b1b8bc3fSopenharmony_ci * @param tuple struct match_tuple
54b1b8bc3fSopenharmony_ci * @return true if success or false if an error occurred
55b1b8bc3fSopenharmony_ci */
56b1b8bc3fSopenharmony_cistatic __always_inline bool get_packet_rst_flag(struct match_tuple *tuple)
57b1b8bc3fSopenharmony_ci{
58b1b8bc3fSopenharmony_ci    if (!tuple) {
59b1b8bc3fSopenharmony_ci        return false;
60b1b8bc3fSopenharmony_ci    }
61b1b8bc3fSopenharmony_ci
62b1b8bc3fSopenharmony_ci    if (tuple->rst == 1) {
63b1b8bc3fSopenharmony_ci        return true;
64b1b8bc3fSopenharmony_ci    }
65b1b8bc3fSopenharmony_ci
66b1b8bc3fSopenharmony_ci    return false;
67b1b8bc3fSopenharmony_ci}
68b1b8bc3fSopenharmony_ci
69b1b8bc3fSopenharmony_ci/**
70b1b8bc3fSopenharmony_ci * @brief Get the ct tuple from match tuple
71b1b8bc3fSopenharmony_ci *
72b1b8bc3fSopenharmony_ci * @param match_tpl struct match_tuple
73b1b8bc3fSopenharmony_ci * @param ct_tpl struct ct_tuple
74b1b8bc3fSopenharmony_ci * @return true if success or false if an error occurred
75b1b8bc3fSopenharmony_ci */
76b1b8bc3fSopenharmony_cistatic __always_inline bool get_ct_tuple(struct match_tuple *match_tpl, struct ct_tuple *ct_tpl)
77b1b8bc3fSopenharmony_ci{
78b1b8bc3fSopenharmony_ci    if (!match_tpl || !ct_tpl) {
79b1b8bc3fSopenharmony_ci        return false;
80b1b8bc3fSopenharmony_ci    }
81b1b8bc3fSopenharmony_ci
82b1b8bc3fSopenharmony_ci    ct_tpl->family = match_tpl->family;
83b1b8bc3fSopenharmony_ci    ct_tpl->protocol = match_tpl->protocol;
84b1b8bc3fSopenharmony_ci    ct_tpl->sport = match_tpl->sport;
85b1b8bc3fSopenharmony_ci    ct_tpl->dport = match_tpl->dport;
86b1b8bc3fSopenharmony_ci
87b1b8bc3fSopenharmony_ci    if (match_tpl->family == AF_INET) {
88b1b8bc3fSopenharmony_ci        ct_tpl->ipv4.saddr = match_tpl->ipv4.saddr;
89b1b8bc3fSopenharmony_ci        ct_tpl->ipv4.daddr = match_tpl->ipv4.daddr;
90b1b8bc3fSopenharmony_ci    } else {
91b1b8bc3fSopenharmony_ci        ct_tpl->ipv6.saddr = match_tpl->ipv6.saddr;
92b1b8bc3fSopenharmony_ci        ct_tpl->ipv6.daddr = match_tpl->ipv6.daddr;
93b1b8bc3fSopenharmony_ci    }
94b1b8bc3fSopenharmony_ci
95b1b8bc3fSopenharmony_ci    return true;
96b1b8bc3fSopenharmony_ci}
97b1b8bc3fSopenharmony_ci
98b1b8bc3fSopenharmony_ci/**
99b1b8bc3fSopenharmony_ci * @brief Determine ingress packet drop or not
100b1b8bc3fSopenharmony_ci *
101b1b8bc3fSopenharmony_ci * @param skb struct __sk_buff
102b1b8bc3fSopenharmony_ci * @return SK_DROP if intercepted or SK_PASS if not
103b1b8bc3fSopenharmony_ci */
104b1b8bc3fSopenharmony_cistatic __always_inline enum sk_action netfirewall_policy_ingress(struct __sk_buff *skb)
105b1b8bc3fSopenharmony_ci{
106b1b8bc3fSopenharmony_ci    struct match_tuple tuple = { 0 };
107b1b8bc3fSopenharmony_ci    if (!get_match_tuple(skb, &tuple, INGRESS)) {
108b1b8bc3fSopenharmony_ci        return SK_PASS;
109b1b8bc3fSopenharmony_ci    }
110b1b8bc3fSopenharmony_ci
111b1b8bc3fSopenharmony_ci    log_tuple(&tuple);
112b1b8bc3fSopenharmony_ci
113b1b8bc3fSopenharmony_ci    struct ct_tuple ct_tpl = {};
114b1b8bc3fSopenharmony_ci    if (!get_ct_tuple(&tuple, &ct_tpl)) {
115b1b8bc3fSopenharmony_ci        return SK_PASS;
116b1b8bc3fSopenharmony_ci    }
117b1b8bc3fSopenharmony_ci
118b1b8bc3fSopenharmony_ci    enum ct_status status = ct_lookup_entry(skb, &ct_tpl, CT_INGRESS);
119b1b8bc3fSopenharmony_ci    log_dbg(DBG_CT_LOOKUP, INGRESS, status);
120b1b8bc3fSopenharmony_ci    if (status != CT_NEW) {
121b1b8bc3fSopenharmony_ci        return SK_PASS;
122b1b8bc3fSopenharmony_ci    }
123b1b8bc3fSopenharmony_ci
124b1b8bc3fSopenharmony_ci    if (get_packet_rst_flag(&tuple)) {
125b1b8bc3fSopenharmony_ci        return SK_PASS;
126b1b8bc3fSopenharmony_ci    }
127b1b8bc3fSopenharmony_ci
128b1b8bc3fSopenharmony_ci    struct bitmap key = { 0 };
129b1b8bc3fSopenharmony_ci    if (!match_action_key(&tuple, &key)) {
130b1b8bc3fSopenharmony_ci        return SK_PASS;
131b1b8bc3fSopenharmony_ci    }
132b1b8bc3fSopenharmony_ci
133b1b8bc3fSopenharmony_ci    if (match_action(&tuple, &key) != SK_PASS) {
134b1b8bc3fSopenharmony_ci        log_intercept(&tuple);
135b1b8bc3fSopenharmony_ci        send_sock_tcp_reset(&tuple, skb, INGRESS);
136b1b8bc3fSopenharmony_ci        return SK_DROP;
137b1b8bc3fSopenharmony_ci    }
138b1b8bc3fSopenharmony_ci
139b1b8bc3fSopenharmony_ci    if (status == CT_NEW) {
140b1b8bc3fSopenharmony_ci        ct_create_entry(&ct_tpl, skb, CT_INGRESS);
141b1b8bc3fSopenharmony_ci    }
142b1b8bc3fSopenharmony_ci
143b1b8bc3fSopenharmony_ci    return SK_PASS;
144b1b8bc3fSopenharmony_ci}
145b1b8bc3fSopenharmony_ci
146b1b8bc3fSopenharmony_cistatic __always_inline bool MatchDnsQuery(const struct match_tuple *tuple)
147b1b8bc3fSopenharmony_ci{
148b1b8bc3fSopenharmony_ci    __be16 port = bpf_htons(tuple->sport);
149b1b8bc3fSopenharmony_ci    if (port == FIREWALL_DNS_QUERY_PORT || port == FIREWALL_DNS_OVER_QUERY_PORT) {
150b1b8bc3fSopenharmony_ci        default_action_key key = DEFAULT_ACT_OUT_KEY;
151b1b8bc3fSopenharmony_ci        enum sk_action *action = bpf_map_lookup_elem(&DEFAULT_ACTION_MAP, &key);
152b1b8bc3fSopenharmony_ci        return action && *action != SK_PASS;
153b1b8bc3fSopenharmony_ci    }
154b1b8bc3fSopenharmony_ci    return false;
155b1b8bc3fSopenharmony_ci}
156b1b8bc3fSopenharmony_ci
157b1b8bc3fSopenharmony_ci/**
158b1b8bc3fSopenharmony_ci * @brief Determine egress packet drop or not
159b1b8bc3fSopenharmony_ci *
160b1b8bc3fSopenharmony_ci * @param skb struct __sk_buff
161b1b8bc3fSopenharmony_ci * @return SK_DROP if intercepted or SK_PASS if not
162b1b8bc3fSopenharmony_ci */
163b1b8bc3fSopenharmony_cistatic __always_inline enum sk_action netfirewall_policy_egress(struct __sk_buff *skb)
164b1b8bc3fSopenharmony_ci{
165b1b8bc3fSopenharmony_ci    struct match_tuple tuple = { 0 };
166b1b8bc3fSopenharmony_ci    if (!get_match_tuple(skb, &tuple, EGRESS)) {
167b1b8bc3fSopenharmony_ci        return SK_PASS;
168b1b8bc3fSopenharmony_ci    }
169b1b8bc3fSopenharmony_ci
170b1b8bc3fSopenharmony_ci    log_tuple(&tuple);
171b1b8bc3fSopenharmony_ci
172b1b8bc3fSopenharmony_ci    if (get_packet_rst_flag(&tuple)) {
173b1b8bc3fSopenharmony_ci        return SK_PASS;
174b1b8bc3fSopenharmony_ci    }
175b1b8bc3fSopenharmony_ci
176b1b8bc3fSopenharmony_ci    struct ct_tuple ct_tpl = {};
177b1b8bc3fSopenharmony_ci    if (!get_ct_tuple(&tuple, &ct_tpl)) {
178b1b8bc3fSopenharmony_ci        return SK_PASS;
179b1b8bc3fSopenharmony_ci    }
180b1b8bc3fSopenharmony_ci
181b1b8bc3fSopenharmony_ci    enum ct_status status = ct_lookup_entry(skb, &ct_tpl, CT_EGRESS);
182b1b8bc3fSopenharmony_ci    log_dbg(DBG_CT_LOOKUP, EGRESS, status);
183b1b8bc3fSopenharmony_ci    if (status != CT_NEW) {
184b1b8bc3fSopenharmony_ci        return SK_PASS;
185b1b8bc3fSopenharmony_ci    }
186b1b8bc3fSopenharmony_ci
187b1b8bc3fSopenharmony_ci    if (get_packet_rst_flag(&tuple)) {
188b1b8bc3fSopenharmony_ci        return SK_PASS;
189b1b8bc3fSopenharmony_ci    }
190b1b8bc3fSopenharmony_ci
191b1b8bc3fSopenharmony_ci    struct bitmap key = { 0 };
192b1b8bc3fSopenharmony_ci    if (!match_action_key(&tuple, &key)) {
193b1b8bc3fSopenharmony_ci        return SK_PASS;
194b1b8bc3fSopenharmony_ci    }
195b1b8bc3fSopenharmony_ci    // Outbound DNS queries need to be released
196b1b8bc3fSopenharmony_ci    if (!MatchDnsQuery(&tuple) && match_action(&tuple, &key) != SK_PASS) {
197b1b8bc3fSopenharmony_ci        log_intercept(&tuple);
198b1b8bc3fSopenharmony_ci        send_sock_tcp_reset(&tuple, skb, EGRESS);
199b1b8bc3fSopenharmony_ci        return SK_DROP;
200b1b8bc3fSopenharmony_ci    }
201b1b8bc3fSopenharmony_ci
202b1b8bc3fSopenharmony_ci    if (status == CT_NEW) {
203b1b8bc3fSopenharmony_ci        ct_create_entry(&ct_tpl, skb, CT_EGRESS);
204b1b8bc3fSopenharmony_ci    }
205b1b8bc3fSopenharmony_ci
206b1b8bc3fSopenharmony_ci    return SK_PASS;
207b1b8bc3fSopenharmony_ci}
208b1b8bc3fSopenharmony_ci
209b1b8bc3fSopenharmony_ci#endif // NET_FIREWALL_H