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