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 <unistd.h>
17 #include <arpa/inet.h>
18 #include <net/if.h>
19 #include <net/route.h>
20 #include <netinet/in.h>
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
24 #include <iostream>
25 #include <vector>
26 #include <thread>
27 #include "securec.h"
28 #include "if_config.h"
29 #include "ip_tools.h"
30 #include "ipv4_address.h"
31 #include "ipv6_address.h"
32 #include "wifi_config_center.h"
33 
34 namespace OHOS {
35 namespace Wifi {
36 const std::string SYSTEM_COMMAND_IP = "/system/bin/ip";
37 const int EXECVE_EXT_COMMAND = 127;
38 const int RECEIVE_BUFFER_LEN = 64;
39 const int MAX_COMMAND_ARG = 32;
40 #ifdef OHOS_ARCH_LITE
41 const std::string SYSTEM_COMMAND_NDC = "/system/bin/ndc";
42 const int IPV6_SUFFIX_LEN = 3;
43 const int MAX_IFNAME_LEN = 13;
44 #endif
45 
GetInstance()46 IfConfig &IfConfig::GetInstance()
47 {
48     static IfConfig ifConfig;
49     return ifConfig;
50 }
51 
IfConfig()52 IfConfig::IfConfig()
53 {}
54 
~IfConfig()55 IfConfig::~IfConfig()
56 {}
57 
58 /**
59  * @Description : Execute script commands
60  * @Return success:true failed:false
61  */
ExecCommand(const std::vector<std::string> & vecCommandArg)62 bool IfConfig::ExecCommand(const std::vector<std::string> &vecCommandArg)
63 {
64     int argvSize = static_cast<int>(vecCommandArg.size());
65     if (argvSize > MAX_COMMAND_ARG) {
66         LOGE("IfConfig ExecCommand vecCommandArg size invalid.");
67         return false;
68     }
69     std::thread t(
70         [vecCommandArg, argvSize]() {
71             int fd[2] = {0};
72             if (pipe(fd) < 0) {
73                 LOGE("ifconfig create pipe failed.");
74                 return;
75             }
76             int pid = fork();
77             if (pid == -1) {
78                 LOGE("ifconfig fork child process failed.");
79                 return;
80             }
81             if (pid == 0) {
82                 const char *execveStr[MAX_COMMAND_ARG];
83                 int i = 0;
84                 for (i = 0; i < argvSize && i < (MAX_COMMAND_ARG - 1); i++) {
85                     execveStr[i] = vecCommandArg[i].c_str();
86                 }
87                 execveStr[i] = nullptr;
88                 char *env[] = {nullptr};
89                 close(fd[0]);
90                 dup2(fd[1], STDOUT_FILENO);
91                 close(fd[1]);
92                 /* last member of execveStr should be nullptr */
93                 if (execve(vecCommandArg[0].c_str(), (char *const*)execveStr, env) < 0) {
94                     LOGE("execve %{public}s failed.", vecCommandArg[0].c_str());
95                 }
96                 _exit(EXECVE_EXT_COMMAND);
97             }
98             close(fd[1]);
99             FILE *fp = fdopen(fd[0], "r");
100             if (fp == nullptr) {
101                 LOGE("ifconfig fdopen failed.");
102                 return;
103             }
104             char buffer[RECEIVE_BUFFER_LEN];
105             while (fgets(buffer, sizeof(buffer), fp) != nullptr) {
106                 LOGD("exec cmd receive: %{public}s", buffer);
107             }
108             fclose(fp);
109         }
110     );
111     t.detach();
112     return true;
113 }
114 
115 /**
116  * @Description : Flush the IpAddr
117  * @Return None
118  */
FlushIpAddr(const std::string & ifName,const int & ipType)119 void IfConfig::FlushIpAddr(const std::string& ifName, const int& ipType)
120 {
121     LOGI("Flush IP, ifName: %{public}s", ifName.c_str());
122 
123     if (ipType != static_cast<int>(IpType::IPTYPE_IPV4)) {
124         return;
125     }
126     struct ifreq ifr;
127     if (memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr)) != EOK ||
128         strcpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifName.c_str()) != EOK) {
129         LOGE("Init the ifreq struct failed!");
130         return;
131     }
132     int fd = socket(AF_INET, SOCK_DGRAM, 0);
133     if (fd < 0) {
134         LOGE("AddIpAddr:socket error");
135         return;
136     }
137     struct sockaddr_in *sin = reinterpret_cast<struct sockaddr_in *>(&ifr.ifr_addr);
138     sin->sin_family = AF_INET;
139     /* ipAddr */
140     if (inet_aton("0.0.0.0", &(sin->sin_addr)) < 0) {
141         LOGE("AddIpAddr:inet_aton error");
142         close(fd);
143         return;
144     }
145     if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
146         LOGE("AddIpAddr:ioctl SIOCSIFADDR error");
147         close(fd);
148         return;
149     }
150     close(fd);
151     return;
152 }
153 
154 /**
155  * @Description : Add the IpAddr
156  * @Return None
157  */
AddIpAddr(const std::string & ifName,const std::string & ipAddr,const std::string & mask,const int & ipType)158 void IfConfig::AddIpAddr(
159     const std::string &ifName, const std::string &ipAddr, const std::string &mask, const int &ipType)
160 {
161     LOGI("Add ip address, ifName = %{public}s", ifName.c_str());
162 
163     if (!CheckIfaceValid(ifName)) {
164         return;
165     }
166     if (ipType == static_cast<int>(IpType::IPTYPE_IPV4)) {
167         struct ifreq ifr;
168         if (memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr)) != EOK ||
169             strcpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifName.c_str()) != EOK) {
170             LOGE("set ifr info failed!");
171             return;
172         }
173 
174         struct sockaddr_in *sin = reinterpret_cast<struct sockaddr_in *>(&ifr.ifr_addr);
175         sin->sin_family = AF_INET;
176 
177         // ipAddr
178         if (inet_aton(ipAddr.c_str(), &(sin->sin_addr)) < 0) {
179             LOGE("inet_aton   error\n");
180             return;
181         }
182 
183         int fd = socket(AF_INET, SOCK_DGRAM, 0);
184         if (fd < 0) {
185             LOGE("socket error\n");
186             return;
187         }
188 
189         if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
190             LOGE("ioctl   SIOCSIFADDR   error\n");
191             close(fd);
192             return;
193         }
194 
195         // netMask
196         if (inet_aton(mask.c_str(), &(sin->sin_addr)) < 0) {
197             LOGE("inet_pton   error\n");
198             close(fd);
199             return;
200         }
201 
202         if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
203             LOGE("ioctl SIOCSIFNETMASK error");
204             close(fd);
205             return;
206         }
207         close(fd);
208     } else {
209         std::vector<std::string> ipRouteCmd;
210         ipRouteCmd.clear();
211         ipRouteCmd.push_back(SYSTEM_COMMAND_IP);
212         ipRouteCmd.push_back("-6");
213         ipRouteCmd.push_back("addr");
214         ipRouteCmd.push_back("add");
215         ipRouteCmd.push_back(ipAddr);
216         ipRouteCmd.push_back("dev");
217         ipRouteCmd.push_back(ifName);
218         ExecCommand(ipRouteCmd);
219     }
220 
221     return;
222 }
223 
224 /**
225  * @Description : set proxy
226  * @param isAuto - whether to automatically proxy[in]
227  * @param proxy - proxy host name[in]
228  * @param port - port[in]
229  * @param noProxys - objects to bypass proxy[in]
230  * @Return None
231  */
SetProxy(bool isAuto,const std::string & proxy,const std::string & port,const std::string & noProxys,const std::string & pac)232 void IfConfig::SetProxy(
233     bool isAuto, const std::string &proxy, const std::string &port, const std::string &noProxys, const std::string &pac)
234 {
235     LOGI("SetProxy pac=[%s]\n", pac.c_str());
236     std::vector<std::string> ipRouteCmd;
237 
238     if (!isAuto) {
239         // Add proxy
240         if (!proxy.empty()) {
241             ipRouteCmd.clear();
242             ipRouteCmd.push_back("export");
243             ipRouteCmd.push_back("http_proxy=" + proxy + ":" + port);
244         }
245 
246         // Bypass proxy
247         if (!noProxys.empty()) {
248             ipRouteCmd.clear();
249             ipRouteCmd.push_back("export");
250             ipRouteCmd.push_back("no_proxy=" + noProxys);
251         }
252     }
253     return;
254 }
255 
GetIpAddr(const std::string & ifName,std::string & ipAddr)256 bool IfConfig::GetIpAddr(const std::string& ifName, std::string& ipAddr)
257 {
258     struct ifreq ifr;
259     if (memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr)) != EOK ||
260         strcpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifName.c_str()) != EOK) {
261         LOGE("set ifr info failed!");
262         return false;
263     }
264     int fd = socket(AF_INET, SOCK_DGRAM, 0);
265     if (fd < 0) {
266         LOGE("socket error\n");
267         return false;
268     }
269     if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
270         perror("ioctl error!\n");
271         close(fd);
272         return false;
273     }
274     struct sockaddr_in *sin = reinterpret_cast<struct sockaddr_in *>(&ifr.ifr_addr);
275     ipAddr = inet_ntoa(sin->sin_addr);
276     close(fd);
277     return true;
278 }
279 
CheckIfaceValid(const std::string & ifname)280 bool IfConfig::CheckIfaceValid(const std::string& ifname)
281 {
282     struct if_nameindex *ifidxs, *ifni;
283     ifidxs = if_nameindex();
284     if (ifidxs == nullptr) {
285         LOGE("can not get interfaces");
286         return false;
287     }
288     for (ifni = ifidxs; !(ifni->if_index == 0 && ifni->if_name == nullptr); ifni++) {
289         if ((ifni->if_name != nullptr) &&
290             strcmp(ifni->if_name, ifname.c_str()) == 0) {
291             if_freenameindex(ifidxs);
292             return true;
293         }
294     }
295     if_freenameindex(ifidxs);
296     LOGE("invalid interface: %{public}s", ifname.c_str());
297     return false;
298 }
299 
300 #ifdef OHOS_ARCH_LITE
301 /**
302  * @Description : Set the network card routing, DNS
303  * @Return success:0 failed:-1
304  */
SetIfDnsAndRoute(const DhcpResult * dhcpResult,int ipType,int instId)305 int IfConfig::SetIfDnsAndRoute(const DhcpResult *dhcpResult, int ipType, int instId)
306 {
307     LOGD("ipType=%d, ip=%s, gateway=%s, subnet=%s, strDns1=%s, strDns2=%s",
308         dhcpResult->iptype,
309         dhcpResult->strOptClientId,
310         dhcpResult->strOptSubnet,
311         dhcpResult->strOptRouter1,
312         dhcpResult->strOptDns1,
313         dhcpResult->strOptDns2);
314     SetNetDns(WifiConfigCenter::GetInstance().GetStaIfaceName(), dhcpResult->strOptDns1, dhcpResult->strOptDns2);
315     AddIfRoute(WifiConfigCenter::GetInstance().GetStaIfaceName(), dhcpResult->strOptClientId, dhcpResult->strOptSubnet,
316         dhcpResult->strOptRouter1, ipType);
317     LOGI("set dns and route finished!");
318     return 0;
319 }
320 
321 /**
322  * @Description : Set DNS
323  * @Return None
324  */
SetNetDns(const std::string & ifName,const std::string & dns1,const std::string & dns2)325 void IfConfig::SetNetDns(const std::string& ifName, const std::string& dns1, const std::string& dns2)
326 {
327     std::vector<std::string> ipRouteCmd;
328     ipRouteCmd.clear();
329     ipRouteCmd.push_back(SYSTEM_COMMAND_NDC);
330     ipRouteCmd.push_back("resolver");
331     ipRouteCmd.push_back("setnetdns");
332     ipRouteCmd.push_back(ifName);
333     ipRouteCmd.push_back("");
334     if (Ipv4Address::IsValidIPv4(dns1) || Ipv6Address::IsValidIPv6(dns1)) {
335         ipRouteCmd.push_back(dns1);
336     }
337     if (Ipv4Address::IsValidIPv4(dns2) || Ipv6Address::IsValidIPv6(dns2)) {
338         ipRouteCmd.push_back(dns2);
339     }
340     ExecCommand(ipRouteCmd);
341     return;
342 }
343 
344 /**
345  * @Description : Add Route
346  * @Return None
347  */
AddIfRoute(const std::string & ifName,const std::string & ipAddr,const std::string & mask,const std::string & gateWay,const int & ipType)348 void IfConfig::AddIfRoute(const std::string &ifName, const std::string &ipAddr, const std::string &mask,
349     const std::string &gateWay, const int &ipType)
350 {
351     if (ipType == static_cast<int>(IpType::IPTYPE_IPV4)) {
352         AddIpv4Route(ifName, ipAddr, mask, gateWay);
353     } else {
354         AddIpv6Route(ifName, ipAddr, mask, gateWay);
355     }
356     return;
357 }
358 
359 /**
360  * @Description : set Ipv4 Route
361  * @Return None
362  */
AddIpv4Route(const std::string & ifName,const std::string & ipAddr,const std::string & mask,const std::string & gateWay)363 void IfConfig::AddIpv4Route(
364     const std::string &ifName, const std::string &ipAddr, const std::string &mask, const std::string &gateWay)
365 {
366     LOGI("Enter AddIpv4Route, ifName is %{public}s, ipAddr is %{private}s, mask is %s, gateWay is %{private}s",
367         ifName.c_str(),
368         ipAddr.c_str(),
369         mask.c_str(),
370         gateWay.c_str());
371 
372     struct rtentry route;
373     if (memset_s(&route, sizeof(route), 0, sizeof(route)) != EOK) {
374         LOGE("memset_s route info failed!");
375         return;
376     }
377 
378     struct sockaddr_in *addr = reinterpret_cast<struct sockaddr_in *>(&route.rt_gateway);
379     addr->sin_family = AF_INET;
380     if (inet_aton(gateWay.c_str(), &(addr->sin_addr)) < 0) {
381         LOGE("inet_aton   error\n");
382         return;
383     }
384     addr = reinterpret_cast<struct sockaddr_in *>(&route.rt_dst);
385     addr->sin_family = AF_INET;
386     addr->sin_addr.s_addr = INADDR_ANY;
387     addr = reinterpret_cast<struct sockaddr_in *>(&route.rt_genmask);
388     addr->sin_family = AF_INET;
389     addr->sin_addr.s_addr = INADDR_ANY;
390     char strIfName[MAX_IFNAME_LEN + 1] = {0};
391     if (strcpy_s(strIfName, sizeof(strIfName), ifName.c_str()) != EOK) {
392         LOGE("strcpy_s error\n");
393         return;
394     }
395     route.rt_dev = strIfName;
396     route.rt_flags = RTF_UP | RTF_GATEWAY;
397     route.rt_metric = 0;
398 
399     int fd = socket(AF_INET, SOCK_DGRAM, 0);
400     if (fd < 0) {
401         LOGE("socket error\n");
402         return;
403     }
404     if (ioctl(fd, SIOCADDRT, &route) < 0) {
405         LOGE("ioctl SIOCADDRT error");
406     }
407     close(fd);
408     return;
409 }
410 
411 /**
412  * @Description : set Ipv6 Route
413  * @Return None
414  */
AddIpv6Route(const std::string & ifName,const std::string & ipAddr,const std::string & mask,const std::string & gateWay)415 void IfConfig::AddIpv6Route(
416     const std::string &ifName, const std::string &ipAddr, const std::string &mask, const std::string &gateWay)
417 {
418     std::vector<std::string> ipRouteCmd;
419     ipRouteCmd.clear();
420     ipRouteCmd.push_back(SYSTEM_COMMAND_IP);
421     ipRouteCmd.push_back("-6 rule add");
422     ipRouteCmd.push_back("fwmark");
423     ipRouteCmd.push_back("0x0/0xffff");
424     ipRouteCmd.push_back("lookup");
425     ipRouteCmd.push_back("254");
426     ipRouteCmd.push_back("prio");
427     ipRouteCmd.push_back("17000");
428     ExecCommand(ipRouteCmd);
429     // Add routing network segment
430     ipRouteCmd.clear();
431     ipRouteCmd.push_back(SYSTEM_COMMAND_IP);
432     ipRouteCmd.push_back("-6 route add");
433     ipRouteCmd.push_back(mask + ipAddr.substr(ipAddr.length() - IPV6_SUFFIX_LEN, ipAddr.length()));
434     ipRouteCmd.push_back("dev");
435     ipRouteCmd.push_back(ifName);
436     ipRouteCmd.push_back("table");
437     ipRouteCmd.push_back("254");
438     ExecCommand(ipRouteCmd);
439     // Delete the default gateway
440     ipRouteCmd.clear();
441     ipRouteCmd.push_back(SYSTEM_COMMAND_IP);
442     ipRouteCmd.push_back("-6 route del default");
443     ipRouteCmd.push_back("dev");
444     ipRouteCmd.push_back(ifName);
445     ipRouteCmd.push_back("table");
446     ipRouteCmd.push_back("254");
447     ExecCommand(ipRouteCmd);
448     // Add the default gateway
449     ipRouteCmd.clear();
450     ipRouteCmd.push_back(SYSTEM_COMMAND_IP);
451     ipRouteCmd.push_back("-6 route add default");
452     ipRouteCmd.push_back("via");
453     ipRouteCmd.push_back(gateWay);
454     ipRouteCmd.push_back("dev");
455     ipRouteCmd.push_back(ifName);
456     ipRouteCmd.push_back("table");
457     ipRouteCmd.push_back("254");
458     ExecCommand(ipRouteCmd);
459     // Flush routing cache
460     ipRouteCmd.clear();
461     ipRouteCmd.push_back(SYSTEM_COMMAND_IP);
462     ipRouteCmd.push_back("-6 route flush cache");
463     ExecCommand(ipRouteCmd);
464 }
465 #endif
466 }  // namespace Wifi
467 }  // namespace OHOS
468