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