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_binding.h"
17 #include <securec.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include "address_utils.h"
23 #include "common_util.h"
24 #include "dhcp_s_define.h"
25 #include "dhcp_logger.h"
26 
27 DEFINE_DHCPLOG_DHCP_LABEL("DhcpServerBinding");
28 
29 #define PENDING_INTERVAL_MAX_TIME 1200
30 #define PENDING_INTERVAL_LEVEL0 3
31 #define PENDING_INTERVAL_LEVEL1 10
32 #define PENDING_INTERVAL_LEVEL2 30
33 #define PENDING_MIN_WAITING_TIMES 1
34 #define PENDING_INTERVAL_LEVEL1_TIMES 2
35 #define PENDING_INTERVAL_LEVEL2_TIMES 5
36 
NextPendingInterval(uint64_t pendingInterval)37 uint64_t NextPendingInterval(uint64_t pendingInterval)
38 {
39     uint64_t next = pendingInterval;
40     if (next < PENDING_INTERVAL_LEVEL0) {
41         next += PENDING_MIN_WAITING_TIMES;
42     } else if (next < PENDING_INTERVAL_LEVEL1) {
43         next += PENDING_INTERVAL_LEVEL1_TIMES;
44     } else if (next < PENDING_INTERVAL_LEVEL2) {
45         next += PENDING_INTERVAL_LEVEL2_TIMES;
46     } else {
47         next = PENDING_INTERVAL_MAX_TIME;
48     }
49     return next;
50 }
51 
IsExpire(AddressBinding * binding)52 int IsExpire(AddressBinding *binding)
53 {
54     if (!binding) {
55         DHCP_LOGE("binding is null.");
56         return DHCP_FALSE;
57     }
58     uint64_t leaseTime = binding->leaseTime;
59     if (!leaseTime) {
60         leaseTime = DHCP_LEASE_TIME;
61     }
62     uint64_t expireIn = binding->expireIn;
63     if (binding->bindingStatus == BIND_PENDING) {
64         expireIn = binding->pendingTime + leaseTime;
65     } else if (binding->bindingStatus == BIND_ASSOCIATED) {
66         expireIn = binding->bindingTime + leaseTime;
67     }
68     uint64_t curr = Tmspsec();
69     if (curr > expireIn) {
70         binding->bindingStatus = BIND_EXPIRED;
71         return DHCP_TRUE;
72     }
73     return DHCP_FALSE;
74 }
75 
76 #define BINDING_MAC_ADDR_POS 0
77 #define BINDING_IP_ADDR_POS 1
78 #define BINDING_LEASE_TIME_POS 2
79 #define BINDING_BINDING_TIME_POS 3
80 #define BINDING_PENDING_TIME_POS 4
81 #define BINDING_PENDING_INTERVAL_POS 5
82 #define BINDING_BINDING_MODE_POS 6
83 #define BINDING_BINDING_STATUS_POS 7
84 #define BINDING_DEVICE_NAME_POS 8
85 #define BINDING_STRING_SIZE 8
86 #define BINDING_STRING_MAX_SIZE 9
87 
WriteAddressBinding(const AddressBinding * binding,char * out,uint32_t size)88 int WriteAddressBinding(const AddressBinding *binding, char *out, uint32_t size)
89 {
90     if (!binding || !out) {
91         return RET_FAILED;
92     }
93     const char *mac = ParseStrMac(binding->chaddr, sizeof(binding->chaddr));
94     const char *ip = ParseStrIp(binding->ipAddress);
95     if (mac == nullptr || ip == nullptr) {
96         return RET_FAILED;
97     }
98     if (snprintf_s(out, size, size - 1, "%s %s %llu %llu %llu %llu %d %d %s", mac, ip, binding->leaseTime,
99         binding->bindingTime, binding->pendingTime, binding->pendingInterval, binding->bindingMode,
100         binding->bindingStatus, binding->deviceName) < 0) {
101         return RET_FAILED;
102     }
103     return RET_SUCCESS;
104 }
105 
ReleaseStrings(char ** strs)106 static void ReleaseStrings(char **strs)
107 {
108     if (strs == nullptr) {
109         return;
110     }
111     int i = 0;
112     while (strs[i] != nullptr) {
113         free(strs[i]);
114         strs[i] = nullptr;
115         ++i;
116     }
117     free(strs);
118     strs = nullptr;
119     return;
120 }
121 
SplitString(const char * buf,const char * split)122 static char **SplitString(const char *buf, const char *split)
123 {
124     const char *pos = buf;
125     const char *p = nullptr;
126     size_t len = strlen(split);
127     int num = 0;
128     while ((p = strstr(pos, split)) != nullptr) {
129         if (p != pos) {
130             ++num;
131         }
132         pos = p + len;
133     }
134     if (*pos != '\0') {
135         ++num;
136     }
137     if (num == 0) {
138         return nullptr;
139     }
140     char **strs = (char **)calloc(num + 1, sizeof(char *));
141     if (strs == nullptr) {
142         return nullptr;
143     }
144     pos = buf;
145     num = 0;
146     while ((p = strstr(pos, split)) != nullptr) {
147         if (p != pos) {
148             size_t strLen = p - pos + 1;
149             strs[num] = (char *)calloc(strLen, sizeof(char));
150             if (strs[num] == nullptr || strncpy_s(strs[num], strLen, pos, p - pos) != EOK) {
151                 ReleaseStrings(strs);
152                 return nullptr;
153             }
154             ++num;
155         }
156         pos = p + len;
157     }
158     if (*pos != '\0') {
159         size_t strLen = strlen(pos) + 1;
160         strs[num] = (char *)calloc(strLen, sizeof(char));
161         if (strs[num] == nullptr || strncpy_s(strs[num], strLen, pos, strlen(pos)) != EOK) {
162             ReleaseStrings(strs);
163             return nullptr;
164         }
165     }
166     return strs;
167 }
168 
ParseAddressBinding(AddressBinding * binding,const char * buf)169 int ParseAddressBinding(AddressBinding *binding, const char *buf)
170 {
171     uint64_t curr = Tmspsec();
172     char **strs = SplitString(buf, " ");
173     if (strs == nullptr) {
174         return -1;
175     }
176     int num = 0;
177     while (strs[num] != nullptr) {
178         ++num;
179     }
180     int ret = -1;
181     do {
182         if (num < BINDING_STRING_SIZE) {
183             break;
184         }
185         ParseMacAddress(strs[BINDING_MAC_ADDR_POS], binding->chaddr);
186         binding->ipAddress = ParseIpAddr(strs[BINDING_IP_ADDR_POS]);
187         binding->leaseTime = atol(strs[BINDING_LEASE_TIME_POS]);
188         binding->bindingTime = atol(strs[BINDING_BINDING_TIME_POS]);
189         binding->pendingTime = atol(strs[BINDING_PENDING_TIME_POS]);
190         if (binding->bindingTime && binding->bindingTime < binding->pendingTime) {
191             break;
192         }
193         if (binding->pendingTime > curr) { /* if pending time over than current system time */
194             binding->bindingTime = binding->bindingTime - binding->pendingTime + curr;
195             binding->pendingTime = curr;
196         }
197         binding->pendingInterval = atol(strs[BINDING_PENDING_INTERVAL_POS]);
198         binding->bindingMode = atoi(strs[BINDING_BINDING_MODE_POS]);
199         binding->bindingStatus = atoi(strs[BINDING_BINDING_STATUS_POS]);
200         if (binding->bindingStatus == BIND_ASSOCIATED) {
201             binding->expireIn = binding->bindingTime + binding->leaseTime;
202         }
203         if (num >= BINDING_STRING_MAX_SIZE) {
204             ParseHostName(strs[BINDING_DEVICE_NAME_POS], binding->deviceName);
205             DHCP_LOGI("ParseHostName deviceName:%{public}s", binding->deviceName);
206         }
207         ret += 1; /* set ret = 0 */
208     } while (0);
209     ReleaseStrings(strs);
210     return ret;
211 }
212