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