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