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