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 #include <arpa/inet.h>
17 #include <cstdio>
18 #include <libbpf.h>
19 #include <linux/bpf.h>
20 #include <net/if.h>
21 #include <netinet/in.h>
22 #include <securec.h>
23 #include <sys/epoll.h>
24 #include <sys/socket.h>
25 #include <vector>
26 #include <ctime>
27 
28 #include "bpf_loader.h"
29 #include "bpf_netfirewall.h"
30 #include "netnative_log_wrapper.h"
31 #include "iservice_registry.h"
32 #include "bpf_ring_buffer.h"
33 #include "ffrt_inner.h"
34 
35 using namespace std;
36 using namespace OHOS;
37 using namespace OHOS::NetsysNative;
38 
39 namespace OHOS {
40 namespace NetManagerStandard {
41 std::shared_ptr<NetsysBpfNetFirewall> NetsysBpfNetFirewall::instance_ = nullptr;
42 bool NetsysBpfNetFirewall::keepListen_ = false;
43 bool NetsysBpfNetFirewall::keepGc_ = false;
44 bool NetsysBpfNetFirewall::isBpfLoaded_ = false;
45 std::unique_ptr<BpfMapper<CtKey, CtVaule>> NetsysBpfNetFirewall::ctRdMap_ = nullptr;
46 std::unique_ptr<BpfMapper<CtKey, CtVaule>> NetsysBpfNetFirewall::ctWrMap_ = nullptr;
47 
NetsysBpfNetFirewall()48 NetsysBpfNetFirewall::NetsysBpfNetFirewall()
49 {
50     NETNATIVE_LOG_D("NetsysBpfNetFirewall construct");
51     isBpfLoaded_ = false;
52 }
53 
GetInstance()54 std::shared_ptr<NetsysBpfNetFirewall> NetsysBpfNetFirewall::GetInstance()
55 {
56     static std::mutex instanceMutex;
57     std::lock_guard<std::mutex> guard(instanceMutex);
58     if (instance_ == nullptr) {
59         instance_.reset(new NetsysBpfNetFirewall());
60         return instance_;
61     }
62     return instance_;
63 }
64 
ConntrackGcTask()65 void NetsysBpfNetFirewall::ConntrackGcTask()
66 {
67     NETNATIVE_LOG_D("ConntrackGcTask: running");
68     std::vector<CtKey> keys = ctRdMap_->GetAllKeys();
69     if (keys.empty()) {
70         NETNATIVE_LOG_D("GcConntrackCb: key is empty");
71         return;
72     }
73 
74     timespec now = { 0 };
75     // bpf_ktime_get_ns: CLOCK_MONOTONIC
76     if (!clock_gettime(CLOCK_MONOTONIC, &now)) {
77         return;
78     }
79     for (const CtKey &k : keys) {
80         CtVaule v = {};
81         if (ctRdMap_->Read(k, v) < 0) {
82             NETNATIVE_LOGE("GcConntrackCb: read failed");
83             continue;
84         }
85 
86         if (v.lifetime < now.tv_sec) {
87             if (ctWrMap_->Delete(k) != 0) {
88                 NETNATIVE_LOGE("GcConntrackCb: delete failed");
89                 continue;
90             }
91         }
92     }
93 }
94 
RingBufferListenThread(void)95 void NetsysBpfNetFirewall::RingBufferListenThread(void)
96 {
97     if (keepListen_) {
98         NETNATIVE_LOG_D("under listening");
99         return;
100     }
101 
102     int mapFd = NetsysBpfRingBuffer::GetRingbufFd(MAP_PATH(EVENT_MAP), 0);
103     if (mapFd < 0) {
104         NETNATIVE_LOGE("failed to get ring buffer fd: errno=%{public}d", errno);
105         return;
106     }
107     ring_buffer *rb = ring_buffer__new(mapFd, NetsysBpfNetFirewall::HandleEvent, NULL, NULL);
108     if (!rb) {
109         NETNATIVE_LOGE("failed to create ring buffer: errno=%{public}d", errno);
110         return;
111     }
112 
113     keepListen_ = true;
114     while (keepListen_) {
115         if (ffrt::this_task::get_id() != 0) {
116             ffrt::sync_io(mapFd);
117         }
118         int err = ring_buffer__poll(rb, RING_BUFFER_POLL_TIME_OUT_MS);
119         if (err < 0) {
120             NETNATIVE_LOGE("Error polling ring buffer: errno=%{public}d", errno);
121             keepListen_ = false;
122             break;
123         }
124     }
125 
126     NETNATIVE_LOGE("Could not get bpf event ring buffer map");
127     ring_buffer__free(rb);
128 }
129 
StartListener()130 int32_t NetsysBpfNetFirewall::StartListener()
131 {
132     if (!isBpfLoaded_) {
133         NETNATIVE_LOG_D("bfp is not loaded");
134         return -1;
135     }
136     ctRdMap_ = std::make_unique<BpfMapper<CtKey, CtVaule>>(MAP_PATH(CT_MAP), BPF_F_RDONLY);
137     ctWrMap_ = std::make_unique<BpfMapper<CtKey, CtVaule>>(MAP_PATH(CT_MAP), BPF_F_WRONLY);
138 
139     ffrt::submit(RingBufferListenThread, {}, {}, ffrt::task_attr().name("RingBufferListen"));
140     ffrt::submit(StartConntrackGcThread, { &ctRdMap_ }, { &ctWrMap_ });
141     return 0;
142 }
143 
StopListener()144 int32_t NetsysBpfNetFirewall::StopListener()
145 {
146     keepListen_ = false;
147     StopConntrackGc();
148     return 0;
149 }
150 
StartConntrackGcThread(void)151 void NetsysBpfNetFirewall::StartConntrackGcThread(void)
152 {
153     if (keepGc_) {
154         NETNATIVE_LOG_D("under keepGc");
155         return;
156     }
157     if (!ctRdMap_->IsValid()) {
158         NETNATIVE_LOGE("GcConntrackCb: ctRdMap is invalid");
159         return;
160     }
161 
162     if (!ctWrMap_->IsValid()) {
163         NETNATIVE_LOGE("GcConntrackCb: ctWrMap is invalid");
164         return;
165     }
166 
167     keepGc_ = true;
168 
169     int rdMapFd = NetsysBpfRingBuffer::GetRingbufFd(MAP_PATH(CT_MAP), BPF_F_RDONLY);
170     int wrMapFd = NetsysBpfRingBuffer::GetRingbufFd(MAP_PATH(CT_MAP), BPF_F_WRONLY);
171     if (rdMapFd < 0 || wrMapFd < 0) {
172         NETNATIVE_LOGE("failed to get rdMapFd or wrMapFd: errno=%{public}d", errno);
173         return;
174     }
175 
176     while (keepGc_) {
177         ffrt::this_task::sleep_for(std::chrono::milliseconds(CONNTRACK_GC_INTTERVAL_MS));
178         if (ffrt::this_task::get_id() != 0) {
179             ffrt::sync_io(rdMapFd);
180             ffrt::sync_io(wrMapFd);
181         }
182         ConntrackGcTask();
183     }
184 }
185 
StopConntrackGc()186 void NetsysBpfNetFirewall::StopConntrackGc()
187 {
188     keepGc_ = false;
189 }
190 
SetBpfLoaded(bool load)191 void NetsysBpfNetFirewall::SetBpfLoaded(bool load)
192 {
193     isBpfLoaded_ = load;
194 }
195 
ClearBpfFirewallRules(NetFirewallRuleDirection direction)196 void NetsysBpfNetFirewall::ClearBpfFirewallRules(NetFirewallRuleDirection direction)
197 {
198     NETNATIVE_LOG_D("ClearBpfFirewallRules: direction=%{public}d", direction);
199     Ipv4LpmKey ip4Key = {};
200     Ipv6LpmKey ip6Key = {};
201     PortKey portKey = 0;
202     ProtoKey protoKey = 0;
203     AppUidKey appIdKey = 0;
204     UidKey uidKey = 0;
205     ActionKey actKey = 1;
206     ActionValue actVal;
207     RuleCode ruleCode;
208     CtKey ctKey;
209     CtVaule ctVal;
210 
211     bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
212     ClearBpfMap(GET_MAP_PATH(ingress, saddr), ip4Key, ruleCode);
213     ClearBpfMap(GET_MAP_PATH(ingress, saddr6), ip6Key, ruleCode);
214     ClearBpfMap(GET_MAP_PATH(ingress, daddr), ip4Key, ruleCode);
215     ClearBpfMap(GET_MAP_PATH(ingress, daddr6), ip6Key, ruleCode);
216     ClearBpfMap(GET_MAP_PATH(ingress, sport), portKey, ruleCode);
217     ClearBpfMap(GET_MAP_PATH(ingress, dport), portKey, ruleCode);
218     ClearBpfMap(GET_MAP_PATH(ingress, proto), protoKey, ruleCode);
219     ClearBpfMap(GET_MAP_PATH(ingress, appuid), appIdKey, ruleCode);
220     ClearBpfMap(GET_MAP_PATH(ingress, uid), uidKey, ruleCode);
221     ClearBpfMap(GET_MAP_PATH(ingress, action), actKey, actVal);
222     ClearBpfMap(MAP_PATH(CT_MAP), ctKey, ctVal);
223 }
224 
ClearFirewallRules()225 int32_t NetsysBpfNetFirewall::ClearFirewallRules()
226 {
227     firewallIpRules_.clear();
228     ClearBpfFirewallRules(NetFirewallRuleDirection::RULE_IN);
229     ClearBpfFirewallRules(NetFirewallRuleDirection::RULE_OUT);
230     return NETFIREWALL_SUCCESS;
231 }
232 
SetBpfFirewallRules(const std::vector<sptr<NetFirewallIpRule>> & ruleList,NetFirewallRuleDirection direction)233 int32_t NetsysBpfNetFirewall::SetBpfFirewallRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList,
234     NetFirewallRuleDirection direction)
235 {
236     BitmapManager manager;
237     int32_t ret = manager.BuildBitmapMap(ruleList);
238     if (ret) {
239         NETNATIVE_LOGE("SetBpfFirewallRules: BuildBitmapMap failed: %{public}d", ret);
240         return ret;
241     }
242 
243     ClearBpfFirewallRules(direction);
244     WriteSrcIpv4BpfMap(manager, direction);
245     WriteSrcIpv6BpfMap(manager, direction);
246     WriteDstIpv4BpfMap(manager, direction);
247     WriteDstIpv6BpfMap(manager, direction);
248     WriteSrcPortBpfMap(manager, direction);
249     WriteDstPortBpfMap(manager, direction);
250     WriteProtoBpfMap(manager, direction);
251     WriteAppUidBpfMap(manager, direction);
252     WriteUidBpfMap(manager, direction);
253     WriteActionBpfMap(manager, direction);
254     return NETFIREWALL_SUCCESS;
255 }
256 
SetFirewallRules(const std::vector<sptr<NetFirewallBaseRule>> & ruleList,bool isFinish)257 int32_t NetsysBpfNetFirewall::SetFirewallRules(const std::vector<sptr<NetFirewallBaseRule>> &ruleList, bool isFinish)
258 {
259     NETNATIVE_LOGI("SetFirewallRules: size=%{public}zu isFinish=%{public}" PRId32, ruleList.size(), isFinish);
260     if (!isBpfLoaded_) {
261         NETNATIVE_LOGE("SetFirewallRules: bpf not loaded");
262         return NETFIREWALL_ERR;
263     }
264     if (ruleList.empty()) {
265         NETNATIVE_LOGE("SetFirewallRules: rules is empty");
266         return NETFIREWALL_ERR;
267     }
268     for (const auto &rule : ruleList) {
269         firewallIpRules_.emplace_back(firewall_rule_cast<NetFirewallIpRule>(rule));
270     }
271     int32_t ret = NETFIREWALL_SUCCESS;
272     if (isFinish) {
273         ret = SetFirewallIpRules(firewallIpRules_);
274         firewallIpRules_.clear();
275     }
276     return ret;
277 }
278 
SetFirewallIpRules(const std::vector<sptr<NetFirewallIpRule>> & ruleList)279 int32_t NetsysBpfNetFirewall::SetFirewallIpRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList)
280 {
281     std::vector<sptr<NetFirewallIpRule>> inRules;
282     std::vector<sptr<NetFirewallIpRule>> outRules;
283 
284     for (const auto &rule : ruleList) {
285         if (rule->ruleDirection == NetFirewallRuleDirection::RULE_IN) {
286             if (rule->protocol == NetworkProtocol::ICMP || rule->protocol == NetworkProtocol::ICMPV6) {
287                 outRules.emplace_back(rule);
288             } else {
289                 inRules.emplace_back(rule);
290             }
291         }
292         if (rule->ruleDirection == NetFirewallRuleDirection::RULE_OUT) {
293             outRules.emplace_back(rule);
294         }
295     }
296 
297     int32_t ret = NETFIREWALL_SUCCESS;
298     if (!inRules.empty()) {
299         ret = SetBpfFirewallRules(inRules, NetFirewallRuleDirection::RULE_IN);
300     }
301     if (!outRules.empty()) {
302         ret += SetBpfFirewallRules(outRules, NetFirewallRuleDirection::RULE_OUT);
303     }
304     return ret;
305 }
306 
SetFirewallDefaultAction(FirewallRuleAction inDefault,FirewallRuleAction outDefault)307 int32_t NetsysBpfNetFirewall::SetFirewallDefaultAction(FirewallRuleAction inDefault, FirewallRuleAction outDefault)
308 {
309     if (!isBpfLoaded_) {
310         NETNATIVE_LOGE("SetFirewallDefaultAction: bpf not loaded");
311         return NETFIREWALL_ERR;
312     }
313     DefaultActionKey key = DEFAULT_ACT_IN_KEY;
314     enum sk_action val = (inDefault == FirewallRuleAction::RULE_ALLOW) ? SK_PASS : SK_DROP;
315     WriteBpfMap(MAP_PATH(DEFAULT_ACTION_MAP), key, val);
316 
317     key = DEFAULT_ACT_OUT_KEY;
318     val = (outDefault == FirewallRuleAction::RULE_ALLOW) ? SK_PASS : SK_DROP;
319     WriteBpfMap(MAP_PATH(DEFAULT_ACTION_MAP), key, val);
320     return NETFIREWALL_SUCCESS;
321 }
322 
SetFirewallCurrentUserId(int32_t userId)323 int32_t NetsysBpfNetFirewall::SetFirewallCurrentUserId(int32_t userId)
324 {
325     if (!isBpfLoaded_) {
326         NETNATIVE_LOGE("SetFirewallCurrentUserId: bpf not loaded");
327         return NETFIREWALL_ERR;
328     }
329 
330     CurrentUserIdKey key = CURRENT_USER_ID_KEY;
331     UidKey val = (UidKey)userId;
332     WriteBpfMap(MAP_PATH(CURRENT_UID_MAP), key, val);
333     return NETFIREWALL_SUCCESS;
334 }
335 
WriteSrcIpv4BpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)336 void NetsysBpfNetFirewall::WriteSrcIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
337 {
338     std::vector<Ip4RuleBitmap> &srcIp4Map = manager.GetSrcIp4Map();
339     if (srcIp4Map.empty()) {
340         NETNATIVE_LOGE("WriteSrcIpv4BpfMap: srcIp4Map is empty");
341         return;
342     }
343     bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
344     for (const auto &node : srcIp4Map) {
345         Bitmap val = node.bitmap;
346         RuleCode rule;
347         memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
348 
349         Ipv4LpmKey key = { 0 };
350         key.prefixlen = node.mask;
351         key.data = static_cast<Ip4Key>(node.data);
352         WriteBpfMap(GET_MAP_PATH(ingress, saddr), key, rule);
353     }
354 }
355 
WriteSrcIpv6BpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)356 void NetsysBpfNetFirewall::WriteSrcIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
357 {
358     std::vector<Ip6RuleBitmap> &srcIp6Map = manager.GetSrcIp6Map();
359     if (srcIp6Map.empty()) {
360         NETNATIVE_LOGE("WriteSrcIpv6BpfMap: srcIp6Map is empty");
361         return;
362     }
363     bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
364     for (const auto &node : srcIp6Map) {
365         Bitmap val = node.bitmap;
366         RuleCode rule;
367         memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
368 
369         Ipv6LpmKey key = { 0 };
370         key.prefixlen = node.prefixlen;
371         key.data = static_cast<Ip6Key>(node.data);
372         WriteBpfMap(GET_MAP_PATH(ingress, saddr6), key, rule);
373     }
374 }
375 
WriteDstIpv4BpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)376 void NetsysBpfNetFirewall::WriteDstIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
377 {
378     std::vector<Ip4RuleBitmap> &dstIp4Map = manager.GetDstIp4Map();
379     if (dstIp4Map.empty()) {
380         NETNATIVE_LOGE("WriteDstIp4BpfMap: dstIp4Map is empty");
381     } else {
382         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
383         for (const auto &node : dstIp4Map) {
384             Bitmap val = node.bitmap;
385             RuleCode rule;
386             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
387 
388             Ipv4LpmKey key = { 0 };
389             key.prefixlen = node.mask;
390             key.data = static_cast<Ip4Key>(node.data);
391             WriteBpfMap(GET_MAP_PATH(ingress, daddr), key, rule);
392         }
393     }
394 }
395 
WriteDstIpv6BpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)396 void NetsysBpfNetFirewall::WriteDstIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
397 {
398     std::vector<Ip6RuleBitmap> &dstIp6Map = manager.GetDstIp6Map();
399     if (dstIp6Map.empty()) {
400         NETNATIVE_LOGE("WriteDstIp6BpfMap: dstIp6Map is empty");
401     } else {
402         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
403         for (const auto &node : dstIp6Map) {
404             Bitmap val = node.bitmap;
405             RuleCode rule;
406             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
407 
408             Ipv6LpmKey key = { 0 };
409             key.prefixlen = node.prefixlen;
410             key.data = static_cast<Ip6Key>(node.data);
411             WriteBpfMap(GET_MAP_PATH(ingress, daddr6), key, rule);
412         }
413     }
414 }
415 
WriteSrcPortBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)416 void NetsysBpfNetFirewall::WriteSrcPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
417 {
418     BpfPortMap &srcPortMap = manager.GetSrcPortMap();
419     if (srcPortMap.Empty()) {
420         NETNATIVE_LOGE("WriteSrcPortBpfMap: srcPortMap is empty");
421     } else {
422         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
423         for (const auto &pair : srcPortMap.Get()) {
424             PortKey key = pair.first;
425             Bitmap val = pair.second;
426             RuleCode rule;
427             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
428             NETNATIVE_LOG_D("sport_map=%{public}d", key);
429             WriteBpfMap(GET_MAP_PATH(ingress, sport), key, rule);
430         }
431     }
432 }
433 
WriteDstPortBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)434 void NetsysBpfNetFirewall::WriteDstPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
435 {
436     BpfPortMap &dstPortMap = manager.GetDstPortMap();
437     if (dstPortMap.Empty()) {
438         NETNATIVE_LOGE("WriteDstPortBpfMap: dstPortMap is empty");
439     } else {
440         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
441         for (const auto &pair : dstPortMap.Get()) {
442             PortKey key = pair.first;
443             Bitmap val = pair.second;
444             RuleCode rule;
445             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
446             NETNATIVE_LOG_D("dport_map=%{public}d", key);
447             WriteBpfMap(GET_MAP_PATH(ingress, dport), key, rule);
448         }
449     }
450 }
451 
WriteProtoBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)452 void NetsysBpfNetFirewall::WriteProtoBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
453 {
454     BpfProtoMap &protoMap = manager.GetProtoMap();
455     if (protoMap.Empty()) {
456         NETNATIVE_LOGE("WriteProtoBpfMap: protoMap is empty");
457     } else {
458         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
459         for (const auto &pair : protoMap.Get()) {
460             ProtoKey key = pair.first;
461             Bitmap val = pair.second;
462             RuleCode rule;
463             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
464             NETNATIVE_LOG_D("proto_map=%{public}d", key);
465             WriteBpfMap(GET_MAP_PATH(ingress, proto), key, rule);
466         }
467     }
468 }
469 
WriteAppUidBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)470 void NetsysBpfNetFirewall::WriteAppUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
471 {
472     BpfAppUidMap &appIdMap = manager.GetAppIdMap();
473     if (appIdMap.Empty()) {
474         NETNATIVE_LOGE("WriteAppUidBpfMap: appIdMap is empty");
475     } else {
476         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
477         for (const auto &pair : appIdMap.Get()) {
478             AppUidKey key = pair.first;
479             Bitmap val = pair.second;
480             RuleCode rule;
481             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
482             NETNATIVE_LOG_D("appuid_map=%{public}d", key);
483             WriteBpfMap(GET_MAP_PATH(ingress, appuid), key, rule);
484         }
485     }
486 }
487 
WriteUidBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)488 void NetsysBpfNetFirewall::WriteUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
489 {
490     BpfUidMap &uidMap = manager.GetUidMap();
491     if (uidMap.Empty()) {
492         NETNATIVE_LOGE("WriteUidBpfMap: uidMap is empty");
493     } else {
494         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
495         for (const auto &pair : uidMap.Get()) {
496             UidKey key = pair.first;
497             Bitmap val = pair.second;
498             RuleCode rule;
499             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
500             NETNATIVE_LOG_D("uidMap=%{public}d", key);
501             WriteBpfMap(GET_MAP_PATH(ingress, uid), key, rule);
502         }
503     }
504 }
505 
WriteActionBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)506 void NetsysBpfNetFirewall::WriteActionBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
507 {
508     BpfActionMap &actionMap = manager.GetActionMap();
509     if (actionMap.Empty()) {
510         NETNATIVE_LOGE("WriteActionBpfMap: actionMap is empty");
511     } else {
512         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
513         for (const auto &pair : actionMap.Get()) {
514             ActionKey key = pair.first;
515             Bitmap val = pair.second;
516             RuleCode rule;
517             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
518             NETNATIVE_LOG_D("action_map=%{public}d", val.Get()[0]);
519             WriteBpfMap(GET_MAP_PATH(ingress, action), key, rule);
520         }
521     }
522 }
523 
RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> & callback)524 int32_t NetsysBpfNetFirewall::RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)
525 {
526     if (!callback) {
527         return -1;
528     }
529 
530     callbacks_.emplace_back(callback);
531 
532     return 0;
533 }
UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> & callback)534 int32_t NetsysBpfNetFirewall::UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)
535 {
536     if (!callback) {
537         return -1;
538     }
539 
540     for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
541         if (*it == callback) {
542             callbacks_.erase(it);
543             return 0;
544         }
545     }
546     return -1;
547 }
548 
ShouldSkipNotify(sptr<InterceptRecord> record)549 bool NetsysBpfNetFirewall::ShouldSkipNotify(sptr<InterceptRecord> record)
550 {
551     if (!record) {
552         return true;
553     }
554     if (oldRecord_ != nullptr && (record->time - oldRecord_->time) < INTERCEPT_BUFF_INTERVAL_SEC) {
555         if (record->localIp == oldRecord_->localIp && record->remoteIp == oldRecord_->remoteIp &&
556             record->localPort == oldRecord_->localPort && record->remotePort == oldRecord_->remotePort &&
557             record->protocol == oldRecord_->protocol && record->appUid == oldRecord_->appUid) {
558             return true;
559         }
560     }
561     oldRecord_ = record;
562     return false;
563 }
564 
NotifyInterceptEvent(InterceptEvent * info)565 void NetsysBpfNetFirewall::NotifyInterceptEvent(InterceptEvent *info)
566 {
567     if (!info) {
568         return;
569     }
570     sptr<InterceptRecord> record = new (std::nothrow) InterceptRecord();
571     record->time = (int32_t)time(NULL);
572     record->localPort = BitmapManager::Nstohl(info->sport);
573     record->remotePort = BitmapManager::Nstohl(info->dport);
574     record->protocol = static_cast<uint16_t>(info->protocol);
575     record->appUid = (int32_t)info->appuid;
576     std::string srcIp;
577     std::string dstIp;
578     if (info->family == AF_INET) {
579         char ip4[INET_ADDRSTRLEN] = {};
580         inet_ntop(AF_INET, &(info->ipv4.saddr), ip4, INET_ADDRSTRLEN);
581         srcIp = ip4;
582         memset_s(ip4, INET_ADDRSTRLEN, 0, INET_ADDRSTRLEN);
583         inet_ntop(AF_INET, &(info->ipv4.daddr), ip4, INET_ADDRSTRLEN);
584         dstIp = ip4;
585     } else {
586         char ip6[INET6_ADDRSTRLEN] = {};
587         inet_ntop(AF_INET6, &(info->ipv6.saddr), ip6, INET6_ADDRSTRLEN);
588         srcIp = ip6;
589         memset_s(ip6, INET6_ADDRSTRLEN, 0, INET6_ADDRSTRLEN);
590         inet_ntop(AF_INET6, &(info->ipv6.daddr), ip6, INET6_ADDRSTRLEN);
591         dstIp = ip6;
592     }
593     if (info->dir == INGRESS) {
594         record->localIp = srcIp;
595         record->remoteIp = dstIp;
596     } else {
597         record->localIp = dstIp;
598         record->remoteIp = srcIp;
599     }
600     if (ShouldSkipNotify(record)) {
601         return;
602     }
603     for (auto callback : callbacks_) {
604         callback->OnIntercept(record);
605     }
606 }
607 
HandleTupleEvent(TupleEvent * ev)608 void NetsysBpfNetFirewall::HandleTupleEvent(TupleEvent *ev)
609 {
610     NETNATIVE_LOG_D(
611         "%{public}s tuple: sport=%{public}u dport=%{public}u protocol=%{public}u appuid=%{public}u uid=%{public}u",
612         (ev->dir == INGRESS) ? "> ingress" : "< egress", ntohs(ev->sport), ntohs(ev->dport), ev->protocol, ev->appuid,
613         ev->uid);
614     if (ev->family == AF_INET) {
615         in_addr in;
616         in.s_addr = ev->ipv4.saddr;
617         NETNATIVE_LOG_D("\tsaddr=%{public}s", inet_ntoa(in));
618 
619         in.s_addr = ev->ipv4.daddr;
620         NETNATIVE_LOG_D("\tdaddr=%{public}s", inet_ntoa(in));
621     } else {
622         char buf[INET6_ADDRSTRLEN] = {};
623         inet_ntop(AF_INET6, &(ev->ipv6.saddr), buf, INET6_ADDRSTRLEN);
624         NETNATIVE_LOG_D("\tsaddr6=%{public}s", buf);
625 
626         memset_s(buf, INET6_ADDRSTRLEN, 0, INET6_ADDRSTRLEN);
627         inet_ntop(AF_INET6, &(ev->ipv6.daddr), buf, INET6_ADDRSTRLEN);
628         NETNATIVE_LOG_D("\tdaddr6=%{public}s", buf);
629     }
630     NETNATIVE_LOG_D("\trstpacket=%{public}u", ev->rst);
631 }
632 
HandleInterceptEvent(InterceptEvent * ev)633 void NetsysBpfNetFirewall::HandleInterceptEvent(InterceptEvent *ev)
634 {
635     GetInstance()->NotifyInterceptEvent(ev);
636 
637     NETNATIVE_LOGI("%{public}s intercept: sport=%{public}u dport=%{public}u protocol=%{public}u appuid=%{public}u",
638         (ev->dir == INGRESS) ? "ingress" : "egress", ntohs(ev->sport), ntohs(ev->dport), ev->protocol, ev->appuid);
639     if (ev->family == AF_INET) {
640         in_addr in;
641         in.s_addr = ev->ipv4.saddr;
642         NETNATIVE_LOGI("\tsaddr=%{public}s", inet_ntoa(in));
643 
644         in.s_addr = ev->ipv4.daddr;
645         NETNATIVE_LOGI("\tdaddr=%{public}s", inet_ntoa(in));
646     } else {
647         char buf[INET6_ADDRSTRLEN] = {};
648         inet_ntop(AF_INET6, &(ev->ipv6.saddr), buf, INET6_ADDRSTRLEN);
649         NETNATIVE_LOGI("\tsaddr6=%{public}s", buf);
650 
651         memset_s(buf, INET6_ADDRSTRLEN, 0, INET6_ADDRSTRLEN);
652         inet_ntop(AF_INET6, &(ev->ipv6.daddr), buf, INET6_ADDRSTRLEN);
653         NETNATIVE_LOGI("\tdaddr6=%{public}s", buf);
654     }
655 }
656 
HandleDebugEvent(DebugEvent * ev)657 void NetsysBpfNetFirewall::HandleDebugEvent(DebugEvent *ev)
658 {
659     const char *direction = ev->dir == INGRESS ? ">" : "<";
660     switch (ev->type) {
661         case DBG_LOOKUP_FAIL:
662             NETNATIVE_LOG_D("bpf map lookup: fail");
663             break;
664         case DBG_MATCH_SADDR: {
665             in_addr in;
666             in.s_addr = ev->arg1;
667             NETNATIVE_LOG_D("%{public}s saddr: %{public}s bitmap: %{public}x", direction, inet_ntoa(in), ev->arg2);
668             break;
669         }
670         case DBG_MATCH_DADDR: {
671             in_addr in;
672             in.s_addr = ev->arg1;
673             NETNATIVE_LOG_D("%{public}s daddr: %{public}s bitmap: %{public}x", direction, inet_ntoa(in), ev->arg2);
674             break;
675         }
676         case DBG_MATCH_SPORT:
677             NETNATIVE_LOG_D("%{public}s sport: %{public}u bitmap: %{public}x", direction, ntohs(ev->arg1), ev->arg2);
678             break;
679         case DBG_MATCH_DPORT:
680             NETNATIVE_LOG_D("%{public}s dport: %{public}u bitmap: %{public}x", direction, ntohs(ev->arg1), ev->arg2);
681             break;
682         case DBG_MATCH_PROTO:
683             NETNATIVE_LOG_D("%{public}s protocol: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
684             break;
685         case DBG_MATCH_APPUID:
686             NETNATIVE_LOG_D("%{public}s appuid: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
687             break;
688         case DBG_MATCH_UID:
689             NETNATIVE_LOG_D("%{public}s uid: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
690             break;
691         case DBG_ACTION_KEY:
692             NETNATIVE_LOG_D("%{public}s actionkey: %{public}x", direction, ev->arg1);
693             break;
694         case DBG_MATCH_ACTION:
695             NETNATIVE_LOG_D("%{public}s    action: %{public}s", direction, (ev->arg1 == SK_PASS ? "PASS" : "DROP"));
696             break;
697         case DBG_CT_LOOKUP:
698             NETNATIVE_LOG_D("%{public}s ct lookup status: %{public}u", direction, ev->arg1);
699             break;
700         default:
701             break;
702     }
703 }
704 
HandleEvent(void * ctx,void * data,size_t len)705 int NetsysBpfNetFirewall::HandleEvent(void *ctx, void *data, size_t len)
706 {
707     if (data && len > 0) {
708         Event *ev = (Event *)data;
709 
710         switch (ev->type) {
711             case EVENT_DEBUG: {
712                 HandleDebugEvent(&(ev->debug));
713                 break;
714             }
715             case EVENT_INTERCEPT: {
716                 HandleInterceptEvent(&(ev->intercept));
717                 break;
718             }
719             case EVENT_TUPLE_DEBUG: {
720                 HandleTupleEvent(&(ev->tuple));
721                 break;
722             }
723             default:
724                 break;
725         }
726     }
727     return 0;
728 }
729 
OnLoadSystemAbilitySuccess(int32_t systemAbilityId,const sptr<IRemoteObject> & remoteObject)730 void OnDemandLoadManagerCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId,
731     const sptr<IRemoteObject> &remoteObject)
732 {
733     NETNATIVE_LOG_D("OnLoadSystemAbilitySuccess systemAbilityId: [%{public}d]", systemAbilityId);
734 }
735 
OnLoadSystemAbilityFail(int32_t systemAbilityId)736 void OnDemandLoadManagerCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId)
737 {
738     NETNATIVE_LOG_D("OnLoadSystemAbilityFail: [%{public}d]", systemAbilityId);
739 }
740 
LoadSystemAbility(int32_t systemAbilityId)741 int32_t NetsysBpfNetFirewall::LoadSystemAbility(int32_t systemAbilityId)
742 {
743     NETNATIVE_LOG_D("LoadSystemAbility: [%{public}d]", systemAbilityId);
744     auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
745     if (saManager == nullptr) {
746         NETNATIVE_LOGE("GetCmProxy registry is null");
747         return -1;
748     }
749 
750     auto object = saManager->CheckSystemAbility(systemAbilityId);
751     if (object != nullptr) {
752         return 0;
753     }
754 
755     sptr<OnDemandLoadManagerCallback> loadCallBack = new (std::nothrow) OnDemandLoadManagerCallback();
756     if (loadCallBack == nullptr) {
757         NETNATIVE_LOGE("new OnDemandLoadCertManagerCallback failed");
758         return -1;
759     }
760 
761     int32_t ret = saManager->LoadSystemAbility(systemAbilityId, loadCallBack);
762     if (ret != ERR_OK) {
763         NETNATIVE_LOGE("systemAbilityId:%d load failed,result code:%d", systemAbilityId, ret);
764         return -1;
765     }
766     return 0;
767 }
768 } // namespace NetManagerStandard
769 } // namespace OHOS