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