1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef NETMANAGER_EXT_BPF_NET_FIREWALL_H
17 #define NETMANAGER_EXT_BPF_NET_FIREWALL_H
18 
19 #include <netdb.h>
20 #include <string>
21 #include <thread>
22 #include <unordered_map>
23 #include <chrono>
24 #include <functional>
25 
26 #include "bitmap_manager.h"
27 #include "bpf_mapper.h"
28 #include "i_netfirewall_callback.h"
29 #include "netfirewall/netfirewall_def.h"
30 #include "netfirewall_parcel.h"
31 #include "system_ability.h"
32 #include "system_ability_load_callback_stub.h"
33 
34 namespace OHOS::NetManagerStandard {
35 // Only used for unittest code currently
36 static constexpr const char *FIREWALL_BPF_PATH = "/system/etc/bpf/netsys.o";
37 
38 static constexpr const int CONNTRACK_GC_INTTERVAL_MS = 60000;
39 static constexpr const int RING_BUFFER_POLL_TIME_OUT_MS = -1;
40 
41 // convert ebpf types from unix style style to CPP's
42 using Ip4Key = ip4_key;
43 using Ip6Key = ip6_key;
44 using Ipv4LpmKey = struct ipv4_lpm_key;
45 using Ipv6LpmKey = struct ipv6_lpm_key;
46 using PortKey = port_key;
47 using ProtoKey = proto_key;
48 using AppUidKey = appuid_key;
49 using DefaultActionKey = default_action_key;
50 using CurrentUserIdKey = current_user_id_key;
51 using ActionKey = action_key;
52 using ActionValue = action_val;
53 using RuleCode = struct bitmap;
54 using StreamDir = enum stream_dir;
55 using EventType = enum event_type;
56 using Event = struct event;
57 using InterceptEvent = struct intercept_event;
58 using DebugEvent = struct debug_event;
59 using TupleEvent = struct match_tuple;
60 using DebugType = enum debug_type;
61 
62 using CtKey = struct ct_tuple;
63 using CtVaule = struct ct_entry;
64 
65 /**
66  * @brief Callback impl for LoadSystemAbility
67  */
68 class OnDemandLoadManagerCallback : public SystemAbilityLoadCallbackStub {
69 public:
70     /**
71      * called when load SA success
72      *
73      * @param systemAbilityId id of SA which was loaded
74      * @param remoteObject poniter of IRemoteObject
75      */
76     void OnLoadSystemAbilitySuccess(int32_t systemAbilityId, const sptr<IRemoteObject> &remoteObject) override;
77 
78     /**
79      * called when load SA fail
80      *
81      * @param systemAbilityId id of SA which was loaded
82      */
83     void OnLoadSystemAbilityFail(int32_t systemAbilityId) override;
84 };
85 
86 /**
87  * Class for setup bpf maps and poll event from bpf ring buffer
88  */
89 class NetsysBpfNetFirewall : public NoCopyable {
90 public:
91     static std::shared_ptr<NetsysBpfNetFirewall> GetInstance();
92 
93     /**
94      * start to listen bpf ring buffer
95      *
96      * @return 0 if success or -1 if an error occurred
97      */
98     int32_t StartListener();
99 
100     /* *
101      * @brief stop listen bpf ring buffer
102      *
103      * @return 0 if success or -1 if an error occurred
104      */
105     int32_t StopListener();
106 
107     /**
108      * Set firewall rules to native
109      *
110      * @param ruleList list of NetFirewallIpRule
111      * @param isFinish transmit finish or not
112      * @return 0 if success or -1 if an error occurred
113      */
114     int32_t SetFirewallRules(const std::vector<sptr<NetFirewallBaseRule>> &ruleList, bool isFinish);
115 
116     /**
117      * Set firewall default action
118      *
119      * @param inDefault  Default action of NetFirewallRuleDirection:RULE_IN
120      * @param outDefault Default action of NetFirewallRuleDirection:RULE_OUT
121      * @return  0 if success or -1 if an error occurred
122      */
123     int32_t SetFirewallDefaultAction(FirewallRuleAction inDefault, FirewallRuleAction outDefault);
124 
125     /**
126      * Set firewall current user id
127      *
128      * @param userId current user id
129      * @return 0 if success or -1 if an error occurred
130      */
131     int32_t SetFirewallCurrentUserId(int32_t userId);
132 
133     /**
134      * Clear all bpf maps
135      *
136      * @return  0 if success or -1 if an error occurred
137      */
138     int32_t ClearFirewallRules();
139 
140     /**
141      * Register callback for recevie intercept event
142      *
143      * @param callback implement of INetFirewallCallback
144      * @return 0 if success or -1 if an error occurred
145      */
146     int32_t RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback);
147 
148     /**
149      * Unregister callback for recevie intercept event
150      *
151      * @param callback register callback for recevie intercept event
152      * @return 0 if success or -1 if an error occurred
153      */
154     int32_t UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback);
155 
156     /**
157      * Load SA on demand
158      *
159      * @param systemAbilityId id of SA want to load
160      * @return 0 if success or -1 if an error occurred
161      */
162     int32_t LoadSystemAbility(int32_t systemAbilityId);
163 
164     /**
165      * Set bpf prog load state
166      *
167      * @param load true if load success or false if an error occurred
168      */
169     void SetBpfLoaded(bool load);
170 
171     /**
172      * Get bpf prog load state
173      */
IsBpfLoaded()174     bool IsBpfLoaded()
175     {
176         return isBpfLoaded_;
177     }
178 
179 private:
ClearBpfMap(const char * path,const Key & key,Value & val)180     template <typename Key, typename Value> int ClearBpfMap(const char *path, const Key &key, Value &val)
181     {
182         (void)key;
183         (void)val;
184         BpfMapper<Key, Value> rdMap(path, BPF_F_RDONLY);
185         if (!rdMap.IsValid()) {
186             return -1;
187         }
188         std::vector<Key> keys = rdMap.GetAllKeys();
189         if (keys.empty()) {
190             NETNATIVE_LOG_D("ClearBpfMap: key is empty");
191             return 0;
192         }
193         BpfMapper<Key, Value> wrMap(path, BPF_F_WRONLY);
194         if (!wrMap.IsValid()) {
195             NETNATIVE_LOGE("ClearBpfMap: wrMap is invalid");
196             return -1;
197         }
198         if (wrMap.Clear(keys) != 0) {
199             NETNATIVE_LOGE("ClearBpfMap: clear failed");
200             return -1;
201         }
202 
203         return 0;
204     }
205 
WriteBpfMap(const char * path,const Key & key,Value & val)206     template <typename Key, typename Value> int WriteBpfMap(const char *path, const Key &key, Value &val)
207     {
208         BpfMapper<Key, Value> map(path, BPF_F_WRONLY);
209         if (!map.IsValid()) {
210             NETNATIVE_LOGE("WriteBpfMap: map invalid: %{public}s", path);
211             return -1;
212         }
213 
214         if (map.Write(key, val, BPF_ANY) != 0) {
215             NETNATIVE_LOGE("WriteBpfMap: map write failed");
216             return -1;
217         }
218 
219         return 0;
220     }
221 
222     NetsysBpfNetFirewall();
223 
224     static void StartConntrackGcThread(void);
225 
226     static void RingBufferListenThread(void);
227 
228     void StopConntrackGc();
229 
230     static int HandleEvent(void *ctx, void *data, size_t len);
231 
232     static void HandleTupleEvent(TupleEvent *ev);
233 
234     static void HandleInterceptEvent(InterceptEvent *ev);
235 
236     static void HandleDebugEvent(DebugEvent *ev);
237 
238     bool ShouldSkipNotify(sptr<InterceptRecord> record);
239 
240     void NotifyInterceptEvent(InterceptEvent *info);
241 
242     static void ConntrackGcTask();
243 
244     void ClearBpfFirewallRules(NetFirewallRuleDirection direction);
245 
246     void WriteSrcIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
247 
248     void WriteSrcIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
249 
250     void WriteDstIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
251 
252     void WriteDstIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
253 
254     void WriteSrcPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
255 
256     void WriteDstPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
257 
258     void WriteProtoBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
259 
260     void WriteAppUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
261 
262     void WriteUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
263 
264     void WriteActionBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction);
265 
266     int32_t SetBpfFirewallRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList,
267         NetFirewallRuleDirection direction);
268 
269     int32_t SetFirewallIpRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList);
270 
271     static std::shared_ptr<NetsysBpfNetFirewall> instance_;
272     static bool isBpfLoaded_;
273     static bool keepListen_;
274     std::unique_ptr<std::thread> thread_;
275     std::vector<sptr<NetsysNative::INetFirewallCallback>> callbacks_;
276     sptr<InterceptRecord> oldRecord_ = nullptr;
277     static bool keepGc_;
278     std::unique_ptr<std::thread> gcThread_;
279     static std::unique_ptr<BpfMapper<CtKey, CtVaule>> ctRdMap_, ctWrMap_;
280     std::vector<sptr<NetFirewallIpRule>> firewallIpRules_;
281 };
282 } // namespace OHOS::NetManagerStandard
283 #endif /* NETMANAGER_EXT_BPF_NET_FIREWALL_H */
284