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