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