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 "dhcp_config.h"
17 #include <errno.h>
18 #include <securec.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23 #include "address_utils.h"
24 #include "common_util.h"
25 #include "dhcp_server_ipv4.h"
26 #include "dhcp_logger.h"
27 
28 DEFINE_DHCPLOG_DHCP_LABEL("DhcpServerConfig");
29 
30 #define FILE_LINE_LEN_MAX       1024
31 #define FILE_LINE_DELIMITER     "="
32 
SetEnableConfigInfo(DhcpConfig * dhcpConfig,const char * pKey,const char * pValue)33 static int SetEnableConfigInfo(DhcpConfig *dhcpConfig, const char *pKey, const char *pValue)
34 {
35     if ((dhcpConfig == nullptr) || (pKey == nullptr) || (pValue == nullptr)) {
36         DHCP_LOGE("SetEnableConfigInfo param dhcpConfig or pKey or pValue is nullptr!");
37         return RET_FAILED;
38     }
39 
40     uint32_t uValue = (uint32_t)atoi(pValue);
41     if ((uValue != 0) && (uValue != 1)) {
42         DHCP_LOGE("enable:%s error", pValue);
43         return RET_FAILED;
44     }
45 
46     if (strcmp(pKey, "distribution") == 0) {
47         dhcpConfig->distribution = uValue;
48     } else if (strcmp(pKey, "broadcast") == 0) {
49         dhcpConfig->broadcast = uValue;
50     }
51     return RET_SUCCESS;
52 }
53 
SetTimeConfigInfo(DhcpConfig * dhcpConfig,const char * pKey,const char * pValue)54 static int SetTimeConfigInfo(DhcpConfig *dhcpConfig, const char *pKey, const char *pValue)
55 {
56     if ((dhcpConfig == nullptr) || (pKey == nullptr) || (pValue == nullptr)) {
57         DHCP_LOGE("SetTimeConfigInfo param dhcpConfig or pKey or pValue is nullptr!");
58         return RET_FAILED;
59     }
60 
61     uint32_t uValue = 0;
62     if ((uValue = (uint32_t)atoi(pValue)) == 0) {
63         DHCP_LOGE("atoi failed, time:%s", pValue);
64         return RET_FAILED;
65     }
66 
67     if (strcmp(pKey, "leaseTime") == 0) {
68         dhcpConfig->leaseTime = uValue;
69     } else if (strcmp(pKey, "renewalTime") == 0) {
70         dhcpConfig->renewalTime = uValue;
71     } else if (strcmp(pKey, "rebindingTime") == 0) {
72         dhcpConfig->rebindingTime = uValue;
73     }
74     return RET_SUCCESS;
75 }
76 
SetNetConfigInfo(DhcpConfig * dhcpConfig,const char * pKey,const char * pValue,int common)77 static int SetNetConfigInfo(DhcpConfig *dhcpConfig, const char *pKey, const char *pValue, int common)
78 {
79     if ((dhcpConfig == nullptr) || (pKey == nullptr) || (pValue == nullptr)) {
80         DHCP_LOGE("SetNetConfigInfo param dhcpConfig or pKey or pValue is nullptr!");
81         return RET_FAILED;
82     }
83 
84     uint32_t uValue = 0;
85     if ((uValue = ParseIpAddr(pValue)) == 0) {
86         DHCP_LOGE("ParseIpAddr failed, ip:%s", pValue);
87         return RET_FAILED;
88     }
89 
90     if (((strcmp(pKey, "serverId") == 0) && common) || ((strcmp(pKey, "server") == 0) && !common)) {
91         dhcpConfig->serverId = uValue;
92     } else if (strcmp(pKey, "gateway") == 0) {
93         dhcpConfig->gateway = uValue;
94     } else if (strcmp(pKey, "netmask") == 0) {
95         dhcpConfig->netmask = uValue;
96     }
97     return RET_SUCCESS;
98 }
99 
SetIpAddressPool(DhcpConfig * dhcpConfig,const char * pValue)100 static int SetIpAddressPool(DhcpConfig *dhcpConfig, const char *pValue)
101 {
102     if ((dhcpConfig == nullptr) || (pValue == nullptr)) {
103         DHCP_LOGE("SetIpAddressPool param dhcpConfig or pValue is nullptr!");
104         return RET_FAILED;
105     }
106 
107     char *pSrc = (char *)pValue;
108     char *pSave = nullptr;
109     char *pTok = strtok_r(pSrc, ",", &pSave);
110     if (((pTok == nullptr) || (strlen(pTok) == 0)) || ((pSave == nullptr) || (strlen(pSave) == 0))) {
111         DHCP_LOGE("strtok_r pTok or pSave nullptr or len is 0!");
112         return RET_FAILED;
113     }
114 
115     uint32_t begin;
116     if ((begin = ParseIpAddr(pTok)) == 0) {
117         DHCP_LOGE("ParseIpAddr begin:%s failed!", pTok);
118         return RET_FAILED;
119     }
120     dhcpConfig->pool.beginAddress = begin;
121     uint32_t end;
122     if ((end = ParseIpAddr(pSave)) == 0) {
123         DHCP_LOGE("ParseIpAddr end:%s failed!", pSave);
124         return RET_FAILED;
125     }
126     dhcpConfig->pool.endAddress = end;
127     return RET_SUCCESS;
128 }
129 
SetDnsInfo(DhcpConfig * dhcpConfig,const char * pValue)130 static int SetDnsInfo(DhcpConfig *dhcpConfig, const char *pValue)
131 {
132     if ((dhcpConfig == nullptr) || (pValue == nullptr)) {
133         DHCP_LOGE("SetDnsInfo param dhcpConfig or pValue is nullptr!");
134         return RET_FAILED;
135     }
136 
137     char *pSrc = (char *)pValue;
138     char *pSave = nullptr;
139     char *pTok = strtok_r(pSrc, ",", &pSave);
140     if ((pTok == nullptr) || (strlen(pTok) == 0)) {
141         DHCP_LOGE("strtok_r pTok nullptr or len is 0!");
142         return RET_FAILED;
143     }
144 
145     DhcpOption optDns = {DOMAIN_NAME_SERVER_OPTION, 0, {0}};
146     if (GetOption(&dhcpConfig->options, optDns.code) != nullptr) {
147         RemoveOption(&dhcpConfig->options, optDns.code);
148     }
149 
150     uint32_t dnsAddress;
151     while (pTok != nullptr) {
152         if ((dnsAddress = ParseIpAddr(pTok)) == 0) {
153             DHCP_LOGE("ParseIpAddr %s failed, code:%d", pTok, optDns.code);
154             return RET_FAILED;
155         }
156         if (AppendAddressOption(&optDns, dnsAddress) != RET_SUCCESS) {
157             DHCP_LOGW("failed append dns option.");
158         }
159         pTok = strtok_r(nullptr, ",", &pSave);
160     }
161     PushBackOption(&dhcpConfig->options, &optDns);
162     return RET_SUCCESS;
163 }
164 
SetIfnameInfo(DhcpConfig * dhcpConfig,const char * pValue)165 static int SetIfnameInfo(DhcpConfig *dhcpConfig, const char *pValue)
166 {
167     if ((dhcpConfig == nullptr) || (pValue == nullptr)) {
168         DHCP_LOGE("SetIfnameInfo dhcpConfig or pValue is nullptr!");
169         return RET_FAILED;
170     }
171     if (strlen(pValue) >= IFACE_NAME_SIZE) {
172         DHCP_LOGE("ifname:%s too long!", pValue);
173         return RET_FAILED;
174     }
175     if (memset_s(dhcpConfig->ifname, IFACE_NAME_SIZE, '\0', IFACE_NAME_SIZE) != EOK ||
176         strncpy_s(dhcpConfig->ifname, IFACE_NAME_SIZE, pValue, strlen(pValue)) != EOK) {
177         return RET_FAILED;
178     }
179     return RET_SUCCESS;
180 }
181 
SetDhcpConfig(DhcpConfig * dhcpConfig,const char * strLine,int common)182 static int SetDhcpConfig(DhcpConfig *dhcpConfig, const char *strLine, int common)
183 {
184     if ((strLine == nullptr) || (strlen(strLine) == 0)) {
185         DHCP_LOGE("SetDhcpConfig param strLine is nullptr or len = 0!");
186         return RET_FAILED;
187     }
188 
189     char *pSrc = (char *)strLine;
190     char *pSave = nullptr;
191     char *pTok = strtok_r(pSrc, FILE_LINE_DELIMITER, &pSave);
192     if (pTok == nullptr) {
193         DHCP_LOGE("strtok_r pTok nullptr!");
194         return RET_FAILED;
195     }
196     if (strcmp(pTok, "interface") == 0) {
197         return SetIfnameInfo(dhcpConfig, pSave);
198     } else if (strcmp(pTok, "dns") == 0) {
199         return SetDnsInfo(dhcpConfig, pSave);
200     } else if (strcmp(pTok, "pool") == 0) {
201         return SetIpAddressPool(dhcpConfig, pSave);
202     } else if ((((strcmp(pTok, "serverId") == 0) && common) || ((strcmp(pTok, "server") == 0) && !common)) ||
203         (strcmp(pTok, "gateway") == 0) || (strcmp(pTok, "netmask") == 0)) {
204         return SetNetConfigInfo(dhcpConfig, pTok, pSave, common);
205     } else if ((strcmp(pTok, "leaseTime") == 0) || (strcmp(pTok, "renewalTime") == 0) ||
206                (strcmp(pTok, "rebindingTime") == 0)) {
207         return SetTimeConfigInfo(dhcpConfig, pTok, pSave);
208     } else if ((strcmp(pTok, "distribution") == 0) || (strcmp(pTok, "broadcast") == 0)) {
209         return SetEnableConfigInfo(dhcpConfig, pTok, pSave);
210     } else {
211         DHCP_LOGD("invalid key:%s", pTok);
212         return RET_SUCCESS;
213     }
214 }
215 
ParseConfigFile(const char * configFile,const char * ifname,DhcpConfig * dhcpConfig)216 static int ParseConfigFile(const char *configFile, const char *ifname, DhcpConfig *dhcpConfig)
217 {
218     if ((configFile == nullptr) || (strlen(configFile) == 0) || (dhcpConfig == nullptr)) {
219         DHCP_LOGE("ParseConfigFile param configFile or dhcpConfig is nullptr or len = 0!");
220         return RET_FAILED;
221     }
222 
223     FILE *fp = fopen(configFile, "r");
224     if (fp == nullptr) {
225         DHCP_LOGE("fopen %{public}s failed, err:%{public}d", configFile, errno);
226         return RET_FAILED;
227     }
228 
229     int bComm = 1;
230     int bValid = 1;
231     char strLine[FILE_LINE_LEN_MAX] = {0};
232     while (fgets(strLine, FILE_LINE_LEN_MAX, fp) != nullptr) {
233         DHCP_LOGI("fgets strLine = %{public}s", strLine);
234         if ((strchr(strLine, '#') != nullptr) || (strchr(strLine, '=') == nullptr) ||
235             !RemoveSpaceCharacters(strLine, FILE_LINE_LEN_MAX)) {
236             if (memset_s(strLine, FILE_LINE_LEN_MAX, 0, FILE_LINE_LEN_MAX) != EOK) {
237                 break;
238             }
239             continue;
240         }
241         if (memcmp(strLine, "interface", strlen("interface")) == 0) {
242             bComm = 0;
243             bValid = 0;
244             if ((ifname == nullptr) || (strlen(ifname) == 0) || (strstr(strLine, ifname) != nullptr)) {
245                 DHCP_LOGI("%s %s find ifname:%s", configFile, strLine, ((ifname == nullptr) ? "" : ifname));
246                 bValid = 1;
247             } else {
248                 DHCP_LOGI("%s %s no find ifname:%s", configFile, strLine, ifname);
249             }
250         }
251         if (bValid && SetDhcpConfig(dhcpConfig, strLine, bComm) != RET_SUCCESS) {
252             DHCP_LOGE("set dhcp config %s %s failed", configFile, strLine);
253             fclose(fp);
254             return RET_FAILED;
255         }
256         if (memset_s(strLine, FILE_LINE_LEN_MAX, 0, FILE_LINE_LEN_MAX) != EOK) {
257             break;
258         }
259     }
260     if (fclose(fp) != 0) {
261         DHCP_LOGE("ParseConfigFile fclose fp failed!");
262     }
263     return RET_SUCCESS;
264 }
265 
CheckDhcpConfig(DhcpConfig * config)266 static int CheckDhcpConfig(DhcpConfig *config)
267 {
268     if (config == nullptr) {
269         DHCP_LOGE("CheckDhcpConfig param config is null");
270         return DHCP_FALSE;
271     }
272     if ((strlen(config->ifname) > 0) && ((config->serverId == 0))) {
273         DHCP_LOGE("failed to config serverId or netmask");
274         return DHCP_FALSE;
275     }
276 
277     if (config->renewalTime == 0) {
278         config->renewalTime = config->leaseTime * DHCP_RENEWAL_MULTIPLE;
279     }
280     if (config->rebindingTime == 0) {
281         config->rebindingTime = config->leaseTime * DHCP_REBIND_MULTIPLE;
282     }
283     return DHCP_TRUE;
284 }
285 
LoadConfig(const char * configFile,const char * ifname,DhcpConfig * config)286 int LoadConfig(const char *configFile, const char *ifname, DhcpConfig *config)
287 {
288     if ((configFile == nullptr) || (strlen(configFile) == 0) || (ifname == nullptr) || (strlen(ifname) == 0) ||
289         (config == nullptr)) {
290         DHCP_LOGE("LoadConfig param configFile or ifname or config is nullptr or len = 0!");
291         return RET_FAILED;
292     }
293 
294     /* Default config. */
295     config->leaseTime = DHCP_LEASE_TIME;
296     config->distribution = 1;
297     config->broadcast = 1;
298 
299     /* Set file config. */
300     if (ParseConfigFile(configFile, ifname, config) != RET_SUCCESS) {
301         DHCP_LOGE("parse config file %{public}s error!", configFile);
302         return RET_FAILED;
303     }
304     DHCP_LOGI("parse config file %{public}s success", configFile);
305 
306     if (!CheckDhcpConfig(config)) {
307         DHCP_LOGE("check dhcp config failed");
308         return RET_FAILED;
309     }
310 
311     if ((strlen(config->ifname) == 0) && SetIfnameInfo(config, ifname) != RET_SUCCESS) {
312         DHCP_LOGE("set ifname %s error!", ifname);
313         return RET_FAILED;
314     }
315     return RET_SUCCESS;
316 }
317