1 /*
2  * Copyright (C) 2021 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 #include "dhcp_socket.h"
16 
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <netpacket/packet.h>
24 #include <net/ethernet.h>
25 #include <net/if.h>
26 #include <arpa/inet.h>
27 
28 #include "dhcp_options.h"
29 #include "securec.h"
30 #include "dhcp_logger.h"
31 
32 DEFINE_DHCPLOG_DHCP_LABEL("DhcpSocket");
33 
GetCheckSum(uint16_t *pData, int nBytes)34 static uint16_t GetCheckSum(uint16_t *pData, int nBytes)
35 {
36     uint32_t uTotalSum = 0;
37 
38     /* Calculates the network checksum by 2 bytes. */
39     while (nBytes >= DHCP_UINT16_BYTES)  {
40         uTotalSum += *pData++;
41         nBytes -= DHCP_UINT16_BYTES;
42     }
43     /* Calculate the network checksum based on the remaining bytes. */
44     if (nBytes > 0) {
45         uint16_t u16Sum;
46         *(uint8_t *)(&u16Sum) = *(uint8_t *)pData;
47         uTotalSum += u16Sum;
48     }
49     /* Checksum conversion from 32-bit to 16-bit. */
50     while (uTotalSum >> DHCP_UINT16_BITS) {
51         uTotalSum = (uTotalSum & 0xffff) + (uTotalSum >> DHCP_UINT16_BITS);
52     }
53 
54     return (uint16_t)(~uTotalSum);
55 }
56 
57 /* Raw socket can receive data frames or data packets from the local network interface. */
CreateRawSocket(int *rawFd)58 int CreateRawSocket(int *rawFd)
59 {
60     int sockFd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
61     if (sockFd == -1) {
62         DHCP_LOGE("CreateRawSocket() failed, socket error:%{public}d.", errno);
63         return SOCKET_OPT_FAILED;
64     }
65     *rawFd = sockFd;
66     return SOCKET_OPT_SUCCESS;
67 }
68 
69 /* Kernel socket can receive data frames or data packets from the local network interface, ip and port. */
CreateKernelSocket(int *sockFd)70 int CreateKernelSocket(int *sockFd)
71 {
72     if (sockFd == NULL) {
73         DHCP_LOGE("CreateKernelSocket() failed, sockFd is NULL!");
74         return SOCKET_OPT_FAILED;
75     }
76     int nFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
77     if (nFd == -1) {
78         DHCP_LOGE("CreateKernelSocket() failed, socket error:%{public}d.", errno);
79         return SOCKET_OPT_FAILED;
80     }
81     *sockFd = nFd;
82     return SOCKET_OPT_SUCCESS;
83 }
84 
BindRawSocket(const int rawFd, const int ifaceIndex, const uint8_t *ifaceAddr)85 int BindRawSocket(const int rawFd, const int ifaceIndex, const uint8_t *ifaceAddr)
86 {
87     if (rawFd < 0) {
88         DHCP_LOGE("BindRawSocket() failed, rawFd:%{public}d error!", rawFd);
89         return SOCKET_OPT_FAILED;
90     }
91 
92     struct sockaddr_ll rawAddr;
93     if (memset_s(&rawAddr, sizeof(rawAddr), 0, sizeof(rawAddr)) != EOK) {
94         DHCP_LOGE("BindRawSocket() failed, memset_s rawAddr error!");
95         close(rawFd);
96         return SOCKET_OPT_FAILED;
97     }
98     rawAddr.sll_ifindex = ifaceIndex;
99     rawAddr.sll_protocol = htons(ETH_P_IP);
100     rawAddr.sll_family = AF_PACKET;
101     if (ifaceAddr != NULL) {
102         rawAddr.sll_halen = MAC_ADDR_LEN;
103         if (memcpy_s(rawAddr.sll_addr, sizeof(rawAddr.sll_addr), ifaceAddr, MAC_ADDR_LEN) != EOK) {
104             DHCP_LOGE("BindRawSocket() failed, memcpy_s rawAddr.sll_addr error!");
105             close(rawFd);
106             return SOCKET_OPT_FAILED;
107         }
108     }
109     int nRet = bind(rawFd, (struct sockaddr *)&rawAddr, sizeof(rawAddr));
110     if (nRet == -1) {
111         DHCP_LOGE("BindRawSocket() index:%{public}d failed, bind error:%{public}d.", ifaceIndex, errno);
112         close(rawFd);
113         return SOCKET_OPT_FAILED;
114     }
115 
116     return SOCKET_OPT_SUCCESS;
117 }
118 
BindKernelSocket(const int sockFd, const char *ifaceName, const uint32_t sockIp, const int sockPort, bool bCast)119 int BindKernelSocket(const int sockFd, const char *ifaceName, const uint32_t sockIp, const int sockPort, bool bCast)
120 {
121     if (sockFd < 0) {
122         DHCP_LOGE("BindKernelSocket() failed, sockFd:%{public}d error!", sockFd);
123         return SOCKET_OPT_FAILED;
124     }
125 
126     /* Bind the specified interface. */
127     if (ifaceName != NULL) {
128         struct ifreq ifaceReq;
129         if (strncpy_s(ifaceReq.ifr_name, sizeof(ifaceReq.ifr_name), ifaceName, strlen(ifaceName)) != EOK) {
130             close(sockFd);
131             return SOCKET_OPT_FAILED;
132         }
133         if (setsockopt(sockFd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifaceReq, sizeof(ifaceReq)) == -1) {
134             DHCP_LOGE("BindKernelSocket() %{public}s SO_BINDTODEVICE error:%{public}d.", ifaceName, errno);
135             close(sockFd);
136             return SOCKET_OPT_FAILED;
137         }
138     }
139 
140     /* Set the broadcast feature of the data sent by the socket. */
141     if (bCast) {
142         int broadcast = 1;
143         if (setsockopt(sockFd, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(int)) == -1) {
144             DHCP_LOGE("BindKernelSocket() sockFd:%{public}d SO_BROADCAST error:%{public}d.", sockFd, errno);
145             close(sockFd);
146             return SOCKET_OPT_FAILED;
147         }
148     }
149 
150     /* Allow multiple sockets to use the same port number. */
151     int bReuseaddr = 1;
152     if (setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, (const char *)&bReuseaddr, sizeof(bReuseaddr)) == -1) {
153         DHCP_LOGE("BindKernelSocket() sockFd:%{public}d SO_REUSEADDR error:%{public}d.", sockFd, errno);
154         close(sockFd);
155         return SOCKET_OPT_FAILED;
156     }
157 
158     struct sockaddr_in kernelAddr;
159     if (memset_s(&kernelAddr, sizeof(kernelAddr), 0, sizeof(kernelAddr)) != EOK) {
160         close(sockFd);
161         return SOCKET_OPT_FAILED;
162     }
163     kernelAddr.sin_addr.s_addr = sockIp;
164     kernelAddr.sin_port = htons(sockPort);
165     kernelAddr.sin_family = AF_INET;
166     int nRet = bind(sockFd, (struct sockaddr *)&kernelAddr, sizeof(kernelAddr));
167     if (nRet == -1) {
168         DHCP_LOGE("BindKernelSocket() sockFd:%{public}d failed, bind error:%{public}d.", sockFd, errno);
169         close(sockFd);
170         return SOCKET_OPT_FAILED;
171     }
172 
173     return SOCKET_OPT_SUCCESS;
174 }
175 
SendToDhcpPacket( const struct DhcpPacket *sendPacket, uint32_t srcIp, uint32_t destIp, int destIndex, const uint8_t *destHwaddr)176 int SendToDhcpPacket(
177     const struct DhcpPacket *sendPacket, uint32_t srcIp, uint32_t destIp, int destIndex, const uint8_t *destHwaddr)
178 {
179     DHCP_LOGI("SendToDhcpPacket enter, destIndex:%{public}d, destHwaddr:%{public}d", destIndex, *destHwaddr);
180     int nFd = -1;
181     if (CreateRawSocket(&nFd) != SOCKET_OPT_SUCCESS) {
182         DHCP_LOGE("SendToDhcpPacket CreateRawSocket fail.");
183         return SOCKET_OPT_FAILED;
184     }
185 
186     struct sockaddr_ll rawAddr;
187     if ((memset_s(&rawAddr, sizeof(rawAddr), 0, sizeof(rawAddr)) != EOK) ||
188         (memcpy_s(rawAddr.sll_addr, sizeof(rawAddr.sll_addr), destHwaddr, MAC_ADDR_LEN) != EOK)) {
189         close(nFd);
190         DHCP_LOGE("SendToDhcpPacket memcpy_s fail.");
191         return SOCKET_OPT_FAILED;
192     }
193     rawAddr.sll_ifindex = destIndex;
194     rawAddr.sll_protocol = htons(ETH_P_IP);
195     rawAddr.sll_family = AF_PACKET;
196     rawAddr.sll_halen = MAC_ADDR_LEN;
197     if (bind(nFd, (struct sockaddr *)&rawAddr, sizeof(rawAddr)) == -1) {
198         close(nFd);
199         DHCP_LOGE("SendToDhcpPacket bind fail.");
200         return SOCKET_OPT_FAILED;
201     }
202 
203     /* Filling the structure information. */
204     struct UdpDhcpPacket udpPackets;
205     if (memset_s(&udpPackets, sizeof(udpPackets), 0, sizeof(udpPackets)) != EOK) {
206         close(nFd);
207         DHCP_LOGE("SendToDhcpPacket memset_s udpPackets fail.");
208         return SOCKET_OPT_FAILED;
209     }
210     /* get append options length , include endpoint length(2) */
211     int optionLen = GetEndOptionIndex(sendPacket->options) + DHCP_APPEND_LEN;
212     int sendLen = sizeof(udpPackets) - sizeof(udpPackets.data.options) + optionLen;
213     int dhcpPackLen = sizeof(struct DhcpPacket) - sizeof(udpPackets.data.options) + optionLen;
214     udpPackets.udp.source = htons(BOOTP_CLIENT);
215     udpPackets.udp.dest = htons(BOOTP_SERVER);
216     udpPackets.udp.len = htons(sizeof(udpPackets.udp) + dhcpPackLen);
217     udpPackets.ip.tot_len = udpPackets.udp.len;
218     udpPackets.ip.protocol = IPPROTO_UDP;
219     udpPackets.ip.saddr = srcIp;
220     udpPackets.ip.daddr = destIp;
221     if (memcpy_s(&(udpPackets.data), sizeof(struct DhcpPacket), sendPacket, sizeof(struct DhcpPacket)) != EOK) {
222         close(nFd);
223         DHCP_LOGE("SendToDhcpPacket memcpy_s sendPacket fail.");
224         return SOCKET_OPT_FAILED;
225     }
226     udpPackets.udp.check = GetCheckSum((uint16_t *)&udpPackets, sizeof(struct UdpDhcpPacket));
227     udpPackets.ip.ihl = sizeof(udpPackets.ip) >> DHCP_UINT16_BYTES;
228     udpPackets.ip.version = IPVERSION;
229     udpPackets.ip.tot_len = htons(sendLen);
230     udpPackets.ip.ttl = IPDEFTTL;
231     udpPackets.ip.check = GetCheckSum((uint16_t *)&(udpPackets.ip), sizeof(udpPackets.ip));
232 
233     ssize_t nBytes = sendto(nFd, &udpPackets, sendLen, 0, (struct sockaddr *)&rawAddr, sizeof(rawAddr));
234     if (nBytes <= 0) {
235         DHCP_LOGE("SendToDhcpPacket optionLen:%{public}d sendLen:%{public}d, "
236             "dhcpPackLen:%{public}d fd:%{public}d failed, sendto error:%{public}d.",
237             optionLen, sendLen, dhcpPackLen, nFd, errno);
238     } else {
239         DHCP_LOGI("SendToDhcpPacket optionLen:%{public}d sendLen:%{public}d, "
240             "dhcpPackLen:%{public}d fd:%{public}d, index:%{public}d, bytes:%{public}d.",
241             optionLen, sendLen, dhcpPackLen, nFd, destIndex, static_cast<int>(nBytes));
242     }
243     close(nFd);
244     return (nBytes <= 0) ? SOCKET_OPT_FAILED : SOCKET_OPT_SUCCESS;
245 }
246 
SendDhcpPacket(struct DhcpPacket *sendPacket, uint32_t srcIp, uint32_t destIp)247 int SendDhcpPacket(struct DhcpPacket *sendPacket, uint32_t srcIp, uint32_t destIp)
248 {
249     int nFd = -1;
250     if ((CreateKernelSocket(&nFd) != SOCKET_OPT_SUCCESS) ||
251         (BindKernelSocket(nFd, NULL, srcIp, BOOTP_CLIENT, false) != SOCKET_OPT_SUCCESS)) {
252         DHCP_LOGE("SendDhcpPacket fd:%{public}d failed!", nFd);
253         return SOCKET_OPT_FAILED;
254     }
255 
256     struct sockaddr_in kernelAddr;
257     if (memset_s(&kernelAddr, sizeof(kernelAddr), 0, sizeof(kernelAddr)) != EOK) {
258         close(nFd);
259         return SOCKET_OPT_FAILED;
260     }
261     kernelAddr.sin_addr.s_addr = destIp;
262     kernelAddr.sin_port = htons(BOOTP_SERVER);
263     kernelAddr.sin_family = AF_INET;
264     int nRet = connect(nFd, (struct sockaddr *)&kernelAddr, sizeof(kernelAddr));
265     if (nRet == -1) {
266         DHCP_LOGE("SendDhcpPacket nFd:%{public}d failed, connect error:%{public}d.", nFd, errno);
267         close(nFd);
268         return SOCKET_OPT_FAILED;
269     }
270 
271     ssize_t nBytes = write(nFd, sendPacket, sizeof(struct DhcpPacket));
272     if (nBytes <= 0) {
273         DHCP_LOGE("SendDhcpPacket fd:%{public}d failed, write error:%{public}d.", nFd, errno);
274     } else {
275         DHCP_LOGI("SendDhcpPacket fd:%{public}d, bytes:%{public}d.", nFd, static_cast<int>(nBytes));
276     }
277     close(nFd);
278     return (nBytes <= 0) ? SOCKET_OPT_FAILED : SOCKET_OPT_SUCCESS;
279 }
280 
CheckReadBytes(const int count, const int totLen)281 int CheckReadBytes(const int count, const int totLen)
282 {
283     if (count < 0) {
284         DHCP_LOGE("CheckReadBytes() couldn't read on raw listening socket, count:%{public}d, error:%{public}d!",
285             count, errno);
286         return SOCKET_OPT_ERROR;
287     }
288 
289     int nCommonSize = sizeof(struct iphdr) + sizeof(struct udphdr);
290     if (count < nCommonSize) {
291         DHCP_LOGE("CheckReadBytes() read size:%{public}d less than common size:%{public}d!", count, nCommonSize);
292         return SOCKET_OPT_FAILED;
293     }
294 
295     if (count < totLen) {
296         DHCP_LOGE("CheckReadBytes() count:%{public}d less than totLen:%{public}d, packet is Truncated!", count, totLen);
297         return SOCKET_OPT_FAILED;
298     }
299 
300     DHCP_LOGI("CheckReadBytes() count:%{public}d, tot:%{public}d, common:%{public}d.", count, totLen, nCommonSize);
301     return SOCKET_OPT_SUCCESS;
302 }
303 
CheckUdpPacket(struct UdpDhcpPacket *pPacket, const int totLen)304 int CheckUdpPacket(struct UdpDhcpPacket *pPacket, const int totLen)
305 {
306     if (pPacket == NULL) {
307         DHCP_LOGE("CheckUdpPacket() failed, pPacket == NULL!");
308         return SOCKET_OPT_FAILED;
309     }
310 
311     if (totLen > (int)sizeof(struct UdpDhcpPacket)) {
312         DHCP_LOGE("CheckUdpPacket() totLen:%{public}d more than %{public}d!", totLen,
313             (int)sizeof(struct UdpDhcpPacket));
314         return SOCKET_OPT_FAILED;
315     }
316 
317     if ((pPacket->ip.protocol != IPPROTO_UDP) || (pPacket->ip.version != IPVERSION)) {
318         DHCP_LOGE("CheckUdpPacket() failed, pPacket->ip.protocol:%{public}d or version:%{public}u error!",
319             pPacket->ip.protocol, pPacket->ip.version);
320         return SOCKET_OPT_FAILED;
321     }
322 
323     uint32_t uIhl = (uint32_t)(sizeof(pPacket->ip) >> DHCP_UINT16_BYTES);
324     if (pPacket->ip.ihl != uIhl) {
325         DHCP_LOGE("CheckUdpPacket() failed, pPacket->ip.ihl:%{public}u error, uIhl:%{public}u!", pPacket->ip.ihl, uIhl);
326         return SOCKET_OPT_FAILED;
327     }
328 
329     if (pPacket->udp.dest != htons(BOOTP_CLIENT)) {
330         DHCP_LOGE("CheckUdpPacket() failed, pPacket->udp.dest:%{public}d error, htons:%{public}d!",
331             pPacket->udp.dest, htons(BOOTP_CLIENT));
332         return SOCKET_OPT_FAILED;
333     }
334 
335     uint16_t uLen = (uint16_t)(totLen - (int)sizeof(pPacket->ip));
336     if (ntohs(pPacket->udp.len) != uLen) {
337         DHCP_LOGE("CheckUdpPacket() failed, pPacket->udp.len:%{public}d error, uLen:%{public}d!",
338             pPacket->udp.len, uLen);
339         return SOCKET_OPT_FAILED;
340     }
341     DHCP_LOGI("CheckUdpPacket() success, totLen:%{public}d.", totLen);
342     return SOCKET_OPT_SUCCESS;
343 }
344 
CheckPacketIpSum(struct UdpDhcpPacket *pPacket, const int bytes)345 int CheckPacketIpSum(struct UdpDhcpPacket *pPacket, const int bytes)
346 {
347     if (pPacket == NULL) {
348         return SOCKET_OPT_FAILED;
349     }
350 
351     if (CheckUdpPacket(pPacket, bytes) != SOCKET_OPT_SUCCESS) {
352         return SOCKET_OPT_FAILED;
353     }
354 
355     /* Check packet ip sum. */
356     uint16_t uCheck = pPacket->ip.check;
357     pPacket->ip.check = 0;
358     uint16_t uCheckSum = GetCheckSum((uint16_t *)&(pPacket->ip), sizeof(pPacket->ip));
359     if (uCheck != uCheckSum) {
360         DHCP_LOGE("CheckPacketIpSum() failed, ip.check:%{public}d, uCheckSum:%{public}d!", uCheck, uCheckSum);
361         return SOCKET_OPT_ERROR;
362     }
363     DHCP_LOGI("CheckPacketIpSum() success, bytes:%{public}d.", bytes);
364     return SOCKET_OPT_SUCCESS;
365 }
366 
CheckPacketUdpSum(struct UdpDhcpPacket *pPacket, const int bytes)367 int CheckPacketUdpSum(struct UdpDhcpPacket *pPacket, const int bytes)
368 {
369     if (pPacket == NULL) {
370         DHCP_LOGE("CheckPacketUdpSum() failed, pPacket == NULL!");
371         return SOCKET_OPT_FAILED;
372     }
373 
374     /* Check packet udp sum. */
375     uint16_t uCheck = pPacket->udp.check;
376     pPacket->udp.check = 0;
377     u_int32_t source = pPacket->ip.saddr;
378     u_int32_t dest = pPacket->ip.daddr;
379     if (memset_s(&pPacket->ip, sizeof(pPacket->ip), 0, sizeof(pPacket->ip)) != EOK) {
380         DHCP_LOGE("CheckPacketUdpSum() failed, memset_s ERROR!");
381         return SOCKET_OPT_FAILED;
382     }
383     pPacket->ip.protocol = IPPROTO_UDP;
384     pPacket->ip.saddr = source;
385     pPacket->ip.daddr = dest;
386     pPacket->ip.tot_len = pPacket->udp.len;
387     uint16_t uCheckSum = GetCheckSum((uint16_t *)pPacket, bytes);
388     if (uCheck && (uCheck != uCheckSum)) {
389         DHCP_LOGE("CheckPacketUdpSum() failed, udp.check:%{public}d, uCheckSum:%{public}d!", uCheck, uCheckSum);
390         return SOCKET_OPT_FAILED;
391     }
392     DHCP_LOGI("CheckPacketUdpSum() success, bytes:%{public}d.", bytes);
393     return SOCKET_OPT_SUCCESS;
394 }
395 
GetDhcpRawPacket(struct DhcpPacket *getPacket, int rawFd)396 int GetDhcpRawPacket(struct DhcpPacket *getPacket, int rawFd)
397 {
398     if (getPacket == NULL) {
399         return SOCKET_OPT_FAILED;
400     }
401 
402     /* Get and check udp dhcp packet bytes. */
403     struct UdpDhcpPacket udpPackets;
404     if (memset_s(&udpPackets, sizeof(struct UdpDhcpPacket), 0, sizeof(struct UdpDhcpPacket)) != EOK) {
405         return SOCKET_OPT_FAILED;
406     }
407     int nBytes = read(rawFd, &udpPackets, sizeof(struct UdpDhcpPacket));
408     int nRet = CheckReadBytes(nBytes, (int)ntohs(udpPackets.ip.tot_len));
409     if (nRet != SOCKET_OPT_SUCCESS) {
410         usleep(SLEEP_TIME_200_MS);
411         return nRet;
412     }
413 
414     /* Check udp dhcp packet sum. */
415     nBytes = (int)ntohs(udpPackets.ip.tot_len);
416     nRet = CheckPacketIpSum(&udpPackets, nBytes);
417     if (nRet != SOCKET_OPT_SUCCESS) {
418         return nRet;
419     }
420     nRet = CheckPacketUdpSum(&udpPackets, nBytes);
421     if (nRet != SOCKET_OPT_SUCCESS) {
422         return nRet;
423     }
424 
425     int nDhcpPacket = nBytes - (int)(sizeof(udpPackets.ip) + sizeof(udpPackets.udp));
426     if (memcpy_s(getPacket, sizeof(struct DhcpPacket), &(udpPackets.data), nDhcpPacket) != EOK) {
427         DHCP_LOGE("GetDhcpRawPacket() memcpy_s packet.data failed!");
428         return SOCKET_OPT_FAILED;
429     }
430     if (ntohl(getPacket->cookie) != MAGIC_COOKIE) {
431         DHCP_LOGE("GetDhcpRawPacket() cook:%{public}x error, COOK:%{public}x!", ntohl(getPacket->cookie), MAGIC_COOKIE);
432         return SOCKET_OPT_FAILED;
433     }
434     return nDhcpPacket;
435 }
436 
GetDhcpKernelPacket(struct DhcpPacket *getPacket, int sockFd)437 int GetDhcpKernelPacket(struct DhcpPacket *getPacket, int sockFd)
438 {
439     if (getPacket == NULL) {
440         return SOCKET_OPT_FAILED;
441     }
442 
443     int nBytes = -1;
444     if ((nBytes = read(sockFd, getPacket, sizeof(struct DhcpPacket))) == -1) {
445         DHCP_LOGE("GetDhcpKernelPacket() couldn't read on kernel listening socket, error:%{public}d!", errno);
446         return SOCKET_OPT_ERROR;
447     }
448 
449     if (ntohl(getPacket->cookie) != MAGIC_COOKIE) {
450         DHCP_LOGE("GetDhcpKernelPacket() cook:%{public}x error, COOK:%{public}x!", ntohl(getPacket->cookie),
451             MAGIC_COOKIE);
452         return SOCKET_OPT_FAILED;
453     }
454     return nBytes;
455 }
456