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
16 #include "nstackx_dev.h"
17 #include "nstackx_util.h"
18 #include "nstackx_error.h"
19 #include "nstackx_log.h"
20 #include "securec.h"
21
22 #define TAG "nStackXDev"
23
GetConnectionTypeByDevName(const char * devName,uint32_t devNameLen,uint16_t * connectType)24 static int32_t GetConnectionTypeByDevName(const char *devName, uint32_t devNameLen, uint16_t *connectType)
25 {
26 int32_t ret = NSTACKX_EFAILED;
27 uint32_t p2pNameLen = (uint32_t)strlen(P2P_DEV_NAME_PRE);
28 uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
29
30 if (devNameLen >= p2pNameLen && memcmp(devName, P2P_DEV_NAME_PRE, p2pNameLen) == 0) {
31 *connectType = CONNECT_TYPE_P2P;
32 ret = NSTACKX_EOK;
33 LOGI(TAG, "connType is P2P(%hu)", *connectType);
34 } else if (devNameLen >= wlanNameLen && memcmp(devName, WLAN_DEV_NAME_PRE, wlanNameLen) == 0) {
35 *connectType = CONNECT_TYPE_WLAN;
36 LOGI(TAG, "connType is WLAN(%hu)", *connectType);
37 ret = NSTACKX_EOK;
38 }
39 return ret;
40 }
41
GetInterfaceInfo(int32_t fd,int32_t option,struct ifreq * interface)42 static int32_t GetInterfaceInfo(int32_t fd, int32_t option, struct ifreq *interface)
43 {
44 if (interface == NULL) {
45 return NSTACKX_EINVAL;
46 }
47 if (ioctl(fd, SIOCGIFFLAGS, (char*)interface) < 0) {
48 LOGE(TAG, "ioctl fail, errno = %d", errno);
49 return NSTACKX_EFAILED;
50 }
51 if (!((uint16_t)interface->ifr_flags & IFF_UP)) {
52 LOGE(TAG, "interface is not up");
53 return NSTACKX_EINVAL;
54 }
55
56 /* get IP of this interface */
57 if (ioctl(fd, option, (char*)interface) < 0) {
58 LOGE(TAG, "ioctl fail, errno = %d", errno);
59 return NSTACKX_EFAILED;
60 }
61 return NSTACKX_EOK;
62 }
63
GetInterfaceIP(int32_t fd,struct ifreq * interface)64 int32_t GetInterfaceIP(int32_t fd, struct ifreq *interface)
65 {
66 return GetInterfaceInfo(fd, SIOCGIFADDR, interface);
67 }
68
GetInterfaceNetMask(int32_t fd,struct ifreq * interface)69 static int32_t GetInterfaceNetMask(int32_t fd, struct ifreq *interface)
70 {
71 return GetInterfaceInfo(fd, SIOCGIFNETMASK, interface);
72 }
73
GetInterfaceList(struct ifconf * ifc,struct ifreq * buf,uint32_t size)74 int32_t GetInterfaceList(struct ifconf *ifc, struct ifreq *buf, uint32_t size)
75 {
76 int32_t fd = socket(AF_INET, SOCK_DGRAM, 0);
77 if (fd < 0) {
78 return NSTACKX_EFAILED;
79 }
80 ifc->ifc_len = (int32_t)size;
81 ifc->ifc_buf = (char*)buf;
82 if (ioctl(fd, SIOCGIFCONF, (char*)ifc) < 0) {
83 LOGE(TAG, "ioctl fail, errno = %d", errno);
84 CloseSocketInner(fd);
85 return NSTACKX_EFAILED;
86 }
87 return fd;
88 }
89
GetConnectionTypeByDev(const uint32_t sourceIp,uint16_t * connectType)90 int32_t GetConnectionTypeByDev(const uint32_t sourceIp, uint16_t *connectType)
91 {
92 struct ifreq buf[INTERFACE_MAX];
93 struct ifconf ifc;
94
95 uint32_t ethNameLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
96 uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
97 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
98 if (fd < 0) {
99 LOGE(TAG, "get interfacelist failed");
100 return NSTACKX_EFAILED;
101 }
102
103 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
104 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
105 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
106 LOGI(TAG, "ndevice name: %s", buf[i].ifr_name);
107 uint32_t ifrNameLen = (uint32_t)strlen(buf[i].ifr_name);
108 if (ifrNameLen < ethNameLen && ifrNameLen < wlanNameLen) {
109 continue;
110 }
111
112 /* get IP of this interface */
113 int32_t state = GetInterfaceIP(fd, &buf[i]);
114 if (state == NSTACKX_EFAILED) {
115 goto L_ERROR;
116 } else if (state == NSTACKX_EINVAL) {
117 continue;
118 }
119 if (sourceIp == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
120 if (GetConnectionTypeByDevName(buf[i].ifr_name, ifrNameLen, connectType) == NSTACKX_EOK) {
121 break;
122 }
123 }
124 }
125 CloseSocketInner(fd);
126 return NSTACKX_EOK;
127 L_ERROR:
128 CloseSocketInner(fd);
129 LOGE(TAG, "get connect type failed");
130 return NSTACKX_EFAILED;
131 }
132
FindDevByInterfaceIP(int32_t fd,struct ifconf ifc,struct ifreq buf[],uint32_t sourceIP)133 static int32_t FindDevByInterfaceIP(int32_t fd, struct ifconf ifc, struct ifreq buf[], uint32_t sourceIP)
134 {
135 int32_t i;
136 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
137 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
138 for (i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
139 /* get IP of this interface */
140 int32_t state = GetInterfaceIP(fd, &buf[i]);
141 if (state == NSTACKX_EFAILED) {
142 return NSTACKX_EFAILED;
143 } else if (state == NSTACKX_EINVAL) {
144 continue;
145 }
146 if (sourceIP == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
147 return i;
148 }
149 }
150 return NSTACKX_EFAILED;
151 }
152
GetInterfaceNameByIP(uint32_t sourceIP,char * interfaceName,size_t nameLen)153 int32_t GetInterfaceNameByIP(uint32_t sourceIP, char *interfaceName, size_t nameLen)
154 {
155 struct ifreq buf[INTERFACE_MAX];
156 struct ifconf ifc;
157 int32_t devIndex;
158 int32_t ret = NSTACKX_EOK;
159 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
160 if (fd < 0) {
161 LOGE(TAG, "can't GetInterfaceList");
162 return NSTACKX_EFAILED;
163 }
164 devIndex = FindDevByInterfaceIP(fd, ifc, buf, sourceIP);
165 CloseSocketInner(fd);
166 if (devIndex >= 0) {
167 if (strcpy_s(interfaceName, nameLen, buf[devIndex].ifr_name) != EOK) {
168 LOGE(TAG, "strcpy failed");
169 ret = NSTACKX_EFAILED;
170 }
171 }
172 return ret;
173 }
174
BindToDeviceInner(int32_t sockfd,const struct ifreq * ifBinding)175 static int32_t BindToDeviceInner(int32_t sockfd, const struct ifreq *ifBinding)
176 {
177 struct ifreq ifr;
178
179 if (ifBinding == NULL) {
180 LOGE(TAG, "no right interface for binding");
181 return NSTACKX_EFAILED;
182 }
183 if (strncpy_s(ifr.ifr_ifrn.ifrn_name, IFNAMSIZ, ifBinding->ifr_name, strlen(ifBinding->ifr_name)) != EOK) {
184 LOGE(TAG, "strncpy fail");
185 return NSTACKX_EFAILED;
186 }
187 if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr)) < 0) {
188 LOGE(TAG, "setsockopt fail, errno = %d", errno);
189 return NSTACKX_EFAILED;
190 }
191 LOGI(TAG, "binding interface %s success", ifBinding->ifr_name);
192 return NSTACKX_EOK;
193 }
194
195 /*
196 * If localAddr isn't NULL, bind to interface correspond to ip,
197 * otherwise, bind to interface which is chosen by strategy.
198 */
BindToDevice(SocketDesc sockfd,const struct sockaddr_in * localAddr)199 int32_t BindToDevice(SocketDesc sockfd, const struct sockaddr_in *localAddr)
200 {
201 struct ifreq buf[INTERFACE_MAX];
202 struct ifconf ifc;
203 struct ifreq *ifBinding = NULL;
204
205 #ifndef DFINDER_SUPPORT_MULTI_NIF
206 uint32_t ethNameLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
207 uint32_t wlanNameLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
208 #endif
209
210 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
211 if (fd < 0) {
212 return NSTACKX_EFAILED;
213 }
214 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
215 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
216 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
217 #ifndef DFINDER_SUPPORT_MULTI_NIF
218 if (strlen(buf[i].ifr_name) < ethNameLen && strlen(buf[i].ifr_name) < wlanNameLen) {
219 continue;
220 }
221 #endif
222 /* get IP of this interface */
223 int32_t state = GetInterfaceIP(fd, &buf[i]);
224 if (state == NSTACKX_EFAILED) {
225 goto L_ERROR;
226 } else if (state == NSTACKX_EINVAL) {
227 continue;
228 }
229 if (localAddr != NULL) {
230 /* find corresponding interface by ip */
231 if (localAddr->sin_addr.s_addr == ((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr.s_addr) {
232 ifBinding = &buf[i];
233 break;
234 }
235 } else {
236 #ifndef DFINDER_SUPPORT_MULTI_NIF
237 /* strategy: ethernet have higher priority */
238 if (memcmp(buf[i].ifr_name, ETH_DEV_NAME_PRE, ethNameLen) == 0) {
239 ifBinding = &buf[i];
240 break;
241 } else if (memcmp(buf[i].ifr_name, WLAN_DEV_NAME_PRE, wlanNameLen) == 0) {
242 ifBinding = &buf[i];
243 }
244 #endif
245 }
246 }
247 CloseSocketInner(fd);
248 return BindToDeviceInner(sockfd, ifBinding);
249 L_ERROR:
250 LOGE(TAG, "ioctl fail, errno = %d", errno);
251 CloseSocketInner(fd);
252 return NSTACKX_EFAILED;
253 }
254
GetIfBroadcastIp(const char * ifName,char * ipString,size_t ipStringLen)255 int32_t GetIfBroadcastIp(const char *ifName, char *ipString, size_t ipStringLen)
256 {
257 struct ifreq buf[INTERFACE_MAX];
258 struct ifconf ifc;
259 uint8_t foundIp = NSTACKX_FALSE;
260
261 if (ifName == NULL) {
262 return NSTACKX_EFAILED;
263 }
264
265 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
266 if (fd < 0) {
267 return NSTACKX_EFAILED;
268 }
269
270 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
271 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
272 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
273 if (strlen(buf[i].ifr_name) < strlen(ifName)) {
274 continue;
275 }
276 if (memcmp(buf[i].ifr_name, ifName, strlen(ifName)) != 0) {
277 continue;
278 }
279 if (GetInterfaceInfo(fd, SIOCGIFBRDADDR, &buf[i]) != NSTACKX_EOK) {
280 continue;
281 }
282 if (buf[i].ifr_addr.sa_family != AF_INET) {
283 continue;
284 }
285
286 if (inet_ntop(AF_INET, &(((struct sockaddr_in *)&(buf[i].ifr_addr))->sin_addr), ipString,
287 (socklen_t)ipStringLen) == NULL) {
288 continue;
289 }
290 foundIp = NSTACKX_TRUE;
291 break;
292 }
293 CloseSocketInner(fd);
294
295 if (!foundIp) {
296 return NSTACKX_EFAILED;
297 }
298
299 return NSTACKX_EOK;
300 }
301
IsValidInterface(const char * interfaceName)302 static uint8_t IsValidInterface(const char *interfaceName)
303 {
304 if (interfaceName == NULL) {
305 return NSTACKX_FALSE;
306 }
307 uint32_t targetDevLen = (uint32_t)strlen(P2P_DEV_NAME_PRE);
308 if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, P2P_DEV_NAME_PRE, targetDevLen) == 0) {
309 return NSTACKX_TRUE;
310 }
311 targetDevLen = (uint32_t)strlen(ETH_DEV_NAME_PRE);
312 if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, ETH_DEV_NAME_PRE, targetDevLen) == 0) {
313 return NSTACKX_TRUE;
314 }
315 targetDevLen = (uint32_t)strlen(WLAN_DEV_NAME_PRE);
316 if (strlen(interfaceName) >= targetDevLen && memcmp(interfaceName, WLAN_DEV_NAME_PRE, targetDevLen) == 0) {
317 return NSTACKX_TRUE;
318 }
319 return NSTACKX_FALSE;
320 }
321
GetTargetInterface(const struct sockaddr_in * dstAddr,struct ifreq * localDev)322 int32_t GetTargetInterface(const struct sockaddr_in *dstAddr, struct ifreq *localDev)
323 {
324 struct ifreq buf[INTERFACE_MAX];
325 struct ifconf ifc;
326 uint32_t localIp;
327 uint32_t netMask;
328 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
329 if (fd < 0) {
330 return NSTACKX_EFAILED;
331 }
332 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
333 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
334 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
335 if (!IsValidInterface(buf[i].ifr_name)) {
336 continue;
337 }
338 /* get IP of this interface */
339 int32_t state = GetInterfaceIP(fd, &buf[i]);
340 if (state == NSTACKX_EFAILED) {
341 goto L_ERROR;
342 } else if (state == NSTACKX_EINVAL) {
343 continue;
344 }
345 localIp = ((struct sockaddr_in *)(&buf[i].ifr_addr))->sin_addr.s_addr;
346 state = GetInterfaceNetMask(fd, &buf[i]);
347 if (state == NSTACKX_EFAILED) {
348 goto L_ERROR;
349 } else if (state == NSTACKX_EINVAL) {
350 continue;
351 }
352 netMask = ((struct sockaddr_in *)&(buf[i].ifr_netmask))->sin_addr.s_addr;
353 /* if localIp and dstIp are in the same LAN, fetch the interface name of this localIp and return */
354 if ((dstAddr->sin_addr.s_addr & netMask) == (localIp & netMask)) {
355 if (strncpy_s(localDev->ifr_ifrn.ifrn_name, IFNAMSIZ, buf[i].ifr_name, strlen(buf[i].ifr_name)) != EOK) {
356 LOGE(TAG, "ifreq name copy failed");
357 goto L_ERROR;
358 }
359 CloseSocketInner(fd);
360 return NSTACKX_EOK;
361 }
362 }
363 L_ERROR:
364 CloseSocketInner(fd);
365 return NSTACKX_EFAILED;
366 }
367
BindToDevInTheSameLan(SocketDesc sockfd,const struct sockaddr_in * sockAddr)368 void BindToDevInTheSameLan(SocketDesc sockfd, const struct sockaddr_in *sockAddr)
369 {
370 struct ifreq localInterface;
371 if (sockfd < 0) {
372 return;
373 }
374 (void)memset_s(&localInterface, sizeof(localInterface), 0, sizeof(localInterface));
375 if (GetTargetInterface(sockAddr, &localInterface) != NSTACKX_EOK) {
376 LOGE(TAG, "get target interface fail");
377 return;
378 }
379 if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&localInterface, sizeof(localInterface)) < 0) {
380 LOGE(TAG, "bind to device fail, errno = %d", errno);
381 return;
382 }
383 LOGI(TAG, "bind to %s successfully", localInterface.ifr_name);
384 }
385
BindToTargetDev(SocketDesc sockfd,const char * targetInterfaceName)386 int32_t BindToTargetDev(SocketDesc sockfd, const char *targetInterfaceName)
387 {
388 struct ifreq buf[INTERFACE_MAX];
389 struct ifconf ifc;
390 int32_t ret = NSTACKX_EFAILED;
391 int32_t fd = GetInterfaceList(&ifc, buf, sizeof(buf));
392 if (fd < 0) {
393 return NSTACKX_EFAILED;
394 }
395 int32_t ifreqLen = (int32_t)sizeof(struct ifreq);
396 int32_t interfaceNum = (int32_t)(ifc.ifc_len / ifreqLen);
397 for (int32_t i = 0; i < interfaceNum && i < INTERFACE_MAX; i++) {
398 /* get IP of this interface */
399 int32_t state = GetInterfaceIP(fd, &buf[i]);
400 if (state == NSTACKX_EFAILED) {
401 break;
402 } else if (state == NSTACKX_EINVAL) {
403 continue;
404 }
405 if (strlen(buf[i].ifr_name) == strlen(targetInterfaceName) &&
406 strcmp(buf[i].ifr_name, targetInterfaceName) == 0) {
407 ret = BindToDeviceInner(sockfd, &buf[i]);
408 break;
409 }
410 }
411 CloseSocketInner(fd);
412 return ret;
413 }
414