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 "dhcp_argument.h"
17 #include <getopt.h>
18 #include <securec.h>
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include "address_utils.h"
24 #include "dhcp_define.h"
25 #include "dhcp_logger.h"
26 #include "hash_table.h"
27
28 #undef LOG_TAG
29 #define LOG_TAG "DhcpArgument"
30
31 static HashTable g_argumentsTable;
32
PutIpArgument(const char * argument,const char * val)33 static int PutIpArgument(const char *argument, const char *val)
34 {
35 if (!ParseIpAddr(val)) {
36 LOGE("%s format error.", argument);
37 return RET_FAILED;
38 }
39 return PutArgument(argument, val);
40 }
41
PutPoolArgument(const char * argument,const char * val)42 static int PutPoolArgument(const char *argument, const char *val)
43 {
44 if (!val) {
45 return 0;
46 }
47 if (strchr(val, ',') == NULL) {
48 LOGE("too few pool option arguments.");
49 return RET_FAILED;
50 }
51 return PutArgument(argument, val);
52 }
53
ShowVersion(const char * argument,const char * val)54 static int ShowVersion(const char *argument, const char *val)
55 {
56 printf("version:%s\n", DHCPD_VERSION);
57 return RET_SUCCESS;
58 }
59
DefaultArgument(const char * argument,const char * val)60 static int DefaultArgument(const char *argument, const char *val)
61 {
62 LOGD("Input argument is: [%s], value is [%s]", (argument == NULL) ? "" : argument,
63 (val == NULL) ? "" : val);
64 return RET_SUCCESS;
65 }
66
67 const char *g_optionString = "i:c:d:g:s:n:P:S:Bp:o:lb:rvhD";
68
69 static struct option g_longOptions[] = {
70 {"ifname", REQUIRED_ARG, 0, 'i'},
71 {"conf", REQUIRED_ARG, 0, 'c'},
72 {"dns", REQUIRED_ARG, 0, 'd'},
73 {"gateway", REQUIRED_ARG, 0, 'g'},
74 {"server", REQUIRED_ARG, 0, 's'},
75 {"netmask", REQUIRED_ARG, 0, 'n'},
76 {"pool", REQUIRED_ARG, 0, 'P'},
77 {"lease", REQUIRED_ARG, 0, 0},
78 {"renewal", REQUIRED_ARG, 0, 0},
79 {"rebinding", REQUIRED_ARG, 0, 0},
80 {"version", NO_ARG, 0, 'v'},
81 {"help", NO_ARG, 0, 'h'},
82 {0, 0, 0, 0},
83 };
84
85 static DhcpUsage usages[] = {
86 {&g_longOptions[NUM_ZERO], "<interface>", "network interface name.", "--ifname eth0", 1, PutArgument},
87 {&g_longOptions[NUM_ONE], "<file>", "configure file name.", "--conf /etc/conf/dhcp_server.conf", 0, PutArgument},
88 {&g_longOptions[NUM_TWO], "<dns1>[,dns2][,dns3][...]", "domain name server IP address list.", "", 0, PutArgument},
89 {&g_longOptions[NUM_THREE], "<gateway>", "gateway option.", "", 0, PutIpArgument},
90 {&g_longOptions[NUM_FOUR], "<server>", "server identifier.", "", 1, PutIpArgument},
91 {&g_longOptions[NUM_FIVE], "<netmask>", "default subnet mask.", "", 1, PutIpArgument},
92 {&g_longOptions[NUM_SIX], "<beginip>,<endip>", "pool address range.", "", 0,
93 PutPoolArgument},
94 {&g_longOptions[NUM_SEVEN], "<leaseTime>", "set lease time value, the value is in units of seconds.", "", 0,
95 PutArgument},
96 {&g_longOptions[NUM_EIGHT], "<renewalTime>", "set renewal time value, the value is in units of seconds.", "", 0,
97 PutArgument},
98 {&g_longOptions[NUM_NINE], "<rebindingTime>", "set rebinding time value, the value is in units of seconds.", "", 0,
99 PutArgument},
100 {&g_longOptions[NUM_TEN], "", "show version information.", "", 0, ShowVersion},
101 {&g_longOptions[NUM_ELEVEN], "", "show help information.", "", 0, DefaultArgument},
102 {0, "", "", ""},
103 };
104
HasArgument(const char * argument)105 int HasArgument(const char *argument)
106 {
107 char name[ARGUMENT_NAME_SIZE] = {'\0'};
108 if (!argument) {
109 return 0;
110 }
111 size_t ssize = strlen(argument);
112 if (ssize > ARGUMENT_NAME_SIZE) {
113 ssize = ARGUMENT_NAME_SIZE;
114 }
115 if (memcpy_s(name, ARGUMENT_NAME_SIZE, argument, ssize) != EOK) {
116 LOGE("failed to set argument name.");
117 return 0;
118 }
119 if (ContainsKey(&g_argumentsTable, (uintptr_t)name)) {
120 return 1;
121 }
122 return 0;
123 }
124
ShowUsage(const DhcpUsage * usage)125 static void ShowUsage(const DhcpUsage *usage)
126 {
127 if (!usage || !usage->opt) {
128 return;
129 }
130 if (usage->opt->val) {
131 printf("-%d,--%s ", usage->opt->val, usage->opt->name);
132 } else {
133 printf(" --%s ", usage->opt->name);
134 }
135 if (usage->params[0] == '\0') {
136 printf("\t\t%s\n", usage->desc);
137 } else {
138 int plen = strlen(usage->params) + strlen(usage->params);
139 if (plen < USAGE_DESC_MAX_LENGTH) {
140 printf("\t\t%s\t\t%s\n", usage->params, usage->desc);
141 } else {
142 printf("\t\t%s\n", usage->params);
143 printf("\t\t\t%s\n\n", usage->desc);
144 }
145 }
146 }
147
PrintRequiredArguments(void)148 void PrintRequiredArguments(void)
149 {
150 size_t argc = sizeof(usages) / sizeof(DhcpUsage);
151 printf("required parameters:");
152 int idx = 0;
153 for (size_t i = 0; i < argc; i++) {
154 DhcpUsage usage = usages[i];
155 if (!usage.opt) {
156 break;
157 }
158 if (usage.required) {
159 if (idx == 0) {
160 printf("\"%s\"", usage.opt->name);
161 } else {
162 printf(", \"%s\"", usage.opt->name);
163 }
164 idx++;
165 }
166 }
167 printf(".\n\n");
168 printf("Usage: dhcp_server [options] \n");
169 printf("e.g: dhcp_server -i eth0 -c /data/service/el1/public/dhcp/dhcp_server.conf \n");
170 printf(" dhcp_server --help \n\n");
171 }
172
PrintUsage(void)173 static void PrintUsage(void)
174 {
175 printf("Usage: dhcp_server [options] \n\n");
176
177 size_t argc = sizeof(usages) / sizeof(DhcpUsage);
178 for (size_t i = 0; i < argc; i++) {
179 DhcpUsage usage = usages[i];
180 if (!usage.opt) {
181 break;
182 }
183 ShowUsage(&usage);
184 }
185 printf("\n");
186 }
187
ShowHelp(int argc)188 void ShowHelp(int argc)
189 {
190 if (argc == NUM_TWO) {
191 PrintUsage();
192 return;
193 }
194 }
195
InitArguments(void)196 int InitArguments(void)
197 {
198 if (CreateHashTable(&g_argumentsTable, ARGUMENT_NAME_SIZE, sizeof(ArgumentInfo), INIT_ARGS_SIZE) != HASH_SUCCESS) {
199 return RET_FAILED;
200 }
201 return RET_SUCCESS;
202 }
203
GetArgument(const char * name)204 ArgumentInfo *GetArgument(const char *name)
205 {
206 char argName[ARGUMENT_NAME_SIZE] = {'\0'};
207 size_t ssize = strlen(name);
208 if (ssize > ARGUMENT_NAME_SIZE) {
209 ssize = ARGUMENT_NAME_SIZE;
210 }
211 if (memcpy_s(argName, ARGUMENT_NAME_SIZE, name, ssize) != EOK) {
212 LOGE("failed to set argument name.");
213 return NULL;
214 }
215 if (ContainsKey(&g_argumentsTable, (uintptr_t)argName)) {
216 ArgumentInfo *arg = (ArgumentInfo *)At(&g_argumentsTable, (uintptr_t)argName);
217 return arg;
218 }
219 return NULL;
220 }
221
PutArgument(const char * argument,const char * val)222 int PutArgument(const char *argument, const char *val)
223 {
224 if (!argument) {
225 return RET_FAILED;
226 }
227 if (!val) {
228 return RET_FAILED;
229 }
230
231 if (HasArgument(argument)) {
232 return RET_FAILED;
233 }
234
235 ArgumentInfo arg;
236 size_t ssize = strlen(argument);
237 if (ssize >= ARGUMENT_NAME_SIZE) {
238 ssize = ARGUMENT_NAME_SIZE -1;
239 }
240 size_t vlen = strlen(val);
241 if (memset_s(arg.name, ARGUMENT_NAME_SIZE, '\0', ARGUMENT_NAME_SIZE) != EOK) {
242 LOGE("failed to reset argument name.");
243 return RET_ERROR;
244 }
245 if (memcpy_s(arg.name, ARGUMENT_NAME_SIZE, argument, ssize) != EOK) {
246 LOGE("failed to set argument name.");
247 return RET_ERROR;
248 }
249 if (vlen >= ARGUMENT_VALUE_SIZE) {
250 LOGE("value string too long.");
251 return RET_ERROR;
252 }
253 if (memset_s(arg.value, ARGUMENT_VALUE_SIZE, '\0', ARGUMENT_NAME_SIZE) != EOK) {
254 LOGE("failed to reset argument value.");
255 return RET_ERROR;
256 }
257 if (memcpy_s(arg.value, ARGUMENT_VALUE_SIZE, val, vlen) != EOK) {
258 LOGE("failed to set argument value.");
259 return RET_ERROR;
260 }
261 int ret = Insert(&g_argumentsTable, (uintptr_t)arg.name, (uintptr_t)&arg);
262 if (ret == HASH_INSERTED) {
263 return RET_SUCCESS;
264 }
265 return RET_FAILED;
266 }
267
FindIndex(int c)268 int FindIndex(int c)
269 {
270 int size = sizeof(g_longOptions) / sizeof(g_longOptions[0]);
271 for (int i = 0; i < size; ++i) {
272 if (g_longOptions[i].val == c) {
273 return i;
274 }
275 }
276 return -1;
277 }
278
ParseArguments(int argc,char * argv[])279 int ParseArguments(int argc, char *argv[])
280 {
281 int ret;
282 opterr = 0;
283 size_t optsc = sizeof(usages) / sizeof(DhcpUsage);
284 int index = -1;
285 int rst = RET_SUCCESS;
286 while ((ret = getopt_long(argc, argv, g_optionString, g_longOptions, &index)) != -1) {
287 if (ret == '?') {
288 LOGW("unknown input arguments! ret = ?");
289 index = -1;
290 continue;
291 }
292 if (index < 0) {
293 index = FindIndex(ret);
294 }
295 if (index < 0 || index >= (int)optsc) {
296 LOGD("unknown input arguments! ret = %c, index = %d", ret, index);
297 index = -1;
298 continue;
299 }
300 DhcpUsage *usage = &usages[index];
301 rst = usage->dealOption(usage->opt->name, optarg);
302 if (rst != RET_SUCCESS) {
303 break;
304 }
305 index = -1;
306 }
307
308 return rst;
309 }
310
FreeArguments(void)311 void FreeArguments(void)
312 {
313 if (!Initialized(&g_argumentsTable)) {
314 return;
315 }
316 DestroyHashTable(&g_argumentsTable);
317 }
318