1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <arpa/inet.h>
17 #include <cstdio>
18 #include <libbpf.h>
19 #include <linux/bpf.h>
20 #include <net/if.h>
21 #include <netinet/in.h>
22 #include <securec.h>
23 #include <sys/epoll.h>
24 #include <sys/socket.h>
25 #include <vector>
26 #include <ctime>
27
28 #include "bpf_loader.h"
29 #include "bpf_netfirewall.h"
30 #include "netnative_log_wrapper.h"
31 #include "iservice_registry.h"
32 #include "bpf_ring_buffer.h"
33 #include "ffrt_inner.h"
34
35 using namespace std;
36 using namespace OHOS;
37 using namespace OHOS::NetsysNative;
38
39 namespace OHOS {
40 namespace NetManagerStandard {
41 std::shared_ptr<NetsysBpfNetFirewall> NetsysBpfNetFirewall::instance_ = nullptr;
42 bool NetsysBpfNetFirewall::keepListen_ = false;
43 bool NetsysBpfNetFirewall::keepGc_ = false;
44 bool NetsysBpfNetFirewall::isBpfLoaded_ = false;
45 std::unique_ptr<BpfMapper<CtKey, CtVaule>> NetsysBpfNetFirewall::ctRdMap_ = nullptr;
46 std::unique_ptr<BpfMapper<CtKey, CtVaule>> NetsysBpfNetFirewall::ctWrMap_ = nullptr;
47
NetsysBpfNetFirewall()48 NetsysBpfNetFirewall::NetsysBpfNetFirewall()
49 {
50 NETNATIVE_LOG_D("NetsysBpfNetFirewall construct");
51 isBpfLoaded_ = false;
52 }
53
GetInstance()54 std::shared_ptr<NetsysBpfNetFirewall> NetsysBpfNetFirewall::GetInstance()
55 {
56 static std::mutex instanceMutex;
57 std::lock_guard<std::mutex> guard(instanceMutex);
58 if (instance_ == nullptr) {
59 instance_.reset(new NetsysBpfNetFirewall());
60 return instance_;
61 }
62 return instance_;
63 }
64
ConntrackGcTask()65 void NetsysBpfNetFirewall::ConntrackGcTask()
66 {
67 NETNATIVE_LOG_D("ConntrackGcTask: running");
68 std::vector<CtKey> keys = ctRdMap_->GetAllKeys();
69 if (keys.empty()) {
70 NETNATIVE_LOG_D("GcConntrackCb: key is empty");
71 return;
72 }
73
74 timespec now = { 0 };
75 // bpf_ktime_get_ns: CLOCK_MONOTONIC
76 if (!clock_gettime(CLOCK_MONOTONIC, &now)) {
77 return;
78 }
79 for (const CtKey &k : keys) {
80 CtVaule v = {};
81 if (ctRdMap_->Read(k, v) < 0) {
82 NETNATIVE_LOGE("GcConntrackCb: read failed");
83 continue;
84 }
85
86 if (v.lifetime < now.tv_sec) {
87 if (ctWrMap_->Delete(k) != 0) {
88 NETNATIVE_LOGE("GcConntrackCb: delete failed");
89 continue;
90 }
91 }
92 }
93 }
94
RingBufferListenThread(void)95 void NetsysBpfNetFirewall::RingBufferListenThread(void)
96 {
97 if (keepListen_) {
98 NETNATIVE_LOG_D("under listening");
99 return;
100 }
101
102 int mapFd = NetsysBpfRingBuffer::GetRingbufFd(MAP_PATH(EVENT_MAP), 0);
103 if (mapFd < 0) {
104 NETNATIVE_LOGE("failed to get ring buffer fd: errno=%{public}d", errno);
105 return;
106 }
107 ring_buffer *rb = ring_buffer__new(mapFd, NetsysBpfNetFirewall::HandleEvent, NULL, NULL);
108 if (!rb) {
109 NETNATIVE_LOGE("failed to create ring buffer: errno=%{public}d", errno);
110 return;
111 }
112
113 keepListen_ = true;
114 while (keepListen_) {
115 if (ffrt::this_task::get_id() != 0) {
116 ffrt::sync_io(mapFd);
117 }
118 int err = ring_buffer__poll(rb, RING_BUFFER_POLL_TIME_OUT_MS);
119 if (err < 0) {
120 NETNATIVE_LOGE("Error polling ring buffer: errno=%{public}d", errno);
121 keepListen_ = false;
122 break;
123 }
124 }
125
126 NETNATIVE_LOGE("Could not get bpf event ring buffer map");
127 ring_buffer__free(rb);
128 }
129
StartListener()130 int32_t NetsysBpfNetFirewall::StartListener()
131 {
132 if (!isBpfLoaded_) {
133 NETNATIVE_LOG_D("bfp is not loaded");
134 return -1;
135 }
136 ctRdMap_ = std::make_unique<BpfMapper<CtKey, CtVaule>>(MAP_PATH(CT_MAP), BPF_F_RDONLY);
137 ctWrMap_ = std::make_unique<BpfMapper<CtKey, CtVaule>>(MAP_PATH(CT_MAP), BPF_F_WRONLY);
138
139 ffrt::submit(RingBufferListenThread, {}, {}, ffrt::task_attr().name("RingBufferListen"));
140 ffrt::submit(StartConntrackGcThread, { &ctRdMap_ }, { &ctWrMap_ });
141 return 0;
142 }
143
StopListener()144 int32_t NetsysBpfNetFirewall::StopListener()
145 {
146 keepListen_ = false;
147 StopConntrackGc();
148 return 0;
149 }
150
StartConntrackGcThread(void)151 void NetsysBpfNetFirewall::StartConntrackGcThread(void)
152 {
153 if (keepGc_) {
154 NETNATIVE_LOG_D("under keepGc");
155 return;
156 }
157 if (!ctRdMap_->IsValid()) {
158 NETNATIVE_LOGE("GcConntrackCb: ctRdMap is invalid");
159 return;
160 }
161
162 if (!ctWrMap_->IsValid()) {
163 NETNATIVE_LOGE("GcConntrackCb: ctWrMap is invalid");
164 return;
165 }
166
167 keepGc_ = true;
168
169 int rdMapFd = NetsysBpfRingBuffer::GetRingbufFd(MAP_PATH(CT_MAP), BPF_F_RDONLY);
170 int wrMapFd = NetsysBpfRingBuffer::GetRingbufFd(MAP_PATH(CT_MAP), BPF_F_WRONLY);
171 if (rdMapFd < 0 || wrMapFd < 0) {
172 NETNATIVE_LOGE("failed to get rdMapFd or wrMapFd: errno=%{public}d", errno);
173 return;
174 }
175
176 while (keepGc_) {
177 ffrt::this_task::sleep_for(std::chrono::milliseconds(CONNTRACK_GC_INTTERVAL_MS));
178 if (ffrt::this_task::get_id() != 0) {
179 ffrt::sync_io(rdMapFd);
180 ffrt::sync_io(wrMapFd);
181 }
182 ConntrackGcTask();
183 }
184 }
185
StopConntrackGc()186 void NetsysBpfNetFirewall::StopConntrackGc()
187 {
188 keepGc_ = false;
189 }
190
SetBpfLoaded(bool load)191 void NetsysBpfNetFirewall::SetBpfLoaded(bool load)
192 {
193 isBpfLoaded_ = load;
194 }
195
ClearBpfFirewallRules(NetFirewallRuleDirection direction)196 void NetsysBpfNetFirewall::ClearBpfFirewallRules(NetFirewallRuleDirection direction)
197 {
198 NETNATIVE_LOG_D("ClearBpfFirewallRules: direction=%{public}d", direction);
199 Ipv4LpmKey ip4Key = {};
200 Ipv6LpmKey ip6Key = {};
201 PortKey portKey = 0;
202 ProtoKey protoKey = 0;
203 AppUidKey appIdKey = 0;
204 UidKey uidKey = 0;
205 ActionKey actKey = 1;
206 ActionValue actVal;
207 RuleCode ruleCode;
208 CtKey ctKey;
209 CtVaule ctVal;
210
211 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
212 ClearBpfMap(GET_MAP_PATH(ingress, saddr), ip4Key, ruleCode);
213 ClearBpfMap(GET_MAP_PATH(ingress, saddr6), ip6Key, ruleCode);
214 ClearBpfMap(GET_MAP_PATH(ingress, daddr), ip4Key, ruleCode);
215 ClearBpfMap(GET_MAP_PATH(ingress, daddr6), ip6Key, ruleCode);
216 ClearBpfMap(GET_MAP_PATH(ingress, sport), portKey, ruleCode);
217 ClearBpfMap(GET_MAP_PATH(ingress, dport), portKey, ruleCode);
218 ClearBpfMap(GET_MAP_PATH(ingress, proto), protoKey, ruleCode);
219 ClearBpfMap(GET_MAP_PATH(ingress, appuid), appIdKey, ruleCode);
220 ClearBpfMap(GET_MAP_PATH(ingress, uid), uidKey, ruleCode);
221 ClearBpfMap(GET_MAP_PATH(ingress, action), actKey, actVal);
222 ClearBpfMap(MAP_PATH(CT_MAP), ctKey, ctVal);
223 }
224
ClearFirewallRules()225 int32_t NetsysBpfNetFirewall::ClearFirewallRules()
226 {
227 firewallIpRules_.clear();
228 ClearBpfFirewallRules(NetFirewallRuleDirection::RULE_IN);
229 ClearBpfFirewallRules(NetFirewallRuleDirection::RULE_OUT);
230 return NETFIREWALL_SUCCESS;
231 }
232
SetBpfFirewallRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList, NetFirewallRuleDirection direction)233 int32_t NetsysBpfNetFirewall::SetBpfFirewallRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList,
234 NetFirewallRuleDirection direction)
235 {
236 BitmapManager manager;
237 int32_t ret = manager.BuildBitmapMap(ruleList);
238 if (ret) {
239 NETNATIVE_LOGE("SetBpfFirewallRules: BuildBitmapMap failed: %{public}d", ret);
240 return ret;
241 }
242
243 ClearBpfFirewallRules(direction);
244 WriteSrcIpv4BpfMap(manager, direction);
245 WriteSrcIpv6BpfMap(manager, direction);
246 WriteDstIpv4BpfMap(manager, direction);
247 WriteDstIpv6BpfMap(manager, direction);
248 WriteSrcPortBpfMap(manager, direction);
249 WriteDstPortBpfMap(manager, direction);
250 WriteProtoBpfMap(manager, direction);
251 WriteAppUidBpfMap(manager, direction);
252 WriteUidBpfMap(manager, direction);
253 WriteActionBpfMap(manager, direction);
254 return NETFIREWALL_SUCCESS;
255 }
256
SetFirewallRules(const std::vector<sptr<NetFirewallBaseRule>> &ruleList, bool isFinish)257 int32_t NetsysBpfNetFirewall::SetFirewallRules(const std::vector<sptr<NetFirewallBaseRule>> &ruleList, bool isFinish)
258 {
259 NETNATIVE_LOGI("SetFirewallRules: size=%{public}zu isFinish=%{public}" PRId32, ruleList.size(), isFinish);
260 if (!isBpfLoaded_) {
261 NETNATIVE_LOGE("SetFirewallRules: bpf not loaded");
262 return NETFIREWALL_ERR;
263 }
264 if (ruleList.empty()) {
265 NETNATIVE_LOGE("SetFirewallRules: rules is empty");
266 return NETFIREWALL_ERR;
267 }
268 for (const auto &rule : ruleList) {
269 firewallIpRules_.emplace_back(firewall_rule_cast<NetFirewallIpRule>(rule));
270 }
271 int32_t ret = NETFIREWALL_SUCCESS;
272 if (isFinish) {
273 ret = SetFirewallIpRules(firewallIpRules_);
274 firewallIpRules_.clear();
275 }
276 return ret;
277 }
278
SetFirewallIpRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList)279 int32_t NetsysBpfNetFirewall::SetFirewallIpRules(const std::vector<sptr<NetFirewallIpRule>> &ruleList)
280 {
281 std::vector<sptr<NetFirewallIpRule>> inRules;
282 std::vector<sptr<NetFirewallIpRule>> outRules;
283
284 for (const auto &rule : ruleList) {
285 if (rule->ruleDirection == NetFirewallRuleDirection::RULE_IN) {
286 if (rule->protocol == NetworkProtocol::ICMP || rule->protocol == NetworkProtocol::ICMPV6) {
287 outRules.emplace_back(rule);
288 } else {
289 inRules.emplace_back(rule);
290 }
291 }
292 if (rule->ruleDirection == NetFirewallRuleDirection::RULE_OUT) {
293 outRules.emplace_back(rule);
294 }
295 }
296
297 int32_t ret = NETFIREWALL_SUCCESS;
298 if (!inRules.empty()) {
299 ret = SetBpfFirewallRules(inRules, NetFirewallRuleDirection::RULE_IN);
300 }
301 if (!outRules.empty()) {
302 ret += SetBpfFirewallRules(outRules, NetFirewallRuleDirection::RULE_OUT);
303 }
304 return ret;
305 }
306
SetFirewallDefaultAction(FirewallRuleAction inDefault, FirewallRuleAction outDefault)307 int32_t NetsysBpfNetFirewall::SetFirewallDefaultAction(FirewallRuleAction inDefault, FirewallRuleAction outDefault)
308 {
309 if (!isBpfLoaded_) {
310 NETNATIVE_LOGE("SetFirewallDefaultAction: bpf not loaded");
311 return NETFIREWALL_ERR;
312 }
313 DefaultActionKey key = DEFAULT_ACT_IN_KEY;
314 enum sk_action val = (inDefault == FirewallRuleAction::RULE_ALLOW) ? SK_PASS : SK_DROP;
315 WriteBpfMap(MAP_PATH(DEFAULT_ACTION_MAP), key, val);
316
317 key = DEFAULT_ACT_OUT_KEY;
318 val = (outDefault == FirewallRuleAction::RULE_ALLOW) ? SK_PASS : SK_DROP;
319 WriteBpfMap(MAP_PATH(DEFAULT_ACTION_MAP), key, val);
320 CtKey ctKey;
321 CtVaule ctVal;
322 ClearBpfMap(MAP_PATH(CT_MAP), ctKey, ctVal);
323 return NETFIREWALL_SUCCESS;
324 }
325
SetFirewallCurrentUserId(int32_t userId)326 int32_t NetsysBpfNetFirewall::SetFirewallCurrentUserId(int32_t userId)
327 {
328 if (!isBpfLoaded_) {
329 NETNATIVE_LOGE("SetFirewallCurrentUserId: bpf not loaded");
330 return NETFIREWALL_ERR;
331 }
332
333 CurrentUserIdKey key = CURRENT_USER_ID_KEY;
334 UidKey val = (UidKey)userId;
335 WriteBpfMap(MAP_PATH(CURRENT_UID_MAP), key, val);
336 return NETFIREWALL_SUCCESS;
337 }
338
WriteSrcIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)339 void NetsysBpfNetFirewall::WriteSrcIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
340 {
341 std::vector<Ip4RuleBitmap> &srcIp4Map = manager.GetSrcIp4Map();
342 if (srcIp4Map.empty()) {
343 NETNATIVE_LOGE("WriteSrcIpv4BpfMap: srcIp4Map is empty");
344 return;
345 }
346 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
347 for (const auto &node : srcIp4Map) {
348 Bitmap val = node.bitmap;
349 RuleCode rule;
350 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
351
352 Ipv4LpmKey key = { 0 };
353 key.prefixlen = node.mask;
354 key.data = static_cast<Ip4Key>(node.data);
355 WriteBpfMap(GET_MAP_PATH(ingress, saddr), key, rule);
356 }
357 }
358
WriteSrcIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)359 void NetsysBpfNetFirewall::WriteSrcIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
360 {
361 std::vector<Ip6RuleBitmap> &srcIp6Map = manager.GetSrcIp6Map();
362 if (srcIp6Map.empty()) {
363 NETNATIVE_LOGE("WriteSrcIpv6BpfMap: srcIp6Map is empty");
364 return;
365 }
366 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
367 for (const auto &node : srcIp6Map) {
368 Bitmap val = node.bitmap;
369 RuleCode rule;
370 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
371
372 Ipv6LpmKey key = { 0 };
373 key.prefixlen = node.prefixlen;
374 key.data = static_cast<Ip6Key>(node.data);
375 WriteBpfMap(GET_MAP_PATH(ingress, saddr6), key, rule);
376 }
377 }
378
WriteDstIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)379 void NetsysBpfNetFirewall::WriteDstIpv4BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
380 {
381 std::vector<Ip4RuleBitmap> &dstIp4Map = manager.GetDstIp4Map();
382 if (dstIp4Map.empty()) {
383 NETNATIVE_LOGE("WriteDstIp4BpfMap: dstIp4Map is empty");
384 } else {
385 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
386 for (const auto &node : dstIp4Map) {
387 Bitmap val = node.bitmap;
388 RuleCode rule;
389 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
390
391 Ipv4LpmKey key = { 0 };
392 key.prefixlen = node.mask;
393 key.data = static_cast<Ip4Key>(node.data);
394 WriteBpfMap(GET_MAP_PATH(ingress, daddr), key, rule);
395 }
396 }
397 }
398
WriteDstIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)399 void NetsysBpfNetFirewall::WriteDstIpv6BpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
400 {
401 std::vector<Ip6RuleBitmap> &dstIp6Map = manager.GetDstIp6Map();
402 if (dstIp6Map.empty()) {
403 NETNATIVE_LOGE("WriteDstIp6BpfMap: dstIp6Map is empty");
404 } else {
405 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
406 for (const auto &node : dstIp6Map) {
407 Bitmap val = node.bitmap;
408 RuleCode rule;
409 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
410
411 Ipv6LpmKey key = { 0 };
412 key.prefixlen = node.prefixlen;
413 key.data = static_cast<Ip6Key>(node.data);
414 WriteBpfMap(GET_MAP_PATH(ingress, daddr6), key, rule);
415 }
416 }
417 }
418
WriteSrcPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)419 void NetsysBpfNetFirewall::WriteSrcPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
420 {
421 BpfPortMap &srcPortMap = manager.GetSrcPortMap();
422 if (srcPortMap.Empty()) {
423 NETNATIVE_LOGE("WriteSrcPortBpfMap: srcPortMap is empty");
424 } else {
425 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
426 for (const auto &pair : srcPortMap.Get()) {
427 PortKey key = pair.first;
428 Bitmap val = pair.second;
429 RuleCode rule;
430 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
431 NETNATIVE_LOG_D("sport_map=%{public}u", key);
432 WriteBpfMap(GET_MAP_PATH(ingress, sport), key, rule);
433 }
434 }
435 }
436
WriteDstPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)437 void NetsysBpfNetFirewall::WriteDstPortBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
438 {
439 BpfPortMap &dstPortMap = manager.GetDstPortMap();
440 if (dstPortMap.Empty()) {
441 NETNATIVE_LOGE("WriteDstPortBpfMap: dstPortMap is empty");
442 } else {
443 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
444 for (const auto &pair : dstPortMap.Get()) {
445 PortKey key = pair.first;
446 Bitmap val = pair.second;
447 RuleCode rule;
448 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
449 NETNATIVE_LOG_D("dport_map=%{public}u", key);
450 WriteBpfMap(GET_MAP_PATH(ingress, dport), key, rule);
451 }
452 }
453 }
454
WriteProtoBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)455 void NetsysBpfNetFirewall::WriteProtoBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
456 {
457 BpfProtoMap &protoMap = manager.GetProtoMap();
458 if (protoMap.Empty()) {
459 NETNATIVE_LOGE("WriteProtoBpfMap: protoMap is empty");
460 } else {
461 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
462 for (const auto &pair : protoMap.Get()) {
463 ProtoKey key = pair.first;
464 Bitmap val = pair.second;
465 RuleCode rule;
466 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
467 NETNATIVE_LOG_D("proto_map=%{public}u", key);
468 WriteBpfMap(GET_MAP_PATH(ingress, proto), key, rule);
469 }
470 }
471 }
472
WriteAppUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)473 void NetsysBpfNetFirewall::WriteAppUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
474 {
475 BpfAppUidMap &appIdMap = manager.GetAppIdMap();
476 if (appIdMap.Empty()) {
477 NETNATIVE_LOGE("WriteAppUidBpfMap: appIdMap is empty");
478 } else {
479 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
480 for (const auto &pair : appIdMap.Get()) {
481 AppUidKey key = pair.first;
482 Bitmap val = pair.second;
483 RuleCode rule;
484 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
485 NETNATIVE_LOG_D("appuid_map=%{public}u", key);
486 WriteBpfMap(GET_MAP_PATH(ingress, appuid), key, rule);
487 }
488 }
489 }
490
WriteUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)491 void NetsysBpfNetFirewall::WriteUidBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
492 {
493 BpfUidMap &uidMap = manager.GetUidMap();
494 if (uidMap.Empty()) {
495 NETNATIVE_LOGE("WriteUidBpfMap: uidMap is empty");
496 } else {
497 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
498 for (const auto &pair : uidMap.Get()) {
499 UidKey key = pair.first;
500 Bitmap val = pair.second;
501 RuleCode rule;
502 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
503 NETNATIVE_LOG_D("uidMap=%{public}u", key);
504 WriteBpfMap(GET_MAP_PATH(ingress, uid), key, rule);
505 }
506 }
507 }
508
WriteActionBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)509 void NetsysBpfNetFirewall::WriteActionBpfMap(BitmapManager &manager, NetFirewallRuleDirection direction)
510 {
511 BpfActionMap &actionMap = manager.GetActionMap();
512 if (actionMap.Empty()) {
513 NETNATIVE_LOGE("WriteActionBpfMap: actionMap is empty");
514 } else {
515 bool ingress = (direction == NetFirewallRuleDirection::RULE_IN);
516 for (const auto &pair : actionMap.Get()) {
517 ActionKey key = pair.first;
518 Bitmap val = pair.second;
519 RuleCode rule;
520 memcpy_s(rule.val, sizeof(RuleCode), val.Get(), sizeof(RuleCode));
521 NETNATIVE_LOG_D("action_map=%{public}u", val.Get()[0]);
522 WriteBpfMap(GET_MAP_PATH(ingress, action), key, rule);
523 }
524 }
525 }
526
RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)527 int32_t NetsysBpfNetFirewall::RegisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)
528 {
529 if (!callback) {
530 return -1;
531 }
532
533 callbacks_.emplace_back(callback);
534
535 return 0;
536 }
UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)537 int32_t NetsysBpfNetFirewall::UnregisterCallback(const sptr<NetsysNative::INetFirewallCallback> &callback)
538 {
539 if (!callback) {
540 return -1;
541 }
542
543 for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
544 if (*it == callback) {
545 callbacks_.erase(it);
546 return 0;
547 }
548 }
549 return -1;
550 }
551
ShouldSkipNotify(sptr<InterceptRecord> record)552 bool NetsysBpfNetFirewall::ShouldSkipNotify(sptr<InterceptRecord> record)
553 {
554 if (!record) {
555 return true;
556 }
557 if (oldRecord_ != nullptr && (record->time - oldRecord_->time) < INTERCEPT_BUFF_INTERVAL_SEC) {
558 if (record->localIp == oldRecord_->localIp && record->remoteIp == oldRecord_->remoteIp &&
559 record->localPort == oldRecord_->localPort && record->remotePort == oldRecord_->remotePort &&
560 record->protocol == oldRecord_->protocol && record->appUid == oldRecord_->appUid) {
561 return true;
562 }
563 }
564 oldRecord_ = record;
565 return false;
566 }
567
NotifyInterceptEvent(InterceptEvent *info)568 void NetsysBpfNetFirewall::NotifyInterceptEvent(InterceptEvent *info)
569 {
570 if (!info) {
571 return;
572 }
573 sptr<InterceptRecord> record = new (std::nothrow) InterceptRecord();
574 record->time = (int32_t)time(NULL);
575 record->localPort = BitmapManager::Nstohl(info->sport);
576 record->remotePort = BitmapManager::Nstohl(info->dport);
577 record->protocol = static_cast<uint16_t>(info->protocol);
578 record->appUid = (int32_t)info->appuid;
579 std::string srcIp;
580 std::string dstIp;
581 if (info->family == AF_INET) {
582 char ip4[INET_ADDRSTRLEN] = {};
583 inet_ntop(AF_INET, &(info->ipv4.saddr), ip4, INET_ADDRSTRLEN);
584 srcIp = ip4;
585 memset_s(ip4, INET_ADDRSTRLEN, 0, INET_ADDRSTRLEN);
586 inet_ntop(AF_INET, &(info->ipv4.daddr), ip4, INET_ADDRSTRLEN);
587 dstIp = ip4;
588 } else {
589 char ip6[INET6_ADDRSTRLEN] = {};
590 inet_ntop(AF_INET6, &(info->ipv6.saddr), ip6, INET6_ADDRSTRLEN);
591 srcIp = ip6;
592 memset_s(ip6, INET6_ADDRSTRLEN, 0, INET6_ADDRSTRLEN);
593 inet_ntop(AF_INET6, &(info->ipv6.daddr), ip6, INET6_ADDRSTRLEN);
594 dstIp = ip6;
595 }
596 if (info->dir == INGRESS) {
597 record->localIp = srcIp;
598 record->remoteIp = dstIp;
599 } else {
600 record->localIp = dstIp;
601 record->remoteIp = srcIp;
602 }
603 if (ShouldSkipNotify(record)) {
604 return;
605 }
606 for (auto callback : callbacks_) {
607 callback->OnIntercept(record);
608 }
609 }
610
HandleTupleEvent(TupleEvent *ev)611 void NetsysBpfNetFirewall::HandleTupleEvent(TupleEvent *ev)
612 {
613 NETNATIVE_LOG_D(
614 "%{public}s tuple: sport=%{public}u dport=%{public}u protocol=%{public}u appuid=%{public}u uid=%{public}u",
615 (ev->dir == INGRESS) ? "> ingress" : "< egress", ntohs(ev->sport), ntohs(ev->dport), ev->protocol, ev->appuid,
616 ev->uid);
617 NETNATIVE_LOG_D("\trstpacket=%{public}u", ev->rst);
618 }
619
HandleInterceptEvent(InterceptEvent *ev)620 void NetsysBpfNetFirewall::HandleInterceptEvent(InterceptEvent *ev)
621 {
622 GetInstance()->NotifyInterceptEvent(ev);
623
624 NETNATIVE_LOGI("%{public}s intercept: sport=%{public}u dport=%{public}u protocol=%{public}u appuid=%{public}u",
625 (ev->dir == INGRESS) ? "ingress" : "egress", ntohs(ev->sport), ntohs(ev->dport), ev->protocol, ev->appuid);
626 }
627
HandleDebugEvent(DebugEvent *ev)628 void NetsysBpfNetFirewall::HandleDebugEvent(DebugEvent *ev)
629 {
630 const char *direction = ev->dir == INGRESS ? ">" : "<";
631 switch (ev->type) {
632 case DBG_MATCH_SPORT:
633 NETNATIVE_LOG_D("%{public}s sport: %{public}u bitmap: %{public}x", direction, ntohs(ev->arg1), ev->arg2);
634 break;
635 case DBG_MATCH_DPORT:
636 NETNATIVE_LOG_D("%{public}s dport: %{public}u bitmap: %{public}x", direction, ntohs(ev->arg1), ev->arg2);
637 break;
638 case DBG_MATCH_PROTO:
639 NETNATIVE_LOG_D("%{public}s protocol: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
640 break;
641 case DBG_MATCH_APPUID:
642 NETNATIVE_LOG_D("%{public}s appuid: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
643 break;
644 case DBG_MATCH_UID:
645 NETNATIVE_LOG_D("%{public}s uid: %{public}u bitmap: %{public}x", direction, ev->arg1, ev->arg2);
646 break;
647 case DBG_ACTION_KEY:
648 NETNATIVE_LOG_D("%{public}s actionkey: %{public}x", direction, ev->arg1);
649 break;
650 case DBG_MATCH_ACTION:
651 NETNATIVE_LOG_D("%{public}s action: %{public}s", direction, (ev->arg1 == SK_PASS ? "PASS" : "DROP"));
652 break;
653 case DBG_CT_LOOKUP:
654 NETNATIVE_LOG_D("%{public}s ct lookup status: %{public}u", direction, ev->arg1);
655 break;
656 case DBG_MATCH_DOMAIN:
657 NETNATIVE_LOG_D("egress match domain, action PASS");
658 break;
659 default:
660 break;
661 }
662 }
663
HandleEvent(void *ctx, void *data, size_t len)664 int NetsysBpfNetFirewall::HandleEvent(void *ctx, void *data, size_t len)
665 {
666 if (data && len > 0) {
667 Event *ev = (Event *)data;
668
669 switch (ev->type) {
670 case EVENT_DEBUG: {
671 HandleDebugEvent(&(ev->debug));
672 break;
673 }
674 case EVENT_INTERCEPT: {
675 HandleInterceptEvent(&(ev->intercept));
676 break;
677 }
678 case EVENT_TUPLE_DEBUG: {
679 HandleTupleEvent(&(ev->tuple));
680 break;
681 }
682 default:
683 break;
684 }
685 }
686 return 0;
687 }
688
OnLoadSystemAbilitySuccess(int32_t systemAbilityId, const sptr<IRemoteObject> &remoteObject)689 void OnDemandLoadManagerCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId,
690 const sptr<IRemoteObject> &remoteObject)
691 {
692 NETNATIVE_LOG_D("OnLoadSystemAbilitySuccess systemAbilityId: [%{public}d]", systemAbilityId);
693 }
694
OnLoadSystemAbilityFail(int32_t systemAbilityId)695 void OnDemandLoadManagerCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId)
696 {
697 NETNATIVE_LOG_D("OnLoadSystemAbilityFail: [%{public}d]", systemAbilityId);
698 }
699
LoadSystemAbility(int32_t systemAbilityId)700 int32_t NetsysBpfNetFirewall::LoadSystemAbility(int32_t systemAbilityId)
701 {
702 NETNATIVE_LOG_D("LoadSystemAbility: [%{public}d]", systemAbilityId);
703 auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
704 if (saManager == nullptr) {
705 NETNATIVE_LOGE("GetCmProxy registry is null");
706 return -1;
707 }
708
709 auto object = saManager->CheckSystemAbility(systemAbilityId);
710 if (object != nullptr) {
711 return 0;
712 }
713
714 sptr<OnDemandLoadManagerCallback> loadCallBack = new (std::nothrow) OnDemandLoadManagerCallback();
715 if (loadCallBack == nullptr) {
716 NETNATIVE_LOGE("new OnDemandLoadCertManagerCallback failed");
717 return -1;
718 }
719
720 int32_t ret = saManager->LoadSystemAbility(systemAbilityId, loadCallBack);
721 if (ret != ERR_OK) {
722 NETNATIVE_LOGE("systemAbilityId:%d load failed,result code:%d", systemAbilityId, ret);
723 return -1;
724 }
725 return 0;
726 }
727
AddDomainCache(const NetAddrInfo &addrInfo)728 void NetsysBpfNetFirewall::AddDomainCache(const NetAddrInfo &addrInfo)
729 {
730 NETNATIVE_LOGI("AddDomainCache");
731 domain_value value = 1;
732 if (addrInfo.aiFamily == AF_INET) {
733 Ipv4LpmKey key = { 0 };
734 key.prefixlen = IPV4_MAX_PREFIXLEN;
735 key.data = addrInfo.aiAddr.sin.s_addr;
736 WriteBpfMap(MAP_PATH(DOMAIN_IPV4_MAP), key, value);
737 } else {
738 Ipv6LpmKey key = { 0 };
739 key.prefixlen = IPV6_MAX_PREFIXLEN;
740 key.data = addrInfo.aiAddr.sin6;
741 WriteBpfMap(MAP_PATH(DOMAIN_IPV6_MAP), key, value);
742 }
743 }
744
ClearDomainCache()745 void NetsysBpfNetFirewall::ClearDomainCache()
746 {
747 NETNATIVE_LOG_D("ClearDomainCache");
748 Ipv4LpmKey ip4Key = {};
749 Ipv6LpmKey ip6Key = {};
750 domain_value value;
751 ClearBpfMap(MAP_PATH(DOMAIN_IPV4_MAP), ip4Key, value);
752 ClearBpfMap(MAP_PATH(DOMAIN_IPV6_MAP), ip6Key, value);
753 }
754 } // namespace NetManagerStandard
755 } // namespace OHOS