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_s_server.h"
17 #include <arpa/inet.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <net/if.h>
21 #include <netinet/in.h>
22 #include <securec.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/select.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <pthread.h>
33 #include "address_utils.h"
34 #include "common_util.h"
35 #include "dhcp_address_pool.h"
36 #include "dhcp_binding.h"
37 #include "dhcp_config.h"
38 #include "dhcp_server_ipv4.h"
39 #include "dhcp_logger.h"
40 #include "dhcp_option.h"
41 #include "dhcp_common_utils.h"
42 
43 DEFINE_DHCPLOG_DHCP_LABEL("DhcpServer");
44 
45 #ifndef DHCP_SEL_WAIT_TIMEOUTS
46 #define DHCP_SEL_WAIT_TIMEOUTS 1000
47 #endif
48 #define OPT_MESSAGE_TYPE_LEGTH 1
49 #define OPT_HEADER_LENGTH 2
50 #define OPT_TIME_LENGTH 4
51 #define OPT_TYPE_FIELD_LENGTH 1
52 #define OPT_MAC_ADDR_LENGTH 6
53 #define MAGIC_COOKIE_LENGTH 4
54 #define OPT_BROADCAST_FLAG_ENABLE 0
55 #define OFFER_MIN_INTERVAL_TIME 5
56 
57 #define PENDING_DEFAULT_TIMEOUT 1200
58 #define PENDING_DEFAULT_INTERVAL 1
59 #define PENDING_INTERVAL_CHECKING_ENABLE 1
60 #define DHCP_MAGIC_COOKIE 0x63825363
61 #define RECV_BUFFER_SIZE 2048
62 #define ALLOW_NOBINDING_REQUEST 1
63 #define REUSE_ADDRESS_ENABLE 1
64 #define WAIT_STOPED_TIME 5
65 #define DHCP_SERVER_SLEEP_TIMEOUTS 600000  // 600ms
66 
67 #define VNEDOR_OPEN_HARMONY "OPEN_HARMONY"
68 
69 const uint8_t MAGIC_COOKIE_DATA[MAGIC_COOKIE_LENGTH] = {0x63, 0x82, 0x53, 0x63};  // Vendor Information "Magic Cookie"
70 
71 enum AssignedNumbers {
72     ETHERNET = 1,               // Ethernet (10Mb)
73     EXPERIMENTAL_ETHERNET,      // Experimental Ethernet (3Mb)
74     AMATEUR_RADIO_AX_25,        // Amateur Radio AX.25
75     PROTEON_PRONET_TOKEN_RING,  // Proteon ProNET Token Ring
76     CHAOS,
77     IEEE802_NETWORKS,
78     ARCNET,
79     HYPERCHANNEL,
80     LANSTAR
81 };
82 
83 struct ServerContext {
84     int broadCastFlagEnable;
85     DhcpAddressPool addressPool;
86     DhcpServerCallback callback;
87     DeviceConnectFun deviceConnectFun;
88     DhcpConfig config;
89     int serverFd;
90     int looperState;
91     int initialized;
92 };
93 
94 enum LooperState {
95     LS_IDLE = 0,
96     LS_STARING,
97     LS_RUNNING,
98     LS_RELOADNG,
99     LS_STOPING,
100     LS_STOPED
101 };
102 typedef struct sockaddr_in sockaddr_in;
103 int FillReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
104 static int OnReceivedDiscover(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
105 static int OnReceivedRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
106 static int OnReceivedDecline(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
107 static int OnReceivedRelease(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
108 static int OnReceivedInform(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
109 static int SendDhcpOffer(PDhcpServerContext ctx, PDhcpMsgInfo reply);
110 static int SendDhcpAck(PDhcpServerContext ctx, PDhcpMsgInfo reply);
111 static int SendDhcpNak(PDhcpServerContext ctx, PDhcpMsgInfo reply);
112 static int ParseMessageOptions(PDhcpMsgInfo msg);
113 
114 static int ParseReplyOptions(PDhcpMsgInfo reply);
115 struct sockaddr_in *BroadcastAddrIn(void);
116 
GetServerInstance(const DhcpServerContext *ctx)117 static struct ServerContext *GetServerInstance(const DhcpServerContext *ctx)
118 {
119     if (!ctx || !ctx->instance) {
120         return nullptr;
121     }
122     return (struct ServerContext *)ctx->instance;
123 }
124 
HasFixSocket(int fd)125 int HasFixSocket(int fd)
126 {
127     int flags;
128     if ((flags = fcntl(fd, F_GETFL)) == -1 || fcntl(fd, F_SETFL, static_cast<unsigned int>(flags) | O_NONBLOCK) == -1) {
129         return DHCP_FALSE;
130     }
131     return DHCP_TRUE;
132 }
133 
134 typedef struct ifreq ifreq;
135 typedef struct sockaddr sockaddr;
136 
BindNetInterface(int fd, const char *ifname)137 int BindNetInterface(int fd, const char *ifname)
138 {
139     DHCP_LOGI("start %{public}s %{public}d   ifname = %{public}s ", __func__, __LINE__, ifname);
140     if (!fd || !ifname) {
141         return RET_FAILED;
142     }
143     ifreq iface;
144     if (memset_s(&iface, sizeof(iface), 0, sizeof(iface)) != EOK) {
145         return RET_FAILED;
146     }
147     ssize_t ifnameSize = strlen(ifname);
148     if (strncpy_s(iface.ifr_ifrn.ifrn_name, sizeof(iface.ifr_ifrn.ifrn_name), ifname, ifnameSize) != EOK) {
149         DHCP_LOGE("start %{public}s %{public}d   copy failed ", __func__, __LINE__);
150         return RET_FAILED;
151     };
152     if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&iface, sizeof(iface)) == -1) {
153         DHCP_LOGE("failed to bind network device interface[%s].", ifname);
154         return RET_FAILED;
155     }
156     DHCP_LOGI("start %{public}s %{public}d   success ", __func__, __LINE__);
157     return RET_SUCCESS;
158 }
159 
InitServer(const char *ifname)160 int InitServer(const char *ifname)
161 {
162     DHCP_LOGI("start %{public}s %{public}d   ifname = %{public}s ", __func__, __LINE__, ifname);
163     sockaddr_in srvAddrIn = {0};
164     int optval = 1;
165     int optrval = 0;
166     srvAddrIn.sin_family = AF_INET;
167     srvAddrIn.sin_port = htons(DHCP_SERVER_PORT);
168     srvAddrIn.sin_addr.s_addr = INADDR_ANY;
169     int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
170     if (fd == -1) {
171         DHCP_LOGE("failed to create server socket!");
172         return -1;
173     }
174     if (!HasFixSocket(fd)) {
175         DHCP_LOGD("failed to fcntl O_NONBLOCK flag!");
176     }
177     if (BindNetInterface(fd, ifname) != RET_SUCCESS) {
178         close(fd);
179         return -1;
180     }
181     socklen_t optlen = sizeof(optrval);
182     if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&optrval, &optlen) == -1) {
183         DHCP_LOGI("failed to receive buffer size.");
184     } else {
185         DHCP_LOGI("receive buffer size is %d", optrval);
186     }
187     if (REUSE_ADDRESS_ENABLE && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) {
188         DHCP_LOGW("failed to setsockopt 'SO_REUSEADDR' for server socket!");
189     }
190     if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) {
191         DHCP_LOGE("failed to setsockopt 'SO_BROADCAST' for server socket!");
192         close(fd);
193         return -1;
194     }
195     if (int ret = bind(fd, (sockaddr *)&srvAddrIn, sizeof(sockaddr)) == -1) {
196         DHCP_LOGE("failed to bind server  %{public}d!", ret);
197         close(fd);
198         return -1;
199     }
200     DHCP_LOGI("start %{public}s %{public}d   SUCCESSs ", __func__, __LINE__);
201     return fd;
202 }
203 
BroadcastAddrIn(void)204 struct sockaddr_in *BroadcastAddrIn(void)
205 {
206     static struct sockaddr_in broadcastAddrIn = {0};
207     if (broadcastAddrIn.sin_port == 0) {
208         broadcastAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
209         broadcastAddrIn.sin_family = AF_INET;
210         broadcastAddrIn.sin_addr.s_addr = INADDR_BROADCAST;
211     }
212     return &broadcastAddrIn;
213 }
214 
SourceAddrIn(void)215 struct sockaddr_in *SourceAddrIn(void)
216 {
217     static struct sockaddr_in sourceAddrIn = {0};
218     sourceAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
219     sourceAddrIn.sin_family = AF_INET;
220     sourceAddrIn.sin_addr.s_addr = INADDR_ANY;
221     return &sourceAddrIn;
222 }
223 
ResetSourceAddr(void)224 struct sockaddr_in *ResetSourceAddr(void)
225 {
226     DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
227     struct sockaddr_in *srcAddr = SourceAddrIn();
228     srcAddr->sin_port = htons(DHCP_CLIENT_PORT);
229     srcAddr->sin_family = AF_INET;
230     srcAddr->sin_addr.s_addr = INADDR_ANY;
231     return srcAddr;
232 }
233 
SourceIpAddress(void)234 uint32_t SourceIpAddress(void)
235 {
236     uint32_t srcIp = SourceAddrIn()->sin_addr.s_addr;
237     return srcIp;
238 }
DestinationAddrIn(void)239 struct sockaddr_in *DestinationAddrIn(void)
240 {
241     static struct sockaddr_in destAddrIn = {0};
242     if (destAddrIn.sin_port == 0) {
243         destAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
244         destAddrIn.sin_family = AF_INET;
245     }
246     return &destAddrIn;
247 }
248 
DestinationAddr(uint32_t ipAddress)249 struct sockaddr_in *DestinationAddr(uint32_t ipAddress)
250 {
251     struct sockaddr_in *destAddr = DestinationAddrIn();
252     destAddr->sin_addr.s_addr = htonl(ipAddress);
253     return destAddr;
254 }
255 
ReceiveDhcpMessage(int sock, PDhcpMsgInfo msgInfo)256 int ReceiveDhcpMessage(int sock, PDhcpMsgInfo msgInfo)
257 {
258     static uint8_t recvBuffer[RECV_BUFFER_SIZE] = {0};
259     struct timeval tmt;
260     fd_set recvFd;
261     FD_ZERO(&recvFd);
262     FD_SET(sock, &recvFd);
263     tmt.tv_sec = 0;
264     tmt.tv_usec = DHCP_SERVER_SLEEP_TIMEOUTS; // 600ms
265     int ret = select(sock + 1, &recvFd, nullptr, nullptr, &tmt);
266     if (ret < 0) {
267         DHCP_LOGE("select error, %d", errno);
268         return ERR_SELECT;
269     }
270     if (ret == 0) {
271         return RET_SELECT_TIME_OUT;
272     }
273     if (!FD_ISSET(sock, &recvFd)) {
274         DHCP_LOGE("failed to select isset.");
275         return RET_ERROR;
276     }
277     socklen_t ssize = sizeof(sockaddr_in);
278     struct sockaddr_in *srcAddrIn = ResetSourceAddr();
279     srcAddrIn->sin_addr.s_addr = INADDR_ANY;
280     DHCP_LOGI("start recv from");
281     int rsize = recvfrom(sock, recvBuffer, RECV_BUFFER_SIZE, 0, (struct sockaddr *)srcAddrIn, (socklen_t *)&ssize);
282     if (!rsize) {
283         DHCP_LOGE("receive error, %d", errno);
284         return RET_FAILED;
285     }
286     if (rsize > (int)sizeof(DhcpMessage) || rsize < DHCP_MSG_HEADER_SIZE) {
287         DHCP_LOGW("message length error, received %d bytes.", rsize);
288         return RET_FAILED;
289     }
290     DHCP_LOGI("recv over");
291     msgInfo->length = rsize;
292     if (memcpy_s(&msgInfo->packet, sizeof(DhcpMessage), recvBuffer, rsize) != EOK) {
293         return RET_FAILED;
294     }
295     if (msgInfo->packet.op != BOOTREQUEST) {
296         DHCP_LOGW("dhcp message type error!");
297         return RET_FAILED;
298     }
299     if (msgInfo->packet.hlen > DHCP_HWADDR_LENGTH) {
300         DHCP_LOGW("hlen error!");
301         return RET_FAILED;
302     }
303     if (IsEmptyHWAddr(msgInfo->packet.chaddr)) {
304         DHCP_LOGW("client hardware address error!");
305         return RET_FAILED;
306     }
307     if (IsReserved(msgInfo->packet.chaddr)) {
308         DHCP_LOGD("ignore client, %s", ParseLogMac(msgInfo->packet.chaddr));
309         return RET_FAILED;
310     }
311     DHCP_LOGI("start %{public}s %{public}d  return success", __func__, __LINE__);
312     return RET_SUCCESS;
313 }
314 
InitReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)315 void InitReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
316 {
317     DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
318     if (!reply) {
319         DHCP_LOGE("reply message pointer is null!");
320         return;
321     }
322     reply->packet.op = BOOTREPLY;
323     reply->packet.htype = ETHERNET;
324     reply->packet.hlen = OPT_MAC_ADDR_LENGTH;
325     reply->packet.secs = 0;
326     reply->packet.ciaddr = 0;
327     if (memset_s(reply->packet.sname, sizeof(reply->packet.sname), '\0', sizeof(reply->packet.sname)) != EOK) {
328         DHCP_LOGE("failed to reset message packet[sname]!");
329         return;
330     };
331     if (memset_s(reply->packet.file, sizeof(reply->packet.file), '\0', sizeof(reply->packet.file)) != EOK) {
332         DHCP_LOGE("failed to reset message packet[file]!");
333         return;
334     }
335 
336     if (FillReply(ctx, received, reply) != RET_SUCCESS) {
337         DHCP_LOGW("failed to fill reply message.");
338     }
339 }
340 
OnUpdateServerConfig(PDhcpServerContext ctx)341 void OnUpdateServerConfig(PDhcpServerContext ctx)
342 {
343     DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
344     ServerContext *srvIns = GetServerInstance(ctx);
345     if (!srvIns) {
346         DHCP_LOGE("dhcp server context pointer is null.");
347         return;
348     }
349     if (srvIns->callback) {
350         srvIns->callback(ST_RELOADNG, 0, ctx->ifname);
351     }
352 }
353 
OnServerStoping(PDhcpServerContext ctx)354 static void OnServerStoping(PDhcpServerContext ctx)
355 {
356     DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
357     ServerContext *srvIns = GetServerInstance(ctx);
358     if (!srvIns) {
359         DHCP_LOGE("dhcp server context pointer is null.");
360         return;
361     }
362     if (srvIns->callback) {
363         srvIns->callback(ST_STOPING, 0, ctx->ifname);
364     }
365 }
366 
OnServerStoped(PDhcpServerContext ctx, int code)367 void OnServerStoped(PDhcpServerContext ctx, int code)
368 {
369     DHCP_LOGI("OnServerStoped.");
370     ServerContext *srvIns = GetServerInstance(ctx);
371     if (!srvIns) {
372         DHCP_LOGE("dhcp server context pointer is null.");
373         return;
374     }
375     if (srvIns->callback) {
376         srvIns->callback(ST_STOPED, code, ctx->ifname);
377     }
378 }
379 
SendDhcpReply(PDhcpServerContext ctx, int replyType, PDhcpMsgInfo reply)380 int SendDhcpReply(PDhcpServerContext ctx, int replyType, PDhcpMsgInfo reply)
381 {
382     if (!reply) {
383         DHCP_LOGE("reply message pointer is null.");
384         return RET_FAILED;
385     }
386     int sendRet = -1;
387     ServerContext *srvIns = GetServerInstance(ctx);
388     if (!srvIns) {
389         DHCP_LOGE("dhcp server context pointer is null.");
390         return RET_FAILED;
391     }
392     switch (replyType) {
393         case REPLY_OFFER:
394             DHCP_LOGD("<== send reply dhcp offer.");
395             sendRet = SendDhcpOffer(ctx, reply);
396             break;
397         case REPLY_ACK:
398             DHCP_LOGD("<== send reply dhcp ack.");
399             sendRet = SendDhcpAck(ctx, reply);
400             break;
401         case REPLY_NAK:
402             DHCP_LOGD("<== send reply dhcp nak.");
403             sendRet = SendDhcpNak(ctx, reply);
404             break;
405         default:
406             break;
407     }
408     if (replyType && sendRet != RET_SUCCESS) {
409         return RET_FAILED;
410     }
411     return  RET_SUCCESS;
412 }
413 
MessageProcess(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)414 static int MessageProcess(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
415 {
416     DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
417     int replyType = REPLY_NONE;
418     if (!received) {
419         return replyType;
420     }
421     PDhcpOption opt = GetOption(&received->options, DHCP_MESSAGE_TYPE_OPTION);
422     if (!opt) {
423         DHCP_LOGE("error dhcp message, missing required message type option.");
424         return replyType;
425     }
426     uint8_t messageType = opt->data[0];
427     switch (messageType) {
428         case DHCPDISCOVER: {
429             DHCP_LOGD("==> Received DHCPDISCOVER message.");
430             replyType = OnReceivedDiscover(ctx, received, reply);
431             break;
432         }
433         case DHCPREQUEST: {
434             DHCP_LOGD("==> Received DHCPREQUEST message.");
435             replyType = OnReceivedRequest(ctx, received, reply);
436             break;
437         }
438         case DHCPDECLINE: {
439             DHCP_LOGD("==> Received DHCPDECLINE message.");
440             replyType = OnReceivedDecline(ctx, received, reply);
441             break;
442         }
443         case DHCPRELEASE: {
444             DHCP_LOGD("==> Received DHCPRELEASE message.");
445             replyType = OnReceivedRelease(ctx, received, reply);
446             break;
447         }
448         case DHCPINFORM: {
449             DHCP_LOGD("==> Received DHCPINFORM message.");
450             replyType = OnReceivedInform(ctx, received, reply);
451             break;
452         }
453         default:
454             break;
455     }
456     return replyType;
457 }
458 
SaveLease(PDhcpServerContext ctx)459 int SaveLease(PDhcpServerContext ctx)
460 {
461     ServerContext *srvIns = GetServerInstance(ctx);
462     if (!srvIns) {
463         DHCP_LOGE("dhcp server context pointer is null.");
464         return RET_FAILED;
465     }
466     int saveRet = SaveBindingRecoders(&srvIns->addressPool, 1);
467     if (saveRet == RET_FAILED) {
468         DHCP_LOGD("failed to save lease recoders. total: %zu", srvIns->addressPool.leaseTable.size());
469     } else if (saveRet == RET_SUCCESS) {
470         DHCP_LOGD("lease recoders saved.");
471     }
472     return saveRet;
473 }
474 
OnLooperStateChanged(PDhcpServerContext ctx)475 static int OnLooperStateChanged(PDhcpServerContext ctx)
476 {
477     ServerContext *srvIns = GetServerInstance(ctx);
478     if (!srvIns) {
479         DHCP_LOGE("dhcp server context pointer is null.");
480         return RET_FAILED;
481     }
482 
483     if (srvIns->looperState == LS_RELOADNG) {
484         OnUpdateServerConfig(ctx);
485         srvIns->looperState = LS_RUNNING;
486     } else if (srvIns->looperState == LS_STOPING) {
487         OnServerStoping(ctx);
488         return RET_BREAK;
489     }
490     return RET_SUCCESS;
491 }
492 
ContinueReceive(PDhcpMsgInfo from, int recvRet)493 static int ContinueReceive(PDhcpMsgInfo from, int recvRet)
494 {
495     if (!from) {
496         return DHCP_TRUE;
497     }
498     if (recvRet != RET_SUCCESS) {
499         return DHCP_TRUE;
500     }
501     DHCP_LOGD("received, length:%{public}d", from->length);
502     if (ParseMessageOptions(from) != 0) {
503         DHCP_LOGE("invalid dhcp message.");
504         return DHCP_TRUE;
505     }
506     if (!GetOption(&from->options, DHCP_MESSAGE_TYPE_OPTION)) {
507         DHCP_LOGW("can't found 'message type' option.");
508         return DHCP_TRUE;
509     }
510     return DHCP_FALSE;
511 }
512 
BeginLooper(void *argc)513 static void *BeginLooper(void *argc) __attribute__((no_sanitize("cfi")))
514 {
515     PDhcpServerContext ctx = (PDhcpServerContext)argc;
516     DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
517     DhcpMsgInfo from;
518     DhcpMsgInfo reply;
519     ServerContext *srvIns = GetServerInstance(ctx);
520     if (!srvIns) {
521         DHCP_LOGE("dhcp server context pointer is null.");
522         return nullptr;
523     }
524     ctx->instance->serverFd = InitServer(ctx->ifname);
525     if (ctx->instance->serverFd < 0) {
526         DHCP_LOGE("failed to initialize server socket.");
527         return nullptr;
528     }
529     InitOptionList(&from.options);
530     InitOptionList(&reply.options);
531     srvIns->looperState = LS_RUNNING;
532     while (srvIns->looperState) {
533         if (OnLooperStateChanged(ctx) != RET_SUCCESS) {
534             DHCP_LOGI("OnLooperStateChanged break, looperState:%{public}d", srvIns->looperState);
535             break;
536         }
537         ClearOptions(&from.options);
538         ClearOptions(&reply.options);
539         int recvRet = ReceiveDhcpMessage(ctx->instance->serverFd, &from);
540         if (recvRet == RET_ERROR || recvRet == ERR_SELECT) {
541             DHCP_LOGI("ReceiveDhcpMessage");
542             continue;
543         }
544         if (ContinueReceive(&from, recvRet)) {
545             continue;
546         }
547         InitReply(ctx, &from, &reply);
548         int replyType = MessageProcess(ctx, &from, &reply);
549         if (replyType && SendDhcpReply(ctx, replyType, &reply) != RET_SUCCESS) {
550             DHCP_LOGE("failed to send reply message.");
551         }
552         NotifyConnetDeviceChanged(replyType, ctx);
553     }
554     FreeOptionList(&from.options);
555     FreeOptionList(&reply.options);
556     DHCP_LOGI("dhcp server message looper stopped.");
557     close(ctx->instance->serverFd);
558     ctx->instance->serverFd = -1;
559     srvIns->looperState = LS_STOPED;
560     return nullptr;
561 }
562 
NotifyConnetDeviceChanged(int replyType, PDhcpServerContext ctx)563 void NotifyConnetDeviceChanged(int replyType, PDhcpServerContext ctx)
564 {
565     DHCP_LOGI("NotifyConnetDeviceChanged replyType:%{public}d", replyType);
566     if (replyType == REPLY_ACK || replyType == REPLY_OFFER) {
567         ServerContext *srvIns = GetServerInstance(ctx);
568         if (srvIns == nullptr) {
569             DHCP_LOGE("NotifyConnetDeviceChanged srvIns is nullptr");
570             return;
571         }
572         int saveRet = SaveBindingRecoders(&srvIns->addressPool, 1);
573         if (saveRet != RET_SUCCESS && saveRet != RET_WAIT_SAVE) {
574             DHCP_LOGW("SaveBindingRecoders failed to save lease recoders.");
575         }
576         if (replyType == REPLY_ACK && srvIns->deviceConnectFun != nullptr) {
577             DHCP_LOGI("NotifyConnetDeviceChanged deviceConnectFun");
578             srvIns->deviceConnectFun(ctx->ifname);
579         }
580     }
581 }
582 
CheckAddressRange(DhcpAddressPool *pool)583 static int CheckAddressRange(DhcpAddressPool *pool)
584 {
585     uint32_t serverNetwork = NetworkAddress(pool->serverId, pool->netmask);
586     uint32_t firstNetwork = NetworkAddress(pool->addressRange.beginAddress, pool->netmask);
587     uint32_t secondNetwork = NetworkAddress(pool->addressRange.endAddress, pool->netmask);
588     if (!serverNetwork || !firstNetwork || !secondNetwork) {
589         DHCP_LOGE("network config error.");
590         return DHCP_FALSE;
591     }
592     if (serverNetwork != firstNetwork || serverNetwork != secondNetwork) {
593         DHCP_LOGE("server network and address pool network belong to different networks.");
594         return DHCP_FALSE;
595     }
596     return DHCP_TRUE;
597 }
598 
InitBindingRecoders(DhcpAddressPool *pool)599 void InitBindingRecoders(DhcpAddressPool *pool)
600 {
601     if (!pool) {
602         DHCP_LOGE("address pool pointer is null.");
603         return;
604     }
605     uint32_t realLeaseTotal = 0;
606     for (auto current: pool->leaseTable) {
607         int invalidBindig;
608         AddressBinding *binding = &current.second;
609         if (binding && !IsEmptyHWAddr(binding->chaddr) && binding->ipAddress) {
610             AddBinding(binding);
611             realLeaseTotal++;
612             invalidBindig = 0;
613         } else {
614             DHCP_LOGE("bad binding recoder.");
615             invalidBindig = 1;
616         }
617         if (!invalidBindig && binding && pool->distribution < binding->ipAddress) {
618             pool->distribution = binding->ipAddress;
619         }
620     }
621     DHCP_LOGD("lease recoder total: %u", realLeaseTotal);
622 }
623 
InitLeaseFile(DhcpAddressPool *pool)624 void InitLeaseFile(DhcpAddressPool *pool)
625 {
626     const char *leasePath  = GetFilePath(DHCPD_LEASE_FILE);
627     if (!leasePath || strlen(leasePath) == 0) {
628         DHCP_LOGE("failed to get lease file path.");
629         return;
630     }
631     if (access(leasePath, 0) != 0) {
632         DHCP_LOGD("lease file path does not exist.");
633         if (!CreatePath(leasePath)) {
634             DHCP_LOGE("failed to create lease file directory.");
635             return;
636         } else {
637             DHCP_LOGD("lease file directory created.");
638         }
639     }
640     if (LoadBindingRecoders(pool) != RET_SUCCESS) {
641         DHCP_LOGW("failed to load lease recoders.");
642     }
643     InitBindingRecoders(pool);
644 }
645 
ExitProcess(void)646 static void ExitProcess(void)
647 {
648     DHCP_LOGD("dhcp server stopped.");
649 }
650 
StartDhcpServer(PDhcpServerContext ctx)651 int StartDhcpServer(PDhcpServerContext ctx)
652 {
653     DHCP_LOGI("%{public}s  %{public}d  start", __func__, __LINE__);
654     if (!ctx) {
655         DHCP_LOGE("server context pointer is null.");
656         return RET_FAILED;
657     }
658     if (strlen(ctx->ifname) == 0) {
659         DHCP_LOGE("context interface is null or empty.");
660         return RET_FAILED;
661     }
662     ServerContext *srvIns = GetServerInstance(ctx);
663     if (!srvIns) {
664         DHCP_LOGE("dhcp server context instance pointer is null.");
665         return RET_FAILED;
666     }
667     if (atexit(ExitProcess) != 0) {
668         DHCP_LOGW("failed to regiester exit process function.");
669     }
670     if (!srvIns->initialized) {
671         DHCP_LOGE("dhcp server no initialized.");
672         return RET_FAILED;
673     }
674     DHCP_LOGD("bind interface: %{public}s, begin dhcp message looper", ctx->ifname);
675     if (srvIns->callback) {
676         srvIns->callback(ST_STARTING, 1, ctx->ifname);
677     }
678     pthread_t threadId;
679     int ret = pthread_create(&threadId, nullptr, BeginLooper, ctx);
680     if (ret != RET_SUCCESS) {
681         DHCP_LOGI("failed to start dhcp server.");
682         OnServerStoped(ctx, ret);
683         return RET_FAILED;
684     }
685     OnServerStoped(ctx, ret);
686     return RET_SUCCESS;
687 }
688 
StopDhcpServer(PDhcpServerContext ctx)689 int StopDhcpServer(PDhcpServerContext ctx)
690 {
691     ServerContext *srvIns = GetServerInstance(ctx);
692     if (!srvIns) {
693         DHCP_LOGE("StopDhcpServer GetServerInstance failed!");
694         return RET_FAILED;
695     }
696     srvIns->looperState = LS_STOPING;
697     DHCP_LOGI("StopDhcpServer looperState LS_STOPING!");
698     return RET_SUCCESS;
699 }
700 
GetServerStatus(PDhcpServerContext ctx)701 int GetServerStatus(PDhcpServerContext ctx)
702 {
703     ServerContext *srvIns = GetServerInstance(ctx);
704     if (!srvIns) {
705         DHCP_LOGE("dhcp server context pointer is null.");
706         return -1;
707     }
708     return srvIns->looperState;
709 }
710 
FillReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)711 int FillReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
712 {
713     if (!received || !reply) {
714         return RET_ERROR;
715     }
716     ServerContext *srvIns = GetServerInstance(ctx);
717     if (!srvIns) {
718         DHCP_LOGE("dhcp server context pointer is null.");
719         return RET_FAILED;
720     }
721     if (received->packet.ciaddr && received->packet.ciaddr != INADDR_BROADCAST) {
722         reply->packet.ciaddr = received->packet.ciaddr;
723     }
724     if (received->packet.flags) {
725         reply->packet.flags = received->packet.flags;
726     }
727     if (received->packet.xid) {
728         reply->packet.xid = received->packet.xid;
729     }
730     if (received->packet.siaddr && received->packet.siaddr != INADDR_BROADCAST) {
731         reply->packet.siaddr = received->packet.siaddr;
732     } else {
733         reply->packet.siaddr = srvIns->addressPool.serverId;
734     }
735     if (received->packet.giaddr && received->packet.giaddr != INADDR_BROADCAST) {
736         reply->packet.giaddr = received->packet.giaddr;
737     } else {
738         if (srvIns->addressPool.gateway) {
739             reply->packet.giaddr = srvIns->addressPool.gateway;
740         }
741     }
742     if (received->packet.hlen) {
743         reply->packet.hlen = received->packet.hlen;
744         DHCP_LOGD("fill reply - chaddr:%s", ParseLogMac(received->packet.chaddr));
745         if (memset_s(reply->packet.chaddr, sizeof(reply->packet.chaddr), 0, sizeof(reply->packet.chaddr)) != EOK) {
746             DHCP_LOGE("failed to reset message packet[chaddr]!");
747             return RET_ERROR;
748         }
749         if (memcpy_s(reply->packet.chaddr, sizeof(reply->packet.chaddr),
750             received->packet.chaddr, sizeof(received->packet.chaddr)) != EOK) {
751             DHCP_LOGE("failed to copy message packet[chaddr]!");
752             return RET_ERROR;
753         }
754     }
755     if (received->packet.giaddr) {
756         reply->packet.giaddr = received->packet.giaddr;
757     }
758     return 0;
759 }
760 
AppendReplyTimeOptions(PDhcpServerContext ctx, PDhcpOptionList options)761 int AppendReplyTimeOptions(PDhcpServerContext ctx, PDhcpOptionList options)
762 {
763     if (!ctx || !options) {
764         DHCP_LOGE("server context or options pointer is null.");
765         return RET_FAILED;
766     }
767     ServerContext *srvIns = GetServerInstance(ctx);
768     if (!srvIns) {
769         DHCP_LOGE("dhcp server context pointer is null.");
770         return RET_FAILED;
771     }
772     uint32_t leaseTime = HostToNetwork(DHCP_LEASE_TIME);
773     if (srvIns->addressPool.leaseTime) {
774         leaseTime = HostToNetwork(srvIns->addressPool.leaseTime);
775     }
776     DhcpOption optLeaseTime = {IP_ADDRESS_LEASE_TIME_OPTION, OPT_TIME_LENGTH, {0}};
777     FillU32Option(&optLeaseTime, leaseTime);
778     PushBackOption(options, &optLeaseTime);
779 
780     uint32_t t1Time = HostToNetwork(DHCP_RENEWAL_TIME);
781     if (srvIns->addressPool.renewalTime) {
782         t1Time = HostToNetwork(srvIns->addressPool.renewalTime);
783     }
784     DhcpOption optRenewTime = {RENEWAL_TIME_VALUE_OPTION, OPT_TIME_LENGTH, {0}};
785     FillU32Option(&optRenewTime, t1Time);
786     PushBackOption(options, &optRenewTime);
787 
788     uint32_t t2Time = HostToNetwork(DHCP_REBINDING_TIME);
789     if (srvIns->addressPool.rebindingTime) {
790         t2Time = HostToNetwork(srvIns->addressPool.rebindingTime);
791     }
792     DhcpOption optRebindTime = {REBINDING_TIME_VALUE_OPTION, OPT_TIME_LENGTH, {0}};
793     FillU32Option(&optRebindTime, t2Time);
794     PushBackOption(options, &optRebindTime);
795 
796     return RET_SUCCESS;
797 }
798 
Repending(DhcpAddressPool *pool, AddressBinding *binding)799 static int Repending(DhcpAddressPool *pool, AddressBinding *binding)
800 {
801     if (!pool) {
802         return REPLY_NONE;
803     }
804     uint32_t bindingIp = binding->ipAddress;
805     DHCP_LOGD(" binding found, bindIp:%s", ParseStrIp(bindingIp));
806     binding->pendingInterval = NextPendingInterval(binding->pendingInterval);
807     uint64_t tms = Tmspsec() - binding->pendingTime;
808     if (tms < binding->pendingInterval) {
809         binding->pendingTime = Tmspsec();
810         DHCP_LOGW("message interval is too short, ignore the message.");
811         return REPLY_NONE;
812     }
813     binding->pendingTime = Tmspsec();
814     binding->pendingInterval = 0;
815     binding->bindingStatus = BIND_PENDING;
816     uint32_t srcIp = SourceIpAddress();
817     if (srcIp && srcIp != INADDR_BROADCAST && bindingIp != INADDR_BROADCAST && srcIp != bindingIp) {
818         DHCP_LOGW("source ip address and bound ip address inconsistency.");
819         return REPLY_NAK;
820     }
821     if (srcIp && srcIp == bindingIp) {
822         if (pool->leaseTable.count(srcIp) == 0) {
823             DHCP_LOGD("can't find lease information.");
824             pool->leaseTable[srcIp] = *binding;
825         } else {
826             pool->leaseTable[srcIp] = *binding;
827         }
828     }
829     return REPLY_OFFER;
830 }
831 
Rebinding(DhcpAddressPool *pool, AddressBinding *binding)832 static int Rebinding(DhcpAddressPool *pool, AddressBinding *binding)
833 {
834     uint64_t pendingTime = binding->pendingTime;
835     int replyType = Repending(pool, binding);
836     binding->bindingStatus = BIND_ASSOCIATED;
837     if (!binding->leaseTime) {
838         binding->leaseTime = pool->leaseTime;
839     }
840     binding->bindingTime = Tmspsec();
841     binding->expireIn = binding->bindingTime + binding->leaseTime;
842     binding->pendingTime = pendingTime;
843     if (replyType == REPLY_OFFER) {
844         replyType = REPLY_ACK;
845     }
846     return replyType;
847 }
848 
AddAddressOption(PDhcpMsgInfo reply, uint8_t code, int32_t address)849 static void AddAddressOption(PDhcpMsgInfo reply, uint8_t code, int32_t address)
850 {
851     if (!reply) {
852         return;
853     }
854     DhcpOption optAddress = {0, 0, {0}};
855     optAddress.code = code;
856     if (AppendAddressOption(&optAddress, address) != RET_SUCCESS) {
857         DHCP_LOGE("failed to append address option.");
858         return;
859     };
860     PushBackOption(&reply->options, &optAddress);
861 }
862 
AddReplyServerIdOption(PDhcpOptionList options, uint32_t serverId)863 int AddReplyServerIdOption(PDhcpOptionList options, uint32_t serverId)
864 {
865     if (!options) {
866         DHCP_LOGE("option list pointer is null.");
867         return RET_FAILED;
868     }
869     if (!serverId || serverId == INADDR_BROADCAST) {
870         DHCP_LOGE("servier id error.");
871         return RET_FAILED;
872     }
873     DhcpOption optSrvId = {SERVER_IDENTIFIER_OPTION, 0, {0}};
874     if (AppendAddressOption(&optSrvId, serverId) != RET_SUCCESS) {
875         DHCP_LOGE("failed to append server id option.");
876         return RET_FAILED;
877     }
878     if (GetOption(options, SERVER_IDENTIFIER_OPTION)) {
879         DHCP_LOGD("server identifier option exists.");
880         return RET_SUCCESS;
881     }
882     PushBackOption(options, &optSrvId);
883     return RET_SUCCESS;
884 }
885 
AddReplyMessageTypeOption(PDhcpMsgInfo reply, uint8_t replyMessageType)886 static void AddReplyMessageTypeOption(PDhcpMsgInfo reply, uint8_t replyMessageType)
887 {
888     if (!reply) {
889         return;
890     }
891     DhcpOption optMsgType = {DHCP_MESSAGE_TYPE_OPTION, OPT_MESSAGE_TYPE_LEGTH, {replyMessageType, 0}};
892     PushBackOption(&reply->options, &optMsgType);
893 }
894 
895 
GetBinding(DhcpAddressPool *pool, PDhcpMsgInfo received)896 AddressBinding *GetBinding(DhcpAddressPool *pool, PDhcpMsgInfo received)
897 {
898     if (!pool) {
899         return nullptr;
900     }
901     if (!received) {
902         return nullptr;
903     }
904     AddressBinding *binding = pool->binding(received->packet.chaddr, &received->options);
905     if (!binding) {
906         binding = pool->newBinding(received->packet.chaddr, &received->options);
907         if (binding == nullptr) {
908             DHCP_LOGE("new binding is null");
909             return nullptr;
910         }
911         if (pool->leaseTime) {
912             binding->leaseTime = pool->leaseTime;
913         }
914         binding->ipAddress = pool->distribue(pool, received->packet.chaddr);
915         DHCP_LOGI("new binding ip");
916     } else {
917         DHCP_LOGI("rebinding ip");
918     }
919     return binding;
920 }
921 
ReplyCommontOption(PDhcpServerContext ctx, PDhcpMsgInfo reply)922 int ReplyCommontOption(PDhcpServerContext ctx, PDhcpMsgInfo reply)
923 {
924     if (!reply) {
925         DHCP_LOGE("reply is nullptr!");
926         return REPLY_NONE;
927     }
928     ServerContext *srvIns = GetServerInstance(ctx);
929     if (!srvIns) {
930         DHCP_LOGE("srvIns is nullptr!");
931         return REPLY_NONE;
932     }
933     AddAddressOption(reply, SUBNET_MASK_OPTION, srvIns->addressPool.netmask);
934     if (srvIns->addressPool.gateway) {
935         AddAddressOption(reply, ROUTER_OPTION, srvIns->addressPool.gateway);
936     }
937     DhcpOption optVendorInfo = {VENDOR_SPECIFIC_INFO_OPTION, static_cast<uint8_t>(strlen(VNEDOR_OPEN_HARMONY)),
938         VNEDOR_OPEN_HARMONY};
939     PushBackOption(&reply->options, &optVendorInfo);
940     uint32_t netAddress = reply->packet.yiaddr & srvIns->addressPool.netmask;
941     uint32_t boastAddress = (~srvIns->addressPool.netmask) | netAddress;
942     AddAddressOption(reply, BROADCAST_ADDRESS_OPTION, boastAddress);
943     return REPLY_OFFER;
944 }
945 
DiscoverReplyLeaseMessage(PDhcpServerContext ctx, PDhcpMsgInfo reply, ServerContext *srvIns, AddressBinding *binding)946 static int DiscoverReplyLeaseMessage(PDhcpServerContext ctx, PDhcpMsgInfo reply, ServerContext *srvIns,
947     AddressBinding *binding)
948 {
949     if (!ctx) {
950         DHCP_LOGE("ctx pointer is null.");
951         return REPLY_NONE;
952     }
953     if (!reply) {
954         DHCP_LOGE("reply message pointer is null.");
955         return REPLY_NONE;
956     }
957     if (!srvIns) {
958         DHCP_LOGE("get server instance is nullptr!");
959         return REPLY_NONE;
960     }
961     if (!binding) {
962         DHCP_LOGI("Discover binding is null, reply none");
963         return REPLY_NONE;
964     }
965     AddressBinding *lease = GetLease(&srvIns->addressPool, binding->ipAddress);
966     if (!lease) {
967         DHCP_LOGI("Discover add lease, binging ip:%{public}s mac:%{public}s",
968             OHOS::DHCP::IntIpv4ToAnonymizeStr(binding->ipAddress).c_str(), ParseLogMac(binding->chaddr));
969         AddLease(&srvIns->addressPool, binding);
970         lease = GetLease(&srvIns->addressPool, binding->ipAddress);
971     }
972     if (!lease) {
973         DHCP_LOGI("Discover lease is null, reply none");
974         return REPLY_NONE;
975     }
976     AddReplyMessageTypeOption(reply, DHCPOFFER);
977     reply->packet.yiaddr = lease->ipAddress;
978     ReplyCommontOption(ctx, reply);
979     DHCP_LOGI("Discover reply offer");
980     return REPLY_OFFER;
981 }
982 
OnReceivedDiscover(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)983 static int OnReceivedDiscover(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
984 {
985     if (!received || !reply) {
986         DHCP_LOGE("receive or reply message pointer is null.");
987         return REPLY_NONE;
988     }
989     DHCP_LOGI("received 'Discover' message from:%{public}s", ParseLogMac(received->packet.chaddr));
990     ServerContext *srvIns = GetServerInstance(ctx);
991     if (!srvIns) {
992         DHCP_LOGE("get server instance is nullptr!");
993         return REPLY_NONE;
994     }
995     uint32_t reqIp = 0;
996     PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
997     if (optReqIp) {
998         reqIp = ParseIp(optReqIp->data);
999         if (reqIp) {
1000             DHCP_LOGI("Discover request ip:%{public}s", OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str());
1001         }
1002     }
1003     uint32_t srcIp = SourceIpAddress();
1004     if (!srvIns->broadCastFlagEnable) {
1005         if (srcIp) {
1006             DHCP_LOGI("Discover client repending:%{public}s", OHOS::DHCP::IntIpv4ToAnonymizeStr(srcIp).c_str());
1007         } else {
1008             srcIp = INADDR_BROADCAST;
1009         }
1010         DestinationAddr(srcIp);
1011     }
1012     AddressBinding *binding = GetBinding(&srvIns->addressPool, received);
1013     if (!binding) {
1014         DHCP_LOGI("Discover binding is null, reply none");
1015         return REPLY_NONE;
1016     }
1017     if (!binding->ipAddress) {
1018         DHCP_LOGI("Discover binding ipAddress is null, reply none");
1019         return REPLY_NONE;
1020     }
1021     if (reqIp != 0 && reqIp != binding->ipAddress) {
1022         DHCP_LOGW("Discover package reqIp:%{public}s, binging ip:%{public}s",
1023             OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str(),
1024             OHOS::DHCP::IntIpv4ToAnonymizeStr(binding->ipAddress).c_str());
1025     }
1026     DeleteMacInLease(&srvIns->addressPool, binding);
1027     return DiscoverReplyLeaseMessage(ctx, reply, srvIns, binding);
1028 }
1029 
GetRequestIpAddress(PDhcpMsgInfo received)1030 static uint32_t GetRequestIpAddress(PDhcpMsgInfo received)
1031 {
1032     uint32_t reqIp = 0;
1033     if (!received) {
1034         return reqIp;
1035     }
1036     PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1037     if (optReqIp) {
1038         reqIp = ParseIp(optReqIp->data);
1039     }
1040     return reqIp;
1041 }
1042 
GetYourIpAddress(PDhcpMsgInfo received, uint32_t *yourIpAddr, DhcpAddressPool *pool)1043 static int GetYourIpAddress(PDhcpMsgInfo received, uint32_t *yourIpAddr, DhcpAddressPool *pool)
1044 {
1045     uint32_t cliIp = received->packet.ciaddr;
1046     uint32_t srcIp = SourceIpAddress();
1047     uint32_t reqIp = GetRequestIpAddress(received);
1048     DHCP_LOGI("cliIp:%{public}s srcIp:%{public}s reqIp:%{public}s",
1049         OHOS::DHCP::IntIpv4ToAnonymizeStr(cliIp).c_str(), OHOS::DHCP::IntIpv4ToAnonymizeStr(srcIp).c_str(),
1050         OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str());
1051     if (cliIp && srcIp && cliIp != srcIp) {
1052         DHCP_LOGE("error dhcp request message, missing required request option.");
1053         return RET_FAILED;
1054     }
1055     if (reqIp && srcIp && reqIp != srcIp) {
1056         DHCP_LOGE("error dhcp request message, request ip error.");
1057         return RET_FAILED;
1058     }
1059     if (cliIp && reqIp && cliIp != reqIp) {
1060         DHCP_LOGE("error dhcp request message, client ip error.");
1061         return RET_FAILED;
1062     }
1063 
1064     if (srcIp && srcIp != INADDR_BROADCAST) {
1065         *yourIpAddr = srcIp;
1066     } else if (cliIp && cliIp != INADDR_BROADCAST) {
1067         *yourIpAddr = cliIp;
1068     } else if (reqIp && reqIp != INADDR_BROADCAST) {
1069         *yourIpAddr = reqIp;
1070     }
1071 
1072     if ((ntohl(*yourIpAddr) < ntohl(pool->addressRange.beginAddress))
1073             || (ntohl(*yourIpAddr) > ntohl(pool->addressRange.endAddress))) {
1074         return RET_FAILED;
1075     }
1076 
1077     if (srcIp && srcIp != INADDR_BROADCAST) {
1078         DestinationAddr(srcIp);
1079     } else if (srcIp == INADDR_ANY) {
1080         DestinationAddr(INADDR_BROADCAST);
1081     }
1082     return RET_SUCCESS;
1083 }
1084 
NotBindingRequest(DhcpAddressPool *pool, PDhcpMsgInfo received, PDhcpMsgInfo reply)1085 static int NotBindingRequest(DhcpAddressPool *pool, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1086 {
1087     uint32_t yourIpAddr = 0;
1088     if (GetYourIpAddress(received, &yourIpAddr, pool) != RET_SUCCESS) {
1089         DHCP_LOGI("GetYourIpAddress REPLY_NONE");
1090         return REPLY_NONE;
1091     }
1092     AddressBinding *lease = GetLease(pool, yourIpAddr);
1093     if (!lease) {
1094         if (SourceIpAddress()) {
1095             DHCP_LOGI("SourceIpAddress True REPLY_ACK");
1096             return REPLY_ACK;
1097         }
1098         DHCP_LOGI("SourceIpAddress REPLY_NAK");
1099         return REPLY_NAK;
1100     }
1101     int sameAddr = AddrEquels(lease->chaddr, received->packet.chaddr, MAC_ADDR_LENGTH);
1102     if (lease->bindingStatus == BIND_ASSOCIATED && !sameAddr) {
1103         if (!IsExpire(lease)) {
1104             DHCP_LOGI("Not IsExpire REPLY_NAK");
1105             return REPLY_NAK;
1106         }
1107         DHCP_LOGI("RemoveLease lease");
1108         RemoveLease(pool, lease);
1109     }
1110     AddressBinding *binding = pool->newBinding(received->packet.chaddr, &received->options);
1111     if (binding == nullptr) {
1112         DHCP_LOGE("Not binding request binding is null.");
1113         return REPLY_NONE;
1114     }
1115     binding->ipAddress = yourIpAddr;
1116     if (pool->leaseTime) {
1117         binding->leaseTime = pool->leaseTime;
1118     }
1119     int replyType = Repending(pool, binding);
1120     if (replyType != REPLY_OFFER) {
1121         DHCP_LOGI("replyType != REPLY_OFFER");
1122         return replyType;
1123     }
1124     lease = GetLease(pool, yourIpAddr);
1125     if (!lease) {
1126         DHCP_LOGI("add new lease recoder.");
1127         AddLease(pool, binding);
1128         lease = GetLease(pool, binding->ipAddress);
1129     }
1130     if (!lease) {
1131         DHCP_LOGI("failed to get lease.");
1132         return REPLY_NONE;
1133     }
1134     lease->bindingStatus = BIND_ASSOCIATED;
1135     lease->bindingTime = Tmspsec();
1136     lease->expireIn = lease->bindingTime + binding->leaseTime;
1137     reply->packet.yiaddr = lease->ipAddress;
1138     DHCP_LOGI("NotBindingRequest REPLY_ACK");
1139     return REPLY_ACK;
1140 }
1141 
ValidateRequestMessage(const PDhcpServerContext ctx, const PDhcpMsgInfo received, PDhcpMsgInfo reply, uint32_t *yourIp)1142 static int ValidateRequestMessage(const PDhcpServerContext ctx, const PDhcpMsgInfo received,
1143     PDhcpMsgInfo reply, uint32_t *yourIp)
1144 {
1145     if (!received || !reply) {
1146         DHCP_LOGE("receive or reply message pointer is null.");
1147         return REPLY_NONE;
1148     }
1149     DHCP_LOGI("received 'Request' message from:%{public}s", ParseLogMac(received->packet.chaddr));
1150     uint32_t yourIpAddr = INADDR_BROADCAST;
1151     ServerContext *srvIns = GetServerInstance(ctx);
1152     if (!srvIns) {
1153         DHCP_LOGI("get server instance failed!");
1154         return RET_FAILED;
1155     }
1156     if (GetYourIpAddress(received, &yourIpAddr, &srvIns->addressPool) != RET_SUCCESS) {
1157         if (yourIpAddr && yourIpAddr != INADDR_BROADCAST) {
1158             AddressBinding *lease = GetLease(&srvIns->addressPool, yourIpAddr);
1159             if (lease) {
1160                 RemoveLease(&srvIns->addressPool, lease);
1161                 DHCP_LOGD("lease recoder has been removed.");
1162             } else {
1163                 DHCP_LOGW("can't found lease recoder.");
1164             }
1165             RemoveBinding(received->packet.chaddr);
1166             return REPLY_NAK;
1167         }
1168         return REPLY_NONE;
1169     }
1170     PDhcpOption optReqSrvId = GetOption(&received->options, SERVER_IDENTIFIER_OPTION);
1171     if (optReqSrvId) {
1172         uint32_t reqSrvId = ParseIp(optReqSrvId->data);
1173         DHCP_LOGD(" reuquest server id is:%s", ParseStrIp(reqSrvId));
1174         if (reqSrvId != srvIns->addressPool.serverId) {
1175             DHCP_LOGW("other dhcp server process.");
1176             return REPLY_NONE;
1177         }
1178     } else {
1179         DHCP_LOGW("request message not specified server identifier option.");
1180     }
1181     *yourIp = yourIpAddr;
1182     return REPLY_ACK;
1183 }
1184 
HasNobindgRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)1185 static int HasNobindgRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1186 {
1187     if (!received || !reply) {
1188         DHCP_LOGE("receive or reply message pointer is null.");
1189         return REPLY_NONE;
1190     }
1191     ServerContext *srvIns = GetServerInstance(ctx);
1192     if (!srvIns) {
1193         DHCP_LOGE("dhcp server context pointer is null.");
1194         return REPLY_NONE;
1195     }
1196     AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1197     if (!binding && ALLOW_NOBINDING_REQUEST) {
1198         uint32_t srcIp = SourceIpAddress();
1199         uint32_t reqIp = GetRequestIpAddress(received);
1200         DHCP_LOGD("allow no binding request mode.");
1201         if (reqIp == 0 && srcIp == 0) {
1202             DHCP_LOGE("error dhcp message.");
1203             return REPLY_NONE;
1204         }
1205         if (!IpInNetwork(reqIp, srvIns->addressPool.serverId, srvIns->addressPool.netmask)) {
1206             DHCP_LOGE("error request ip.");
1207             return REPLY_NAK;
1208         }
1209         return NotBindingRequest(&srvIns->addressPool, received, reply);
1210     }
1211     return REPLY_NONE;
1212 }
1213 
GetVendorIdentifierOption(PDhcpMsgInfo received)1214 int GetVendorIdentifierOption(PDhcpMsgInfo received)
1215 {
1216     PDhcpOption optVendorIdentifier = GetOption(&received->options, VENDOR_CLASS_IDENTIFIER_OPTION);
1217     if (optVendorIdentifier) {
1218         char strVendorIdentifier[DEVICE_NAME_STRING_LENGTH] = {0};
1219         if (memcpy_s(strVendorIdentifier, DEVICE_NAME_STRING_LENGTH, (char*)optVendorIdentifier->data,
1220             optVendorIdentifier->length) != EOK) {
1221             DHCP_LOGE("GetVendorIdentifierOption strClientIdentifier memcpy_s failed!");
1222             return REPLY_NONE;
1223         }
1224         DHCP_LOGD("GetVendorIdentifierOption strClientIdentifier:%{public}s", strVendorIdentifier);
1225     } else {
1226         DHCP_LOGD("GetVendorIdentifierOption pClientIdentifier is null");
1227     }
1228     return REPLY_NAK;
1229 }
1230 
GetHostNameOption(PDhcpMsgInfo received, AddressBinding *bindin)1231 int GetHostNameOption(PDhcpMsgInfo received, AddressBinding *bindin)
1232 {
1233     if (!bindin) {
1234         DHCP_LOGE("GetHostNameOption bindin is nullptr!");
1235         return REPLY_NONE;
1236     }
1237     PDhcpOption optHostName = GetOption(&received->options, HOST_NAME_OPTION);
1238     if (optHostName) {
1239         if (memcpy_s(bindin->deviceName, DEVICE_NAME_STRING_LENGTH, (char*)optHostName->data,
1240             optHostName->length) != EOK) {
1241             DHCP_LOGE("GetHostNameOption pHost memcpy_s failed!");
1242             return REPLY_NONE;
1243         }
1244         DHCP_LOGI("GetHostNameOption deviceName:%{public}s", bindin->deviceName);
1245     } else {
1246         DHCP_LOGD("GetHostNameOption pHost is null");
1247     }
1248     return REPLY_NAK;
1249 }
1250 
GetUserClassOption(PDhcpMsgInfo received, AddressBinding *bindin)1251 int GetUserClassOption(PDhcpMsgInfo received, AddressBinding *bindin)
1252 {
1253     if (!bindin) {
1254         DHCP_LOGE("GetUserClassOption bindin is nullptr!");
1255         return REPLY_NONE;
1256     }
1257     PDhcpOption option = GetOption(&received->options, USER_CLASS_OPTION);
1258     if (option) {
1259         if (memcpy_s(bindin->userClass, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1260             DHCP_LOGE("GetUserClassOption memcpy_s failed!");
1261             return REPLY_NONE;
1262         }
1263         DHCP_LOGD("GetUserClassOption userClass:%{public}s", bindin->userClass);
1264     } else {
1265         DHCP_LOGD("GetUserClassOption pHost is null");
1266     }
1267     return REPLY_ACK;
1268 }
1269 
GetRapidCommitOption(PDhcpMsgInfo received, AddressBinding *bindin)1270 int GetRapidCommitOption(PDhcpMsgInfo received, AddressBinding *bindin)
1271 {
1272     if (!bindin) {
1273         DHCP_LOGE("GetRapidCommitOption bindin is nullptr!");
1274         return REPLY_NONE;
1275     }
1276     PDhcpOption option = GetOption(&received->options, RAPID_COMMIT_OPTION);
1277     if (option) {
1278         char value[DEVICE_NAME_STRING_LENGTH] = {0};
1279         if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1280             DHCP_LOGE("GetRapidCommitOption memcpy_s failed!");
1281             return REPLY_NONE;
1282         }
1283         DHCP_LOGD("GetRapidCommitOption value:%{public}s", value);
1284     } else {
1285         DHCP_LOGD("GetRapidCommitOption pHost is null");
1286     }
1287     return REPLY_ACK;
1288 }
1289 
GetOnlyIpv6Option(PDhcpMsgInfo received, AddressBinding *bindin)1290 int GetOnlyIpv6Option(PDhcpMsgInfo received, AddressBinding *bindin)
1291 {
1292     if (!bindin) {
1293         DHCP_LOGE("GetOnlyIpv6Option bindin is nullptr!");
1294         return REPLY_NONE;
1295     }
1296     PDhcpOption option = GetOption(&received->options, IPV6_ONLY_PREFERRED_OPTION);
1297     if (option) {
1298         char value[DEVICE_NAME_STRING_LENGTH] = {0};
1299         if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1300             DHCP_LOGE("GetOnlyIpv6Option memcpy_s failed!");
1301             return REPLY_NONE;
1302         }
1303         DHCP_LOGD("GetOnlyIpv6Option value:%{public}s", value);
1304     } else {
1305         DHCP_LOGD("GetOnlyIpv6Option pHost is null");
1306     }
1307     return REPLY_ACK;
1308 }
1309 
GetPortalUrlOption(PDhcpMsgInfo received, AddressBinding *bindin)1310 int GetPortalUrlOption(PDhcpMsgInfo received, AddressBinding *bindin)
1311 {
1312     if (!bindin) {
1313         DHCP_LOGE("GetPortalUrlOption bindin is nullptr!");
1314         return REPLY_NONE;
1315     }
1316     PDhcpOption option = GetOption(&received->options, IPV6_ONLY_PREFERRED_OPTION);
1317     if (option) {
1318         char value[DEVICE_NAME_STRING_LENGTH] = {0};
1319         if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1320             DHCP_LOGE("GetPortalUrlOption memcpy_s failed!");
1321             return REPLY_NONE;
1322         }
1323         DHCP_LOGD("GetPortalUrlOption value:%{public}s", value);
1324     } else {
1325         DHCP_LOGD("GetPortalUrlOption pHost is null");
1326     }
1327     return REPLY_ACK;
1328 }
1329 
ParseDhcpOption(PDhcpMsgInfo received, AddressBinding *bindin)1330 int ParseDhcpOption(PDhcpMsgInfo received, AddressBinding *bindin)
1331 {
1332     if (!bindin) {
1333         DHCP_LOGE("ParseDhcpOption bindin is nullptr!");
1334         return REPLY_NONE;
1335     }
1336     DHCP_LOGE("enter ParseDhcpOption");
1337     GetHostNameOption(received, bindin);
1338     GetVendorIdentifierOption(received);
1339     GetUserClassOption(received, bindin);
1340     GetRapidCommitOption(received, bindin);
1341     GetOnlyIpv6Option(received, bindin);
1342     GetPortalUrlOption(received, bindin);
1343     return REPLY_ACK;
1344 }
1345 
OnReceivedRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)1346 static int OnReceivedRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1347 {
1348     int ret;
1349     uint32_t yourIpAddr;
1350     if ((ret = ValidateRequestMessage(ctx, received, reply, &yourIpAddr)) != REPLY_ACK) {
1351         DHCP_LOGE("Request validateRequestMessage ret:%{public}d", ret);
1352         return ret;
1353     }
1354     ServerContext *srvIns = GetServerInstance(ctx);
1355     if (srvIns == nullptr) {
1356         DHCP_LOGE("OnReceivedRequest, srvIns is null");
1357         return REPLY_NONE;
1358     }
1359     AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1360     if (binding == nullptr) {
1361         DHCP_LOGI("Request enter HasNobindgRequest!");
1362         return HasNobindgRequest(ctx, received, reply);
1363     }
1364     Rebinding(&srvIns->addressPool, binding);
1365     AddressBinding *lease = GetLease(&srvIns->addressPool, yourIpAddr);
1366     if (lease) {
1367         ParseDhcpOption(received, lease);
1368         DHCP_LOGI("request in lease, yourIpAddr:%{public}s, mac:%{public}s",
1369             OHOS::DHCP::IntIpv4ToAnonymizeStr(yourIpAddr).c_str(), ParseLogMac(lease->chaddr));
1370         int sameAddr = AddrEquels(lease->chaddr, received->packet.chaddr, MAC_ADDR_LENGTH);
1371         if (!sameAddr && !IsExpire(lease)) {
1372             DHCP_LOGW("invalid request ip address, reply nak, sameAddr:%{public}d", sameAddr);
1373             return REPLY_NAK;
1374         }
1375         if (!sameAddr && IsExpire(lease)) {
1376             if (memcpy_s(lease->chaddr, DHCP_HWADDR_LENGTH, binding->chaddr, MAC_ADDR_LENGTH) != EOK) {
1377                 DHCP_LOGW("failed to update lease client address, sameAddr:%{public}d", sameAddr);
1378             }
1379         }
1380         lease->bindingStatus = BIND_ASSOCIATED;
1381         lease->bindingTime = binding->bindingTime;
1382         lease->expireIn = binding->expireIn;
1383         DHCP_LOGI("Request found lease recoder, sameAddr:%{public}d", sameAddr);
1384     } else {
1385         DHCP_LOGW("Request can not found lease recoder.");
1386     }
1387     uint32_t bindingIp = binding->ipAddress;
1388     if (bindingIp && yourIpAddr != INADDR_BROADCAST && yourIpAddr != bindingIp) {
1389         DHCP_LOGE("error request ip binding. reply nak");
1390         return REPLY_NAK;
1391     }
1392     reply->packet.yiaddr = bindingIp;
1393     ReplyCommontOption(ctx, reply);
1394     DHCP_LOGI("Request reply ack!");
1395     return REPLY_ACK;
1396 }
1397 
OnReceivedDecline(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)1398 static int OnReceivedDecline(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1399 {
1400     if (!received || !reply) {
1401         return REPLY_NONE;
1402     }
1403     ServerContext *srvIns = GetServerInstance(ctx);
1404     if (!srvIns) {
1405         return REPLY_NONE;
1406     }
1407     DHCP_LOGI("received 'Decline' message from: %s.", ParseLogMac(received->packet.chaddr));
1408     uint32_t reqIp = 0;
1409     PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1410     if (optReqIp) {
1411         reqIp = ParseIp(optReqIp->data);
1412     }
1413     if (!reqIp) {
1414         DHCP_LOGD("invalid request ip address.");
1415         return REPLY_NONE;
1416     }
1417     AddressBinding* binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1418     if (!binding) {
1419         DHCP_LOGD("client not binding.");
1420         return REPLY_NONE;
1421     }
1422     if (binding->ipAddress != reqIp) {
1423         DHCP_LOGD("invalid request ip address.");
1424         return REPLY_NONE;
1425     }
1426     if (srvIns->addressPool.leaseTable.count(reqIp) > 0) {
1427         AddressBinding *lease = &srvIns->addressPool.leaseTable[reqIp];
1428         if (lease) {
1429             lease->bindingStatus = BIND_MODE_RESERVED;
1430             lease->expireIn = Tmspsec() + lease->leaseTime;
1431         } else {
1432             DHCP_LOGE("failed to get lease info.");
1433         }
1434     }
1435     RemoveBinding(received->packet.chaddr);
1436     return REPLY_NONE;
1437 }
1438 
OnReceivedRelease(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)1439 static int OnReceivedRelease(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1440 {
1441     if (!received || !reply) {
1442         return REPLY_NONE;
1443     }
1444     DHCP_LOGI("received 'Release' message from: %s", ParseLogMac(received->packet.chaddr));
1445     if (!ctx || !ctx->instance) {
1446         return RET_FAILED;
1447     }
1448     PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1449     if (!optReqIp) {
1450         DHCP_LOGW("missing required request option.");
1451     }
1452     ServerContext *srvIns = GetServerInstance(ctx);
1453     if (!srvIns) {
1454         DHCP_LOGE("dhcp server context pointer is null.");
1455         return RET_FAILED;
1456     }
1457     AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1458     if (!binding) {
1459         DHCP_LOGD("client not binding.");
1460         return REPLY_NONE;
1461     }
1462     uint32_t bindIp = binding->ipAddress;
1463     uint32_t reqIp = 0;
1464     if (optReqIp) {
1465         reqIp = ParseIp(optReqIp->data);
1466     }
1467     uint32_t srcIp = SourceIpAddress();
1468     if (srcIp != 0 && reqIp != 0 && reqIp != srcIp) {
1469         DHCP_LOGE("error release message, invalid request ip address.");
1470         return REPLY_NONE;
1471     }
1472     if (bindIp != 0 && reqIp != 0 && reqIp != bindIp) {
1473         DHCP_LOGE("error release message, invalid request ip address.");
1474         return REPLY_NONE;
1475     }
1476     AddressBinding *lease = GetLease(&srvIns->addressPool, bindIp);
1477     if (lease) {
1478         RemoveLease(&srvIns->addressPool, lease);
1479         DHCP_LOGD("lease recoder has been removed.");
1480     } else {
1481         DHCP_LOGW("can't found lease recoder.");
1482     }
1483 
1484     if (ReleaseBinding(received->packet.chaddr) != RET_SUCCESS) {
1485         DHCP_LOGW("failed to release client[%s] bind.", ParseLogMac(received->packet.chaddr));
1486     }
1487     DHCP_LOGD("client released.");
1488     return REPLY_NONE;
1489 }
1490 
OnReceivedInform(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)1491 static int OnReceivedInform(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1492 {
1493     if (!received || !reply) {
1494         return REPLY_NONE;
1495     }
1496     ServerContext *srvIns = GetServerInstance(ctx);
1497     if (!srvIns) {
1498         DHCP_LOGE("dhcp server context pointer is null.");
1499         return RET_FAILED;
1500     }
1501     DHCP_LOGI("received 'Inform' message from: %s", ParseLogMac(received->packet.chaddr));
1502     if (IsEmptyHWAddr(received->packet.chaddr)) {
1503         DHCP_LOGD("error dhcp 'Inform' message.");
1504     }
1505     return REPLY_ACK;
1506 }
1507 
AppendFixedOptions(PDhcpServerContext ctx, PDhcpMsgInfo reply)1508 static int AppendFixedOptions(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1509 {
1510     ServerContext *srvIns = GetServerInstance(ctx);
1511     if (!srvIns) {
1512         return RET_FAILED;
1513     }
1514     if (!reply) {
1515         return RET_FAILED;
1516     }
1517     if (srvIns->addressPool.fixedOptions.size > 0) {
1518         DhcpOptionNode *pNode = srvIns->addressPool.fixedOptions.first->next;
1519         for (size_t i = 0; pNode != nullptr && i < srvIns->addressPool.fixedOptions.size; i++) {
1520             PDhcpOption opt = nullptr;
1521             if (pNode->option.code) {
1522                 opt = GetOption(&reply->options, pNode->option.code);
1523             }
1524             if (opt == nullptr) {
1525                 PushBackOption(&reply->options, &pNode->option);
1526             }
1527             pNode = pNode->next;
1528         }
1529     }
1530     return RET_SUCCESS;
1531 }
AppendReplyTypeOption(PDhcpMsgInfo reply, int replyType)1532 int AppendReplyTypeOption(PDhcpMsgInfo reply, int replyType)
1533 {
1534     if (!reply) {
1535         return RET_FAILED;
1536     }
1537     if (!replyType) {
1538         return RET_FAILED;
1539     }
1540     uint8_t msgType = 0;
1541     switch (replyType) {
1542         case REPLY_OFFER:
1543             msgType = DHCPOFFER;
1544             break;
1545         case REPLY_ACK:
1546             msgType = DHCPACK;
1547             break;
1548         case REPLY_NAK:
1549             msgType = DHCPNAK;
1550             break;
1551         default:
1552             break;
1553     }
1554     PDhcpOption pOptMsgType = GetOption(&reply->options, DHCP_MESSAGE_TYPE_OPTION);
1555     if (!pOptMsgType) {
1556         DHCP_LOGD("append message type option for reply message, type:%hhu", msgType);
1557         DhcpOption optMsgType = {DHCP_MESSAGE_TYPE_OPTION, OPT_MESSAGE_TYPE_LEGTH, {msgType, 0}};
1558         PushFrontOption(&reply->options, &optMsgType);
1559     } else {
1560         if (pOptMsgType->data[0] != msgType) {
1561             DHCP_LOGD("error dhcp nak message type.");
1562             return RET_FAILED;
1563         }
1564     }
1565     return RET_SUCCESS;
1566 }
1567 
SendDhcpOffer(PDhcpServerContext ctx, PDhcpMsgInfo reply)1568 static int SendDhcpOffer(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1569 {
1570     ServerContext *srvIns = GetServerInstance(ctx);
1571     if (!srvIns) {
1572         DHCP_LOGE("failed to get server instance");
1573         return RET_FAILED;
1574     }
1575     if (AppendReplyTypeOption(reply, REPLY_OFFER) != RET_SUCCESS) {
1576         DHCP_LOGE("failed to append reply type options");
1577         return RET_FAILED;
1578     }
1579     if (AppendReplyTimeOptions(ctx, &reply->options) != RET_SUCCESS ||
1580         AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1581         DHCP_LOGE("failed to append reply time options");
1582         return RET_FAILED;
1583     }
1584     if (AppendFixedOptions(ctx, reply) != RET_SUCCESS) {
1585         DHCP_LOGW("failed to append fixed reply options.");
1586     }
1587     if (ParseReplyOptions(reply) != RET_SUCCESS) {
1588         DHCP_LOGE("failed to parse reply options.");
1589         return RET_FAILED;
1590     }
1591     int ret;
1592     struct sockaddr_in *bcastAddrIn = BroadcastAddrIn();
1593     struct sockaddr_in *destAddrIn = DestinationAddrIn();
1594     if (srvIns->broadCastFlagEnable == 1 && destAddrIn) {
1595         int broadCastFlag = 1;
1596         if (reply->packet.flags && (reply->packet.flags >> (DHCP_MESSAGE_FLAG_LENGTH - 1)) == 0) {
1597             broadCastFlag = 0;
1598         }
1599         if (!broadCastFlag && destAddrIn->sin_addr.s_addr) {
1600             ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1601                 sizeof(*destAddrIn));
1602         } else {
1603             ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)bcastAddrIn,
1604                 sizeof(*bcastAddrIn));
1605         }
1606     } else {
1607         ret = sendto(
1608             srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)bcastAddrIn, sizeof(*bcastAddrIn));
1609     }
1610     if (!ret) {
1611         DHCP_LOGD("failed to send dhcp offer message.");
1612         return RET_FAILED;
1613     }
1614     DHCP_LOGI("send reply offer, length:%d", reply->length);
1615     return RET_SUCCESS;
1616 }
1617 
SendDhcpAck(PDhcpServerContext ctx, PDhcpMsgInfo reply)1618 static int SendDhcpAck(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1619 {
1620     if (AppendReplyTypeOption(reply, REPLY_ACK) != RET_SUCCESS) {
1621         DHCP_LOGE("failed to append reply type options");
1622         return RET_FAILED;
1623     }
1624     if (AppendFixedOptions(ctx, reply) != RET_SUCCESS) {
1625         DHCP_LOGW("failed to append fixed reply options.");
1626     }
1627     if (!ctx || !ctx->instance) {
1628         DHCP_LOGE("dhcp server context pointer is null.");
1629         return RET_FAILED;
1630     }
1631     ServerContext *srvIns = GetServerInstance(ctx);
1632 
1633     if (AppendReplyTimeOptions(ctx, &reply->options) != RET_SUCCESS) {
1634         DHCP_LOGE("failed to append reply time options");
1635         return RET_FAILED;
1636     }
1637     if (AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1638         DHCP_LOGE("failed to add reply server options");
1639         return RET_FAILED;
1640     }
1641     if (ParseReplyOptions(reply) != RET_SUCCESS) {
1642         DHCP_LOGE("failed to parse reply options");
1643         return RET_FAILED;
1644     }
1645     sockaddr_in *destAddrIn = DestinationAddrIn();
1646     int ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1647         sizeof(*destAddrIn));
1648     if (!ret) {
1649         DHCP_LOGD("failed to send dhcp ack message.");
1650         return RET_FAILED;
1651     }
1652     DHCP_LOGI("send reply ack, size:%d", reply->length);
1653     return RET_SUCCESS;
1654 }
1655 
SendDhcpNak(PDhcpServerContext ctx, PDhcpMsgInfo reply)1656 static int SendDhcpNak(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1657 {
1658     if (AppendReplyTypeOption(reply, REPLY_NAK) != RET_SUCCESS) {
1659         DHCP_LOGE("failed to append reply type options");
1660         return RET_FAILED;
1661     }
1662     ServerContext *srvIns = GetServerInstance(ctx);
1663     if (srvIns == nullptr) {
1664         DHCP_LOGE("SendDhcpNak, srvIns is null");
1665         return RET_FAILED;
1666     }
1667     if (AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1668         DHCP_LOGE("SendDhcpNak serverId fail!");
1669         return RET_FAILED;
1670     }
1671     DhcpOption optVendorInfo = {MESSAGE_OPTION, static_cast<uint8_t>(strlen("wrong network")), "wrong network"};
1672     PushBackOption(&reply->options, &optVendorInfo);
1673     if (ParseReplyOptions(reply) != RET_SUCCESS) {
1674         DHCP_LOGE("failed to parse reply options");
1675         return RET_FAILED;
1676     }
1677 
1678     struct sockaddr_in *destAddrIn = BroadcastAddrIn();
1679     int ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1680         sizeof(*destAddrIn));
1681     if (!ret) {
1682         DHCP_LOGD("failed to send dhcp ack message.");
1683         return RET_FAILED;
1684     }
1685     DHCP_LOGI("send reply nak, size:%d", reply->length);
1686     return RET_SUCCESS;
1687 }
1688 
ParseMessageOptions(PDhcpMsgInfo msg)1689 static int ParseMessageOptions(PDhcpMsgInfo msg)
1690 {
1691     DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
1692     if (msg->length < (DHCP_MSG_HEADER_SIZE + MAGIC_COOKIE_LENGTH)) {
1693         return RET_FAILED;
1694     }
1695     DhcpOption *current, *end;
1696     current = (DhcpOption *)msg->packet.options;
1697     end = (DhcpOption *)(((uint8_t *)msg->packet.options) + (msg->length - DHCP_MSG_HEADER_SIZE));
1698 
1699     if (memcmp(current, MAGIC_COOKIE_DATA, sizeof(MAGIC_COOKIE_DATA)) != 0) {
1700         DHCP_LOGD("bad magic cookie.");
1701         return RET_FAILED;
1702     }
1703 
1704     current = (DhcpOption *)(((uint8_t *)current) + MAGIC_COOKIE_LENGTH);
1705     uint8_t *pos = (((uint8_t *)current) + MAGIC_COOKIE_LENGTH);
1706     uint8_t *maxPos = (((uint8_t *)current) + (DHCP_OPTION_SIZE - MAGIC_COOKIE_LENGTH - OPT_HEADER_LENGTH -1));
1707     int optTotal = 0;
1708     while (current < end && current->code != END_OPTION) {
1709         if (((uint8_t *)end) - ((uint8_t *)current) < OPT_HEADER_LENGTH) {
1710             DHCP_LOGE("current->code out of option range.");
1711             return RET_FAILED;
1712         }
1713         pos += (OPT_HEADER_LENGTH + current->length);
1714         if (pos >= maxPos) {
1715             DHCP_LOGD("out of option max pos.");
1716             return RET_FAILED;
1717         }
1718         if (PushBackOption(&msg->options, current) != RET_SUCCESS) {
1719             DHCP_LOGD("failed to PushOption.");
1720         }
1721         current = (DhcpOption *)(((uint8_t *)current) + OPT_HEADER_LENGTH + current->length);
1722         optTotal++;
1723     }
1724     if (current < end && current->code == END_OPTION) {
1725         DHCP_LOGD("option list size:%zu xid:%u", msg->options.size, msg->packet.xid);
1726         return RET_SUCCESS;
1727     }
1728 
1729     DHCP_LOGD("option list parse failed.");
1730     return RET_FAILED;
1731 }
1732 
ResetMessageOptions(PDhcpMsgInfo reply)1733 static int ResetMessageOptions(PDhcpMsgInfo reply)
1734 {
1735     if (!reply || reply->options.size == 0) {
1736         DHCP_LOGE("message pointer is null.");
1737         return RET_ERROR;
1738     }
1739     if (memset_s(reply->packet.options, DHCP_OPTIONS_SIZE, 0, DHCP_OPTIONS_SIZE) != EOK) {
1740         DHCP_LOGE("failed to reset message options!");
1741         return RET_ERROR;
1742     }
1743     return RET_SUCCESS;
1744 }
1745 
ValidateReplyOptions(PDhcpMsgInfo reply)1746 static int ValidateReplyOptions(PDhcpMsgInfo reply)
1747 {
1748     if (!reply) {
1749         DHCP_LOGE("reply message pointer is null.");
1750         return RET_FAILED;
1751     }
1752     int ret = RET_FAILED;
1753     if ((ret = ResetMessageOptions(reply)) != RET_SUCCESS) {
1754         return ret;
1755     }
1756     reply->length = DHCP_MSG_HEADER_SIZE;
1757     PDhcpOptionNode pNode = reply->options.first;
1758     if (!pNode) {
1759         return RET_ERROR;
1760     }
1761     PDhcpOption pOptMsgType = GetOption(&reply->options, DHCP_MESSAGE_TYPE_OPTION);
1762     if (!pOptMsgType) {
1763         DHCP_LOGE("unknown reply message type.");
1764         return ret;
1765     }
1766     return RET_SUCCESS;
1767 }
1768 
ParseReplyOptions(PDhcpMsgInfo reply)1769 static int ParseReplyOptions(PDhcpMsgInfo reply)
1770 {
1771     int ret = RET_FAILED;
1772     if ((ret = ValidateReplyOptions(reply)) != RET_SUCCESS) {
1773         return ret;
1774     }
1775     PDhcpOptionNode pNode = reply->options.first->next;
1776     DhcpOption endOpt = {END_OPTION, 0, {0}};
1777     PushBackOption(&reply->options, &endOpt);
1778     int replyOptsLength = 0;
1779     uint8_t *current = reply->packet.options, olen = MAGIC_COOKIE_LENGTH;
1780     size_t remainingSize = sizeof(reply->packet.options);
1781     uint32_t cookie = htonl(DHCP_MAGIC_COOKIE);
1782     if (memcpy_s(current, remainingSize, &cookie, olen) != EOK) {
1783         DHCP_LOGE("memcpy cookie out of options buffer!");
1784         return RET_FAILED;
1785     }
1786     replyOptsLength += olen;
1787     remainingSize -= olen;
1788     current += olen;
1789     ret = RET_SUCCESS;
1790     while (pNode && (uint32_t)pNode->option.length < DHCP_OPTION_SIZE) {
1791         if ((uint32_t)pNode->option.code == END_OPTION) {
1792             olen = OPT_HEADER_LENGTH + 1;
1793         } else {
1794             olen = OPT_HEADER_LENGTH + pNode->option.length;
1795         }
1796         if (memcpy_s(current, remainingSize, &pNode->option, olen) != EOK) {
1797             DHCP_LOGE("memcpy current option out of options buffer!");
1798             ret = RET_FAILED;
1799             break;
1800         }
1801         remainingSize -= olen;
1802         current += olen;
1803         replyOptsLength += olen;
1804         if ((uint32_t)pNode->option.code == END_OPTION) {
1805             break;
1806         }
1807         pNode = pNode->next;
1808         if (replyOptsLength >= DHCP_OPTIONS_SIZE) {
1809             DHCP_LOGE("current option out of options buffer!");
1810             ret = RET_FAILED;
1811             break;
1812         }
1813     }
1814     reply->length += replyOptsLength;
1815     return ret;
1816 }
1817 
RegisterDhcpCallback(PDhcpServerContext ctx, DhcpServerCallback callback)1818 void RegisterDhcpCallback(PDhcpServerContext ctx, DhcpServerCallback callback)
1819 {
1820     DHCP_LOGI("start %{public}s   %{public}d.", __func__, __LINE__);
1821     ServerContext *srvIns = GetServerInstance(ctx);
1822     if (!srvIns) {
1823         DHCP_LOGE("dhcp server context pointer is null.");
1824         return;
1825     }
1826     srvIns->callback = callback;
1827 }
1828 
RegisterDeviceChangedCallback(PDhcpServerContext ctx, DeviceConnectFun func)1829 void RegisterDeviceChangedCallback(PDhcpServerContext ctx, DeviceConnectFun func)
1830 {
1831     DHCP_LOGI("start %{public}s %{public}d.", __func__, __LINE__);
1832     ServerContext *srvIns = GetServerInstance(ctx);
1833     if (!srvIns) {
1834         DHCP_LOGE("dhcp server context pointer is null.");
1835         return;
1836     }
1837     srvIns->deviceConnectFun = func;
1838 }
1839 
InitServerContext(DhcpConfig *config, DhcpServerContext *ctx)1840 static int InitServerContext(DhcpConfig *config, DhcpServerContext *ctx)
1841 {
1842     if (!config) {
1843         DHCP_LOGE("server configure pointer is null.");
1844         return RET_FAILED;
1845     }
1846     ServerContext *srvIns = GetServerInstance(ctx);
1847     if (!srvIns) {
1848         DHCP_LOGE("dhcp server context pointer is null.");
1849         return RET_FAILED;
1850     }
1851     if (InitAddressPool(&srvIns->addressPool, config->ifname, nullptr) != RET_SUCCESS) {
1852         DHCP_LOGD("failed to init address pool.");
1853         return RET_FAILED;
1854     }
1855     if (memcpy_s(ctx->ifname, sizeof(ctx->ifname), config->ifname, strlen(config->ifname)) != EOK) {
1856         DHCP_LOGD("failed to set interface name.");
1857         return RET_FAILED;
1858     }
1859     srvIns->serverFd = 0;
1860     srvIns->callback = 0;
1861     srvIns->looperState = LS_IDLE;
1862     srvIns->broadCastFlagEnable = static_cast<int>(config->broadcast);
1863     srvIns->addressPool.serverId = config->serverId;
1864     srvIns->addressPool.netmask = config->netmask;
1865     srvIns->addressPool.gateway = config->gateway;
1866     if (config->pool.beginAddress && config->pool.endAddress) {
1867         srvIns->addressPool.addressRange.beginAddress = config->pool.beginAddress;
1868         srvIns->addressPool.addressRange.endAddress = config->pool.endAddress;
1869     } else {
1870         srvIns->addressPool.addressRange.beginAddress = FirstIpAddress(config->serverId, config->netmask);
1871         srvIns->addressPool.addressRange.endAddress = LastIpAddress(config->serverId, config->netmask);
1872     }
1873     if (memcpy_s(srvIns->addressPool.ifname, sizeof(srvIns->addressPool.ifname),
1874         config->ifname, strlen(config->ifname)) != EOK) {
1875         DHCP_LOGD("failed to set interface name.");
1876         return RET_FAILED;
1877     }
1878     if (!CheckAddressRange(&srvIns->addressPool)) {
1879         DHCP_LOGE("failed to validate address range.");
1880         return RET_FAILED;
1881     }
1882     InitLeaseFile(&srvIns->addressPool);
1883     srvIns->addressPool.leaseTime = config->leaseTime;
1884     srvIns->addressPool.renewalTime = config->renewalTime;
1885     srvIns->addressPool.rebindingTime = config->rebindingTime;
1886     return RET_SUCCESS;
1887 }
1888 
InitServerFixedOptions(DhcpConfig *config, DhcpServerContext *ctx)1889 int InitServerFixedOptions(DhcpConfig *config, DhcpServerContext *ctx)
1890 {
1891     if (!config) {
1892         DHCP_LOGE("server configure pointer is null.");
1893         return RET_FAILED;
1894     }
1895     ServerContext *srvIns = GetServerInstance(ctx);
1896     if (!srvIns) {
1897         DHCP_LOGE("dhcp server context pointer is null.");
1898         return RET_FAILED;
1899     }
1900 
1901     if (!HasInitialized(&config->options)) {
1902         DHCP_LOGE("dhcp configure has not been initialized.");
1903         return RET_FAILED;
1904     }
1905     if (InitOptionList(&srvIns->addressPool.fixedOptions) != RET_SUCCESS) {
1906         return RET_FAILED;
1907     }
1908     if (config->options.first != nullptr && config->options.size > 0) {
1909         DhcpOptionNode *pNode = config->options.first->next;
1910         for (size_t i = 0; pNode != nullptr && i < config->options.size; i++) {
1911             PushBackOption(&srvIns->addressPool.fixedOptions, &pNode->option);
1912             DHCP_LOGD("append fixed option ==> %hhu,%d", pNode->option.code,
1913                 pNode->option.length);
1914             pNode = pNode->next;
1915         }
1916     }
1917     return RET_SUCCESS;
1918 }
1919 
InitializeServer(DhcpConfig *config)1920 PDhcpServerContext InitializeServer(DhcpConfig *config)
1921 {
1922     DHCP_LOGI("start %{public}s   %{public}d.", __func__, __LINE__);
1923     DhcpServerContext *context = nullptr;
1924     if (!config) {
1925         DHCP_LOGE("dhcp server config pointer is null.");
1926         return nullptr;
1927     }
1928     if (strlen(config->ifname) == 0) {
1929         DHCP_LOGE("can't found interface name config.");
1930         return nullptr;
1931     }
1932     if (!config->serverId || !config->netmask) {
1933         DHCP_LOGE("missing required parameter or config item: \"serverId\", \"netmask\"");
1934         return nullptr;
1935     }
1936     if ((context = (DhcpServerContext *)calloc(1, sizeof(DhcpServerContext))) == nullptr) {
1937         DHCP_LOGE("failed to calloc server context.");
1938         return nullptr;
1939     }
1940     if ((context->instance = (ServerContext *)calloc(1, sizeof(ServerContext))) == nullptr) {
1941         DHCP_LOGE("failed to calloc server instance.");
1942         FreeServerContext(&context);
1943         return nullptr;
1944     }
1945     if (InitServerContext(config, context) != RET_SUCCESS) {
1946         DHCP_LOGE("failed initialize dhcp server context.");
1947         FreeServerContext(&context);
1948         return nullptr;
1949     }
1950     if (InitServerFixedOptions(config, context) != RET_SUCCESS) {
1951         DHCP_LOGE("failed initialize dhcp server fixed options.");
1952         FreeServerContext(&context);
1953         return nullptr;
1954     }
1955     DHCP_LOGI("server id: %{private}s", ParseStrIp(config->serverId));
1956     DHCP_LOGI("netmask: %{private}s", ParseStrIp(config->netmask));
1957     if (config->gateway) {
1958         DHCP_LOGI("gateway: %{private}s", ParseStrIp(config->gateway));
1959     }
1960     DHCP_LOGI("address range begin of: %{private}s", ParseStrIp(config->pool.beginAddress));
1961     DHCP_LOGI("address range end of: %{private}s", ParseStrIp(config->pool.endAddress));
1962     context->instance->initialized = 1;
1963     return context;
1964 }
1965 
FreeServerContext(PDhcpServerContext *ctx)1966 int FreeServerContext(PDhcpServerContext *ctx)
1967 {
1968     if (ctx == nullptr || *ctx == nullptr) {
1969         DHCP_LOGE("dhcp server context pointer is null.");
1970         return RET_FAILED;
1971     }
1972     ServerContext *srvIns = GetServerInstance(*ctx);
1973     if (!srvIns) {
1974         DHCP_LOGE("dhcp server instance pointer is null.");
1975         return RET_FAILED;
1976     }
1977     int times = 5;
1978     while (srvIns->looperState != LS_STOPED && srvIns->looperState != LS_IDLE) {
1979         DHCP_LOGE("FreeServerContext wait 300ms.");
1980         usleep(300000);
1981         times--;
1982         if (times <= 0) {
1983             return RET_FAILED;
1984         }
1985     }
1986     FreeAddressPool(&srvIns->addressPool);
1987     if ((*ctx)->instance != nullptr) {
1988         free((*ctx)->instance);
1989         (*ctx)->instance = nullptr;
1990     }
1991     free(*ctx);
1992     *ctx = nullptr;
1993     return RET_SUCCESS;
1994 }
1995