• 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     NETNATIVE_LOG_D("ClearBpfFirewallRules: direction=%{public}d", direction);
218     Ipv4LpmKey ip4Key = {};
219     Ipv6LpmKey ip6Key = {};
220     PortKey portKey = 0;
221     ProtoKey protoKey = 0;
222     AppUidKey appIdKey = 0;
223     UidKey uidKey = 0;
224     ActionKey actKey = 1;
225     ActionValue actVal;
226     RuleCode ruleCode;
227     CtKey ctKey;
228     CtVaule ctVal;
229 
230     bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
231     ClearBpfMap(GET_MAP_PATH(ingress, saddr), ip4Key, ruleCode);
232     ClearBpfMap(GET_MAP_PATH(ingress, saddr6), ip6Key, ruleCode);
233     ClearBpfMap(GET_MAP_PATH(ingress, daddr), ip4Key, ruleCode);
234     ClearBpfMap(GET_MAP_PATH(ingress, daddr6), ip6Key, ruleCode);
235     ClearBpfMap(GET_MAP_PATH(ingress, sport), portKey, ruleCode);
236     ClearBpfMap(GET_MAP_PATH(ingress, dport), portKey, ruleCode);
237     ClearBpfMap(GET_MAP_PATH(ingress, proto), protoKey, ruleCode);
238     ClearBpfMap(GET_MAP_PATH(ingress, appuid), appIdKey, ruleCode);
239     ClearBpfMap(GET_MAP_PATH(ingress, uid), uidKey, ruleCode);
240     ClearBpfMap(GET_MAP_PATH(ingress, action), actKey, actVal);
241     ClearBpfMap(MAP_PATH(CT_MAP), ctKey, ctVal);
242 }
243 
ClearFirewallRules(NetFirewallRuleType type)244 int32_t NetsysBpfNetFirewall::ClearFirewallRules(NetFirewallRuleType type)
245 {
246     switch (type) {
247         case NetFirewallRuleType::RULE_IP: {
248             firewallIpRules_.clear();
249             ClearBpfFirewallRules(NetFirewallRuleDirection::RULE_IN);
250             ClearBpfFirewallRules(NetFirewallRuleDirection::RULE_OUT);
251             break;
252         }
253         case NetFirewallRuleType::RULE_DOMAIN: {
254             firewallDomainRules_.clear();
255             ClearDomainRules();
256             break;
257         }
258         case NetFirewallRuleType::RULE_DEFAULT_ACTION: {
259             ClearFirewallDefaultAction();
260             break;
261         }
262         case NetFirewallRuleType::RULE_ALL: {
263             firewallIpRules_.clear();
264             ClearBpfFirewallRules(NetFirewallRuleDirection::RULE_IN);
265             ClearBpfFirewallRules(NetFirewallRuleDirection::RULE_OUT);
266             firewallDomainRules_.clear();
267             ClearDomainRules();
268             ClearFirewallDefaultAction();
269             break;
270         }
271         default:
272             break;
273     }
274     return NETFIREWALL_SUCCESS;
275 }
276 
SetBpfFirewallRules(const std::vector<sptr<NetFirewallIpRule>> & ruleList,NetFirewallRuleDirection direction)277 int32_t NetsysBpfNetFirewall::SetBpfFirewallRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList,
278     NetFirewallRuleDirection direction)
279 {
280     BitmapManager manager;
281     int32_t ret = manager.BuildBitmapMap(ruleList);
282     if (ret) {
283         NETNATIVE_LOGE("SetBpfFirewallRules: BuildBitmapMap failed: %{public}d", ret);
284         return ret;
285     }
286 
287     ClearBpfFirewallRules(direction);
288     WriteSrcIpv4BpfMap(manager, direction);
289     WriteSrcIpv6BpfMap(manager, direction);
290     WriteDstIpv4BpfMap(manager, direction);
291     WriteDstIpv6BpfMap(manager, direction);
292     WriteSrcPortBpfMap(manager, direction);
293     WriteDstPortBpfMap(manager, direction);
294     WriteProtoBpfMap(manager, direction);
295     WriteAppUidBpfMap(manager, direction);
296     WriteUidBpfMap(manager, direction);
297     WriteActionBpfMap(manager, direction);
298     return NETFIREWALL_SUCCESS;
299 }
300 
SetFirewallRules(NetFirewallRuleType type,const std::vector<sptr<NetFirewallBaseRule>> & ruleList,bool isFinish)301 int32_t NetsysBpfNetFirewall::SetFirewallRules(NetFirewallRuleType type,
302     const std::vector<sptr<NetFirewallBaseRule>> &ruleList, bool isFinish)
303 {
304     NETNATIVE_LOGI("SetFirewallRules: size=%{public}zu isFinish=%{public}" PRId32, ruleList.size(), isFinish);
305     if (!isBpfLoaded_) {
306         NETNATIVE_LOGE("SetFirewallRules: bpf not loaded");
307         return NETFIREWALL_ERR;
308     }
309     if (ruleList.empty()) {
310         NETNATIVE_LOGE("SetFirewallRules: rules is empty");
311         return NETFIREWALL_ERR;
312     }
313     int32_t ret = NETFIREWALL_SUCCESS;
314     switch (type) {
315         case NetFirewallRuleType::RULE_IP: {
316             for (const auto &rule : ruleList) {
317                 firewallIpRules_.emplace_back(firewall_rule_cast<NetFirewallIpRule>(rule));
318             }
319             if (isFinish) {
320                 ret = SetFirewallIpRules(firewallIpRules_);
321                 firewallIpRules_.clear();
322             }
323             break;
324         }
325         case NetFirewallRuleType::RULE_DOMAIN: {
326             for (const auto &rule : ruleList) {
327                 firewallDomainRules_.emplace_back(firewall_rule_cast<NetFirewallDomainRule>(rule));
328             }
329             if (isFinish) {
330                 ret = SetFirewallDomainRules(firewallDomainRules_);
331                 firewallDomainRules_.clear();
332             }
333             break;
334         }
335         default:
336             break;
337     }
338     return ret;
339 }
340 
SetFirewallDomainRules(const std::vector<sptr<NetFirewallDomainRule>> & ruleList)341 int32_t NetsysBpfNetFirewall::SetFirewallDomainRules(const std::vector<sptr<NetFirewallDomainRule>> &ruleList)
342 {
343     if (ruleList.empty()) {
344         NETNATIVE_LOGE("SetFirewallDomainRules: rules is empty");
345         return NETFIREWALL_ERR;
346     }
347     DomainValue domainVaule = { 0 };
348     bool isWildcard = false;
349     ClearDomainRules();
350     int ret = 0;
351     for (const auto &rule : ruleList) {
352         domainVaule.uid = static_cast<uint32_t>(rule->userId);
353         domainVaule.appuid = static_cast<uint32_t>(rule->appUid);
354         for (const auto &param : rule->domains) {
355             if (param.isWildcard) {
356                 isWildcard = true;
357             } else {
358                 isWildcard = false;
359             }
360             DomainHashKey key = { 0 };
361             GetDomainHashKey(param.domain, key);
362             ret = SetBpfFirewallDomainRules(rule->ruleAction, key, domainVaule, isWildcard);
363         }
364     }
365     return ret;
366 }
367 
GetDomainHashKey(const std::string & domain,DomainHashKey & out)368 void NetsysBpfNetFirewall::GetDomainHashKey(const std::string &domain, DomainHashKey &out)
369 {
370     if (domain.empty()) {
371         NETNATIVE_LOGE("GetDomainHashKey: domain is empty");
372         return;
373     }
374     std::string text(domain);
375     text.erase(std::remove(text.begin(), text.end(), '*'), text.end());
376 
377     std::regex delimit("\\.");
378     std::vector<std::string> v(std::sregex_token_iterator(text.begin(), text.end(), delimit, -1),
379         std::sregex_token_iterator());
380 
381     int i = 0;
382     for (auto &s : v) {
383         int strLen = static_cast<int>(s.length());
384         out.data[i++] = (uint8_t)strLen;
385         if (memcpy_s(out.data + i, DNS_DOMAIN_LEN - i, (uint8_t *)s.c_str(), strLen) != EOK) {
386             NETNATIVE_LOGE("GetDomainHashKey: memcpy_s failed");
387             return;
388         }
389         i += strLen;
390     }
391 }
392 
SetBpfFirewallDomainRules(FirewallRuleAction action,DomainHashKey & key,DomainValue value,bool isWildcard)393 int32_t NetsysBpfNetFirewall::SetBpfFirewallDomainRules(FirewallRuleAction action, DomainHashKey &key,
394     DomainValue value, bool isWildcard)
395 {
396     NETNATIVE_LOG_D("SetBpfFirewallDomainRules: action=%{public}d, userid=%{public}d appuid=%{public}d",
397         (action == FirewallRuleAction::RULE_ALLOW), value.uid, value.appuid);
398     int32_t ret = 0;
399     if (action == FirewallRuleAction::RULE_ALLOW) {
400         ret = WriteBpfMap(MAP_PATH(DOMAIN_PASS_MAP), key, value);
401     } else if (action == FirewallRuleAction::RULE_DENY) {
402         ret = WriteBpfMap(MAP_PATH(DOMAIN_DENY_MAP), key, value);
403     }
404     return ret;
405 }
406 
ClearDomainRules()407 void NetsysBpfNetFirewall::ClearDomainRules()
408 {
409     NETNATIVE_LOG_D("ClearDomainRules");
410     ClearDomainCache();
411     DomainHashKey key = { 0 };
412     DomainValue value = { 0 };
413     ClearBpfMap(MAP_PATH(DOMAIN_PASS_MAP), key, value);
414     ClearBpfMap(MAP_PATH(DOMAIN_DENY_MAP), key, value);
415 }
416 
SetFirewallIpRules(const std::vector<sptr<NetFirewallIpRule>> & ruleList)417 int32_t NetsysBpfNetFirewall::SetFirewallIpRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList)
418 {
419     std::vector<sptr<NetFirewallIpRule>> inRules;
420     std::vector<sptr<NetFirewallIpRule>> outRules;
421 
422     for (const auto &rule : ruleList) {
423         if (rule->ruleDirection == NetFirewallRuleDirection::RULE_IN) {
424             if (rule->protocol == NetworkProtocol::ICMP || rule->protocol == NetworkProtocol::ICMPV6) {
425                 outRules.emplace_back(rule);
426             } else {
427                 inRules.emplace_back(rule);
428             }
429         }
430         if (rule->ruleDirection == NetFirewallRuleDirection::RULE_OUT) {
431             outRules.emplace_back(rule);
432         }
433     }
434 
435     int32_t ret = NETFIREWALL_SUCCESS;
436     if (!inRules.empty()) {
437         ret = SetBpfFirewallRules(inRules, NetFirewallRuleDirection::RULE_IN);
438     }
439     if (!outRules.empty()) {
440         ret += SetBpfFirewallRules(outRules, NetFirewallRuleDirection::RULE_OUT);
441     }
442     return ret;
443 }
444 
ClearFirewallDefaultAction()445 void NetsysBpfNetFirewall::ClearFirewallDefaultAction()
446 {
447     defalut_action_value val = { SK_PASS };
448     int32_t userId = -1;
449     ClearBpfMap(MAP_PATH(DEFAULT_ACTION_MAP), (uid_key)userId, val);
450 }
451 
SetFirewallDefaultAction(int32_t userId,FirewallRuleAction inDefault,FirewallRuleAction outDefault)452 int32_t NetsysBpfNetFirewall::SetFirewallDefaultAction(int32_t userId, FirewallRuleAction inDefault,
453     FirewallRuleAction outDefault)
454 {
455     if (!isBpfLoaded_) {
456         NETNATIVE_LOGE("SetFirewallDefaultAction: bpf not loaded");
457         return NETFIREWALL_ERR;
458     }
459     defalut_action_value val = { SK_PASS };
460     val.inaction = (inDefault == FirewallRuleAction::RULE_ALLOW) ? SK_PASS : SK_DROP;
461     val.outaction = (outDefault == FirewallRuleAction::RULE_ALLOW) ? SK_PASS : SK_DROP;
462     WriteBpfMap(MAP_PATH(DEFAULT_ACTION_MAP), (uid_key)userId, val);
463     CtKey ctKey;
464     CtVaule ctVal;
465     ClearBpfMap(MAP_PATH(CT_MAP), ctKey, ctVal);
466     return NETFIREWALL_SUCCESS;
467 }
468 
SetFirewallCurrentUserId(int32_t userId)469 int32_t NetsysBpfNetFirewall::SetFirewallCurrentUserId(int32_t userId)
470 {
471     if (!isBpfLoaded_) {
472         NETNATIVE_LOGE("SetFirewallCurrentUserId: bpf not loaded");
473         return NETFIREWALL_ERR;
474     }
475 
476     CurrentUserIdKey key = CURRENT_USER_ID_KEY;
477     UidKey val = (UidKey)userId;
478     WriteBpfMap(MAP_PATH(CURRENT_UID_MAP), key, val);
479     return NETFIREWALL_SUCCESS;
480 }
481 
WriteSrcIpv4BpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)482 void NetsysBpfNetFirewall::WriteSrcIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
483 {
484     std::vector<Ip4RuleBitmap> &srcIp4Map = manager.GetSrcIp4Map();
485     if (srcIp4Map.empty()) {
486         NETNATIVE_LOGE("WriteSrcIpv4BpfMap: srcIp4Map is empty");
487         return;
488     }
489     bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
490     for (const auto &node : srcIp4Map) {
491         Bitmap val = node.bitmap;
492         RuleCode rule;
493         memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
494 
495         Ipv4LpmKey key = { 0 };
496         key.prefixlen = node.mask;
497         key.data = static_cast<Ip4Key>(node.data);
498         WriteBpfMap(GET_MAP_PATH(ingress, saddr), key, rule);
499     }
500 }
501 
WriteSrcIpv6BpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)502 void NetsysBpfNetFirewall::WriteSrcIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
503 {
504     std::vector<Ip6RuleBitmap> &srcIp6Map = manager.GetSrcIp6Map();
505     if (srcIp6Map.empty()) {
506         NETNATIVE_LOGE("WriteSrcIpv6BpfMap: srcIp6Map is empty");
507         return;
508     }
509     bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
510     for (const auto &node : srcIp6Map) {
511         Bitmap val = node.bitmap;
512         RuleCode rule;
513         memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
514 
515         Ipv6LpmKey key = { 0 };
516         key.prefixlen = node.prefixlen;
517         key.data = static_cast<Ip6Key>(node.data);
518         WriteBpfMap(GET_MAP_PATH(ingress, saddr6), key, rule);
519     }
520 }
521 
WriteDstIpv4BpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)522 void NetsysBpfNetFirewall::WriteDstIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
523 {
524     std::vector<Ip4RuleBitmap> &dstIp4Map = manager.GetDstIp4Map();
525     if (dstIp4Map.empty()) {
526         NETNATIVE_LOGE("WriteDstIp4BpfMap: dstIp4Map is empty");
527     } else {
528         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
529         for (const auto &node : dstIp4Map) {
530             Bitmap val = node.bitmap;
531             RuleCode rule;
532             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
533 
534             Ipv4LpmKey key = { 0 };
535             key.prefixlen = node.mask;
536             key.data = static_cast<Ip4Key>(node.data);
537             WriteBpfMap(GET_MAP_PATH(ingress, daddr), key, rule);
538         }
539     }
540 }
541 
WriteDstIpv6BpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)542 void NetsysBpfNetFirewall::WriteDstIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
543 {
544     std::vector<Ip6RuleBitmap> &dstIp6Map = manager.GetDstIp6Map();
545     if (dstIp6Map.empty()) {
546         NETNATIVE_LOGE("WriteDstIp6BpfMap: dstIp6Map is empty");
547     } else {
548         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
549         for (const auto &node : dstIp6Map) {
550             Bitmap val = node.bitmap;
551             RuleCode rule;
552             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
553 
554             Ipv6LpmKey key = { 0 };
555             key.prefixlen = node.prefixlen;
556             key.data = static_cast<Ip6Key>(node.data);
557             WriteBpfMap(GET_MAP_PATH(ingress, daddr6), key, rule);
558         }
559     }
560 }
561 
WriteSrcPortBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)562 void NetsysBpfNetFirewall::WriteSrcPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
563 {
564     BpfPortMap &srcPortMap = manager.GetSrcPortMap();
565     if (srcPortMap.Empty()) {
566         NETNATIVE_LOGE("WriteSrcPortBpfMap: srcPortMap is empty");
567     } else {
568         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
569         for (const auto &pair : srcPortMap.Get()) {
570             PortKey key = pair.first;
571             Bitmap val = pair.second;
572             RuleCode rule;
573             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
574             NETNATIVE_LOG_D("sport_map=%{public}u", key);
575             WriteBpfMap(GET_MAP_PATH(ingress, sport), key, rule);
576         }
577     }
578 }
579 
WriteDstPortBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)580 void NetsysBpfNetFirewall::WriteDstPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
581 {
582     BpfPortMap &dstPortMap = manager.GetDstPortMap();
583     if (dstPortMap.Empty()) {
584         NETNATIVE_LOGE("WriteDstPortBpfMap: dstPortMap is empty");
585     } else {
586         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
587         for (const auto &pair : dstPortMap.Get()) {
588             PortKey key = pair.first;
589             Bitmap val = pair.second;
590             RuleCode rule;
591             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
592             NETNATIVE_LOG_D("dport_map=%{public}u", key);
593             WriteBpfMap(GET_MAP_PATH(ingress, dport), key, rule);
594         }
595     }
596 }
597 
WriteProtoBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)598 void NetsysBpfNetFirewall::WriteProtoBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
599 {
600     BpfProtoMap &protoMap = manager.GetProtoMap();
601     if (protoMap.Empty()) {
602         NETNATIVE_LOGE("WriteProtoBpfMap: protoMap is empty");
603     } else {
604         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
605         for (const auto &pair : protoMap.Get()) {
606             ProtoKey key = pair.first;
607             Bitmap val = pair.second;
608             RuleCode rule;
609             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
610             NETNATIVE_LOG_D("proto_map=%{public}u", key);
611             WriteBpfMap(GET_MAP_PATH(ingress, proto), key, rule);
612         }
613     }
614 }
615 
WriteAppUidBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)616 void NetsysBpfNetFirewall::WriteAppUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
617 {
618     BpfAppUidMap &appIdMap = manager.GetAppIdMap();
619     if (appIdMap.Empty()) {
620         NETNATIVE_LOGE("WriteAppUidBpfMap: appIdMap is empty");
621     } else {
622         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
623         for (const auto &pair : appIdMap.Get()) {
624             AppUidKey key = pair.first;
625             Bitmap val = pair.second;
626             RuleCode rule;
627             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
628             NETNATIVE_LOG_D("appuid_map=%{public}u", key);
629             WriteBpfMap(GET_MAP_PATH(ingress, appuid), key, rule);
630         }
631     }
632 }
633 
WriteUidBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)634 void NetsysBpfNetFirewall::WriteUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
635 {
636     BpfUidMap &uidMap = manager.GetUidMap();
637     if (uidMap.Empty()) {
638         NETNATIVE_LOGE("WriteUidBpfMap: uidMap is empty");
639     } else {
640         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
641         for (const auto &pair : uidMap.Get()) {
642             UidKey key = pair.first;
643             Bitmap val = pair.second;
644             RuleCode rule;
645             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
646             NETNATIVE_LOG_D("uidMap=%{public}u", key);
647             WriteBpfMap(GET_MAP_PATH(ingress, uid), key, rule);
648         }
649     }
650 }
651 
WriteActionBpfMap(BitmapManager & manager,NetFirewallRuleDirection direction)652 void NetsysBpfNetFirewall::WriteActionBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
653 {
654     BpfActionMap &actionMap = manager.GetActionMap();
655     if (actionMap.Empty()) {
656         NETNATIVE_LOGE("WriteActionBpfMap: actionMap is empty");
657     } else {
658         bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
659         for (const auto &pair : actionMap.Get()) {
660             ActionKey key = pair.first;
661             Bitmap val = pair.second;
662             RuleCode rule;
663             memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
664             NETNATIVE_LOG_D("action_map=%{public}u", val.Get()[0]);
665             WriteBpfMap(GET_MAP_PATH(ingress, action), key, rule);
666         }
667     }
668 }
669 
RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> & callback)670 int32_t NetsysBpfNetFirewall::RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)
671 {
672     if (!callback) {
673         return -1;
674     }
675 
676     callbacks_.emplace_back(callback);
677 
678     return 0;
679 }
UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> & callback)680 int32_t NetsysBpfNetFirewall::UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)
681 {
682     if (!callback) {
683         return -1;
684     }
685 
686     for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
687         if (*it == callback) {
688             callbacks_.erase(it);
689             return 0;
690         }
691     }
692     return -1;
693 }
694 
ShouldSkipNotify(sptr<InterceptRecord> record)695 bool NetsysBpfNetFirewall::ShouldSkipNotify(sptr<InterceptRecord> record)
696 {
697     if (!record) {
698         return true;
699     }
700     if (oldRecord_ != nullptr && (record->time - oldRecord_->time) < INTERCEPT_BUFF_INTERVAL_SEC) {
701         if (record->localIp == oldRecord_->localIp && record->remoteIp == oldRecord_->remoteIp &&
702             record->localPort == oldRecord_->localPort && record->remotePort == oldRecord_->remotePort &&
703             record->protocol == oldRecord_->protocol && record->appUid == oldRecord_->appUid) {
704             return true;
705         }
706     }
707     oldRecord_ = record;
708     return false;
709 }
710 
NotifyInterceptEvent(InterceptEvent * info)711 void NetsysBpfNetFirewall::NotifyInterceptEvent(InterceptEvent *info)
712 {
713     if (!info) {
714         return;
715     }
716     sptr<InterceptRecord> record = sptr<InterceptRecord>::MakeSptr();
717     record->time = (int32_t)time(NULL);
718     record->localPort = BitmapManager::Nstohl(info->sport);
719     record->remotePort = BitmapManager::Nstohl(info->dport);
720     record->protocol = static_cast<uint16_t>(info->protocol);
721     record->appUid = (int32_t)info->appuid;
722     std::string srcIp;
723     std::string dstIp;
724     if (info->family == AF_INET) {
725         char ip4[INET_ADDRSTRLEN] = {};
726         inet_ntop(AF_INET, &(info->ipv4.saddr), ip4, INET_ADDRSTRLEN);
727         srcIp = ip4;
728         memset_s(ip4, INET_ADDRSTRLEN, 0, INET_ADDRSTRLEN);
729         inet_ntop(AF_INET, &(info->ipv4.daddr), ip4, INET_ADDRSTRLEN);
730         dstIp = ip4;
731     } else {
732         char ip6[INET6_ADDRSTRLEN] = {};
733         inet_ntop(AF_INET6, &(info->ipv6.saddr), ip6, INET6_ADDRSTRLEN);
734         srcIp = ip6;
735         memset_s(ip6, INET6_ADDRSTRLEN, 0, INET6_ADDRSTRLEN);
736         inet_ntop(AF_INET6, &(info->ipv6.daddr), ip6, INET6_ADDRSTRLEN);
737         dstIp = ip6;
738     }
739     if (info->dir == INGRESS) {
740         record->localIp = srcIp;
741         record->remoteIp = dstIp;
742     } else {
743         record->localIp = dstIp;
744         record->remoteIp = srcIp;
745     }
746     if (ShouldSkipNotify(record)) {
747         return;
748     }
749     for (auto callback : callbacks_) {
750         callback->OnIntercept(record);
751     }
752 }
753 
HandleTupleEvent(TupleEvent * ev)754 void NetsysBpfNetFirewall::HandleTupleEvent(TupleEvent *ev)
755 {
756     NETNATIVE_LOG_D(
757         "%{public}s tuple: sport=%{public}u dport=%{public}u protocol=%{public}u appuid=%{public}u uid=%{public}u",
758         (ev->dir == INGRESS) ? "> ingress" : "< egress", ntohs(ev->sport), ntohs(ev->dport), ev->protocol, ev->appuid,
759         ev->uid);
760     NETNATIVE_LOG_D("\trstpacket=%{public}u", ev->rst);
761 }
762 
HandleInterceptEvent(InterceptEvent * ev)763 void NetsysBpfNetFirewall::HandleInterceptEvent(InterceptEvent *ev)
764 {
765     GetInstance()->NotifyInterceptEvent(ev);
766 
767     NETNATIVE_LOGI("%{public}s intercept: sport=%{public}u dport=%{public}u protocol=%{public}u appuid=%{public}u",
768         (ev->dir == INGRESS) ? "ingress" : "egress", ntohs(ev->sport), ntohs(ev->dport), ev->protocol, ev->appuid);
769 }
770 
HandleDebugEvent(DebugEvent * ev)771 void NetsysBpfNetFirewall::HandleDebugEvent(DebugEvent *ev)
772 {
773     const char *direction = ev->dir == INGRESS ? ">" : "<";
774     switch (ev->type) {
775         case DBG_MATCH_SPORT:
776             NETNATIVE_LOG_D("%{public}s sport: %{public}u bitmap: %{public}x", direction, ntohs(ev->arg1), ev->arg2);
777             break;
778         case DBG_MATCH_DPORT:
779             NETNATIVE_LOG_D("%{public}s dport: %{public}u bitmap: %{public}x", direction, ntohs(ev->arg1), ev->arg2);
780             break;
781         case DBG_MATCH_PROTO:
782             NETNATIVE_LOG_D("%{public}s protocol: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
783             break;
784         case DBG_MATCH_APPUID:
785             NETNATIVE_LOG_D("%{public}s appuid: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
786             break;
787         case DBG_MATCH_UID:
788             NETNATIVE_LOG_D("%{public}s uid: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
789             break;
790         case DBG_ACTION_KEY:
791             NETNATIVE_LOG_D("%{public}s actionkey: %{public}x", direction, ev->arg1);
792             break;
793         case DBG_MATCH_ACTION:
794             NETNATIVE_LOG_D("%{public}s    action: %{public}s", direction, (ev->arg1 == SK_PASS ? "PASS" : "DROP"));
795             break;
796         case DBG_CT_LOOKUP:
797             NETNATIVE_LOG_D("%{public}s ct lookup status: %{public}u", direction, ev->arg1);
798             break;
799         case DBG_MATCH_DOMAIN:
800             NETNATIVE_LOG_D("egress match domain, action PASS");
801             break;
802         case DBG_MATCH_DOMAIN_ACTION:
803             NETNATIVE_LOG_D("%{public}s match domain action: %{public}s", direction,
804                 (ev->arg1 == SK_PASS ? "PASS" : "DROP"));
805             break;
806         default:
807             break;
808     }
809 }
810 
HandleEvent(void * ctx,void * data,size_t len)811 int NetsysBpfNetFirewall::HandleEvent(void *ctx, void *data, size_t len)
812 {
813     if (data && len > 0) {
814         Event *ev = (Event *)data;
815 
816         switch (ev->type) {
817             case EVENT_DEBUG: {
818                 HandleDebugEvent(&(ev->debug));
819                 break;
820             }
821             case EVENT_INTERCEPT: {
822                 HandleInterceptEvent(&(ev->intercept));
823                 break;
824             }
825             case EVENT_TUPLE_DEBUG: {
826                 HandleTupleEvent(&(ev->tuple));
827                 break;
828             }
829             default:
830                 break;
831         }
832     }
833     return 0;
834 }
835 
OnLoadSystemAbilitySuccess(int32_t systemAbilityId,const sptr<IRemoteObject> & remoteObject)836 void OnDemandLoadManagerCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId,
837     const sptr<IRemoteObject> &remoteObject)
838 {
839     NETNATIVE_LOG_D("OnLoadSystemAbilitySuccess systemAbilityId: [%{public}d]", systemAbilityId);
840 }
841 
OnLoadSystemAbilityFail(int32_t systemAbilityId)842 void OnDemandLoadManagerCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId)
843 {
844     NETNATIVE_LOG_D("OnLoadSystemAbilityFail: [%{public}d]", systemAbilityId);
845 }
846 
LoadSystemAbility(int32_t systemAbilityId)847 int32_t NetsysBpfNetFirewall::LoadSystemAbility(int32_t systemAbilityId)
848 {
849     NETNATIVE_LOG_D("LoadSystemAbility: [%{public}d]", systemAbilityId);
850     auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
851     if (saManager == nullptr) {
852         NETNATIVE_LOGE("GetCmProxy registry is null");
853         return -1;
854     }
855 
856     auto object = saManager->CheckSystemAbility(systemAbilityId);
857     if (object != nullptr) {
858         return 0;
859     }
860 
861     sptr<OnDemandLoadManagerCallback> loadCallBack = new (std::nothrow) OnDemandLoadManagerCallback();
862     if (loadCallBack == nullptr) {
863         NETNATIVE_LOGE("new OnDemandLoadCertManagerCallback failed");
864         return -1;
865     }
866 
867     int32_t ret = saManager->LoadSystemAbility(systemAbilityId, loadCallBack);
868     if (ret != ERR_OK) {
869         NETNATIVE_LOGE("systemAbilityId:%d load failed,result code:%d", systemAbilityId, ret);
870         return -1;
871     }
872     return 0;
873 }
874 
AddDomainCache(const NetAddrInfo & addrInfo)875 void NetsysBpfNetFirewall::AddDomainCache(const NetAddrInfo &addrInfo)
876 {
877     NETNATIVE_LOGI("AddDomainCache");
878     domain_value value = { 0 };
879     if (addrInfo.aiFamily == AF_INET) {
880         Ipv4LpmKey key = { 0 };
881         key.prefixlen = IPV4_MAX_PREFIXLEN;
882         key.data = addrInfo.aiAddr.sin.s_addr;
883         WriteBpfMap(MAP_PATH(DOMAIN_IPV4_MAP), key, value);
884     } else {
885         Ipv6LpmKey key = { 0 };
886         key.prefixlen = IPV6_MAX_PREFIXLEN;
887         key.data = addrInfo.aiAddr.sin6;
888         WriteBpfMap(MAP_PATH(DOMAIN_IPV6_MAP), key, value);
889     }
890 }
891 
ClearDomainCache()892 void NetsysBpfNetFirewall::ClearDomainCache()
893 {
894     NETNATIVE_LOG_D("ClearDomainCache");
895     Ipv4LpmKey ip4Key = {};
896     Ipv6LpmKey ip6Key = {};
897     domain_value value { 0 };
898     ClearBpfMap(MAP_PATH(DOMAIN_IPV4_MAP), ip4Key, value);
899     ClearBpfMap(MAP_PATH(DOMAIN_IPV6_MAP), ip6Key, value);
900 }
901 } // namespace NetManagerStandard
902 } // namespace OHOS