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