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 }