1 /*
2  * Copyright (c) 2022 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 "netlink_manager.h"
17 
18 #include <cerrno>
19 #include <linux/netlink.h>
20 #include <linux/rtnetlink.h>
21 #include <map>
22 #include <mutex>
23 #include <sys/socket.h>
24 #include <unistd.h>
25 
26 #include "netlink_define.h"
27 #include "netnative_log_wrapper.h"
28 #include "wrapper_distributor.h"
29 
30 namespace OHOS {
31 namespace nmd {
32 using namespace NetlinkDefine;
33 namespace {
34 constexpr int32_t NFLOG_QUOTA_GROUP = 1;
35 constexpr int32_t UEVENT_GROUP = 0xffffffff;
36 struct DistributorParam {
37     int32_t groups;
38     int32_t format;
39     bool flag;
40 };
41 
42 const std::map<int32_t, DistributorParam> distributorParamList_ = {
43     {NETLINK_KOBJECT_UEVENT, {UEVENT_GROUP, NETLINK_FORMAT_ASCII, false}},
44     {NETLINK_ROUTE,
45      {RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE |
46           (1 << (RTNLGRP_ND_USEROPT - 1)),
47       NETLINK_FORMAT_BINARY, false}},
48     {NETLINK_NFLOG, {NFLOG_QUOTA_GROUP, NETLINK_FORMAT_BINARY, false}},
49     {NETLINK_NETFILTER, {0, NETLINK_FORMAT_BINARY_UNICAST, true}}};
50 
51 std::map<int32_t, std::unique_ptr<WrapperDistributor>> distributorMap_;
52 
CreateNetlinkDistributor(int32_t netlinkType,const DistributorParam & param,std::mutex & externMutex)53 bool CreateNetlinkDistributor(int32_t netlinkType, const DistributorParam &param, std::mutex& externMutex)
54 {
55     sockaddr_nl sockAddr;
56     int32_t size = BUFFER_SIZE;
57     int32_t on = 1;
58     int32_t socketFd;
59 
60     sockAddr.nl_family = AF_NETLINK;
61     sockAddr.nl_pid = 0;
62     sockAddr.nl_groups = param.groups;
63 
64     if ((socketFd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, netlinkType)) < 0) {
65         NETNATIVE_LOGE("Creat socket for family failed NetLinkType is %{public}d: %{public}s = %{public}d", netlinkType,
66                        strerror(errno), errno);
67         return false;
68     }
69 
70     if (setsockopt(socketFd, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)) < 0 &&
71         setsockopt(socketFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) {
72         NETNATIVE_LOGE("Set buffer for revieve msg failed the error is : %{public}d, EMSG: %{public}s", errno,
73                        strerror(errno));
74         close(socketFd);
75         return false;
76     }
77 
78     if (setsockopt(socketFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
79         NETNATIVE_LOGE("Uevent socket SO_PASSCRED set failed dump for this: %{public}d, EMSG: %{public}s", errno,
80                        strerror(errno));
81         close(socketFd);
82         return false;
83     }
84 
85     if (bind(socketFd, reinterpret_cast<sockaddr *>(&sockAddr), sizeof(sockAddr)) < 0) {
86         NETNATIVE_LOGE("Bind netlink socket failed dumps is this : %{public}d, EMSG: %{public}s", errno,
87                        strerror(errno));
88         close(socketFd);
89         return false;
90     }
91     NETNATIVE_LOGI("CreateNetlinkDistributor netlinkType: %{public}d, socketFd: %{public}d", netlinkType, socketFd);
92     distributorMap_[netlinkType] = std::make_unique<WrapperDistributor>(socketFd, param.format, externMutex);
93     return true;
94 }
95 } // namespace
96 
NetlinkManager()97 NetlinkManager::NetlinkManager()
98 {
99     for (const auto &it : distributorParamList_) {
100         CreateNetlinkDistributor(it.first, it.second, linkCallbackMutex_);
101     }
102     if (callbacks_ == nullptr) {
103         callbacks_ = std::make_shared<std::vector<sptr<NetsysNative::INotifyCallback>>>();
104     }
105 }
106 
~NetlinkManager()107 NetlinkManager::~NetlinkManager()
108 {
109     if (callbacks_ != nullptr) {
110         callbacks_->clear();
111         callbacks_ = nullptr;
112     }
113 }
114 
StartListener()115 int32_t NetlinkManager::StartListener()
116 {
117     for (auto &it : distributorMap_) {
118         if (it.second == nullptr) {
119             continue;
120         }
121         it.second->RegisterNetlinkCallbacks(callbacks_);
122         if (it.second->Start() != 0) {
123             NETNATIVE_LOGE("Start netlink listener failed");
124             return NetlinkResult::ERROR;
125         }
126     }
127     return NetlinkResult::OK;
128 }
129 
StopListener()130 int32_t NetlinkManager::StopListener()
131 {
132     for (auto &it : distributorMap_) {
133         if (it.second == nullptr) {
134             continue;
135         }
136         if (it.second->Stop() != 0) {
137             NETNATIVE_LOGE("Stop netlink listener failed");
138             return NetlinkResult::ERROR;
139         }
140     }
141     return NetlinkResult::OK;
142 }
143 
RegisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)144 int32_t NetlinkManager::RegisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)
145 {
146     std::lock_guard<std::mutex> lock(linkCallbackMutex_);
147     if (callback == nullptr) {
148         NETNATIVE_LOGE("callback is nullptr");
149         return NetlinkResult::ERR_NULL_PTR;
150     }
151     for (const auto &cb : *callbacks_) {
152         if (cb == callback) {
153             NETNATIVE_LOGI("callback is already registered");
154             return NetlinkResult::OK;
155         }
156     }
157     callbacks_->push_back(callback);
158     NETNATIVE_LOGI("callback is registered successfully current size is %{public}zu", callbacks_->size());
159     return NetlinkResult::OK;
160 }
161 
UnregisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)162 int32_t NetlinkManager::UnregisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)
163 {
164     std::lock_guard<std::mutex> lock(linkCallbackMutex_);
165     if (callback == nullptr) {
166         NETNATIVE_LOGE("callback is nullptr");
167         return NetlinkResult::ERR_NULL_PTR;
168     }
169     for (auto it = callbacks_->begin(); it != callbacks_->end(); ++it) {
170         if (*it == callback) {
171             callbacks_->erase(it);
172             NETNATIVE_LOGI("callback is unregistered successfully");
173             return NetlinkResult::OK;
174         }
175     }
176     NETNATIVE_LOGI("callback has not registered current callback number is %{public}zu", callbacks_->size());
177     return NetlinkResult::ERR_INVALID_PARAM;
178 }
179 } // namespace nmd
180 } // namespace OHOS
181