1 /*
2 * Copyright (C) 2021-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 "dhcpd_interface.h"
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include "network_interface.h"
20 #include "wifi_global_func.h"
21 #include "wifi_logger.h"
22 #include "securec.h"
23 #ifndef OHOS_ARCH_LITE
24 #include "ipc_skeleton.h"
25 #endif
26
27 DEFINE_WIFILOG_DHCP_LABEL("WifiDhcpdInterface");
28
29 namespace OHOS {
30 namespace Wifi {
31 const int EU_I64_ADDR_LEN = 64;
32 const int GENE_V6_ADDR_LEN = 64; /* Generally, the prefix length cannot exceed 64 characters. */
33 const int IP_V6_ADDR_LEN = 128;
34 const int MAX_STA_NUMBER = 254 - 3 + 1; /* from DhcpRange.strStartip to DhcpRange.strEndip. */
35 const std::string IP_V4_MASK("255.255.255.0");
36 const std::string IP_V4_DEFAULT("192.168.62.1");
37
DhcpdInterface()38 DhcpdInterface::DhcpdInterface()
39 : mBindIpv4(Ipv4Address::invalidInetAddress), mBindIpv6(Ipv6Address::INVALID_INET6_ADDRESS)
40 {}
41
~DhcpdInterface()42 DhcpdInterface::~DhcpdInterface()
43 {}
44
RegisterDhcpCallBack(const std::string & ifaceName,ServerCallBack & event)45 bool DhcpdInterface::RegisterDhcpCallBack(const std::string &ifaceName, ServerCallBack &event)
46 {
47 if (RegisterDhcpServerCallBack(ifaceName.c_str(), &event) != 0) {
48 WIFI_LOGE("Register dhcp server callBack failed!");
49 return false;
50 }
51 return true;
52 }
53
StartDhcpServerFromInterface(const std::string & ifaceName,Ipv4Address & ipv4,Ipv6Address & ipv6,const std::string & ipAddress,bool isIpV4,const int32_t & leaseTime)54 bool DhcpdInterface::StartDhcpServerFromInterface(const std::string &ifaceName, Ipv4Address &ipv4, Ipv6Address &ipv6,
55 const std::string &ipAddress, bool isIpV4, const int32_t &leaseTime)
56 {
57 mStartDhcpServerFlag = true;
58 std::vector<Ipv4Address> vecIpv4Addr;
59 std::vector<Ipv6Address> vecIpv6Addr;
60 if (!NetworkInterface::FetchApOrP2pIpAddress(ifaceName, vecIpv4Addr, vecIpv6Addr)) {
61 WIFI_LOGW("Get ipaddress failed!");
62 }
63
64 // set ap interface to bind an ip address
65 if (!AssignIpAddr(mBindIpv4, mBindIpv6, vecIpv4Addr, vecIpv6Addr, ipAddress, isIpV4)) {
66 WIFI_LOGE("Assign ip address for interface failed!");
67 return false;
68 }
69 ipv4 = mBindIpv4;
70 ipv6 = mBindIpv6;
71 if (!ApplyIpAddress(ifaceName, mBindIpv4, mBindIpv6)) {
72 WIFI_LOGE("bind interface address failed!");
73 return false;
74 }
75
76 if (!SetDhcpIpRange(ifaceName)) {
77 WIFI_LOGE("Set dhcp range ip address failed!");
78 return false;
79 }
80 if (!UpdateDefaultConfigFile(leaseTime)) {
81 WIFI_LOGE("UpdateDefaultConfigFile failed!");
82 return false;
83 }
84 if (StartDhcpServer(ifaceName.c_str()) != 0) {
85 WIFI_LOGE("Start dhcp server failed!");
86 return false;
87 }
88
89 return true;
90 }
91
SetDhcpIpRange(const std::string & ifaceName)92 bool DhcpdInterface::SetDhcpIpRange(const std::string &ifaceName)
93 {
94 if (!mBindIpv4.IsValid()) { /* currently, we just support ipv4 */
95 WIFI_LOGE("current interface does not bind ipv4!");
96 return false;
97 }
98 std::string ipAddr = mBindIpv4.GetAddressWithString();
99 CallAdapterSetRange(ipAddr, ifaceName);
100 return true;
101 }
102
UpdateDefaultConfigFile(const int32_t & leaseTime)103 bool DhcpdInterface::UpdateDefaultConfigFile(const int32_t &leaseTime)
104 {
105 std::string time = std::to_string(leaseTime);
106 int result = UpdateLeasesTime(time.c_str());
107 WIFI_LOGI("UpdateDefaultConfigFile leaseTime:%{public}d result:%{public}d", leaseTime, result);
108 return (result == 0) ? true : false;
109 }
110
GetConnectedStationInfo(const std::string & ifaceName,std::map<std::string,StationInfo> & result)111 bool DhcpdInterface::GetConnectedStationInfo(const std::string &ifaceName, std::map<std::string, StationInfo> &result)
112 {
113 DhcpStationInfo *staInfos = NULL;
114 int staNumber = MAX_STA_NUMBER;
115 int staSize = 0;
116 staInfos = (struct DhcpStationInfo*)malloc(sizeof(DhcpStationInfo) * staNumber);
117 if (staInfos == NULL) {
118 WIFI_LOGE("GetConnectedStationInfo malloc is failed!");
119 return false;
120 }
121 GetConnectedStaInfo(ifaceName, staNumber, staInfos, &staSize);
122 for (int i = 0; i < staSize; i++) {
123 StationInfo info;
124 info.deviceName = staInfos[i].deviceName;
125 info.bssid = staInfos[i].macAddr;
126 info.bssidType = REAL_DEVICE_ADDRESS;
127 info.ipAddr = staInfos[i].ipAddr;
128 result.insert(std::make_pair(info.bssid, info));
129 }
130 free(staInfos);
131 return true;
132 }
133
StopDhcp(const std::string & ifaceName)134 bool DhcpdInterface::StopDhcp(const std::string &ifaceName)
135 {
136 WIFI_LOGI("StopDhcp ifaceName:%{public}s, flag:%{public}d", ifaceName.c_str(), mStartDhcpServerFlag);
137 if (ifaceName.empty() || mStartDhcpServerFlag == false) {
138 WIFI_LOGE("StopDhcp return!");
139 return false;
140 }
141 mStartDhcpServerFlag = false;
142 std::string rangeName;
143 std::string tagName = ifaceName;
144 transform(tagName.begin(), tagName.end(), tagName.begin(), ::tolower);
145 if (tagName.find("p2p") != std::string::npos) {
146 rangeName = "p2p";
147 } else {
148 rangeName = ifaceName;
149 }
150
151 WIFI_LOGI("StopDhcp ifaceName:%{public}s, rangeName:%{public}s", ifaceName.c_str(), rangeName.c_str());
152 if (RemoveAllDhcpRange(rangeName.c_str()) != 0) {
153 WIFI_LOGW("failed to remove [%{public}s] dhcp range.", rangeName.c_str());
154 }
155 if (StopDhcpServer(ifaceName.c_str()) != 0) {
156 WIFI_LOGE("Dhcp server stop failed or already stopped!");
157 return false;
158 }
159 if (!NetworkInterface::ClearAllIpAddress(ifaceName)) {
160 WIFI_LOGW("Clear interface binding ip address failed!");
161 }
162 return true;
163 }
164
ApplyIpAddress(const std::string & ifaceName,const Ipv4Address & ipv4,const Ipv6Address & ipv6)165 bool DhcpdInterface::ApplyIpAddress(const std::string &ifaceName, const Ipv4Address &ipv4, const Ipv6Address &ipv6)
166 {
167 bool ret = NetworkInterface::AddIpAddress(ifaceName, ipv4);
168 if (ipv6.IsValid()) {
169 ret |= NetworkInterface::AddIpAddress(ifaceName, ipv6);
170 }
171 return ret;
172 }
173
AssignIpAddr(Ipv4Address & ipv4,Ipv6Address & ipv6,const std::vector<Ipv4Address> & vecIpv4Addr,const std::vector<Ipv6Address> & vecIpv6Addr,const std::string & ipAddress,bool isIpV4)174 bool DhcpdInterface::AssignIpAddr(Ipv4Address &ipv4, Ipv6Address &ipv6, const std::vector<Ipv4Address> &vecIpv4Addr,
175 const std::vector<Ipv6Address> &vecIpv6Addr, const std::string &ipAddress, bool isIpV4)
176 {
177 if (isIpV4) {
178 ipv4 = AssignIpAddrV4(vecIpv4Addr, IP_V4_MASK, ipAddress);
179 if (ipv4 == Ipv4Address::invalidInetAddress) {
180 WIFI_LOGE("Failed to allocate the IP address.");
181 return false;
182 }
183 } else {
184 Ipv6Address apShareIp(Ipv6Address::INVALID_INET6_ADDRESS);
185 for (auto iter = vecIpv6Addr.begin(); iter != vecIpv6Addr.end(); ++iter) {
186 if (Ipv6Address::IsAddrLocallink(iter->GetIn6Addr()) || !iter->IsValid()) {
187 continue;
188 }
189 apShareIp = *iter;
190 break;
191 }
192 Ipv6Address prefixIp = (apShareIp.GetAddressPrefixLength() > (IP_V6_ADDR_LEN - EU_I64_ADDR_LEN))
193 ? AssignIpAddrV6(vecIpv6Addr)
194 : apShareIp;
195 if (!prefixIp.IsValid()) {
196 WIFI_LOGE("Failed to allocate the IP address.");
197 return false;
198 }
199
200 ipv6 = Ipv6Address::Create(prefixIp.GetAddressWithString(), prefixIp.GetAddressPrefixLength(), 0);
201 }
202 return true;
203 }
204
CompareSubNet(const std::vector<Ipv4Address> & vecIpAddr,const struct in_addr & input,const struct in_addr & mask) const205 bool DhcpdInterface::CompareSubNet(
206 const std::vector<Ipv4Address> &vecIpAddr, const struct in_addr &input, const struct in_addr &mask) const
207 {
208 /* Check whether the network ID is the same as the IP address in vecIpAddr. */
209 for (auto address : vecIpAddr) {
210 struct in_addr tmpAddr = {INADDR_ANY};
211 if (inet_aton(address.GetAddressWithString().c_str(), &tmpAddr) == 0) {
212 WIFI_LOGE("convert ipaddress %{private}s failed!", address.GetAddressWithString().c_str());
213 return true;
214 }
215 if (CALC_SUBNET(tmpAddr.s_addr, mask.s_addr) == input.s_addr) {
216 return true;
217 }
218 }
219 return false;
220 }
221
AssignIpAddrV4(const std::vector<Ipv4Address> & vecIpAddr,const std::string & mask,const std::string & ipAddress) const222 Ipv4Address DhcpdInterface::AssignIpAddrV4(const std::vector<Ipv4Address> &vecIpAddr, const std::string &mask,
223 const std::string &ipAddress) const
224 {
225 struct in_addr maskAddr = {INADDR_ANY};
226 if (inet_aton(mask.c_str(), &maskAddr) == 0) {
227 WIFI_LOGE("convert mask to ipaddress failed![%s].", mask.c_str());
228 return Ipv4Address::invalidInetAddress;
229 }
230 struct in_addr initAddr = {INADDR_ANY};
231 std::string destIpAddress = ipAddress.empty() ? IP_V4_DEFAULT : ipAddress;
232 if (inet_aton(destIpAddress.c_str(), &initAddr) == 0) {
233 WIFI_LOGE("convert default ipaddress failed![%s].", destIpAddress.c_str());
234 return Ipv4Address::invalidInetAddress;
235 }
236 struct in_addr tmpAddr = {INADDR_ANY};
237 while (true) {
238 tmpAddr.s_addr = CALC_SUBNET(initAddr.s_addr, maskAddr.s_addr);
239 if (!CompareSubNet(vecIpAddr, tmpAddr, maskAddr)) {
240 return Ipv4Address::Create(initAddr, maskAddr);
241 }
242 /* For conflict, try to change the new network. */
243 uint32_t cSubnet = ntohl(htonl(IN_CLASSC_NET & IN_CLASSB_HOST) & tmpAddr.s_addr) >> IN_CLASSC_NSHIFT;
244 cSubnet++;
245 if (cSubnet == 0xFF) {
246 WIFI_LOGE("No available IPv4 address is found.\n");
247 return Ipv4Address::invalidInetAddress;
248 } else {
249 tmpAddr.s_addr = (tmpAddr.s_addr & htonl(IN_CLASSB_NET)) | htonl(cSubnet << IN_CLASSC_NSHIFT);
250 initAddr.s_addr = tmpAddr.s_addr | (initAddr.s_addr & htonl(IN_CLASSC_HOST));
251 }
252 }
253 return Ipv4Address::invalidInetAddress;
254 }
255
AssignIpAddrV6(const std::vector<Ipv6Address> & vecIpAddr)256 Ipv6Address DhcpdInterface::AssignIpAddrV6(const std::vector<Ipv6Address> &vecIpAddr)
257 {
258 struct in6_addr prefix = IN6ADDR_ANY_INIT;
259 std::random_device rd;
260 int loopNum = 10;
261 while (loopNum > 0) {
262 bool bFlag = true;
263 prefix.s6_addr[0] = 0xFD;
264 for (int i = 1; i < (GENE_V6_ADDR_LEN / CHAR_BIT); i++) {
265 prefix.s6_addr[i] = std::abs((int)rd()) % CHAR_MAX;
266 }
267 for (auto address : vecIpAddr) {
268 struct in6_addr tmpAddr = IN6ADDR_ANY_INIT;
269 if (inet_pton(AF_INET6, address.GetAddressWithString().c_str(), &tmpAddr) <= 0) {
270 WIFI_LOGI("IpAddr:bad ip:%s and inet_pton error.", address.GetAddressWithString().c_str());
271 continue;
272 }
273 if (memcmp(&tmpAddr, &prefix, sizeof(in6_addr)) == 0) {
274 bFlag = false;
275 WIFI_LOGI("same IP: %x and %x.", tmpAddr.s6_addr32[0], tmpAddr.s6_addr32[1]);
276 break;
277 }
278 }
279 if (bFlag) {
280 char retStr[256] = {0};
281 if (inet_ntop(AF_INET6, &prefix, retStr, sizeof(retStr)) != nullptr) {
282 return Ipv6Address::Create(std::string(retStr), GENE_V6_ADDR_LEN, 0);
283 } else {
284 WIFI_LOGE("inet_ntop convert ipv6 address failed!");
285 return Ipv6Address::INVALID_INET6_ADDRESS;
286 }
287 }
288 loopNum--;
289 }
290 WIFI_LOGE("Fatal error,can not generate valid ULA addr!");
291 return Ipv6Address::INVALID_INET6_ADDRESS;
292 }
293
CallAdapterSetRange(std::string & ipAddr,const std::string & ifaceName)294 bool DhcpdInterface::CallAdapterSetRange(std::string &ipAddr, const std::string &ifaceName)
295 {
296 std::string::size_type pos = ipAddr.rfind(".");
297 if (pos == std::string::npos) {
298 return false;
299 }
300 std::string ipHead = ipAddr.substr(0, pos);
301 std::string subnet = "255.255.255.0";
302 std::string p2p = "p2p";
303
304 DhcpRange range;
305 if (strcpy_s(range.strStartip, INET_ADDRSTRLEN, (ipHead + ".3").c_str()) != EOK
306 || strcpy_s(range.strEndip, INET_ADDRSTRLEN, (ipHead + ".254").c_str()) != EOK
307 || strcpy_s(range.strSubnet, INET_ADDRSTRLEN, subnet.c_str()) != EOK) {
308 return false;
309 }
310 range.iptype = 0;
311 std::string tagName = ifaceName;
312 transform(tagName.begin(), tagName.end(), tagName.begin(), ::tolower);
313 if (tagName.find("p2p") != std::string::npos) {
314 if (strcpy_s(range.strTagName, DHCP_MAX_FILE_BYTES, "p2p") != EOK) {
315 return false;
316 }
317 if (PutDhcpRange(range.strTagName, &range) != 0) {
318 return false;
319 }
320 if (SetDhcpName(ifaceName.c_str(), range.strTagName) != 0) {
321 return false;
322 }
323 } else {
324 if (strcpy_s(range.strTagName, INET_ADDRSTRLEN, ifaceName.c_str()) != EOK) {
325 return false;
326 }
327 if (SetDhcpRange(ifaceName.c_str(), &range) != 0) {
328 return false;
329 }
330 }
331 return true;
332 }
333
GetConnectedStaInfo(const std::string & ifaceName,int staNumber,DhcpStationInfo * staInfos,int * staSize)334 bool DhcpdInterface::GetConnectedStaInfo(const std::string &ifaceName, int staNumber, DhcpStationInfo *staInfos,
335 int *staSize)
336 {
337 if (staInfos == nullptr || staSize == nullptr) {
338 WIFI_LOGI("GetConnectedStaInfo param is null!\n");
339 return false;
340 }
341 #ifndef OHOS_ARCH_LITE
342 std::string identity = IPCSkeleton::ResetCallingIdentity();
343 #endif
344 int result = GetDhcpClientInfos(ifaceName.c_str(), staNumber, staInfos, staSize);
345 #ifndef OHOS_ARCH_LITE
346 IPCSkeleton::SetCallingIdentity(identity);
347 #endif
348 if (result != 0) {
349 return false;
350 }
351 if (staInfos == NULL) {
352 return false;
353 }
354 return true;
355 }
356 } // namespace Wifi
357 } // namespace OHOS