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