1 /*
2 * Copyright (C) 2021 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 #include <strings.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <sys/stat.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <ctype.h>
25
26 #include "securec.h"
27 #include "dhcp_client.h"
28 #include "dhcp_function.h"
29
30 #undef LOG_TAG
31 #define LOG_TAG "WifiDhcpMain"
32
33 /* Static declared. */
34 static int Usage(void);
35 static int RunChildProcess(void);
36 static int CreateDaemon(void);
37 static int CheckClientProParam(const int argc, char *argv[]);
38 static int GetClientOption(int argc, char *argv[]);
39 static int InitSpecifiedClientCfg(int argc, char *argv[]);
40 static int ExecClientProAction(const char *action);
41 static int GetClientNetworkInfo(void);
42
43 static struct DhcpClientCfg *g_cltCfg;
44
45 /* Static defined. */
Usage(void)46 static int Usage(void)
47 {
48 printf("\nUsage: dhcp_client_service ACTION INTERFACE [OPTION]\n");
49 printf(" ACTION = start|stop|status|help|ver\n");
50 printf(" start - start INTERFACE's network interface service\n");
51 printf(" stop - stop INTERFACE's network interface service\n");
52 printf(" status - show INTERFACE's service status and exit\n");
53 printf(" help - displays usage info, INTERFACE is optional\n");
54 printf(" ver - displays client version, INTERFACE is optional\n");
55 printf(" INTERFACE = ifname, eg: wlan0\n");
56 printf(" OPTION = -w <directory>|-a or -4\n");
57 printf(" -w <directory> - specify the client's working directory\n");
58 printf(" -a - handle dhcp v4 and v6\n");
59 printf(" -4 - only handle dhcp v4\n");
60 printf("\n========== running process operate ==========\n");
61 printf(" send dhcp release packet = kill -USR1 <pid> \n");
62 printf(" send dhcp renew packet = kill -USR2 <pid> \n\n");
63 return DHCP_OPT_SUCCESS;
64 }
65
RunChildProcess(void)66 static int RunChildProcess(void)
67 {
68 if (setpgrp() == -1) {
69 LOGE("RunChildProcess() can not change process group, return!");
70 return DHCP_OPT_FAILED;
71 }
72
73 if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
74 LOGE("RunChildProcess() signal SIGHUP SIG_ERR, return!");
75 return DHCP_OPT_FAILED;
76 }
77
78 /* Ensure we can never get a controlling terminal. */
79 pid_t childPid;
80 switch (childPid = fork()) {
81 case -1:
82 LOGE("RunChildProcess() fork grandchild failed, return!");
83 return DHCP_OPT_FAILED;
84 case 0:
85 /* Grandchild process continue run. */
86 break;
87 default:
88 /* Child process exit now. */
89 exit(EXIT_SUCCESS);
90 }
91 LOGI("RunChildProcess() child: fork grand suc, childPid:%{public}d,pid():%{public}d,ppid():%{public}d.",
92 childPid, getpid(), getppid());
93 return DHCP_OPT_SUCCESS;
94 }
95
CreateDaemon(void)96 static int CreateDaemon(void)
97 {
98 LOGI("CreateDaemon() enter, pid:%{public}d, ppid:%{public}d.", getpid(), getppid());
99
100 /* A daemon process need close all open files. */
101 if (fclose(stdin) != 0) {
102 LOGE("CreateDaemon() fclose stdin error:%{public}d!", errno);
103 return DHCP_OPT_FAILED;
104 }
105 if (fclose(stdout) != 0) {
106 LOGE("CreateDaemon() fclose stdout error:%{public}d!", errno);
107 return DHCP_OPT_FAILED;
108 }
109 if (fclose(stderr) != 0) {
110 LOGE("CreateDaemon() fclose stderr error:%{public}d!", errno);
111 return DHCP_OPT_FAILED;
112 }
113
114 /* Ensure that the process is not a fork subprocess, init process id is 1. */
115 if (getppid() == 1) {
116 LOGI("CreateDaemon() getppid() == 1, the process's parent is already init process!");
117 /* Set default permissions for files and directories. */
118 umask(DEFAULT_UMASK);
119 return DHCP_OPT_SUCCESS;
120 }
121
122 pid_t pid;
123 switch (pid = fork()) {
124 case -1:
125 LOGE("CreateDaemon() fork first child failed, return!");
126 return DHCP_OPT_FAILED;
127 case 0:
128 if (RunChildProcess() != DHCP_OPT_SUCCESS) {
129 LOGE("CreateDaemon() RunChildProcess failed, return!");
130 return DHCP_OPT_FAILED;
131 };
132 /* Child process continue run. */
133 break;
134 default:
135 /* Parent process exit now. */
136 exit(EXIT_SUCCESS);
137 }
138
139 /* We have forked, setpgrp, forked once more, from now on, we are a daemon process. */
140 LOGI("CreateDaemon() grandchild continue run, pid:%{public}d,getpid():%{public}d,getppid():%{public}d.",
141 pid, getpid(), getppid());
142 umask(DEFAULT_UMASK);
143 return DHCP_OPT_SUCCESS;
144 }
145
CheckClientProParam(const int argc,char * argv[])146 static int CheckClientProParam(const int argc, char *argv[])
147 {
148 if (argc <= NUMBER_ONE) {
149 printf("CheckClientProParam() argc:%d error, please input valid ACTION!\n", argc);
150 Usage();
151 return -1;
152 }
153
154 /* Check client process param ACTION "help","ver". */
155 const char *cmdParam = argv[NUMBER_ONE];
156 if (strncasecmp(cmdParam, "help", NUMBER_FOUR) == 0) {
157 Usage();
158 return 1;
159 } else if (strncasecmp(cmdParam, "ver", NUMBER_THREE) == 0) {
160 printf("%s, version %s\n", DHCPC_NAME, DHCPC_VERSION);
161 return 1;
162 } else {
163 /* Check client process param ACTION "start","stop","status". */
164 if ((strncasecmp(cmdParam, "start", NUMBER_FIVE) != 0) && (strncasecmp(cmdParam, "stop", NUMBER_FOUR) != 0) &&
165 (strncasecmp(cmdParam, "status", NUMBER_FIVE) != 0)) {
166 printf("CheckClientProParam() argv[1]:%s error, please input valid ACTION!\n", cmdParam);
167 Usage();
168 return -1;
169 }
170 /* Check client process running argc. */
171 if (argc <= NUMBER_TWO) {
172 printf("CheckClientProParam() argc:%d error, please input valid INTERFACE!\n", argc);
173 Usage();
174 return -1;
175 }
176 }
177 return 0;
178 }
179
GetClientOption(int argc,char * argv[])180 static int GetClientOption(int argc, char *argv[])
181 {
182 int ch;
183 while ((ch = getopt(argc - NUMBER_TWO, argv + NUMBER_TWO, "w:a46")) != -1) {
184 switch (ch) {
185 case 'w': /* Specify the client's working directory. */
186 LOGI("GetClientOption() cur workDir:%{public}s, optarg:%{public}s", g_cltCfg->workDir, optarg);
187 if (strncpy_s(g_cltCfg->workDir, sizeof(g_cltCfg->workDir), optarg, DIR_MAX_LEN - 1) != EOK) {
188 return -1;
189 }
190 break;
191 case 'a': /* Handle dhcp v4 and v6. */
192 g_cltCfg->getMode = DHCP_IP_TYPE_ALL;
193 break;
194 case '4': /* Only handle dhcp v4. */
195 LOGI("GetClientOption() cur getMode:%{public}u, optarg:%{public}s", g_cltCfg->getMode, optarg);
196 g_cltCfg->getMode = DHCP_IP_TYPE_V4;
197 break;
198 case '6': /* Only handle dhcp v6. */
199 g_cltCfg->getMode = DHCP_IP_TYPE_V6;
200 break;
201 default:
202 printf("GetClientOption() please input valid OPTION!\n");
203 Usage();
204 return -1;
205 }
206 }
207 return 0;
208 }
209
CheckIfaceNameIsLegal(const char * argv)210 static int CheckIfaceNameIsLegal(const char *argv)
211 {
212 if (argv == NULL) {
213 LOGE("parameter error, argv is NULL!");
214 return DHCP_OPT_FAILED;
215 }
216
217 char ifaceName[INFNAME_SIZE] = {0};
218 if (strncpy_s(ifaceName, INFNAME_SIZE, argv, INFNAME_SIZE - 1) != EOK) {
219 LOGE("call strncpy_s fail!");
220 return DHCP_OPT_FAILED;
221 }
222
223 if (strlen(ifaceName) == 0) {
224 LOGE("parameter error, ifaceName len is zero!");
225 return DHCP_OPT_FAILED;
226 }
227
228 for (int i = 0; i < strlen(ifaceName) - 1; ++i) {
229 if ((isalnum(ifaceName[i]) == 0) && ifaceName[i] != '-' && ifaceName[i] != '_') {
230 LOGE("parameter error, ifaceName is illegal!");
231 return DHCP_OPT_FAILED;
232 }
233 }
234
235 return DHCP_OPT_SUCCESS;
236 }
237
InitSpecifiedClientCfg(int argc,char * argv[])238 static int InitSpecifiedClientCfg(int argc, char *argv[])
239 {
240 if (argc < NUMBER_TWO + 1) {
241 LOGE("parameter error!");
242 return DHCP_OPT_FAILED;
243 }
244
245 if (CheckIfaceNameIsLegal(argv[NUMBER_TWO]) != DHCP_OPT_SUCCESS) {
246 LOGE("parameter error, CheckIfaceNameIsLegal fail!");
247 return DHCP_OPT_FAILED;
248 }
249
250 g_cltCfg = GetDhcpClientCfg();
251 if ((strncpy_s(g_cltCfg->workDir, sizeof(g_cltCfg->workDir), WORKDIR, DIR_MAX_LEN - 1) != EOK) ||
252 (strncpy_s(g_cltCfg->ifaceName, sizeof(g_cltCfg->ifaceName), argv[NUMBER_TWO], INFNAME_SIZE - 1) != EOK)) {
253 return DHCP_OPT_FAILED;
254 }
255 g_cltCfg->getMode = DHCP_IP_TYPE_ALL;
256 if ((argc > NUMBER_THREE) && (GetClientOption(argc, argv) != 0)) {
257 LOGE("InitSpecifiedClientCfg() GetClientOption failed!");
258 return DHCP_OPT_FAILED;
259 }
260
261 if (strlen(g_cltCfg->workDir) == 0) {
262 LOGE("InitSpecifiedClientCfg() g_cltCfg->workDir:%{public}s error!", g_cltCfg->workDir);
263 return DHCP_OPT_FAILED;
264 }
265 if (CreateDirs(g_cltCfg->workDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != DHCP_OPT_SUCCESS) {
266 LOGE("InitSpecifiedClientCfg() CreateDirs %{public}s failed!", g_cltCfg->workDir);
267 return DHCP_OPT_FAILED;
268 }
269
270 if (snprintf_s(g_cltCfg->confFile, DIR_MAX_LEN, DIR_MAX_LEN - 1, "%s%s", g_cltCfg->workDir, DHCPC_CONF) < 0) {
271 return DHCP_OPT_FAILED;
272 }
273
274 if (snprintf_s(g_cltCfg->pidFile, DIR_MAX_LEN, DIR_MAX_LEN - 1, "%s%s.pid",
275 g_cltCfg->workDir, g_cltCfg->ifaceName) < 0) {
276 return DHCP_OPT_FAILED;
277 }
278
279 if (snprintf_s(g_cltCfg->resultFile, DIR_MAX_LEN, DIR_MAX_LEN - 1, "%s%s.result",
280 g_cltCfg->workDir, g_cltCfg->ifaceName) < 0) {
281 return DHCP_OPT_FAILED;
282 }
283
284 if (snprintf_s(g_cltCfg->leaseFile, DIR_MAX_LEN, DIR_MAX_LEN - 1, "%sdhcp_client_service-%s.lease",
285 g_cltCfg->workDir, g_cltCfg->ifaceName) < 0) {
286 return DHCP_OPT_FAILED;
287 }
288
289 LOGD("InitSpecifiedClientCfg: "
290 "g_cltCfg->workDir:%{public}s,confFile:%{public}s,pidFile:%{public}s,resultFile:%{public}s,getMode:%{public}d",
291 g_cltCfg->workDir, g_cltCfg->confFile, g_cltCfg->pidFile, g_cltCfg->resultFile, g_cltCfg->getMode);
292
293 return DHCP_OPT_SUCCESS;
294 }
295
ExecClientProAction(const char * action)296 static int ExecClientProAction(const char *action)
297 {
298 /* Stop the specified network interface service. */
299 if (strncasecmp(action, "stop", NUMBER_FOUR) == 0) {
300 if (StopProcess(g_cltCfg->pidFile) != DHCP_OPT_SUCCESS) {
301 LOGD("ExecClientProAction() StopProcess pidFile:%{public}s not success.", g_cltCfg->pidFile);
302 } else {
303 LOGD("ExecClientProAction() StopProcess pidFile:%{public}s success.", g_cltCfg->pidFile);
304 }
305 return 1;
306 }
307
308 /* Get the specified client process running status. */
309 int proStatus = GetProStatus(g_cltCfg->pidFile);
310 if (strncasecmp(action, "status", NUMBER_FIVE) == 0) {
311 LOGI("ExecClientProAction() action:%{public}s GetProStatus proStatus:%{public}d.", action, proStatus);
312 return 1;
313 }
314
315 /* Check the specified client process param ACTION. */
316 if (strncasecmp(action, "start", NUMBER_FIVE) != 0) {
317 LOGE("ExecClientProAction() argv[1]:%{public}s error, please input valid ACTION!", action);
318 Usage();
319 return -1;
320 }
321 if (proStatus == 1) {
322 LOGI("ExecClientProAction() the specified client process is already started!");
323 return 1;
324 }
325
326 /* Record the parent process id that creates the daemon */
327 g_cltCfg->parentProcessId = getppid();
328
329 /* Create a daemon process. */
330 if (CreateDaemon() != DHCP_OPT_SUCCESS) {
331 LOGE("ExecClientProAction() CreateDaemon failed!");
332 return -1;
333 }
334
335 /* Init the specified client process id info. */
336 if (InitPidfile(g_cltCfg->workDir, g_cltCfg->pidFile, getpid()) != DHCP_OPT_SUCCESS) {
337 LOGE("ExecClientProAction() InitPidfile failed, ifaceName:%{public}s.", g_cltCfg->ifaceName);
338 return -1;
339 }
340
341 return 0;
342 }
343
GetClientNetworkInfo(void)344 static int GetClientNetworkInfo(void)
345 {
346 if (GetLocalInterface(g_cltCfg->ifaceName, &g_cltCfg->ifaceIndex, g_cltCfg->ifaceMac, NULL) != DHCP_OPT_SUCCESS) {
347 LOGE("GetClientNetworkInfo() GetLocalInterface failed, ifaceName:%{public}s.", g_cltCfg->ifaceName);
348 return DHCP_OPT_FAILED;
349 }
350 char macAddr[MAC_ADDR_LEN * MAC_ADDR_CHAR_NUM];
351 if (memset_s(macAddr, sizeof(macAddr), 0, sizeof(macAddr)) != EOK) {
352 return DHCP_OPT_FAILED;
353 }
354 MacChConToMacStr(g_cltCfg->ifaceMac, MAC_ADDR_LEN, macAddr, sizeof(macAddr));
355 LOGD("GetClientNetworkInfo() g_cltCfg->ifaceName:%{public}s -> ifaceIndex:%{private}d,ifaceMac:%{private}s.",
356 g_cltCfg->ifaceName, g_cltCfg->ifaceIndex, macAddr);
357
358 if (GetLocalIp(g_cltCfg->ifaceName, &g_cltCfg->ifaceIpv4) != DHCP_OPT_SUCCESS) {
359 LOGE("GetClientNetworkInfo() failed, g_cltCfg->ifaceName:%{public}s.", g_cltCfg->ifaceName);
360 return DHCP_OPT_FAILED;
361 }
362 char *cIp = Ip4IntConToStr(g_cltCfg->ifaceIpv4, true);
363 if (cIp == NULL) {
364 LOGE("GetClientNetworkInfo() Ip4IntConToStr g_cltCfg->ifaceIpv4 failed!");
365 return DHCP_OPT_FAILED;
366 }
367 LOGD("GetClientNetworkInfo() GetLocalIp ifaceName:%{public}s -> ifaceIpv4:%{private}u - %{private}s.",
368 g_cltCfg->ifaceName, g_cltCfg->ifaceIpv4, cIp);
369 free(cIp);
370 cIp = NULL;
371
372 /* Generate clientid for the specified client process interface. */
373 if (g_cltCfg->pOptClientId == NULL) {
374 g_cltCfg->pOptClientId = malloc(DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES + MAC_ADDR_LEN + 1);
375 if (g_cltCfg->pOptClientId == NULL) {
376 LOGE("GetClientNetworkInfo() g_cltCfg->pOptClientId malloc failed!");
377 return DHCP_OPT_FAILED;
378 }
379 g_cltCfg->pOptClientId[DHCP_OPT_CODE_INDEX] = CLIENT_IDENTIFIER_OPTION;
380 g_cltCfg->pOptClientId[DHCP_OPT_LEN_INDEX] = MAC_ADDR_LEN + 1;
381 /* Generate format: 1 + ifaceMac. */
382 g_cltCfg->pOptClientId[DHCP_OPT_DATA_INDEX] = NUMBER_ONE;
383 if (memcpy_s(g_cltCfg->pOptClientId + DHCP_OPT_DATA_INDEX + 1,
384 MAC_ADDR_LEN,
385 g_cltCfg->ifaceMac,
386 MAC_ADDR_LEN) != EOK) {
387 return DHCP_OPT_FAILED;
388 }
389 }
390
391 return DHCP_OPT_SUCCESS;
392 }
393
main(int argc,char * argv[])394 int main(int argc, char *argv[])
395 {
396 /* Check client process running param ACTION. */
397 int nCheck = CheckClientProParam(argc, argv);
398 if (nCheck != 0) {
399 return (nCheck == 1) ? EXIT_SUCCESS : EXIT_FAILURE;
400 }
401
402 /* Init the specified client process config. */
403 if (InitSpecifiedClientCfg(argc, argv) != DHCP_OPT_SUCCESS) {
404 LOGE("main() InitSpecifiedClientCfg failed!");
405 return EXIT_FAILURE;
406 }
407
408 /* Exec the specified client process ACTION. */
409 if (argc < NUMBER_ONE + 1) {
410 LOGE("parameter number is error!");
411 return EXIT_FAILURE;
412 }
413 const char *cmdParam = argv[NUMBER_ONE];
414 int nExec = ExecClientProAction(cmdParam);
415 if (nExec != 0) {
416 return (nExec == 1) ? EXIT_SUCCESS : EXIT_FAILURE;
417 }
418
419 /* Get the specified client process interface network info. */
420 if (GetClientNetworkInfo() != DHCP_OPT_SUCCESS) {
421 LOGE("main() GetClientNetworkInfo failed!");
422 return EXIT_FAILURE;
423 }
424
425 /* Start the specified network interface service. */
426 if (StartProcess() != DHCP_OPT_SUCCESS) {
427 LOGE("main() StartProcess failed!");
428 return EXIT_FAILURE;
429 }
430
431 LOGI("main() end, argc:%{public}d.", argc);
432 return EXIT_SUCCESS;
433 }
434