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_config.h" 17518678f8Sopenharmony_ci#include <errno.h> 18518678f8Sopenharmony_ci#include <securec.h> 19518678f8Sopenharmony_ci#include <stdio.h> 20518678f8Sopenharmony_ci#include <stdlib.h> 21518678f8Sopenharmony_ci#include <string.h> 22518678f8Sopenharmony_ci#include <time.h> 23518678f8Sopenharmony_ci#include "address_utils.h" 24518678f8Sopenharmony_ci#include "common_util.h" 25518678f8Sopenharmony_ci#include "dhcp_server_ipv4.h" 26518678f8Sopenharmony_ci#include "dhcp_logger.h" 27518678f8Sopenharmony_ci 28518678f8Sopenharmony_ciDEFINE_DHCPLOG_DHCP_LABEL("DhcpServerConfig"); 29518678f8Sopenharmony_ci 30518678f8Sopenharmony_ci#define FILE_LINE_LEN_MAX 1024 31518678f8Sopenharmony_ci#define FILE_LINE_DELIMITER "=" 32518678f8Sopenharmony_ci 33518678f8Sopenharmony_cistatic int SetEnableConfigInfo(DhcpConfig *dhcpConfig, const char *pKey, const char *pValue) 34518678f8Sopenharmony_ci{ 35518678f8Sopenharmony_ci if ((dhcpConfig == nullptr) || (pKey == nullptr) || (pValue == nullptr)) { 36518678f8Sopenharmony_ci DHCP_LOGE("SetEnableConfigInfo param dhcpConfig or pKey or pValue is nullptr!"); 37518678f8Sopenharmony_ci return RET_FAILED; 38518678f8Sopenharmony_ci } 39518678f8Sopenharmony_ci 40518678f8Sopenharmony_ci uint32_t uValue = (uint32_t)atoi(pValue); 41518678f8Sopenharmony_ci if ((uValue != 0) && (uValue != 1)) { 42518678f8Sopenharmony_ci DHCP_LOGE("enable:%s error", pValue); 43518678f8Sopenharmony_ci return RET_FAILED; 44518678f8Sopenharmony_ci } 45518678f8Sopenharmony_ci 46518678f8Sopenharmony_ci if (strcmp(pKey, "distribution") == 0) { 47518678f8Sopenharmony_ci dhcpConfig->distribution = uValue; 48518678f8Sopenharmony_ci } else if (strcmp(pKey, "broadcast") == 0) { 49518678f8Sopenharmony_ci dhcpConfig->broadcast = uValue; 50518678f8Sopenharmony_ci } 51518678f8Sopenharmony_ci return RET_SUCCESS; 52518678f8Sopenharmony_ci} 53518678f8Sopenharmony_ci 54518678f8Sopenharmony_cistatic int SetTimeConfigInfo(DhcpConfig *dhcpConfig, const char *pKey, const char *pValue) 55518678f8Sopenharmony_ci{ 56518678f8Sopenharmony_ci if ((dhcpConfig == nullptr) || (pKey == nullptr) || (pValue == nullptr)) { 57518678f8Sopenharmony_ci DHCP_LOGE("SetTimeConfigInfo param dhcpConfig or pKey or pValue is nullptr!"); 58518678f8Sopenharmony_ci return RET_FAILED; 59518678f8Sopenharmony_ci } 60518678f8Sopenharmony_ci 61518678f8Sopenharmony_ci uint32_t uValue = 0; 62518678f8Sopenharmony_ci if ((uValue = (uint32_t)atoi(pValue)) == 0) { 63518678f8Sopenharmony_ci DHCP_LOGE("atoi failed, time:%s", pValue); 64518678f8Sopenharmony_ci return RET_FAILED; 65518678f8Sopenharmony_ci } 66518678f8Sopenharmony_ci 67518678f8Sopenharmony_ci if (strcmp(pKey, "leaseTime") == 0) { 68518678f8Sopenharmony_ci dhcpConfig->leaseTime = uValue; 69518678f8Sopenharmony_ci } else if (strcmp(pKey, "renewalTime") == 0) { 70518678f8Sopenharmony_ci dhcpConfig->renewalTime = uValue; 71518678f8Sopenharmony_ci } else if (strcmp(pKey, "rebindingTime") == 0) { 72518678f8Sopenharmony_ci dhcpConfig->rebindingTime = uValue; 73518678f8Sopenharmony_ci } 74518678f8Sopenharmony_ci return RET_SUCCESS; 75518678f8Sopenharmony_ci} 76518678f8Sopenharmony_ci 77518678f8Sopenharmony_cistatic int SetNetConfigInfo(DhcpConfig *dhcpConfig, const char *pKey, const char *pValue, int common) 78518678f8Sopenharmony_ci{ 79518678f8Sopenharmony_ci if ((dhcpConfig == nullptr) || (pKey == nullptr) || (pValue == nullptr)) { 80518678f8Sopenharmony_ci DHCP_LOGE("SetNetConfigInfo param dhcpConfig or pKey or pValue is nullptr!"); 81518678f8Sopenharmony_ci return RET_FAILED; 82518678f8Sopenharmony_ci } 83518678f8Sopenharmony_ci 84518678f8Sopenharmony_ci uint32_t uValue = 0; 85518678f8Sopenharmony_ci if ((uValue = ParseIpAddr(pValue)) == 0) { 86518678f8Sopenharmony_ci DHCP_LOGE("ParseIpAddr failed, ip:%s", pValue); 87518678f8Sopenharmony_ci return RET_FAILED; 88518678f8Sopenharmony_ci } 89518678f8Sopenharmony_ci 90518678f8Sopenharmony_ci if (((strcmp(pKey, "serverId") == 0) && common) || ((strcmp(pKey, "server") == 0) && !common)) { 91518678f8Sopenharmony_ci dhcpConfig->serverId = uValue; 92518678f8Sopenharmony_ci } else if (strcmp(pKey, "gateway") == 0) { 93518678f8Sopenharmony_ci dhcpConfig->gateway = uValue; 94518678f8Sopenharmony_ci } else if (strcmp(pKey, "netmask") == 0) { 95518678f8Sopenharmony_ci dhcpConfig->netmask = uValue; 96518678f8Sopenharmony_ci } 97518678f8Sopenharmony_ci return RET_SUCCESS; 98518678f8Sopenharmony_ci} 99518678f8Sopenharmony_ci 100518678f8Sopenharmony_cistatic int SetIpAddressPool(DhcpConfig *dhcpConfig, const char *pValue) 101518678f8Sopenharmony_ci{ 102518678f8Sopenharmony_ci if ((dhcpConfig == nullptr) || (pValue == nullptr)) { 103518678f8Sopenharmony_ci DHCP_LOGE("SetIpAddressPool param dhcpConfig or pValue is nullptr!"); 104518678f8Sopenharmony_ci return RET_FAILED; 105518678f8Sopenharmony_ci } 106518678f8Sopenharmony_ci 107518678f8Sopenharmony_ci char *pSrc = (char *)pValue; 108518678f8Sopenharmony_ci char *pSave = nullptr; 109518678f8Sopenharmony_ci char *pTok = strtok_r(pSrc, ",", &pSave); 110518678f8Sopenharmony_ci if (((pTok == nullptr) || (strlen(pTok) == 0)) || ((pSave == nullptr) || (strlen(pSave) == 0))) { 111518678f8Sopenharmony_ci DHCP_LOGE("strtok_r pTok or pSave nullptr or len is 0!"); 112518678f8Sopenharmony_ci return RET_FAILED; 113518678f8Sopenharmony_ci } 114518678f8Sopenharmony_ci 115518678f8Sopenharmony_ci uint32_t begin; 116518678f8Sopenharmony_ci if ((begin = ParseIpAddr(pTok)) == 0) { 117518678f8Sopenharmony_ci DHCP_LOGE("ParseIpAddr begin:%s failed!", pTok); 118518678f8Sopenharmony_ci return RET_FAILED; 119518678f8Sopenharmony_ci } 120518678f8Sopenharmony_ci dhcpConfig->pool.beginAddress = begin; 121518678f8Sopenharmony_ci uint32_t end; 122518678f8Sopenharmony_ci if ((end = ParseIpAddr(pSave)) == 0) { 123518678f8Sopenharmony_ci DHCP_LOGE("ParseIpAddr end:%s failed!", pSave); 124518678f8Sopenharmony_ci return RET_FAILED; 125518678f8Sopenharmony_ci } 126518678f8Sopenharmony_ci dhcpConfig->pool.endAddress = end; 127518678f8Sopenharmony_ci return RET_SUCCESS; 128518678f8Sopenharmony_ci} 129518678f8Sopenharmony_ci 130518678f8Sopenharmony_cistatic int SetDnsInfo(DhcpConfig *dhcpConfig, const char *pValue) 131518678f8Sopenharmony_ci{ 132518678f8Sopenharmony_ci if ((dhcpConfig == nullptr) || (pValue == nullptr)) { 133518678f8Sopenharmony_ci DHCP_LOGE("SetDnsInfo param dhcpConfig or pValue is nullptr!"); 134518678f8Sopenharmony_ci return RET_FAILED; 135518678f8Sopenharmony_ci } 136518678f8Sopenharmony_ci 137518678f8Sopenharmony_ci char *pSrc = (char *)pValue; 138518678f8Sopenharmony_ci char *pSave = nullptr; 139518678f8Sopenharmony_ci char *pTok = strtok_r(pSrc, ",", &pSave); 140518678f8Sopenharmony_ci if ((pTok == nullptr) || (strlen(pTok) == 0)) { 141518678f8Sopenharmony_ci DHCP_LOGE("strtok_r pTok nullptr or len is 0!"); 142518678f8Sopenharmony_ci return RET_FAILED; 143518678f8Sopenharmony_ci } 144518678f8Sopenharmony_ci 145518678f8Sopenharmony_ci DhcpOption optDns = {DOMAIN_NAME_SERVER_OPTION, 0, {0}}; 146518678f8Sopenharmony_ci if (GetOption(&dhcpConfig->options, optDns.code) != nullptr) { 147518678f8Sopenharmony_ci RemoveOption(&dhcpConfig->options, optDns.code); 148518678f8Sopenharmony_ci } 149518678f8Sopenharmony_ci 150518678f8Sopenharmony_ci uint32_t dnsAddress; 151518678f8Sopenharmony_ci while (pTok != nullptr) { 152518678f8Sopenharmony_ci if ((dnsAddress = ParseIpAddr(pTok)) == 0) { 153518678f8Sopenharmony_ci DHCP_LOGE("ParseIpAddr %s failed, code:%d", pTok, optDns.code); 154518678f8Sopenharmony_ci return RET_FAILED; 155518678f8Sopenharmony_ci } 156518678f8Sopenharmony_ci if (AppendAddressOption(&optDns, dnsAddress) != RET_SUCCESS) { 157518678f8Sopenharmony_ci DHCP_LOGW("failed append dns option."); 158518678f8Sopenharmony_ci } 159518678f8Sopenharmony_ci pTok = strtok_r(nullptr, ",", &pSave); 160518678f8Sopenharmony_ci } 161518678f8Sopenharmony_ci PushBackOption(&dhcpConfig->options, &optDns); 162518678f8Sopenharmony_ci return RET_SUCCESS; 163518678f8Sopenharmony_ci} 164518678f8Sopenharmony_ci 165518678f8Sopenharmony_cistatic int SetIfnameInfo(DhcpConfig *dhcpConfig, const char *pValue) 166518678f8Sopenharmony_ci{ 167518678f8Sopenharmony_ci if ((dhcpConfig == nullptr) || (pValue == nullptr)) { 168518678f8Sopenharmony_ci DHCP_LOGE("SetIfnameInfo dhcpConfig or pValue is nullptr!"); 169518678f8Sopenharmony_ci return RET_FAILED; 170518678f8Sopenharmony_ci } 171518678f8Sopenharmony_ci if (strlen(pValue) >= IFACE_NAME_SIZE) { 172518678f8Sopenharmony_ci DHCP_LOGE("ifname:%s too long!", pValue); 173518678f8Sopenharmony_ci return RET_FAILED; 174518678f8Sopenharmony_ci } 175518678f8Sopenharmony_ci if (memset_s(dhcpConfig->ifname, IFACE_NAME_SIZE, '\0', IFACE_NAME_SIZE) != EOK || 176518678f8Sopenharmony_ci strncpy_s(dhcpConfig->ifname, IFACE_NAME_SIZE, pValue, strlen(pValue)) != EOK) { 177518678f8Sopenharmony_ci return RET_FAILED; 178518678f8Sopenharmony_ci } 179518678f8Sopenharmony_ci return RET_SUCCESS; 180518678f8Sopenharmony_ci} 181518678f8Sopenharmony_ci 182518678f8Sopenharmony_cistatic int SetDhcpConfig(DhcpConfig *dhcpConfig, const char *strLine, int common) 183518678f8Sopenharmony_ci{ 184518678f8Sopenharmony_ci if ((strLine == nullptr) || (strlen(strLine) == 0)) { 185518678f8Sopenharmony_ci DHCP_LOGE("SetDhcpConfig param strLine is nullptr or len = 0!"); 186518678f8Sopenharmony_ci return RET_FAILED; 187518678f8Sopenharmony_ci } 188518678f8Sopenharmony_ci 189518678f8Sopenharmony_ci char *pSrc = (char *)strLine; 190518678f8Sopenharmony_ci char *pSave = nullptr; 191518678f8Sopenharmony_ci char *pTok = strtok_r(pSrc, FILE_LINE_DELIMITER, &pSave); 192518678f8Sopenharmony_ci if (pTok == nullptr) { 193518678f8Sopenharmony_ci DHCP_LOGE("strtok_r pTok nullptr!"); 194518678f8Sopenharmony_ci return RET_FAILED; 195518678f8Sopenharmony_ci } 196518678f8Sopenharmony_ci if (strcmp(pTok, "interface") == 0) { 197518678f8Sopenharmony_ci return SetIfnameInfo(dhcpConfig, pSave); 198518678f8Sopenharmony_ci } else if (strcmp(pTok, "dns") == 0) { 199518678f8Sopenharmony_ci return SetDnsInfo(dhcpConfig, pSave); 200518678f8Sopenharmony_ci } else if (strcmp(pTok, "pool") == 0) { 201518678f8Sopenharmony_ci return SetIpAddressPool(dhcpConfig, pSave); 202518678f8Sopenharmony_ci } else if ((((strcmp(pTok, "serverId") == 0) && common) || ((strcmp(pTok, "server") == 0) && !common)) || 203518678f8Sopenharmony_ci (strcmp(pTok, "gateway") == 0) || (strcmp(pTok, "netmask") == 0)) { 204518678f8Sopenharmony_ci return SetNetConfigInfo(dhcpConfig, pTok, pSave, common); 205518678f8Sopenharmony_ci } else if ((strcmp(pTok, "leaseTime") == 0) || (strcmp(pTok, "renewalTime") == 0) || 206518678f8Sopenharmony_ci (strcmp(pTok, "rebindingTime") == 0)) { 207518678f8Sopenharmony_ci return SetTimeConfigInfo(dhcpConfig, pTok, pSave); 208518678f8Sopenharmony_ci } else if ((strcmp(pTok, "distribution") == 0) || (strcmp(pTok, "broadcast") == 0)) { 209518678f8Sopenharmony_ci return SetEnableConfigInfo(dhcpConfig, pTok, pSave); 210518678f8Sopenharmony_ci } else { 211518678f8Sopenharmony_ci DHCP_LOGD("invalid key:%s", pTok); 212518678f8Sopenharmony_ci return RET_SUCCESS; 213518678f8Sopenharmony_ci } 214518678f8Sopenharmony_ci} 215518678f8Sopenharmony_ci 216518678f8Sopenharmony_cistatic int ParseConfigFile(const char *configFile, const char *ifname, DhcpConfig *dhcpConfig) 217518678f8Sopenharmony_ci{ 218518678f8Sopenharmony_ci if ((configFile == nullptr) || (strlen(configFile) == 0) || (dhcpConfig == nullptr)) { 219518678f8Sopenharmony_ci DHCP_LOGE("ParseConfigFile param configFile or dhcpConfig is nullptr or len = 0!"); 220518678f8Sopenharmony_ci return RET_FAILED; 221518678f8Sopenharmony_ci } 222518678f8Sopenharmony_ci 223518678f8Sopenharmony_ci FILE *fp = fopen(configFile, "r"); 224518678f8Sopenharmony_ci if (fp == nullptr) { 225518678f8Sopenharmony_ci DHCP_LOGE("fopen %{public}s failed, err:%{public}d", configFile, errno); 226518678f8Sopenharmony_ci return RET_FAILED; 227518678f8Sopenharmony_ci } 228518678f8Sopenharmony_ci 229518678f8Sopenharmony_ci int bComm = 1; 230518678f8Sopenharmony_ci int bValid = 1; 231518678f8Sopenharmony_ci char strLine[FILE_LINE_LEN_MAX] = {0}; 232518678f8Sopenharmony_ci while (fgets(strLine, FILE_LINE_LEN_MAX, fp) != nullptr) { 233518678f8Sopenharmony_ci DHCP_LOGI("fgets strLine = %{public}s", strLine); 234518678f8Sopenharmony_ci if ((strchr(strLine, '#') != nullptr) || (strchr(strLine, '=') == nullptr) || 235518678f8Sopenharmony_ci !RemoveSpaceCharacters(strLine, FILE_LINE_LEN_MAX)) { 236518678f8Sopenharmony_ci if (memset_s(strLine, FILE_LINE_LEN_MAX, 0, FILE_LINE_LEN_MAX) != EOK) { 237518678f8Sopenharmony_ci break; 238518678f8Sopenharmony_ci } 239518678f8Sopenharmony_ci continue; 240518678f8Sopenharmony_ci } 241518678f8Sopenharmony_ci if (memcmp(strLine, "interface", strlen("interface")) == 0) { 242518678f8Sopenharmony_ci bComm = 0; 243518678f8Sopenharmony_ci bValid = 0; 244518678f8Sopenharmony_ci if ((ifname == nullptr) || (strlen(ifname) == 0) || (strstr(strLine, ifname) != nullptr)) { 245518678f8Sopenharmony_ci DHCP_LOGI("%s %s find ifname:%s", configFile, strLine, ((ifname == nullptr) ? "" : ifname)); 246518678f8Sopenharmony_ci bValid = 1; 247518678f8Sopenharmony_ci } else { 248518678f8Sopenharmony_ci DHCP_LOGI("%s %s no find ifname:%s", configFile, strLine, ifname); 249518678f8Sopenharmony_ci } 250518678f8Sopenharmony_ci } 251518678f8Sopenharmony_ci if (bValid && SetDhcpConfig(dhcpConfig, strLine, bComm) != RET_SUCCESS) { 252518678f8Sopenharmony_ci DHCP_LOGE("set dhcp config %s %s failed", configFile, strLine); 253518678f8Sopenharmony_ci fclose(fp); 254518678f8Sopenharmony_ci return RET_FAILED; 255518678f8Sopenharmony_ci } 256518678f8Sopenharmony_ci if (memset_s(strLine, FILE_LINE_LEN_MAX, 0, FILE_LINE_LEN_MAX) != EOK) { 257518678f8Sopenharmony_ci break; 258518678f8Sopenharmony_ci } 259518678f8Sopenharmony_ci } 260518678f8Sopenharmony_ci if (fclose(fp) != 0) { 261518678f8Sopenharmony_ci DHCP_LOGE("ParseConfigFile fclose fp failed!"); 262518678f8Sopenharmony_ci } 263518678f8Sopenharmony_ci return RET_SUCCESS; 264518678f8Sopenharmony_ci} 265518678f8Sopenharmony_ci 266518678f8Sopenharmony_cistatic int CheckDhcpConfig(DhcpConfig *config) 267518678f8Sopenharmony_ci{ 268518678f8Sopenharmony_ci if (config == nullptr) { 269518678f8Sopenharmony_ci DHCP_LOGE("CheckDhcpConfig param config is null"); 270518678f8Sopenharmony_ci return DHCP_FALSE; 271518678f8Sopenharmony_ci } 272518678f8Sopenharmony_ci if ((strlen(config->ifname) > 0) && ((config->serverId == 0))) { 273518678f8Sopenharmony_ci DHCP_LOGE("failed to config serverId or netmask"); 274518678f8Sopenharmony_ci return DHCP_FALSE; 275518678f8Sopenharmony_ci } 276518678f8Sopenharmony_ci 277518678f8Sopenharmony_ci if (config->renewalTime == 0) { 278518678f8Sopenharmony_ci config->renewalTime = config->leaseTime * DHCP_RENEWAL_MULTIPLE; 279518678f8Sopenharmony_ci } 280518678f8Sopenharmony_ci if (config->rebindingTime == 0) { 281518678f8Sopenharmony_ci config->rebindingTime = config->leaseTime * DHCP_REBIND_MULTIPLE; 282518678f8Sopenharmony_ci } 283518678f8Sopenharmony_ci return DHCP_TRUE; 284518678f8Sopenharmony_ci} 285518678f8Sopenharmony_ci 286518678f8Sopenharmony_ciint LoadConfig(const char *configFile, const char *ifname, DhcpConfig *config) 287518678f8Sopenharmony_ci{ 288518678f8Sopenharmony_ci if ((configFile == nullptr) || (strlen(configFile) == 0) || (ifname == nullptr) || (strlen(ifname) == 0) || 289518678f8Sopenharmony_ci (config == nullptr)) { 290518678f8Sopenharmony_ci DHCP_LOGE("LoadConfig param configFile or ifname or config is nullptr or len = 0!"); 291518678f8Sopenharmony_ci return RET_FAILED; 292518678f8Sopenharmony_ci } 293518678f8Sopenharmony_ci 294518678f8Sopenharmony_ci /* Default config. */ 295518678f8Sopenharmony_ci config->leaseTime = DHCP_LEASE_TIME; 296518678f8Sopenharmony_ci config->distribution = 1; 297518678f8Sopenharmony_ci config->broadcast = 1; 298518678f8Sopenharmony_ci 299518678f8Sopenharmony_ci /* Set file config. */ 300518678f8Sopenharmony_ci if (ParseConfigFile(configFile, ifname, config) != RET_SUCCESS) { 301518678f8Sopenharmony_ci DHCP_LOGE("parse config file %{public}s error!", configFile); 302518678f8Sopenharmony_ci return RET_FAILED; 303518678f8Sopenharmony_ci } 304518678f8Sopenharmony_ci DHCP_LOGI("parse config file %{public}s success", configFile); 305518678f8Sopenharmony_ci 306518678f8Sopenharmony_ci if (!CheckDhcpConfig(config)) { 307518678f8Sopenharmony_ci DHCP_LOGE("check dhcp config failed"); 308518678f8Sopenharmony_ci return RET_FAILED; 309518678f8Sopenharmony_ci } 310518678f8Sopenharmony_ci 311518678f8Sopenharmony_ci if ((strlen(config->ifname) == 0) && SetIfnameInfo(config, ifname) != RET_SUCCESS) { 312518678f8Sopenharmony_ci DHCP_LOGE("set ifname %s error!", ifname); 313518678f8Sopenharmony_ci return RET_FAILED; 314518678f8Sopenharmony_ci } 315518678f8Sopenharmony_ci return RET_SUCCESS; 316518678f8Sopenharmony_ci} 317