1/*
2 * Copyright (C) 2021 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#include "dhcp_function.h"
16#include <arpa/inet.h>
17#include <time.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <stdlib.h>
23#include <sys/socket.h>
24#include <unistd.h>
25#include <ifaddrs.h>
26#include <netdb.h>
27#include <net/if.h>
28#include <stdio.h>
29#include <errno.h>
30#include <netinet/in.h>
31#include <sys/ioctl.h>
32#include "securec.h"
33#include "dhcp_client_def.h"
34#include "dhcp_logger.h"
35
36DEFINE_DHCPLOG_DHCP_LABEL("DhcpFunction");
37
38bool Ip4StrConToInt(const char *strIp, uint32_t *uIp, bool bHost)
39{
40    if ((strIp == NULL) || (strlen(strIp) == 0)) {
41        DHCP_LOGE("Ip4StrConToInt failed, strIp == NULL or \"\"!");
42        return false;
43    }
44
45    struct in_addr addr4;
46    int nRet = inet_pton(AF_INET, strIp, &addr4);
47    if (nRet != 1) {
48        DHCP_LOGE("Ip4StrConToInt strIp:%{private}s failed, inet_pton nRet:%{public}d!", strIp, nRet);
49        if (nRet == 0) {
50            DHCP_LOGE("Ip4StrConToInt strIp:%{private}s not in presentation format!", strIp);
51        } else {
52            DHCP_LOGE("Ip4StrConToInt strIp:%{private}s inet_pton does not contain a valid address family!", strIp);
53        }
54        return false;
55    }
56
57    if (bHost) {
58        *uIp = ntohl(addr4.s_addr);
59    } else {
60        *uIp = addr4.s_addr;
61    }
62
63    return true;
64}
65
66std::string Ip4IntConvertToStr(uint32_t ip, bool host)
67{
68    char bufIp4[INET_ADDRSTRLEN] = {0};
69    struct in_addr addr4;
70    if (host) {
71        addr4.s_addr = htonl(ip);
72    } else {
73        addr4.s_addr = ip;
74    }
75
76    std::string strIp = "";
77    if (inet_ntop(AF_INET, &addr4, bufIp4, INET_ADDRSTRLEN) == nullptr) {
78        DHCP_LOGE("Ip4IntConvertToStr uIp:%{private}u failed, inet_ntop nullptr!", ip);
79    } else {
80        strIp = bufIp4;
81        DHCP_LOGI("Ip4IntConvertToStr uIp:%{private}u -> strIp:%{private}s.", ip, strIp.c_str());
82    }
83
84    return strIp;
85}
86
87bool Ip6StrConToChar(const char *strIp, uint8_t chIp[], size_t chlen)
88{
89    if ((strIp == NULL) || (strlen(strIp) == 0)) {
90        DHCP_LOGE("Ip6StrConToChar failed, strIp == NULL or \"\"!");
91        return false;
92    }
93
94    struct in6_addr addr6;
95    if (memset_s(&addr6, sizeof(addr6), 0, sizeof(addr6)) != EOK) {
96        return false;
97    }
98    int nRet = inet_pton(AF_INET6, strIp, &addr6);
99    if (nRet != 1) {
100        DHCP_LOGE("Ip6StrConToChar strIp:%{private}s failed, inet_pton nRet:%{public}d!", strIp, nRet);
101        if (nRet == 0) {
102            DHCP_LOGE("Ip6StrConToChar strIp:%{private}s not in presentation format!", strIp);
103        } else {
104            DHCP_LOGE("Ip6StrConToChar strIp:%{private}s inet_pton does not contain a valid address family!", strIp);
105        }
106        return false;
107    }
108
109    DHCP_LOGI("Ip6StrConToChar strIp:%{private}s -> ", strIp);
110    for (size_t i = 0; (i < chlen) && (i < sizeof(addr6.s6_addr)); i++) {
111        DHCP_LOGI("Ip6StrConToChar addr6.s6_addr: %{private}zu - %{private}02x", i, addr6.s6_addr[i]);
112        chIp[i] = addr6.s6_addr[i];
113    }
114
115    return true;
116}
117
118const char *MacChConToMacStr(const unsigned char *pChMac, size_t chLen, char *pStrMac, size_t strLen)
119{
120    if ((pChMac == NULL) || (chLen == 0)) {
121        DHCP_LOGE("MacChConToMacStr failed, pChMac == NULL or chLen == 0!");
122        return NULL;
123    }
124
125    if ((pStrMac == NULL) || (strLen < (chLen * MAC_ADDR_CHAR_NUM))) {
126        DHCP_LOGE("MacChConToMacStr failed, pStrMac == NULL or strLen:%{public}d error!", (int)strLen);
127        return NULL;
128    }
129
130    const unsigned char *pSrc = pChMac;
131    const unsigned char *pSrcEnd = pSrc + chLen;
132    char *pDest = pStrMac;
133    for (; pSrc < pSrcEnd; pSrc++) {
134        /* The first character of pStrMac starts with a letter, not ':'. */
135        if (pSrc != pChMac) {
136            *(pDest++) = ':';
137        }
138        pDest += snprintf_s(pDest, MAC_ADDR_CHAR_NUM, MAC_ADDR_CHAR_NUM - 1, "%.2x", *pSrc);
139    }
140    /* The last character of pStrMac ends with '\0'. */
141    *(pDest++) = '\0';
142    return pStrMac;
143}
144
145int GetLocalInterface(const char *ifname, int *ifindex, unsigned char *hwaddr, uint32_t *ifaddr4)
146{
147    if ((ifname == NULL) || (strlen(ifname) == 0) || hwaddr == NULL) {
148        DHCP_LOGE("GetLocalInterface() failed, ifname == NULL or hwaddr is NULL");
149        return DHCP_OPT_FAILED;
150    }
151
152    int fd;
153    struct ifreq iface;
154    struct sockaddr_in *pSockIn = NULL;
155
156    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
157        DHCP_LOGE("GetLocalInterface() ifname:%{public}s failed, socket err:%{public}d!", ifname, errno);
158        return DHCP_OPT_FAILED;
159    }
160
161    if (memset_s(&iface, sizeof(iface), 0, sizeof(iface)) != EOK) {
162        DHCP_LOGE("GetLocalInterface() ifname:%{public}s failed, memset_s error!", ifname);
163        close(fd);
164        return DHCP_OPT_FAILED;
165    }
166    if (strncpy_s(iface.ifr_name, sizeof(iface.ifr_name), ifname, strlen(ifname)) != EOK) {
167        DHCP_LOGE("GetLocalInterface() ifname:%{public}s failed, strncpy_s error!", ifname);
168        close(fd);
169        return DHCP_OPT_FAILED;
170    }
171
172    if (ioctl(fd, SIOCGIFINDEX, &iface) != 0) {
173        DHCP_LOGE("GetLocalInterface() %{public}s failed, SIOCGIFINDEX err:%{public}d!", ifname, errno);
174        close(fd);
175        return DHCP_OPT_FAILED;
176    }
177    *ifindex = iface.ifr_ifindex;
178
179    if (ioctl(fd, SIOCGIFHWADDR, &iface) != 0) {
180        DHCP_LOGE("GetLocalInterface() %{public}s failed, SIOCGIFHWADDR err:%{public}d!", ifname, errno);
181        close(fd);
182        return DHCP_OPT_FAILED;
183    }
184    if (memcpy_s(hwaddr, MAC_ADDR_LEN, iface.ifr_hwaddr.sa_data, MAC_ADDR_LEN) != EOK) {
185        DHCP_LOGE("GetLocalInterface() ifname:%{public}s failed, memcpy_s error!", ifname);
186        close(fd);
187        return DHCP_OPT_FAILED;
188    }
189
190    if (ifaddr4 != NULL) {
191        if (ioctl(fd, SIOCGIFADDR, &iface) < 0) {
192            DHCP_LOGE("GetLocalInterface() %{public}s failed, SIOCGIFADDR err:%{public}d!", ifname, errno);
193            close(fd);
194            return DHCP_OPT_FAILED;
195        }
196        pSockIn = (struct sockaddr_in *)&iface.ifr_addr;
197        *ifaddr4 = pSockIn->sin_addr.s_addr;
198    }
199    close(fd);
200    return DHCP_OPT_SUCCESS;
201}
202
203int GetLocalIp(const char *ifname, uint32_t *ifaddr4)
204{
205    if ((ifname == NULL) || (strlen(ifname) == 0)) {
206        DHCP_LOGE("GetLocalIp() failed, ifname == NULL or \"\"!");
207        return DHCP_OPT_FAILED;
208    }
209
210    struct ifaddrs *ifaddr = NULL;
211    struct ifaddrs *ifa = NULL;
212    int family, s;
213    char strIp[NI_MAXHOST];
214
215    if (getifaddrs(&ifaddr) == -1) {
216        DHCP_LOGE("GetLocalIp() ifname:%{public}s failed, getifaddrs error:%{public}d!", ifname, errno);
217        return DHCP_OPT_FAILED;
218    }
219
220    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
221        if (strcmp(ifa->ifa_name, ifname) != 0) {
222            continue;
223        }
224
225        if (ifa->ifa_addr == NULL) {
226            DHCP_LOGE("GetLocalIp() ifname:%{public}s failed, ifa->ifa_addr == NULL!", ifname);
227            continue;
228        }
229
230        family = ifa->ifa_addr->sa_family;
231        if ((family != AF_INET) && (family != AF_INET6)) {
232            continue;
233        }
234
235        if (memset_s(strIp, sizeof(strIp), 0, sizeof(strIp)) != EOK) {
236            return DHCP_OPT_FAILED;
237        }
238        s = getnameinfo(ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
239            strIp, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
240        if (s != 0) {
241            DHCP_LOGE("GetLocalIp() %{public}s failed, getnameinfo error:%{public}s!", ifname, gai_strerror(s));
242            return DHCP_OPT_FAILED;
243        }
244
245        /* Output all ip with ifa_name is ifname and family is AF_INET or AF_INET6. */
246        if (family == AF_INET) {
247            uint32_t hostIp = 0;
248            if (!Ip4StrConToInt(strIp, &hostIp, true)) {
249                DHCP_LOGE("GetLocalIp() %{public}s failed, Ip4StrConToInt strIp:%{private}s error!", ifname, strIp);
250                return DHCP_OPT_FAILED;
251            }
252            DHCP_LOGI("GetLocalIp() %{public}s, AF_INET str:%{private}s -> host:%{private}u.", ifname, strIp, hostIp);
253            *ifaddr4 = hostIp;
254        } else {
255            DHCP_LOGI("GetLocalIp() %{public}s, AF_INET6 strIp:%{private}s.", ifname, strIp);
256        }
257    }
258
259    freeifaddrs(ifaddr);
260    return DHCP_OPT_SUCCESS;
261}
262
263int SetIpOrMask(const char *ifname, int fd, uint32_t netAddr, unsigned long cmd)
264{
265    struct ifreq ifr;
266    struct sockaddr_in sin;
267    if (memset_s(&ifr, sizeof(struct ifreq), 0, sizeof(struct ifreq)) != EOK) {
268        DHCP_LOGE("SetIpOrMask() failed, memset_s ifr error!");
269        return DHCP_OPT_FAILED;
270    }
271
272    if (strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifname, strlen(ifname)) != EOK) {
273        DHCP_LOGE("SetIpOrMask() %{public}s failed, , strncpy_s ifr.ifr_name error!", ifname);
274        return DHCP_OPT_FAILED;
275    }
276
277    if (memset_s(&sin, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in)) != EOK) {
278        DHCP_LOGE("SetIpOrMask() failed, memset_s sin error!");
279        return DHCP_OPT_FAILED;
280    }
281    sin.sin_family = AF_INET;
282    sin.sin_addr.s_addr = netAddr;
283    if (memcpy_s(&ifr.ifr_addr, sizeof(ifr.ifr_addr), &sin, sizeof(struct sockaddr)) != EOK) {
284        DHCP_LOGE("SetIpOrMask() failed, memcpy_s ifr.ifr_addr error!");
285        return DHCP_OPT_FAILED;
286    }
287
288    if (ioctl(fd, cmd, &ifr) < 0) {
289        DHCP_LOGE("SetIpOrMask() %{public}s failed!", ifname);
290        return DHCP_OPT_FAILED;
291    }
292    return DHCP_OPT_SUCCESS;
293}
294
295int SetLocalInterface(const char *ifname, uint32_t ipAddr, uint32_t netMask)
296{
297    if ((ifname == NULL) || (strlen(ifname) == 0)) {
298        DHCP_LOGE("SetLocalInterface() failed, ifname == NULL or \"\"!");
299        return DHCP_OPT_FAILED;
300    }
301
302    int fd = socket(AF_INET, SOCK_DGRAM, 0);
303    if (fd < 0) {
304        DHCP_LOGE("SetLocalInterface() ifname:%{public}s failed, socket error:%{public}d!", ifname, errno);
305        return DHCP_OPT_FAILED;
306    }
307
308    if (SetIpOrMask(ifname, fd, ipAddr, SIOCSIFADDR) != DHCP_OPT_SUCCESS) {
309        close(fd);
310        return DHCP_OPT_FAILED;
311    }
312
313    if (SetIpOrMask(ifname, fd, netMask, SIOCSIFNETMASK) != DHCP_OPT_SUCCESS) {
314        close(fd);
315        return DHCP_OPT_FAILED;
316    }
317    close(fd);
318    return DHCP_OPT_SUCCESS;
319}
320
321int InitPidfile(const char *pidDir, const char *pidFile, pid_t pid)
322{
323    if ((pidDir == NULL) || (strlen(pidDir) == 0) || (pidFile == NULL) || (strlen(pidFile) == 0)) {
324        DHCP_LOGE("InitPidfile() failed, pidDir or pidFile == NULL or \"\"!");
325        return DHCP_OPT_FAILED;
326    }
327    DHCP_LOGI("InitPidfile() pidDir:%{public}s, pidFile:%{public}s.", pidDir, pidFile);
328    unlink(pidFile);
329
330    int fd;
331    if ((fd = open(pidFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
332        DHCP_LOGE("InitPidfile() failed, open pidFile:%{public}s error:%{public}d!", pidFile, errno);
333        return DHCP_OPT_FAILED;
334    }
335
336    char buf[PID_MAX_LEN] = {0};
337    if (snprintf_s(buf, PID_MAX_LEN, PID_MAX_LEN - 1, "%d", pid) < 0) {
338        DHCP_LOGE("InitPidfile() pidFile:%{public}s failed, snprintf_s error:%{public}d!", pidFile, errno);
339        close(fd);
340        return DHCP_OPT_FAILED;
341    }
342    ssize_t bytes;
343    if ((bytes = write(fd, buf, strlen(buf))) <= 0) {
344        DHCP_LOGE("InitPidfile() failed, write pidFile:%{public}s error:%{public}d, bytes:%{public}zd!",
345            pidFile, errno, bytes);
346        close(fd);
347        return DHCP_OPT_FAILED;
348    }
349    DHCP_LOGI("InitPidfile() buf:%{public}s write pidFile:%{public}s, bytes:%{public}zd!", buf, pidFile, bytes);
350    close(fd);
351
352    if (chdir(pidDir) != 0) {
353        DHCP_LOGE("InitPidfile() failed, chdir pidDir:%{public}s error:%{public}d!", pidDir, errno);
354        return DHCP_OPT_FAILED;
355    }
356
357    /* Set default permissions for the specified client process id files and directories. */
358    umask(DEFAULT_UMASK);
359
360    /* Change attribs to the specified client process id files: 644 (user=rw, group=r, other=r). */
361    chmod(pidFile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
362
363    return DHCP_OPT_SUCCESS;
364}
365
366pid_t GetPID(const char *pidFile)
367{
368    /* Check pidFile is or not exists. */
369    struct stat sb;
370    if (stat(pidFile, &sb) != 0) {
371        DHCP_LOGW("GetPID() pidFile:%{public}s stat error:%{public}d!", pidFile, errno);
372        return -1;
373    }
374    DHCP_LOGI("GetPID() pidFile:%{public}s stat st_size:%{public}d.", pidFile, (int)sb.st_size);
375
376    int fd;
377    if ((fd = open(pidFile, O_RDONLY)) < 0) {
378        DHCP_LOGE("GetPID() failed, open pidFile:%{public}s error!", pidFile);
379        return -1;
380    }
381
382    lseek(fd, 0, SEEK_SET);
383
384    char buf[PID_MAX_LEN] = {0};
385    if (sb.st_size > PID_MAX_LEN) {
386        DHCP_LOGE("GetPID() invalid length, size:%{public}d", (int)sb.st_size);
387        return -1;
388    }
389    ssize_t bytes;
390    if ((bytes = read(fd, buf, sb.st_size)) < 0) {
391        DHCP_LOGE("GetPID() failed, read pidFile:%{public}s error, bytes:%{public}zd!", pidFile, bytes);
392        close(fd);
393        return -1;
394    }
395    DHCP_LOGI("GetPID() read pidFile:%{public}s, buf:%{public}s, bytes:%{public}zd.", pidFile, buf, bytes);
396    close(fd);
397
398    return atoi(buf);
399}
400
401int CreateDirs(const char *dirs, int mode)
402{
403    if ((dirs == NULL) || (strlen(dirs) == 0) || (strlen(dirs) >= DIR_MAX_LEN)) {
404        DHCP_LOGE("CreateDirs() dirs:%{public}s error!", dirs);
405        return DHCP_OPT_FAILED;
406    }
407
408    int nSrcLen = (int)strlen(dirs);
409    char strDir[DIR_MAX_LEN] = {0};
410    if (strncpy_s(strDir, sizeof(strDir), dirs, strlen(dirs)) != EOK) {
411        DHCP_LOGE("CreateDirs() strncpy_s dirs:%{public}s failed!", dirs);
412        return DHCP_OPT_FAILED;
413    }
414    if (strDir[nSrcLen - 1] != '/') {
415        if (nSrcLen == (DIR_MAX_LEN - 1)) {
416            DHCP_LOGE("CreateDirs() dirs:%{public}s len:%{public}d error!", dirs, nSrcLen);
417            return DHCP_OPT_FAILED;
418        }
419        if (strcat_s(strDir, sizeof(strDir), "/") != EOK) {
420            DHCP_LOGE("CreateDirs() strcat_s strDir:%{public}s failed!", strDir);
421            return DHCP_OPT_FAILED;
422        }
423        nSrcLen++;
424    }
425
426    int i = (strDir[0] == '/') ? 1 : 0;
427    for (; i <= nSrcLen - 1; i++) {
428        if (strDir[i] == '/') {
429            strDir[i] = 0;
430            if ((access(strDir, F_OK) != 0) && (mkdir(strDir, mode) != 0)) {
431                DHCP_LOGE("CreateDirs() mkdir %{public}s %{public}.4o failed:%{public}d!", strDir, mode, errno);
432                return DHCP_OPT_FAILED;
433            }
434            strDir[i] = '/';
435        }
436    }
437    DHCP_LOGI("CreateDirs() %{public}s %{public}.4o success.", dirs, mode);
438    return DHCP_OPT_SUCCESS;
439}
440