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     CtKey ctKey;
321     CtVaule ctVal;
322     ClearBpfMap(MAP_PATH(CT_MAP), ctKey, ctVal);
323     return NETFIREWALL_SUCCESS;
324 }
325 
SetFirewallCurrentUserId(int32_t userId)326 int32_t NetsysBpfNetFirewall::SetFirewallCurrentUserId(int32_t userId)
327 {
328     if (!isBpfLoaded_) {
329         NETNATIVE_LOGE("SetFirewallCurrentUserId: bpf not loaded");
330         return NETFIREWALL_ERR;
331     }
332 
333     CurrentUserIdKey key = CURRENT_USER_ID_KEY;
334     UidKey val = (UidKey)userId;
335     WriteBpfMap(MAP_PATH(CURRENT_UID_MAP), key, val);
336     return NETFIREWALL_SUCCESS;
337 }
338 
WriteSrcIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)339 void NetsysBpfNetFirewall::WriteSrcIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
340 {
341     std::vector<Ip4RuleBitmap> &srcIp4Map = manager.GetSrcIp4Map();
342     if (srcIp4Map.empty()) {
343         NETNATIVE_LOGE("WriteSrcIpv4BpfMap: srcIp4Map is empty");
344         return;
345     }
346     bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
347     for (const auto &node : srcIp4Map) {
348         Bitmap val = node.bitmap;
349         RuleCode rule;
350         memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
351 
352         Ipv4LpmKey key = { 0 };
353         key.prefixlen = node.mask;
354         key.data = static_cast<Ip4Key>(node.data);
355         WriteBpfMap(GET_MAP_PATH(ingress, saddr), key, rule);
356     }
357 }
358 
WriteSrcIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)359 void NetsysBpfNetFirewall::WriteSrcIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
360 {
361     std::vector<Ip6RuleBitmap> &srcIp6Map = manager.GetSrcIp6Map();
362     if (srcIp6Map.empty()) {
363         NETNATIVE_LOGE("WriteSrcIpv6BpfMap: srcIp6Map is empty");
364         return;
365     }
366     bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
367     for (const auto &node : srcIp6Map) {
368         Bitmap val = node.bitmap;
369         RuleCode rule;
370         memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
371 
372         Ipv6LpmKey key = { 0 };
373         key.prefixlen = node.prefixlen;
374         key.data = static_cast<Ip6Key>(node.data);
375         WriteBpfMap(GET_MAP_PATH(ingress, saddr6), key, rule);
376     }
377 }
378 
WriteDstIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)379 void NetsysBpfNetFirewall::WriteDstIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
380 {
381     std::vector<Ip4RuleBitmap> &dstIp4Map = manager.GetDstIp4Map();
382     if (dstIp4Map.empty()) {
383         NETNATIVE_LOGE("WriteDstIp4BpfMap: dstIp4Map is empty");
384     } else {
385         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
386         for (const auto &node : dstIp4Map) {
387             Bitmap val = node.bitmap;
388             RuleCode rule;
389             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
390 
391             Ipv4LpmKey key = { 0 };
392             key.prefixlen = node.mask;
393             key.data = static_cast<Ip4Key>(node.data);
394             WriteBpfMap(GET_MAP_PATH(ingress, daddr), key, rule);
395         }
396     }
397 }
398 
WriteDstIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)399 void NetsysBpfNetFirewall::WriteDstIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
400 {
401     std::vector<Ip6RuleBitmap> &dstIp6Map = manager.GetDstIp6Map();
402     if (dstIp6Map.empty()) {
403         NETNATIVE_LOGE("WriteDstIp6BpfMap: dstIp6Map is empty");
404     } else {
405         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
406         for (const auto &node : dstIp6Map) {
407             Bitmap val = node.bitmap;
408             RuleCode rule;
409             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
410 
411             Ipv6LpmKey key = { 0 };
412             key.prefixlen = node.prefixlen;
413             key.data = static_cast<Ip6Key>(node.data);
414             WriteBpfMap(GET_MAP_PATH(ingress, daddr6), key, rule);
415         }
416     }
417 }
418 
WriteSrcPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)419 void NetsysBpfNetFirewall::WriteSrcPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
420 {
421     BpfPortMap &srcPortMap = manager.GetSrcPortMap();
422     if (srcPortMap.Empty()) {
423         NETNATIVE_LOGE("WriteSrcPortBpfMap: srcPortMap is empty");
424     } else {
425         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
426         for (const auto &pair : srcPortMap.Get()) {
427             PortKey key = pair.first;
428             Bitmap val = pair.second;
429             RuleCode rule;
430             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
431             NETNATIVE_LOG_D("sport_map=%{public}u", key);
432             WriteBpfMap(GET_MAP_PATH(ingress, sport), key, rule);
433         }
434     }
435 }
436 
WriteDstPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)437 void NetsysBpfNetFirewall::WriteDstPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
438 {
439     BpfPortMap &dstPortMap = manager.GetDstPortMap();
440     if (dstPortMap.Empty()) {
441         NETNATIVE_LOGE("WriteDstPortBpfMap: dstPortMap is empty");
442     } else {
443         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
444         for (const auto &pair : dstPortMap.Get()) {
445             PortKey key = pair.first;
446             Bitmap val = pair.second;
447             RuleCode rule;
448             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
449             NETNATIVE_LOG_D("dport_map=%{public}u", key);
450             WriteBpfMap(GET_MAP_PATH(ingress, dport), key, rule);
451         }
452     }
453 }
454 
WriteProtoBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)455 void NetsysBpfNetFirewall::WriteProtoBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
456 {
457     BpfProtoMap &protoMap = manager.GetProtoMap();
458     if (protoMap.Empty()) {
459         NETNATIVE_LOGE("WriteProtoBpfMap: protoMap is empty");
460     } else {
461         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
462         for (const auto &pair : protoMap.Get()) {
463             ProtoKey key = pair.first;
464             Bitmap val = pair.second;
465             RuleCode rule;
466             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
467             NETNATIVE_LOG_D("proto_map=%{public}u", key);
468             WriteBpfMap(GET_MAP_PATH(ingress, proto), key, rule);
469         }
470     }
471 }
472 
WriteAppUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)473 void NetsysBpfNetFirewall::WriteAppUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
474 {
475     BpfAppUidMap &appIdMap = manager.GetAppIdMap();
476     if (appIdMap.Empty()) {
477         NETNATIVE_LOGE("WriteAppUidBpfMap: appIdMap is empty");
478     } else {
479         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
480         for (const auto &pair : appIdMap.Get()) {
481             AppUidKey key = pair.first;
482             Bitmap val = pair.second;
483             RuleCode rule;
484             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
485             NETNATIVE_LOG_D("appuid_map=%{public}u", key);
486             WriteBpfMap(GET_MAP_PATH(ingress, appuid), key, rule);
487         }
488     }
489 }
490 
WriteUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)491 void NetsysBpfNetFirewall::WriteUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
492 {
493     BpfUidMap &uidMap = manager.GetUidMap();
494     if (uidMap.Empty()) {
495         NETNATIVE_LOGE("WriteUidBpfMap: uidMap is empty");
496     } else {
497         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
498         for (const auto &pair : uidMap.Get()) {
499             UidKey key = pair.first;
500             Bitmap val = pair.second;
501             RuleCode rule;
502             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
503             NETNATIVE_LOG_D("uidMap=%{public}u", key);
504             WriteBpfMap(GET_MAP_PATH(ingress, uid), key, rule);
505         }
506     }
507 }
508 
WriteActionBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)509 void NetsysBpfNetFirewall::WriteActionBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
510 {
511     BpfActionMap &actionMap = manager.GetActionMap();
512     if (actionMap.Empty()) {
513         NETNATIVE_LOGE("WriteActionBpfMap: actionMap is empty");
514     } else {
515         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
516         for (const auto &pair : actionMap.Get()) {
517             ActionKey key = pair.first;
518             Bitmap val = pair.second;
519             RuleCode rule;
520             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
521             NETNATIVE_LOG_D("action_map=%{public}u", val.Get()[0]);
522             WriteBpfMap(GET_MAP_PATH(ingress, action), key, rule);
523         }
524     }
525 }
526 
RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)527 int32_t NetsysBpfNetFirewall::RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)
528 {
529     if (!callback) {
530         return -1;
531     }
532 
533     callbacks_.emplace_back(callback);
534 
535     return 0;
536 }
UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)537 int32_t NetsysBpfNetFirewall::UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)
538 {
539     if (!callback) {
540         return -1;
541     }
542 
543     for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
544         if (*it == callback) {
545             callbacks_.erase(it);
546             return 0;
547         }
548     }
549     return -1;
550 }
551 
ShouldSkipNotify(sptr<InterceptRecord> record)552 bool NetsysBpfNetFirewall::ShouldSkipNotify(sptr<InterceptRecord> record)
553 {
554     if (!record) {
555         return true;
556     }
557     if (oldRecord_ != nullptr && (record->time - oldRecord_->time) < INTERCEPT_BUFF_INTERVAL_SEC) {
558         if (record->localIp == oldRecord_->localIp && record->remoteIp == oldRecord_->remoteIp &&
559             record->localPort == oldRecord_->localPort && record->remotePort == oldRecord_->remotePort &&
560             record->protocol == oldRecord_->protocol && record->appUid == oldRecord_->appUid) {
561             return true;
562         }
563     }
564     oldRecord_ = record;
565     return false;
566 }
567 
NotifyInterceptEvent(InterceptEvent *info)568 void NetsysBpfNetFirewall::NotifyInterceptEvent(InterceptEvent *info)
569 {
570     if (!info) {
571         return;
572     }
573     sptr<InterceptRecord> record = new (std::nothrow) InterceptRecord();
574     record->time = (int32_t)time(NULL);
575     record->localPort = BitmapManager::Nstohl(info->sport);
576     record->remotePort = BitmapManager::Nstohl(info->dport);
577     record->protocol = static_cast<uint16_t>(info->protocol);
578     record->appUid = (int32_t)info->appuid;
579     std::string srcIp;
580     std::string dstIp;
581     if (info->family == AF_INET) {
582         char ip4[INET_ADDRSTRLEN] = {};
583         inet_ntop(AF_INET, &(info->ipv4.saddr), ip4, INET_ADDRSTRLEN);
584         srcIp = ip4;
585         memset_s(ip4, INET_ADDRSTRLEN, 0, INET_ADDRSTRLEN);
586         inet_ntop(AF_INET, &(info->ipv4.daddr), ip4, INET_ADDRSTRLEN);
587         dstIp = ip4;
588     } else {
589         char ip6[INET6_ADDRSTRLEN] = {};
590         inet_ntop(AF_INET6, &(info->ipv6.saddr), ip6, INET6_ADDRSTRLEN);
591         srcIp = ip6;
592         memset_s(ip6, INET6_ADDRSTRLEN, 0, INET6_ADDRSTRLEN);
593         inet_ntop(AF_INET6, &(info->ipv6.daddr), ip6, INET6_ADDRSTRLEN);
594         dstIp = ip6;
595     }
596     if (info->dir == INGRESS) {
597         record->localIp = srcIp;
598         record->remoteIp = dstIp;
599     } else {
600         record->localIp = dstIp;
601         record->remoteIp = srcIp;
602     }
603     if (ShouldSkipNotify(record)) {
604         return;
605     }
606     for (auto callback : callbacks_) {
607         callback->OnIntercept(record);
608     }
609 }
610 
HandleTupleEvent(TupleEvent *ev)611 void NetsysBpfNetFirewall::HandleTupleEvent(TupleEvent *ev)
612 {
613     NETNATIVE_LOG_D(
614         "%{public}s tuple: sport=%{public}u dport=%{public}u protocol=%{public}u appuid=%{public}u uid=%{public}u",
615         (ev->dir == INGRESS) ? "> ingress" : "< egress", ntohs(ev->sport), ntohs(ev->dport), ev->protocol, ev->appuid,
616         ev->uid);
617     NETNATIVE_LOG_D("\trstpacket=%{public}u", ev->rst);
618 }
619 
HandleInterceptEvent(InterceptEvent *ev)620 void NetsysBpfNetFirewall::HandleInterceptEvent(InterceptEvent *ev)
621 {
622     GetInstance()->NotifyInterceptEvent(ev);
623 
624     NETNATIVE_LOGI("%{public}s intercept: sport=%{public}u dport=%{public}u protocol=%{public}u appuid=%{public}u",
625         (ev->dir == INGRESS) ? "ingress" : "egress", ntohs(ev->sport), ntohs(ev->dport), ev->protocol, ev->appuid);
626 }
627 
HandleDebugEvent(DebugEvent *ev)628 void NetsysBpfNetFirewall::HandleDebugEvent(DebugEvent *ev)
629 {
630     const char *direction = ev->dir == INGRESS ? ">" : "<";
631     switch (ev->type) {
632         case DBG_MATCH_SPORT:
633             NETNATIVE_LOG_D("%{public}s sport: %{public}u bitmap: %{public}x", direction, ntohs(ev->arg1), ev->arg2);
634             break;
635         case DBG_MATCH_DPORT:
636             NETNATIVE_LOG_D("%{public}s dport: %{public}u bitmap: %{public}x", direction, ntohs(ev->arg1), ev->arg2);
637             break;
638         case DBG_MATCH_PROTO:
639             NETNATIVE_LOG_D("%{public}s protocol: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
640             break;
641         case DBG_MATCH_APPUID:
642             NETNATIVE_LOG_D("%{public}s appuid: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
643             break;
644         case DBG_MATCH_UID:
645             NETNATIVE_LOG_D("%{public}s uid: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
646             break;
647         case DBG_ACTION_KEY:
648             NETNATIVE_LOG_D("%{public}s actionkey: %{public}x", direction, ev->arg1);
649             break;
650         case DBG_MATCH_ACTION:
651             NETNATIVE_LOG_D("%{public}s    action: %{public}s", direction, (ev->arg1 == SK_PASS ? "PASS" : "DROP"));
652             break;
653         case DBG_CT_LOOKUP:
654             NETNATIVE_LOG_D("%{public}s ct lookup status: %{public}u", direction, ev->arg1);
655             break;
656         case DBG_MATCH_DOMAIN:
657             NETNATIVE_LOG_D("egress match domain, action PASS");
658             break;
659         default:
660             break;
661     }
662 }
663 
HandleEvent(void *ctx, void *data, size_t len)664 int NetsysBpfNetFirewall::HandleEvent(void *ctx, void *data, size_t len)
665 {
666     if (data && len > 0) {
667         Event *ev = (Event *)data;
668 
669         switch (ev->type) {
670             case EVENT_DEBUG: {
671                 HandleDebugEvent(&(ev->debug));
672                 break;
673             }
674             case EVENT_INTERCEPT: {
675                 HandleInterceptEvent(&(ev->intercept));
676                 break;
677             }
678             case EVENT_TUPLE_DEBUG: {
679                 HandleTupleEvent(&(ev->tuple));
680                 break;
681             }
682             default:
683                 break;
684         }
685     }
686     return 0;
687 }
688 
OnLoadSystemAbilitySuccess(int32_t systemAbilityId, const sptr<IRemoteObject> &remoteObject)689 void OnDemandLoadManagerCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId,
690     const sptr<IRemoteObject> &remoteObject)
691 {
692     NETNATIVE_LOG_D("OnLoadSystemAbilitySuccess systemAbilityId: [%{public}d]", systemAbilityId);
693 }
694 
OnLoadSystemAbilityFail(int32_t systemAbilityId)695 void OnDemandLoadManagerCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId)
696 {
697     NETNATIVE_LOG_D("OnLoadSystemAbilityFail: [%{public}d]", systemAbilityId);
698 }
699 
LoadSystemAbility(int32_t systemAbilityId)700 int32_t NetsysBpfNetFirewall::LoadSystemAbility(int32_t systemAbilityId)
701 {
702     NETNATIVE_LOG_D("LoadSystemAbility: [%{public}d]", systemAbilityId);
703     auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
704     if (saManager == nullptr) {
705         NETNATIVE_LOGE("GetCmProxy registry is null");
706         return -1;
707     }
708 
709     auto object = saManager->CheckSystemAbility(systemAbilityId);
710     if (object != nullptr) {
711         return 0;
712     }
713 
714     sptr<OnDemandLoadManagerCallback> loadCallBack = new (std::nothrow) OnDemandLoadManagerCallback();
715     if (loadCallBack == nullptr) {
716         NETNATIVE_LOGE("new OnDemandLoadCertManagerCallback failed");
717         return -1;
718     }
719 
720     int32_t ret = saManager->LoadSystemAbility(systemAbilityId, loadCallBack);
721     if (ret != ERR_OK) {
722         NETNATIVE_LOGE("systemAbilityId:%d load failed,result code:%d", systemAbilityId, ret);
723         return -1;
724     }
725     return 0;
726 }
727 
AddDomainCache(const NetAddrInfo &addrInfo)728 void NetsysBpfNetFirewall::AddDomainCache(const NetAddrInfo &addrInfo)
729 {
730     NETNATIVE_LOGI("AddDomainCache");
731     domain_value value = 1;
732     if (addrInfo.aiFamily == AF_INET) {
733         Ipv4LpmKey key = { 0 };
734         key.prefixlen = IPV4_MAX_PREFIXLEN;
735         key.data = addrInfo.aiAddr.sin.s_addr;
736         WriteBpfMap(MAP_PATH(DOMAIN_IPV4_MAP), key, value);
737     } else {
738         Ipv6LpmKey key = { 0 };
739         key.prefixlen = IPV6_MAX_PREFIXLEN;
740         key.data = addrInfo.aiAddr.sin6;
741         WriteBpfMap(MAP_PATH(DOMAIN_IPV6_MAP), key, value);
742     }
743 }
744 
ClearDomainCache()745 void NetsysBpfNetFirewall::ClearDomainCache()
746 {
747     NETNATIVE_LOG_D("ClearDomainCache");
748     Ipv4LpmKey ip4Key = {};
749     Ipv6LpmKey ip6Key = {};
750     domain_value value;
751     ClearBpfMap(MAP_PATH(DOMAIN_IPV4_MAP), ip4Key, value);
752     ClearBpfMap(MAP_PATH(DOMAIN_IPV6_MAP), ip6Key, value);
753 }
754 } // namespace NetManagerStandard
755 } // namespace OHOS