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 <errno.h>
17 #include <signal.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include "dhcp_dhcpd.h"
22 #include "securec.h"
23 #include "address_utils.h"
24 #include "dhcp_address_pool.h"
25 #include "dhcp_argument.h"
26 #include "dhcp_config.h"
27 #include "dhcp_s_define.h"
28 #include "dhcp_server_ipv4.h"
29 #include "dhcp_logger.h"
30 #include "dhcp_option.h"
31 #include "dhcp_s_server.h"
32 #include "dhcp_common_utils.h"
33 
34 DEFINE_DHCPLOG_DHCP_LABEL("DhcpServerMain");
35 
36 #define DEFAUTL_NET_MASK "255.255.255.0"
37 
38 static DhcpConfig g_dhcpConfig;
39 
40 static PDhcpServerContext g_dhcpServer = 0;
41 static DeviceConnectFun deviceConnectFun;
42 enum SignalEvent {
43     EXIT = 0,
44     RELOAD,
45     RESTART,
46 };
47 
LoadLocalConfig(DhcpAddressPool * pool)48 void LoadLocalConfig(DhcpAddressPool *pool)
49 {
50     DHCP_LOGD("loading local configure ...");
51 }
52 
ReloadLocalConfig(DhcpAddressPool * pool)53 void ReloadLocalConfig(DhcpAddressPool *pool)
54 {
55     DHCP_LOGD("reloading local configure ...");
56 }
57 
InitNetworkAbout(DhcpConfig * config)58 static int InitNetworkAbout(DhcpConfig *config)
59 {
60     ArgumentInfo *arg = GetArgument("netmask");
61     if (arg) {
62         DHCP_LOGI("subnet mask:%s", arg->value);
63         uint32_t argNetmask = ParseIpAddr(arg->value);
64         if (argNetmask) {
65             config->netmask = argNetmask;
66         } else {
67             DHCP_LOGW("error netmask argument.");
68             return RET_FAILED;
69         }
70     } else {
71         if (!config->netmask) {
72             config->netmask = ParseIpAddr(DEFAUTL_NET_MASK);
73         }
74     }
75     arg = GetArgument("gateway");
76     if (arg) {
77         DHCP_LOGI("gateway:%s", arg->value);
78         uint32_t argGateway = ParseIpAddr(arg->value);
79         if (argGateway) {
80             config->gateway = argGateway;
81         } else {
82             DHCP_LOGE("error gateway argument.");
83             return RET_FAILED;
84         }
85     } else {
86         config->gateway = config->serverId;
87         DHCP_LOGW("InitNetworkAbout, set gateway to serverId as default.");
88     }
89     return RET_SUCCESS;
90 }
91 
PareseAddreesRange(DhcpConfig * config)92 static int PareseAddreesRange(DhcpConfig *config)
93 {
94     ArgumentInfo *arg = GetArgument("pool");
95     if (arg) {
96         DHCP_LOGD("pool info:%s", arg->value);
97         int index = 0;
98         char *src = arg->value;
99         constexpr const char *delim = ",";
100         char *pSave = nullptr;
101         char *poolPartArg;
102         poolPartArg = strtok_r(src, delim, &pSave);
103         while (poolPartArg) {
104             if (index == 0) {
105                 config->pool.beginAddress = ParseIpAddr(poolPartArg);
106                 DHCP_LOGD("address range begin of: %s", poolPartArg);
107             } else if (index == 1) {
108                 config->pool.endAddress = ParseIpAddr(poolPartArg);
109                 DHCP_LOGD("address range end of: %s", poolPartArg);
110             }
111             index++;
112             poolPartArg = strtok_r(nullptr, delim, &pSave);
113         }
114         if (!config->pool.beginAddress || !config->pool.endAddress) {
115             DHCP_LOGE("'pool' argument format error.");
116             return RET_FAILED;
117         }
118         return RET_SUCCESS;
119     }
120     DHCP_LOGW("failed to get 'pool' argument.");
121     return RET_FAILED;
122 }
123 
InitAddressRange(DhcpConfig * config)124 static int InitAddressRange(DhcpConfig *config)
125 {
126     if (HasArgument("pool")) {
127         if (PareseAddreesRange(config) != RET_SUCCESS) {
128             DHCP_LOGW("dhcp range config error.");
129             return RET_FAILED;
130         }
131     } else {
132         if (!config->pool.beginAddress || !config->pool.endAddress) {
133             config->pool.beginAddress = FirstIpAddress(config->serverId, config->netmask);
134             config->pool.endAddress = LastIpAddress(config->serverId, config->netmask);
135         }
136     }
137     return RET_SUCCESS;
138 }
139 
InitDomainNameServer(DhcpConfig * config)140 static int InitDomainNameServer(DhcpConfig *config)
141 {
142     DhcpOption argOpt = {DOMAIN_NAME_SERVER_OPTION, 0, {0}};
143     ArgumentInfo *arg = GetArgument("dns");
144     uint32_t dnsAddress = 0;
145     if (arg) {
146         char *pSave = nullptr;
147         char *pTok = strtok_r(arg->value, ",", &pSave);
148         if ((pTok == nullptr) || (strlen(pTok) == 0)) {
149             DHCP_LOGE("strtok_r pTok nullptr or len is 0!");
150             return RET_FAILED;
151         }
152         while (pTok != nullptr) {
153             if ((dnsAddress = ParseIpAddr(pTok)) == 0) {
154                 DHCP_LOGE("ParseIpAddr %s failed, code:%d", pTok, argOpt.code);
155                 return RET_FAILED;
156             }
157             if (AppendAddressOption(&argOpt, dnsAddress) != RET_SUCCESS) {
158                 DHCP_LOGW("failed to append dns option.");
159             }
160             pTok = strtok_r(nullptr, ",", &pSave);
161         }
162     } else {
163         DHCP_LOGW("%{public}s, set dns to serverId as default.", __func__);
164         dnsAddress = config->serverId;
165         if (AppendAddressOption(&argOpt, dnsAddress) != RET_SUCCESS) {
166             DHCP_LOGW("failed to append dns option.");
167         }
168     }
169 
170     if (GetOption(&config->options, argOpt.code) != nullptr) {
171         RemoveOption(&config->options, DOMAIN_NAME_SERVER_OPTION);
172     }
173     PushBackOption(&config->options, &argOpt);
174     return RET_SUCCESS;
175 }
176 
InitServerId(DhcpConfig * config)177 static int InitServerId(DhcpConfig *config)
178 {
179     ArgumentInfo *arg = GetArgument("server");
180     if (arg) {
181         DHCP_LOGI("server id:%s", arg->value);
182         uint32_t argServerId = ParseIpAddr(arg->value);
183         if (argServerId) {
184             config->serverId = argServerId;
185         } else {
186             DHCP_LOGE("error server argument.");
187             return RET_FAILED;
188         }
189     } else {
190         if (!config->serverId) {
191             DHCP_LOGE("failed to get 'server' argument or config item.");
192             return RET_FAILED;
193         }
194     }
195     return RET_SUCCESS;
196 }
197 
InitLeaseTime(DhcpConfig * config)198 static int InitLeaseTime(DhcpConfig *config)
199 {
200     ArgumentInfo *arg = GetArgument("lease");
201     if (arg) {
202         std::string strValue = arg->value;
203         config->leaseTime = static_cast<uint32_t>(OHOS::DHCP::CheckDataLegal(strValue));
204     } else {
205         if (!config->leaseTime) {
206             config->leaseTime = DHCP_LEASE_TIME;
207         }
208     }
209     return RET_SUCCESS;
210 }
211 
InitRenewalTime(DhcpConfig * config)212 static int InitRenewalTime(DhcpConfig *config)
213 {
214     ArgumentInfo *arg = GetArgument("renewal");
215     if (arg) {
216         std::string strValue = arg->value;
217         config->renewalTime = static_cast<uint32_t>(OHOS::DHCP::CheckDataLegal(strValue));
218     } else {
219         if (!config->rebindingTime) {
220             config->rebindingTime = DHCP_RENEWAL_TIME;
221         }
222         config->renewalTime = DHCP_RENEWAL_TIME;
223     }
224     return RET_SUCCESS;
225 }
226 
InitRebindingTime(DhcpConfig * config)227 static int InitRebindingTime(DhcpConfig *config)
228 {
229     ArgumentInfo *arg = GetArgument("rebinding");
230     if (arg) {
231         std::string strValue = arg->value;
232         config->rebindingTime = static_cast<uint32_t>(OHOS::DHCP::CheckDataLegal(strValue));
233     } else {
234         if (!config->rebindingTime) {
235             config->rebindingTime =  DHCP_REBINDING_TIME;
236         }
237     }
238     return RET_SUCCESS;
239 }
InitConfigByArguments(DhcpConfig * config)240 static int InitConfigByArguments(DhcpConfig *config)
241 {
242     if (!config) {
243         DHCP_LOGE("dhcp configure pointer is null.");
244         return RET_FAILED;
245     }
246     if (InitServerId(config) != RET_SUCCESS) {
247         return RET_FAILED;
248     }
249     if (InitNetworkAbout(config) != RET_SUCCESS) {
250         return RET_FAILED;
251     }
252     if (InitAddressRange(config) != RET_SUCCESS) {
253         return RET_FAILED;
254     }
255     if (InitLeaseTime(config) != RET_SUCCESS) {
256         return RET_FAILED;
257     }
258     if (InitRenewalTime(config) != RET_SUCCESS) {
259         return RET_FAILED;
260     }
261     if (InitRebindingTime(config) != RET_SUCCESS) {
262         return RET_FAILED;
263     }
264     if (InitDomainNameServer(config) != RET_SUCCESS) {
265         return RET_FAILED;
266     }
267     return RET_SUCCESS;
268 }
269 
ServerActionCallback(int state,int code,const char * ifname)270 int ServerActionCallback(int state, int code, const char *ifname)
271 {
272     int ret = 0;
273     switch (state) {
274         case ST_STARTING: {
275             if (code == 0) {
276                 DHCP_LOGD(" callback[%s] ==> server starting ...", ifname);
277             } else if (code == 1) {
278                 DHCP_LOGD(" callback[%s] ==> server started.", ifname);
279             } else if (code == NUM_TWO) {
280                 DHCP_LOGD(" callback[%s] ==> server start failed.", ifname);
281             }
282             break;
283         }
284         case ST_RELOADNG: {
285             DHCP_LOGD(" callback[%s] ==> reloading ...", ifname);
286             break;
287         }
288         case ST_STOPED: {
289             DHCP_LOGD(" callback[%s] ==> server stopped.", ifname);
290             break;
291         }
292         default:
293             break;
294     }
295     return ret;
296 }
297 
InitializeDhcpConfig(const char * ifname,DhcpConfig * config)298 static int InitializeDhcpConfig(const char *ifname, DhcpConfig *config)
299 {
300     if (!config) {
301         DHCP_LOGE("dhcp configure pointer is null.");
302         return RET_FAILED;
303     }
304     if (InitOptionList(&config->options) != RET_SUCCESS) {
305         DHCP_LOGE("failed to initialize options.");
306         return RET_FAILED;
307     }
308     char configFile[ARGUMENT_VALUE_SIZE] = DHCPD_CONFIG_FILE;
309     if (HasArgument("conf")) {
310         ArgumentInfo *configArg = GetArgument("conf");
311         if (configArg) {
312             if (memcpy_s(configFile, ARGUMENT_VALUE_SIZE, configArg->value, strlen(configArg->value)) != EOK) {
313                 DHCP_LOGE("conf memcpy_s failed.");
314                 return RET_FAILED;
315             }
316         } else {
317             DHCP_LOGE("failed to get config file name.");
318             return RET_FAILED;
319         }
320     }
321     DHCP_LOGI("load local dhcp config file:%{public}s", configFile);
322     if (LoadConfig(configFile, ifname, config) != RET_SUCCESS) {
323         DHCP_LOGE("failed to load configure file.");
324         return RET_FAILED;
325     }
326     DHCP_LOGI("init config by argument.");
327     if (InitConfigByArguments(config) != RET_SUCCESS) {
328         DHCP_LOGE("failed to parse arguments.");
329         return RET_FAILED;
330     }
331 
332     return RET_SUCCESS;
333 }
334 
FreeLocalConfig(void)335 static void FreeLocalConfig(void)
336 {
337     FreeOptionList(&g_dhcpConfig.options);
338 }
339 
FreeSeverResources(void)340 void FreeSeverResources(void)
341 {
342     DHCP_LOGI("FreeSeverResources enter");
343     FreeArguments();
344     FreeLocalConfig();
345     if (FreeServerContext(&g_dhcpServer) != RET_SUCCESS) {
346         DHCP_LOGE("Free server context failed!");
347         return;
348     }
349 }
350 
StartDhcpServerMain(const std::string & ifName,const std::string & netMask,const std::string & ipRange,const std::string & localIp)351 int StartDhcpServerMain(const std::string& ifName, const std::string& netMask, const std::string& ipRange,
352     const std::string& localIp)
353 {
354     DHCP_LOGI("StartDhcpServerMain.");
355 
356     if (InitArguments() != RET_SUCCESS) {
357         DHCP_LOGE("failed to init arguments table.");
358         return 1;
359     }
360     int ret = ParseArguments(ifName, netMask, ipRange, localIp);
361     if (ret != RET_SUCCESS) {DHCP_LOGE("error ParseArguments.");
362         FreeArguments();
363         return 1;
364     }
365     ArgumentInfo *ifaceName = GetArgument("ifname");
366     if (!ifaceName || strlen(ifaceName->value) == 0) {
367         printf("missing required parameters:\"ifname\"\n");
368         FreeArguments();
369         return 1;
370     }
371     if (InitializeDhcpConfig(ifaceName->value, &g_dhcpConfig) != RET_SUCCESS) {
372         DHCP_LOGW("failed to initialize config.");
373     }
374     if (strcpy_s(g_dhcpConfig.ifname, IFACE_NAME_SIZE, ifaceName->value) != EOK) {
375         DHCP_LOGE("cpy ifname failed!");
376         return 1;
377     }
378     g_dhcpServer = InitializeServer(&g_dhcpConfig);
379     if (g_dhcpServer == nullptr) {
380         DHCP_LOGE("failed to initialize dhcp server.");
381         FreeSeverResources();
382         return 1;
383     }
384 
385     RegisterDhcpCallback(g_dhcpServer, ServerActionCallback);
386     RegisterDeviceChangedCallback(g_dhcpServer, deviceConnectFun);
387     if (StartDhcpServer(g_dhcpServer) != RET_SUCCESS) {
388         FreeSeverResources();
389         return 1;
390     }
391     return 0;
392 }
393 
StopDhcpServerMain()394 int StopDhcpServerMain()
395 {
396     DHCP_LOGI("StopDhcpServerMain.");
397     if (StopDhcpServer(g_dhcpServer) != RET_SUCCESS) {
398         FreeSeverResources();
399         return 1;
400     }
401     FreeSeverResources();
402     return 0;
403 }
404 
RegisterDeviceConnectCallBack(DeviceConnectFun fun)405 int RegisterDeviceConnectCallBack(DeviceConnectFun fun)
406 {
407     DHCP_LOGI("RegisterDeviceConnectCallBack enter!");
408     deviceConnectFun = fun;
409     return 0;
410 }