1518678f8Sopenharmony_ci/*
2518678f8Sopenharmony_ci * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3518678f8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4518678f8Sopenharmony_ci * you may not use this file except in compliance with the License.
5518678f8Sopenharmony_ci * You may obtain a copy of the License at
6518678f8Sopenharmony_ci *
7518678f8Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8518678f8Sopenharmony_ci *
9518678f8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10518678f8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11518678f8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12518678f8Sopenharmony_ci * See the License for the specific language governing permissions and
13518678f8Sopenharmony_ci * limitations under the License.
14518678f8Sopenharmony_ci */
15518678f8Sopenharmony_ci
16518678f8Sopenharmony_ci#include "dhcp_argument.h"
17518678f8Sopenharmony_ci#include <map>
18518678f8Sopenharmony_ci#include <getopt.h>
19518678f8Sopenharmony_ci#include <securec.h>
20518678f8Sopenharmony_ci#include <stddef.h>
21518678f8Sopenharmony_ci#include <stdint.h>
22518678f8Sopenharmony_ci#include <stdio.h>
23518678f8Sopenharmony_ci#include <string.h>
24518678f8Sopenharmony_ci#include "address_utils.h"
25518678f8Sopenharmony_ci#include "dhcp_s_define.h"
26518678f8Sopenharmony_ci#include "dhcp_logger.h"
27518678f8Sopenharmony_ci
28518678f8Sopenharmony_ciDEFINE_DHCPLOG_DHCP_LABEL("DhcpArgument");
29518678f8Sopenharmony_ci
30518678f8Sopenharmony_cistatic std::map<std::string, ArgumentInfo> g_argumentsTable;
31518678f8Sopenharmony_ci
32518678f8Sopenharmony_cistatic int PutIpArgument(const char *argument, const char *val)
33518678f8Sopenharmony_ci{
34518678f8Sopenharmony_ci    if (!ParseIpAddr(val)) {
35518678f8Sopenharmony_ci        DHCP_LOGE("%s format error.", argument);
36518678f8Sopenharmony_ci        return RET_FAILED;
37518678f8Sopenharmony_ci    }
38518678f8Sopenharmony_ci    return PutArgument(argument, val);
39518678f8Sopenharmony_ci}
40518678f8Sopenharmony_ci
41518678f8Sopenharmony_cistatic int PutPoolArgument(const char *argument, const char *val)
42518678f8Sopenharmony_ci{
43518678f8Sopenharmony_ci    if (!val) {
44518678f8Sopenharmony_ci        return 0;
45518678f8Sopenharmony_ci    }
46518678f8Sopenharmony_ci    if (strchr(val, ',') == nullptr) {
47518678f8Sopenharmony_ci        DHCP_LOGE("too few pool option arguments.");
48518678f8Sopenharmony_ci        return RET_FAILED;
49518678f8Sopenharmony_ci    }
50518678f8Sopenharmony_ci    return PutArgument(argument, val);
51518678f8Sopenharmony_ci}
52518678f8Sopenharmony_ci
53518678f8Sopenharmony_cistatic int ShowVersion(const char *argument, const char *val)
54518678f8Sopenharmony_ci{
55518678f8Sopenharmony_ci    DHCP_LOGI("version:%s\n", DHCPD_VERSION);
56518678f8Sopenharmony_ci    return RET_SUCCESS;
57518678f8Sopenharmony_ci}
58518678f8Sopenharmony_ci
59518678f8Sopenharmony_cistatic int DefaultArgument(const char *argument, const char *val)
60518678f8Sopenharmony_ci{
61518678f8Sopenharmony_ci    DHCP_LOGI("Input argument is: [%s], value is [%s]", (argument == nullptr) ? "" : argument,
62518678f8Sopenharmony_ci        (val == nullptr) ? "" : val);
63518678f8Sopenharmony_ci    return RET_SUCCESS;
64518678f8Sopenharmony_ci}
65518678f8Sopenharmony_ci
66518678f8Sopenharmony_ciconst char *g_optionString = "i:c:d:g:s:n:P:S:Bp:o:lb:rvhD";
67518678f8Sopenharmony_ci
68518678f8Sopenharmony_cistatic struct option g_longOptions[] = {
69518678f8Sopenharmony_ci    {"ifname", REQUIRED_ARG, 0, 'i'},
70518678f8Sopenharmony_ci    {"conf", REQUIRED_ARG, 0, 'c'},
71518678f8Sopenharmony_ci    {"dns", REQUIRED_ARG, 0, 'd'},
72518678f8Sopenharmony_ci    {"gateway", REQUIRED_ARG, 0, 'g'},
73518678f8Sopenharmony_ci    {"server", REQUIRED_ARG, 0, 's'},
74518678f8Sopenharmony_ci    {"netmask", REQUIRED_ARG, 0, 'n'},
75518678f8Sopenharmony_ci    {"pool", REQUIRED_ARG, 0, 'P'},
76518678f8Sopenharmony_ci    {"lease", REQUIRED_ARG, 0, 0},
77518678f8Sopenharmony_ci    {"renewal", REQUIRED_ARG, 0, 0},
78518678f8Sopenharmony_ci    {"rebinding", REQUIRED_ARG, 0, 0},
79518678f8Sopenharmony_ci    {"version", NO_ARG, 0, 'v'},
80518678f8Sopenharmony_ci    {"help", NO_ARG, 0, 'h'},
81518678f8Sopenharmony_ci    {0, 0, 0, 0},
82518678f8Sopenharmony_ci};
83518678f8Sopenharmony_ci
84518678f8Sopenharmony_cistatic DhcpUsage usages[] = {
85518678f8Sopenharmony_ci    {&g_longOptions[NUM_ZERO], "<interface>", "network interface name.", "--ifname eth0", 1, PutArgument},
86518678f8Sopenharmony_ci    {&g_longOptions[NUM_ONE], "<file>", "configure file name.", "--conf /etc/conf/dhcp_server.conf", 0, PutArgument},
87518678f8Sopenharmony_ci    {&g_longOptions[NUM_TWO], "<dns1>[,dns2][,dns3][...]", "domain name server IP address list.", "", 0, PutArgument},
88518678f8Sopenharmony_ci    {&g_longOptions[NUM_THREE], "<gateway>", "gateway option.", "", 0, PutIpArgument},
89518678f8Sopenharmony_ci    {&g_longOptions[NUM_FOUR], "<server>", "server identifier.", "", 1, PutIpArgument},
90518678f8Sopenharmony_ci    {&g_longOptions[NUM_FIVE], "<netmask>", "default subnet mask.", "", 1, PutIpArgument},
91518678f8Sopenharmony_ci    {&g_longOptions[NUM_SIX], "<beginip>,<endip>", "pool address range.", "", 0,
92518678f8Sopenharmony_ci        PutPoolArgument},
93518678f8Sopenharmony_ci    {&g_longOptions[NUM_SEVEN], "<leaseTime>", "set lease time value, the value is in units of seconds.", "", 0,
94518678f8Sopenharmony_ci        PutArgument},
95518678f8Sopenharmony_ci    {&g_longOptions[NUM_EIGHT], "<renewalTime>", "set renewal time value, the value is in units of seconds.", "", 0,
96518678f8Sopenharmony_ci        PutArgument},
97518678f8Sopenharmony_ci    {&g_longOptions[NUM_NINE], "<rebindingTime>", "set rebinding time value, the value is in units of seconds.", "", 0,
98518678f8Sopenharmony_ci        PutArgument},
99518678f8Sopenharmony_ci    {&g_longOptions[NUM_TEN], "", "show version information.", "", 0, ShowVersion},
100518678f8Sopenharmony_ci    {&g_longOptions[NUM_ELEVEN], "", "show help information.", "", 0, DefaultArgument},
101518678f8Sopenharmony_ci    {0, "", "", ""},
102518678f8Sopenharmony_ci};
103518678f8Sopenharmony_ci
104518678f8Sopenharmony_ciint HasArgument(const char *argument)
105518678f8Sopenharmony_ci{
106518678f8Sopenharmony_ci    char name[ARGUMENT_NAME_SIZE] = {'\0'};
107518678f8Sopenharmony_ci    if (!argument) {
108518678f8Sopenharmony_ci        return 0;
109518678f8Sopenharmony_ci    }
110518678f8Sopenharmony_ci    size_t ssize = strlen(argument);
111518678f8Sopenharmony_ci    if (ssize > ARGUMENT_NAME_SIZE) {
112518678f8Sopenharmony_ci        ssize = ARGUMENT_NAME_SIZE;
113518678f8Sopenharmony_ci    }
114518678f8Sopenharmony_ci    if (memcpy_s(name, ARGUMENT_NAME_SIZE, argument, ssize) != EOK) {
115518678f8Sopenharmony_ci        DHCP_LOGE("failed to set argument name.");
116518678f8Sopenharmony_ci        return 0;
117518678f8Sopenharmony_ci    }
118518678f8Sopenharmony_ci    if (g_argumentsTable.empty()) {
119518678f8Sopenharmony_ci        return 0;
120518678f8Sopenharmony_ci    }
121518678f8Sopenharmony_ci    if (g_argumentsTable.count(name) > 0) {
122518678f8Sopenharmony_ci        return 1;
123518678f8Sopenharmony_ci    }
124518678f8Sopenharmony_ci    return 0;
125518678f8Sopenharmony_ci}
126518678f8Sopenharmony_ci
127518678f8Sopenharmony_cistatic void ShowUsage(const DhcpUsage *usage)
128518678f8Sopenharmony_ci{
129518678f8Sopenharmony_ci    if (!usage || !usage->opt) {
130518678f8Sopenharmony_ci        return;
131518678f8Sopenharmony_ci    }
132518678f8Sopenharmony_ci    if (usage->opt->val) {
133518678f8Sopenharmony_ci        DHCP_LOGI("-%{public}c,--%{public}s ", (char)usage->opt->val, usage->opt->name);
134518678f8Sopenharmony_ci    } else {
135518678f8Sopenharmony_ci        DHCP_LOGI("   --%{public}s ", usage->opt->name);
136518678f8Sopenharmony_ci    }
137518678f8Sopenharmony_ci    if (usage->params[0] == '\0') {
138518678f8Sopenharmony_ci        DHCP_LOGI("\t\t%{public}s\n", usage->desc);
139518678f8Sopenharmony_ci    } else {
140518678f8Sopenharmony_ci        int plen = strlen(usage->params) + strlen(usage->params);
141518678f8Sopenharmony_ci        if (plen < USAGE_DESC_MAX_LENGTH) {
142518678f8Sopenharmony_ci            DHCP_LOGI("\t\t%{public}s\t\t%{public}s\n", usage->params, usage->desc);
143518678f8Sopenharmony_ci        } else {
144518678f8Sopenharmony_ci            DHCP_LOGI("\t\t%{public}s\n", usage->params);
145518678f8Sopenharmony_ci            DHCP_LOGI("\t\t\t%{public}s\n\n", usage->desc);
146518678f8Sopenharmony_ci        }
147518678f8Sopenharmony_ci    }
148518678f8Sopenharmony_ci}
149518678f8Sopenharmony_ci
150518678f8Sopenharmony_civoid PrintRequiredArguments(void)
151518678f8Sopenharmony_ci{
152518678f8Sopenharmony_ci    size_t argc = sizeof(usages) / sizeof(DhcpUsage);
153518678f8Sopenharmony_ci    DHCP_LOGI("required parameters:");
154518678f8Sopenharmony_ci    int idx = 0;
155518678f8Sopenharmony_ci    for (size_t i = 0; i < argc; i++) {
156518678f8Sopenharmony_ci        DhcpUsage usage = usages[i];
157518678f8Sopenharmony_ci        if (!usage.opt) {
158518678f8Sopenharmony_ci            break;
159518678f8Sopenharmony_ci        }
160518678f8Sopenharmony_ci        if (usage.required) {
161518678f8Sopenharmony_ci            if (idx == 0) {
162518678f8Sopenharmony_ci                DHCP_LOGI("\"%{public}s\"", usage.opt->name);
163518678f8Sopenharmony_ci            } else {
164518678f8Sopenharmony_ci                DHCP_LOGI(", \"%{public}s\"", usage.opt->name);
165518678f8Sopenharmony_ci            }
166518678f8Sopenharmony_ci            idx++;
167518678f8Sopenharmony_ci        }
168518678f8Sopenharmony_ci    }
169518678f8Sopenharmony_ci    DHCP_LOGI(".\n\n");
170518678f8Sopenharmony_ci    DHCP_LOGI("Usage: dhcp_server [options] \n");
171518678f8Sopenharmony_ci    DHCP_LOGI("e.g: dhcp_server -i eth0 -c /data/service/el1/public/dhcp/dhcp_server.conf \n");
172518678f8Sopenharmony_ci    DHCP_LOGI("     dhcp_server --help \n\n");
173518678f8Sopenharmony_ci}
174518678f8Sopenharmony_ci
175518678f8Sopenharmony_cistatic void PrintUsage(void)
176518678f8Sopenharmony_ci{
177518678f8Sopenharmony_ci    DHCP_LOGI("Usage: dhcp_server [options] \n\n");
178518678f8Sopenharmony_ci
179518678f8Sopenharmony_ci    size_t argc = sizeof(usages) / sizeof(DhcpUsage);
180518678f8Sopenharmony_ci    for (size_t i = 0; i < argc; i++) {
181518678f8Sopenharmony_ci        DhcpUsage usage = usages[i];
182518678f8Sopenharmony_ci        if (!usage.opt) {
183518678f8Sopenharmony_ci            break;
184518678f8Sopenharmony_ci        }
185518678f8Sopenharmony_ci        ShowUsage(&usage);
186518678f8Sopenharmony_ci    }
187518678f8Sopenharmony_ci    DHCP_LOGI("\n");
188518678f8Sopenharmony_ci}
189518678f8Sopenharmony_ci
190518678f8Sopenharmony_civoid ShowHelp(int argc)
191518678f8Sopenharmony_ci{
192518678f8Sopenharmony_ci    if (argc == NUM_TWO) {
193518678f8Sopenharmony_ci        PrintUsage();
194518678f8Sopenharmony_ci        return;
195518678f8Sopenharmony_ci    }
196518678f8Sopenharmony_ci}
197518678f8Sopenharmony_ci
198518678f8Sopenharmony_ciint InitArguments(void)
199518678f8Sopenharmony_ci{
200518678f8Sopenharmony_ci    DHCP_LOGI("start InitArguments.");
201518678f8Sopenharmony_ci    g_argumentsTable.clear();
202518678f8Sopenharmony_ci    DHCP_LOGI("end InitArguments.");
203518678f8Sopenharmony_ci    return RET_SUCCESS;
204518678f8Sopenharmony_ci}
205518678f8Sopenharmony_ci
206518678f8Sopenharmony_ciArgumentInfo *GetArgument(const char *name)
207518678f8Sopenharmony_ci{
208518678f8Sopenharmony_ci    char argName[ARGUMENT_NAME_SIZE] = {'\0'};
209518678f8Sopenharmony_ci    size_t ssize = strlen(name);
210518678f8Sopenharmony_ci    if (ssize > ARGUMENT_NAME_SIZE) {
211518678f8Sopenharmony_ci        ssize = ARGUMENT_NAME_SIZE;
212518678f8Sopenharmony_ci    }
213518678f8Sopenharmony_ci    if (memcpy_s(argName, ARGUMENT_NAME_SIZE, name, ssize) != EOK) {
214518678f8Sopenharmony_ci        DHCP_LOGE("failed to set argument name.");
215518678f8Sopenharmony_ci        return nullptr;
216518678f8Sopenharmony_ci    }
217518678f8Sopenharmony_ci    if (g_argumentsTable.count(argName) > 0) {
218518678f8Sopenharmony_ci        return &g_argumentsTable[argName];
219518678f8Sopenharmony_ci    }
220518678f8Sopenharmony_ci    return nullptr;
221518678f8Sopenharmony_ci}
222518678f8Sopenharmony_ci
223518678f8Sopenharmony_ciint PutArgument(const char *argument, const char *val)
224518678f8Sopenharmony_ci{
225518678f8Sopenharmony_ci    DHCP_LOGI("start PutArgument.");
226518678f8Sopenharmony_ci    if (!argument) {
227518678f8Sopenharmony_ci        return RET_FAILED;
228518678f8Sopenharmony_ci    }
229518678f8Sopenharmony_ci    if (!val) {
230518678f8Sopenharmony_ci        return RET_FAILED;
231518678f8Sopenharmony_ci    }
232518678f8Sopenharmony_ci
233518678f8Sopenharmony_ci    if (HasArgument(argument)) {
234518678f8Sopenharmony_ci        return RET_FAILED;
235518678f8Sopenharmony_ci    }
236518678f8Sopenharmony_ci
237518678f8Sopenharmony_ci    ArgumentInfo arg;
238518678f8Sopenharmony_ci    size_t ssize = strlen(argument);
239518678f8Sopenharmony_ci    if (ssize >= ARGUMENT_NAME_SIZE) {
240518678f8Sopenharmony_ci        ssize = ARGUMENT_NAME_SIZE -1;
241518678f8Sopenharmony_ci    }
242518678f8Sopenharmony_ci    size_t vlen = strlen(val);
243518678f8Sopenharmony_ci    if (memset_s(arg.name, ARGUMENT_NAME_SIZE, '\0', ARGUMENT_NAME_SIZE) != EOK) {
244518678f8Sopenharmony_ci        DHCP_LOGE("failed to reset argument name.");
245518678f8Sopenharmony_ci        return RET_ERROR;
246518678f8Sopenharmony_ci    }
247518678f8Sopenharmony_ci    if (memcpy_s(arg.name, ARGUMENT_NAME_SIZE, argument, ssize) != EOK) {
248518678f8Sopenharmony_ci        DHCP_LOGE("failed to set argument name.");
249518678f8Sopenharmony_ci        return RET_ERROR;
250518678f8Sopenharmony_ci    }
251518678f8Sopenharmony_ci    if (vlen >= ARGUMENT_VALUE_SIZE) {
252518678f8Sopenharmony_ci        DHCP_LOGE("value string too long.");
253518678f8Sopenharmony_ci        return RET_ERROR;
254518678f8Sopenharmony_ci    }
255518678f8Sopenharmony_ci    if (memset_s(arg.value, ARGUMENT_VALUE_SIZE, '\0', ARGUMENT_NAME_SIZE) != EOK) {
256518678f8Sopenharmony_ci        DHCP_LOGE("failed to reset argument value.");
257518678f8Sopenharmony_ci        return RET_ERROR;
258518678f8Sopenharmony_ci    }
259518678f8Sopenharmony_ci    if (memcpy_s(arg.value, ARGUMENT_VALUE_SIZE, val, vlen) != EOK) {
260518678f8Sopenharmony_ci        DHCP_LOGE("failed to set argument value.");
261518678f8Sopenharmony_ci        return RET_ERROR;
262518678f8Sopenharmony_ci    }
263518678f8Sopenharmony_ci    g_argumentsTable[std::string(arg.name)] = arg;
264518678f8Sopenharmony_ci    return RET_SUCCESS;
265518678f8Sopenharmony_ci}
266518678f8Sopenharmony_ci
267518678f8Sopenharmony_ciint FindIndex(int c)
268518678f8Sopenharmony_ci{
269518678f8Sopenharmony_ci    int size = sizeof(g_longOptions) / sizeof(g_longOptions[0]);
270518678f8Sopenharmony_ci    for (int i = 0; i < size; ++i) {
271518678f8Sopenharmony_ci        if (g_longOptions[i].val == c) {
272518678f8Sopenharmony_ci            return i;
273518678f8Sopenharmony_ci        }
274518678f8Sopenharmony_ci    }
275518678f8Sopenharmony_ci    return -1;
276518678f8Sopenharmony_ci}
277518678f8Sopenharmony_ci
278518678f8Sopenharmony_ciint ParseArguments(const std::string& ifName, const std::string& netMask, const std::string& ipRange,
279518678f8Sopenharmony_ci    const std::string& localIp)
280518678f8Sopenharmony_ci{
281518678f8Sopenharmony_ci    DHCP_LOGI("start ParseArguments.");
282518678f8Sopenharmony_ci    PutArgument("ifname", ifName.c_str());
283518678f8Sopenharmony_ci    PutIpArgument("server", localIp.c_str());
284518678f8Sopenharmony_ci    PutIpArgument("netmask", netMask.c_str());
285518678f8Sopenharmony_ci    PutPoolArgument("pool", ipRange.c_str());
286518678f8Sopenharmony_ci    return 0;
287518678f8Sopenharmony_ci}
288518678f8Sopenharmony_ci
289518678f8Sopenharmony_civoid FreeArguments(void)
290518678f8Sopenharmony_ci{
291518678f8Sopenharmony_ci    g_argumentsTable.clear();
292518678f8Sopenharmony_ci}
293