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