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