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