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 <map>
18 #include <getopt.h>
19 #include <securec.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include "address_utils.h"
25 #include "dhcp_s_define.h"
26 #include "dhcp_logger.h"
27 
28 DEFINE_DHCPLOG_DHCP_LABEL("DhcpArgument");
29 
30 static std::map<std::string, ArgumentInfo> 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 (g_argumentsTable.empty()) {
119         return 0;
120     }
121     if (g_argumentsTable.count(name) > 0) {
122         return 1;
123     }
124     return 0;
125 }
126 
ShowUsage(const DhcpUsage * usage)127 static void ShowUsage(const DhcpUsage *usage)
128 {
129     if (!usage || !usage->opt) {
130         return;
131     }
132     if (usage->opt->val) {
133         DHCP_LOGI("-%{public}c,--%{public}s ", (char)usage->opt->val, usage->opt->name);
134     } else {
135         DHCP_LOGI("   --%{public}s ", usage->opt->name);
136     }
137     if (usage->params[0] == '\0') {
138         DHCP_LOGI("\t\t%{public}s\n", usage->desc);
139     } else {
140         int plen = strlen(usage->params) + strlen(usage->params);
141         if (plen < USAGE_DESC_MAX_LENGTH) {
142             DHCP_LOGI("\t\t%{public}s\t\t%{public}s\n", usage->params, usage->desc);
143         } else {
144             DHCP_LOGI("\t\t%{public}s\n", usage->params);
145             DHCP_LOGI("\t\t\t%{public}s\n\n", usage->desc);
146         }
147     }
148 }
149 
PrintRequiredArguments(void)150 void PrintRequiredArguments(void)
151 {
152     size_t argc = sizeof(usages) / sizeof(DhcpUsage);
153     DHCP_LOGI("required parameters:");
154     int idx = 0;
155     for (size_t i = 0; i < argc; i++) {
156         DhcpUsage usage = usages[i];
157         if (!usage.opt) {
158             break;
159         }
160         if (usage.required) {
161             if (idx == 0) {
162                 DHCP_LOGI("\"%{public}s\"", usage.opt->name);
163             } else {
164                 DHCP_LOGI(", \"%{public}s\"", usage.opt->name);
165             }
166             idx++;
167         }
168     }
169     DHCP_LOGI(".\n\n");
170     DHCP_LOGI("Usage: dhcp_server [options] \n");
171     DHCP_LOGI("e.g: dhcp_server -i eth0 -c /data/service/el1/public/dhcp/dhcp_server.conf \n");
172     DHCP_LOGI("     dhcp_server --help \n\n");
173 }
174 
PrintUsage(void)175 static void PrintUsage(void)
176 {
177     DHCP_LOGI("Usage: dhcp_server [options] \n\n");
178 
179     size_t argc = sizeof(usages) / sizeof(DhcpUsage);
180     for (size_t i = 0; i < argc; i++) {
181         DhcpUsage usage = usages[i];
182         if (!usage.opt) {
183             break;
184         }
185         ShowUsage(&usage);
186     }
187     DHCP_LOGI("\n");
188 }
189 
ShowHelp(int argc)190 void ShowHelp(int argc)
191 {
192     if (argc == NUM_TWO) {
193         PrintUsage();
194         return;
195     }
196 }
197 
InitArguments(void)198 int InitArguments(void)
199 {
200     DHCP_LOGI("start InitArguments.");
201     g_argumentsTable.clear();
202     DHCP_LOGI("end InitArguments.");
203     return RET_SUCCESS;
204 }
205 
GetArgument(const char * name)206 ArgumentInfo *GetArgument(const char *name)
207 {
208     char argName[ARGUMENT_NAME_SIZE] = {'\0'};
209     size_t ssize = strlen(name);
210     if (ssize > ARGUMENT_NAME_SIZE) {
211         ssize = ARGUMENT_NAME_SIZE;
212     }
213     if (memcpy_s(argName, ARGUMENT_NAME_SIZE, name, ssize) != EOK) {
214         DHCP_LOGE("failed to set argument name.");
215         return nullptr;
216     }
217     if (g_argumentsTable.count(argName) > 0) {
218         return &g_argumentsTable[argName];
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     g_argumentsTable[std::string(arg.name)] = arg;
264     return RET_SUCCESS;
265 }
266 
FindIndex(int c)267 int FindIndex(int c)
268 {
269     int size = sizeof(g_longOptions) / sizeof(g_longOptions[0]);
270     for (int i = 0; i < size; ++i) {
271         if (g_longOptions[i].val == c) {
272             return i;
273         }
274     }
275     return -1;
276 }
277 
ParseArguments(const std::string & ifName,const std::string & netMask,const std::string & ipRange,const std::string & localIp)278 int ParseArguments(const std::string& ifName, const std::string& netMask, const std::string& ipRange,
279     const std::string& localIp)
280 {
281     DHCP_LOGI("start ParseArguments.");
282     PutArgument("ifname", ifName.c_str());
283     PutIpArgument("server", localIp.c_str());
284     PutIpArgument("netmask", netMask.c_str());
285     PutPoolArgument("pool", ipRange.c_str());
286     return 0;
287 }
288 
FreeArguments(void)289 void FreeArguments(void)
290 {
291     g_argumentsTable.clear();
292 }
293