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