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 ¶m : 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