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