blob: d3482290a765106f8b82806103cb03ee069d7215 [file] [log] [blame]
Juan Lang201cdcc2006-01-25 13:14:12 +01001/* Copyright (C) 2003,2006 Juan Lang
Juan Lang38fa5ad2003-05-13 03:32:20 +00002 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020015 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Juan Lang38fa5ad2003-05-13 03:32:20 +000016 *
17 * Implementation notes
Juan Lang50b7cf02003-11-30 06:03:21 +000018 * FIXME:
19 * - I don't support IPv6 addresses here, since SIOCGIFCONF can't return them
Juan Lang38fa5ad2003-05-13 03:32:20 +000020 *
Juan Lang53e634b2006-01-20 16:16:56 +010021 * There are three implemented methods for determining the MAC address of an
Juan Lang38fa5ad2003-05-13 03:32:20 +000022 * interface:
23 * - a specific IOCTL (Linux)
24 * - looking in the ARP cache (at least Solaris)
Francois Gougetbb8e6252006-12-04 19:55:35 +010025 * - using the sysctl interface (FreeBSD and Mac OS X)
Juan Lang38fa5ad2003-05-13 03:32:20 +000026 * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
27 * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
28 */
29
30#include "config.h"
31
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000032#include <stdarg.h>
Juan Lang38fa5ad2003-05-13 03:32:20 +000033#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36
Patrik Stridvallba78aac2003-08-08 21:07:23 +000037#ifdef HAVE_UNISTD_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000038#include <unistd.h>
39#endif
40
41#include <sys/types.h>
Marcus Meissner2c8aeb62006-10-22 21:15:46 +020042#ifdef HAVE_SYS_PARAM_H
43#include <sys/param.h>
44#endif
Juan Lang38fa5ad2003-05-13 03:32:20 +000045
Patrik Stridvallba78aac2003-08-08 21:07:23 +000046#ifdef HAVE_SYS_SOCKET_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000047#include <sys/socket.h>
48#endif
49
Patrik Stridvallba78aac2003-08-08 21:07:23 +000050#ifdef HAVE_NETINET_IN_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000051#include <netinet/in.h>
52#endif
53
Patrik Stridvallba78aac2003-08-08 21:07:23 +000054#ifdef HAVE_ARPA_INET_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000055#include <arpa/inet.h>
56#endif
57
Patrik Stridvallba78aac2003-08-08 21:07:23 +000058#ifdef HAVE_NET_IF_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000059#include <net/if.h>
60#endif
61
Patrik Stridvallba78aac2003-08-08 21:07:23 +000062#ifdef HAVE_NET_IF_ARP_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000063#include <net/if_arp.h>
64#endif
65
Patrik Stridvallba78aac2003-08-08 21:07:23 +000066#ifdef HAVE_NET_ROUTE_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000067#include <net/route.h>
68#endif
69
Patrik Stridvallba78aac2003-08-08 21:07:23 +000070#ifdef HAVE_SYS_IOCTL_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000071#include <sys/ioctl.h>
72#endif
73
Patrik Stridvallba78aac2003-08-08 21:07:23 +000074#ifdef HAVE_SYS_SYSCTL_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000075#include <sys/sysctl.h>
76#endif
77
Patrik Stridvallba78aac2003-08-08 21:07:23 +000078#ifdef HAVE_SYS_SOCKIO_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000079#include <sys/sockio.h>
80#endif
81
Patrik Stridvallba78aac2003-08-08 21:07:23 +000082#ifdef HAVE_NET_IF_DL_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000083#include <net/if_dl.h>
84#endif
85
Patrik Stridvallba78aac2003-08-08 21:07:23 +000086#ifdef HAVE_NET_IF_TYPES_H
Juan Lang38fa5ad2003-05-13 03:32:20 +000087#include <net/if_types.h>
88#endif
89
Juan Lang38fa5ad2003-05-13 03:32:20 +000090#include "ifenum.h"
91
Patrik Stridvallba78aac2003-08-08 21:07:23 +000092#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
Juan Lang38fa5ad2003-05-13 03:32:20 +000093#define ifreq_len(ifr) \
94 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
95#else
96#define ifreq_len(ifr) sizeof(struct ifreq)
97#endif
98
99#ifndef ETH_ALEN
100#define ETH_ALEN 6
101#endif
102
Vitaly Lipatovf3827222006-02-24 13:27:45 +0300103#ifndef IF_NAMESIZE
104#define IF_NAMESIZE 16
105#endif
106
Juan Lang38fa5ad2003-05-13 03:32:20 +0000107#ifndef INADDR_NONE
108#define INADDR_NONE (~0U)
109#endif
110
111#define INITIAL_INTERFACES_ASSUMED 4
112
113#define INDEX_IS_LOOPBACK 0x00800000
114
Juan Lang38fa5ad2003-05-13 03:32:20 +0000115/* Functions */
116
Juan Lang38fa5ad2003-05-13 03:32:20 +0000117static int isLoopbackInterface(int fd, const char *name)
118{
119 int ret = 0;
120
121 if (name) {
122 struct ifreq ifr;
123
Peter Berg Larsene732fc02005-03-28 14:17:51 +0000124 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000125 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
126 ret = ifr.ifr_flags & IFF_LOOPBACK;
127 }
128 return ret;
129}
130
Juan Lang540dca32006-01-27 19:19:32 +0100131/* The comments say MAX_ADAPTER_NAME is required, but really only IF_NAMESIZE
132 * bytes are necessary.
Juan Lang38fa5ad2003-05-13 03:32:20 +0000133 */
Juan Lang540dca32006-01-27 19:19:32 +0100134char *getInterfaceNameByIndex(DWORD index, char *name)
Juan Lang38fa5ad2003-05-13 03:32:20 +0000135{
Juan Lang540dca32006-01-27 19:19:32 +0100136 return if_indextoname(index, name);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000137}
138
139DWORD getInterfaceIndexByName(const char *name, PDWORD index)
140{
Juan Lang540dca32006-01-27 19:19:32 +0100141 DWORD ret;
142 unsigned int idx;
Juan Lang38fa5ad2003-05-13 03:32:20 +0000143
144 if (!name)
145 return ERROR_INVALID_PARAMETER;
146 if (!index)
147 return ERROR_INVALID_PARAMETER;
Juan Lang540dca32006-01-27 19:19:32 +0100148 idx = if_nametoindex(name);
149 if (idx) {
150 *index = idx;
Juan Lang50b7cf02003-11-30 06:03:21 +0000151 ret = NO_ERROR;
Juan Lang540dca32006-01-27 19:19:32 +0100152 }
Juan Lang38fa5ad2003-05-13 03:32:20 +0000153 else
Juan Lang50b7cf02003-11-30 06:03:21 +0000154 ret = ERROR_INVALID_DATA;
155 return ret;
Juan Lang38fa5ad2003-05-13 03:32:20 +0000156}
157
Juan Lang540dca32006-01-27 19:19:32 +0100158DWORD getNumNonLoopbackInterfaces(void)
Juan Lang38fa5ad2003-05-13 03:32:20 +0000159{
Juan Lang540dca32006-01-27 19:19:32 +0100160 DWORD numInterfaces;
161 int fd = socket(PF_INET, SOCK_DGRAM, 0);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000162
Juan Lang540dca32006-01-27 19:19:32 +0100163 if (fd != -1) {
164 struct if_nameindex *indexes = if_nameindex();
Juan Lang38fa5ad2003-05-13 03:32:20 +0000165
Juan Lang540dca32006-01-27 19:19:32 +0100166 if (indexes) {
167 struct if_nameindex *p;
168
169 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
170 if (!isLoopbackInterface(fd, p->if_name))
171 numInterfaces++;
172 if_freenameindex(indexes);
173 }
174 else
175 numInterfaces = 0;
176 close(fd);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000177 }
Juan Lang540dca32006-01-27 19:19:32 +0100178 else
179 numInterfaces = 0;
180 return numInterfaces;
181}
182
183DWORD getNumInterfaces(void)
184{
185 DWORD numInterfaces;
186 struct if_nameindex *indexes = if_nameindex();
187
188 if (indexes) {
189 struct if_nameindex *p;
190
191 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
192 numInterfaces++;
193 if_freenameindex(indexes);
194 }
195 else
196 numInterfaces = 0;
197 return numInterfaces;
Juan Lang38fa5ad2003-05-13 03:32:20 +0000198}
199
200InterfaceIndexTable *getInterfaceIndexTable(void)
201{
Juan Lang50b7cf02003-11-30 06:03:21 +0000202 DWORD numInterfaces;
203 InterfaceIndexTable *ret;
Juan Lang540dca32006-01-27 19:19:32 +0100204 struct if_nameindex *indexes = if_nameindex();
205
206 if (indexes) {
207 struct if_nameindex *p;
Juan Lang9ec6e332007-11-15 11:05:10 -0800208 DWORD size = sizeof(InterfaceIndexTable);
Juan Lang540dca32006-01-27 19:19:32 +0100209
210 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
211 numInterfaces++;
Juan Lang9ec6e332007-11-15 11:05:10 -0800212 if (numInterfaces > 1)
213 size += (numInterfaces - 1) * sizeof(DWORD);
Juan Lang14725932007-11-15 11:07:27 -0800214 ret = HeapAlloc(GetProcessHeap(), 0, size);
Juan Lang540dca32006-01-27 19:19:32 +0100215 if (ret) {
Juan Lang14725932007-11-15 11:07:27 -0800216 ret->numIndexes = 0;
Juan Lang540dca32006-01-27 19:19:32 +0100217 for (p = indexes; p && p->if_name; p++)
218 ret->indexes[ret->numIndexes++] = p->if_index;
219 }
220 if_freenameindex(indexes);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000221 }
Juan Lang540dca32006-01-27 19:19:32 +0100222 else
223 ret = NULL;
Juan Lang38fa5ad2003-05-13 03:32:20 +0000224 return ret;
225}
226
227InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
228{
Juan Lang50b7cf02003-11-30 06:03:21 +0000229 DWORD numInterfaces;
230 InterfaceIndexTable *ret;
Juan Lang540dca32006-01-27 19:19:32 +0100231 int fd = socket(PF_INET, SOCK_DGRAM, 0);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000232
Juan Lang540dca32006-01-27 19:19:32 +0100233 if (fd != -1) {
234 struct if_nameindex *indexes = if_nameindex();
235
236 if (indexes) {
237 struct if_nameindex *p;
Juan Lang0502de42007-11-15 11:06:50 -0800238 DWORD size = sizeof(InterfaceIndexTable);
Juan Lang540dca32006-01-27 19:19:32 +0100239
240 for (p = indexes, numInterfaces = 0; p && p->if_name; p++)
241 if (!isLoopbackInterface(fd, p->if_name))
242 numInterfaces++;
Juan Lang0502de42007-11-15 11:06:50 -0800243 if (numInterfaces > 1)
244 size += (numInterfaces - 1) * sizeof(DWORD);
Juan Lang14725932007-11-15 11:07:27 -0800245 ret = HeapAlloc(GetProcessHeap(), 0, size);
Juan Lang540dca32006-01-27 19:19:32 +0100246 if (ret) {
Juan Lang14725932007-11-15 11:07:27 -0800247 ret->numIndexes = 0;
Juan Lang540dca32006-01-27 19:19:32 +0100248 for (p = indexes; p && p->if_name; p++)
249 if (!isLoopbackInterface(fd, p->if_name))
250 ret->indexes[ret->numIndexes++] = p->if_index;
251 }
252 if_freenameindex(indexes);
253 }
254 else
255 ret = NULL;
256 close(fd);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000257 }
Juan Lang540dca32006-01-27 19:19:32 +0100258 else
259 ret = NULL;
Juan Lang38fa5ad2003-05-13 03:32:20 +0000260 return ret;
261}
262
Juan Lang201cdcc2006-01-25 13:14:12 +0100263static DWORD getInterfaceBCastAddrByName(const char *name)
Juan Lang38fa5ad2003-05-13 03:32:20 +0000264{
265 DWORD ret = INADDR_ANY;
266
267 if (name) {
268 int fd = socket(PF_INET, SOCK_DGRAM, 0);
269
270 if (fd != -1) {
271 struct ifreq ifr;
272
Peter Berg Larsene732fc02005-03-28 14:17:51 +0000273 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000274 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
275 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
276 close(fd);
277 }
278 }
279 return ret;
280}
281
Juan Lang201cdcc2006-01-25 13:14:12 +0100282static DWORD getInterfaceMaskByName(const char *name)
Juan Lang38fa5ad2003-05-13 03:32:20 +0000283{
284 DWORD ret = INADDR_NONE;
285
286 if (name) {
287 int fd = socket(PF_INET, SOCK_DGRAM, 0);
288
289 if (fd != -1) {
290 struct ifreq ifr;
291
Peter Berg Larsene732fc02005-03-28 14:17:51 +0000292 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000293 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
294 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
295 close(fd);
296 }
297 }
298 return ret;
299}
300
Juan Lang38fa5ad2003-05-13 03:32:20 +0000301#if defined (SIOCGIFHWADDR)
Francois Gouget0c2430c2009-05-13 10:35:50 +0200302static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
Juan Lang38fa5ad2003-05-13 03:32:20 +0000303 PDWORD type)
304{
305 DWORD ret;
306 int fd;
307
308 if (!name || !len || !addr || !type)
309 return ERROR_INVALID_PARAMETER;
310
311 fd = socket(PF_INET, SOCK_DGRAM, 0);
312 if (fd != -1) {
313 struct ifreq ifr;
314
315 memset(&ifr, 0, sizeof(struct ifreq));
Peter Berg Larsene732fc02005-03-28 14:17:51 +0000316 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000317 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
318 ret = ERROR_INVALID_DATA;
319 else {
Hans Leidekkerfe442b22004-09-08 01:23:57 +0000320 unsigned int addrLen;
Juan Lang38fa5ad2003-05-13 03:32:20 +0000321
322 switch (ifr.ifr_hwaddr.sa_family)
323 {
Dmitry Timoshkov2581db82003-10-14 05:27:43 +0000324#ifdef ARPHRD_LOOPBACK
Juan Lang38fa5ad2003-05-13 03:32:20 +0000325 case ARPHRD_LOOPBACK:
326 addrLen = 0;
327 *type = MIB_IF_TYPE_LOOPBACK;
328 break;
Dmitry Timoshkov2581db82003-10-14 05:27:43 +0000329#endif
330#ifdef ARPHRD_ETHER
Juan Lang38fa5ad2003-05-13 03:32:20 +0000331 case ARPHRD_ETHER:
332 addrLen = ETH_ALEN;
333 *type = MIB_IF_TYPE_ETHERNET;
334 break;
Dmitry Timoshkov2581db82003-10-14 05:27:43 +0000335#endif
336#ifdef ARPHRD_FDDI
Juan Lang38fa5ad2003-05-13 03:32:20 +0000337 case ARPHRD_FDDI:
338 addrLen = ETH_ALEN;
339 *type = MIB_IF_TYPE_FDDI;
340 break;
Dmitry Timoshkov2581db82003-10-14 05:27:43 +0000341#endif
342#ifdef ARPHRD_IEEE802
Juan Lang38fa5ad2003-05-13 03:32:20 +0000343 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
344 addrLen = ETH_ALEN;
345 *type = MIB_IF_TYPE_TOKENRING;
346 break;
Dmitry Timoshkov2581db82003-10-14 05:27:43 +0000347#endif
348#ifdef ARPHRD_IEEE802_TR
Juan Lang38fa5ad2003-05-13 03:32:20 +0000349 case ARPHRD_IEEE802_TR: /* also Token Ring? */
350 addrLen = ETH_ALEN;
351 *type = MIB_IF_TYPE_TOKENRING;
352 break;
Dmitry Timoshkov2581db82003-10-14 05:27:43 +0000353#endif
354#ifdef ARPHRD_SLIP
Juan Lang38fa5ad2003-05-13 03:32:20 +0000355 case ARPHRD_SLIP:
356 addrLen = 0;
357 *type = MIB_IF_TYPE_SLIP;
358 break;
Dmitry Timoshkov2581db82003-10-14 05:27:43 +0000359#endif
360#ifdef ARPHRD_PPP
Juan Lang38fa5ad2003-05-13 03:32:20 +0000361 case ARPHRD_PPP:
362 addrLen = 0;
363 *type = MIB_IF_TYPE_PPP;
364 break;
Dmitry Timoshkov2581db82003-10-14 05:27:43 +0000365#endif
Juan Lang38fa5ad2003-05-13 03:32:20 +0000366 default:
367 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
368 *type = MIB_IF_TYPE_OTHER;
369 }
370 if (addrLen > *len) {
371 ret = ERROR_INSUFFICIENT_BUFFER;
372 *len = addrLen;
373 }
374 else {
375 if (addrLen > 0)
376 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
377 /* zero out remaining bytes for broken implementations */
378 memset(addr + addrLen, 0, *len - addrLen);
379 *len = addrLen;
380 ret = NO_ERROR;
381 }
382 }
383 close(fd);
384 }
385 else
386 ret = ERROR_NO_MORE_FILES;
387 return ret;
388}
389#elif defined (SIOCGARP)
Francois Gouget0c2430c2009-05-13 10:35:50 +0200390static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
Juan Lang38fa5ad2003-05-13 03:32:20 +0000391 PDWORD type)
392{
393 DWORD ret;
394 int fd;
395
396 if (!name || !len || !addr || !type)
397 return ERROR_INVALID_PARAMETER;
398
399 fd = socket(PF_INET, SOCK_DGRAM, 0);
400 if (fd != -1) {
401 if (isLoopbackInterface(fd, name)) {
402 *type = MIB_IF_TYPE_LOOPBACK;
403 memset(addr, 0, *len);
404 *len = 0;
Robert Lunnon00c74e92003-07-09 21:55:09 +0000405 ret=NOERROR;
Juan Lang38fa5ad2003-05-13 03:32:20 +0000406 }
407 else {
408 struct arpreq arp;
409 struct sockaddr_in *saddr;
Juan Lang201cdcc2006-01-25 13:14:12 +0100410 struct ifreq ifr;
Juan Lang38fa5ad2003-05-13 03:32:20 +0000411
Juan Lang201cdcc2006-01-25 13:14:12 +0100412 /* get IP addr */
413 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
414 ioctl(fd, SIOCGIFADDR, &ifr);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000415 memset(&arp, 0, sizeof(struct arpreq));
416 arp.arp_pa.sa_family = AF_INET;
417 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
418 saddr->sin_family = AF_INET;
Juan Lang201cdcc2006-01-25 13:14:12 +0100419 memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
Juan Lang38fa5ad2003-05-13 03:32:20 +0000420 if ((ioctl(fd, SIOCGARP, &arp)))
421 ret = ERROR_INVALID_DATA;
422 else {
423 /* FIXME: heh: who said it was ethernet? */
424 int addrLen = ETH_ALEN;
425
426 if (addrLen > *len) {
427 ret = ERROR_INSUFFICIENT_BUFFER;
428 *len = addrLen;
429 }
430 else {
431 if (addrLen > 0)
432 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
433 /* zero out remaining bytes for broken implementations */
434 memset(addr + addrLen, 0, *len - addrLen);
435 *len = addrLen;
436 *type = MIB_IF_TYPE_ETHERNET;
437 ret = NO_ERROR;
438 }
439 }
440 }
Robert Lunnon00c74e92003-07-09 21:55:09 +0000441 close(fd);
442 }
Juan Lang38fa5ad2003-05-13 03:32:20 +0000443 else
444 ret = ERROR_NO_MORE_FILES;
Robert Lunnon00c74e92003-07-09 21:55:09 +0000445
Juan Lang38fa5ad2003-05-13 03:32:20 +0000446 return ret;
447}
448#elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
Francois Gouget0c2430c2009-05-13 10:35:50 +0200449static DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
Juan Lang38fa5ad2003-05-13 03:32:20 +0000450 PDWORD type)
451{
452 DWORD ret;
453 struct if_msghdr *ifm;
454 struct sockaddr_dl *sdl;
455 u_char *p, *buf;
456 size_t mibLen;
457 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
458 int addrLen;
459 BOOL found = FALSE;
460
461 if (!name || !len || !addr || !type)
462 return ERROR_INVALID_PARAMETER;
463
Alexandre Julliardb168f122003-05-21 18:26:00 +0000464 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
Juan Lang38fa5ad2003-05-13 03:32:20 +0000465 return ERROR_NO_MORE_FILES;
466
Jakob Eriksson9ed61de2005-03-24 21:01:35 +0000467 buf = HeapAlloc(GetProcessHeap(), 0, mibLen);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000468 if (!buf)
469 return ERROR_NOT_ENOUGH_MEMORY;
470
471 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
Juan Lang76d87792004-12-13 13:21:39 +0000472 HeapFree(GetProcessHeap(), 0, buf);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000473 return ERROR_NO_MORE_FILES;
474 }
475
476 ret = ERROR_INVALID_DATA;
477 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
478 ifm = (struct if_msghdr *)p;
479 sdl = (struct sockaddr_dl *)(ifm + 1);
480
481 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
482 continue;
483
484 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
485 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
486 continue;
487
488 found = TRUE;
489 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
490 if (addrLen > *len) {
491 ret = ERROR_INSUFFICIENT_BUFFER;
492 *len = addrLen;
493 }
494 else {
495 if (addrLen > 0)
496 memcpy(addr, LLADDR(sdl), addrLen);
497 /* zero out remaining bytes for broken implementations */
498 memset(addr + addrLen, 0, *len - addrLen);
499 *len = addrLen;
500#if defined(HAVE_NET_IF_TYPES_H)
501 switch (sdl->sdl_type)
502 {
503 case IFT_ETHER:
504 *type = MIB_IF_TYPE_ETHERNET;
505 break;
506 case IFT_FDDI:
507 *type = MIB_IF_TYPE_FDDI;
508 break;
509 case IFT_ISO88024: /* Token Bus */
510 *type = MIB_IF_TYPE_TOKENRING;
511 break;
512 case IFT_ISO88025: /* Token Ring */
513 *type = MIB_IF_TYPE_TOKENRING;
514 break;
515 case IFT_PPP:
516 *type = MIB_IF_TYPE_PPP;
517 break;
518 case IFT_SLIP:
519 *type = MIB_IF_TYPE_SLIP;
520 break;
521 case IFT_LOOP:
522 *type = MIB_IF_TYPE_LOOPBACK;
523 break;
524 default:
525 *type = MIB_IF_TYPE_OTHER;
526 }
527#else
528 /* default if we don't know */
529 *type = MIB_IF_TYPE_ETHERNET;
530#endif
531 ret = NO_ERROR;
532 }
533 }
Juan Lang76d87792004-12-13 13:21:39 +0000534 HeapFree(GetProcessHeap(), 0, buf);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000535 return ret;
536}
537#endif
538
539DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
540 PDWORD type)
541{
Juan Lang540dca32006-01-27 19:19:32 +0100542 char nameBuf[IF_NAMESIZE];
543 char *name = getInterfaceNameByIndex(index, nameBuf);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000544
545 if (name)
546 return getInterfacePhysicalByName(name, len, addr, type);
547 else
548 return ERROR_INVALID_DATA;
549}
550
Hans Leidekkerf0491f62009-04-29 11:41:02 +0200551DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
Juan Lang38fa5ad2003-05-13 03:32:20 +0000552{
553 DWORD ret;
554 int fd;
555
556 if (!name)
557 return ERROR_INVALID_PARAMETER;
558 if (!mtu)
559 return ERROR_INVALID_PARAMETER;
560
561 fd = socket(PF_INET, SOCK_DGRAM, 0);
562 if (fd != -1) {
563 struct ifreq ifr;
564
Peter Berg Larsene732fc02005-03-28 14:17:51 +0000565 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000566 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
567 ret = ERROR_INVALID_DATA;
568 else {
Robert Lunnon761fce52004-01-14 05:31:23 +0000569#ifndef __sun
Juan Lang38fa5ad2003-05-13 03:32:20 +0000570 *mtu = ifr.ifr_mtu;
Robert Lunnon761fce52004-01-14 05:31:23 +0000571#else
572 *mtu = ifr.ifr_metric;
573#endif
Juan Lang38fa5ad2003-05-13 03:32:20 +0000574 ret = NO_ERROR;
575 }
Juan Lang36ac9f82005-12-13 11:11:53 +0100576 close(fd);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000577 }
578 else
579 ret = ERROR_NO_MORE_FILES;
580 return ret;
581}
582
Hans Leidekkerf0491f62009-04-29 11:41:02 +0200583DWORD getInterfaceStatusByName(const char *name, PDWORD status)
Juan Lang38fa5ad2003-05-13 03:32:20 +0000584{
585 DWORD ret;
586 int fd;
587
588 if (!name)
589 return ERROR_INVALID_PARAMETER;
590 if (!status)
591 return ERROR_INVALID_PARAMETER;
592
593 fd = socket(PF_INET, SOCK_DGRAM, 0);
594 if (fd != -1) {
595 struct ifreq ifr;
596
Peter Berg Larsene732fc02005-03-28 14:17:51 +0000597 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000598 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
599 ret = ERROR_INVALID_DATA;
600 else {
601 if (ifr.ifr_flags & IFF_UP)
602 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
603 else
604 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
605 ret = NO_ERROR;
606 }
Juan Lang36ac9f82005-12-13 11:11:53 +0100607 close(fd);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000608 }
609 else
610 ret = ERROR_NO_MORE_FILES;
611 return ret;
612}
613
Juan Lang38fa5ad2003-05-13 03:32:20 +0000614DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
615{
616 BYTE addr[MAX_INTERFACE_PHYSADDR];
617 DWORD ret, len = sizeof(addr), type;
618
619 if (!name)
620 return ERROR_INVALID_PARAMETER;
621 if (!entry)
622 return ERROR_INVALID_PARAMETER;
623
624 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
625 WCHAR *assigner;
626 const char *walker;
627
628 memset(entry, 0, sizeof(MIB_IFROW));
629 for (assigner = entry->wszName, walker = name; *walker;
630 walker++, assigner++)
631 *assigner = *walker;
632 *assigner = 0;
633 getInterfaceIndexByName(name, &entry->dwIndex);
634 entry->dwPhysAddrLen = len;
635 memcpy(entry->bPhysAddr, addr, len);
636 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
637 entry->dwType = type;
638 /* FIXME: how to calculate real speed? */
639 getInterfaceMtuByName(name, &entry->dwMtu);
640 /* lie, there's no "administratively down" here */
641 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
642 getInterfaceStatusByName(name, &entry->dwOperStatus);
643 /* punt on dwLastChange? */
644 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
645 memcpy(entry->bDescr, name, entry->dwDescrLen);
646 entry->bDescr[entry->dwDescrLen] = '\0';
647 entry->dwDescrLen++;
648 ret = NO_ERROR;
649 }
650 else
651 ret = ERROR_INVALID_DATA;
652 return ret;
653}
654
Juan Lang201cdcc2006-01-25 13:14:12 +0100655/* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
656 * the count to you in *pcAddresses. It also returns to you the struct ifconf
657 * used by the call to ioctl, so that you may process the addresses further.
658 * Free ifc->ifc_buf using HeapFree.
659 * Returns NO_ERROR on success, something else on failure.
660 */
661static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
662{
663 DWORD ret;
664 int fd;
665
666 fd = socket(PF_INET, SOCK_DGRAM, 0);
667 if (fd != -1) {
668 int ioctlRet = 0;
669 DWORD guessedNumAddresses = 0, numAddresses = 0;
670 caddr_t ifPtr;
Mark Adamsa91d6912007-01-25 20:14:53 -0500671 int lastlen;
Juan Lang201cdcc2006-01-25 13:14:12 +0100672
673 ret = NO_ERROR;
674 ifc->ifc_len = 0;
675 ifc->ifc_buf = NULL;
676 /* there is no way to know the interface count beforehand,
677 so we need to loop again and again upping our max each time
Mark Adamsa91d6912007-01-25 20:14:53 -0500678 until returned is constant across 2 calls */
Juan Lang201cdcc2006-01-25 13:14:12 +0100679 do {
Mark Adamsa91d6912007-01-25 20:14:53 -0500680 lastlen = ifc->ifc_len;
Juan Lang201cdcc2006-01-25 13:14:12 +0100681 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
682 if (guessedNumAddresses == 0)
683 guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
684 else
685 guessedNumAddresses *= 2;
686 ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
687 ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
688 ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
Mark Adamsa91d6912007-01-25 20:14:53 -0500689 } while ((ioctlRet == 0) && (ifc->ifc_len != lastlen));
Juan Lang201cdcc2006-01-25 13:14:12 +0100690
691 if (ioctlRet == 0) {
692 ifPtr = ifc->ifc_buf;
693 while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
Mark Adams1e263e62007-01-25 20:15:58 -0500694 struct ifreq *ifr = (struct ifreq *)ifPtr;
695
696 if (ifr->ifr_addr.sa_family == AF_INET)
697 numAddresses++;
698
Juan Lang201cdcc2006-01-25 13:14:12 +0100699 ifPtr += ifreq_len((struct ifreq *)ifPtr);
700 }
701 }
702 else
703 ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
704 if (!ret)
705 *pcAddresses = numAddresses;
706 else
707 {
708 HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
709 ifc->ifc_buf = NULL;
710 }
711 close(fd);
712 }
713 else
714 ret = ERROR_NO_SYSTEM_RESOURCES;
715 return ret;
716}
717
718DWORD getNumIPAddresses(void)
719{
720 DWORD numAddresses = 0;
721 struct ifconf ifc;
722
723 if (!enumIPAddresses(&numAddresses, &ifc))
724 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
725 return numAddresses;
726}
727
Juan Lang5cd6b342006-01-24 12:18:50 +0100728DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
729{
730 DWORD ret;
731
732 if (!ppIpAddrTable)
733 ret = ERROR_INVALID_PARAMETER;
734 else
735 {
Juan Lang201cdcc2006-01-25 13:14:12 +0100736 DWORD numAddresses = 0;
737 struct ifconf ifc;
Juan Lang5cd6b342006-01-24 12:18:50 +0100738
Juan Lang201cdcc2006-01-25 13:14:12 +0100739 ret = enumIPAddresses(&numAddresses, &ifc);
740 if (!ret)
741 {
Juan Lange1a83692007-11-15 11:06:07 -0800742 DWORD size = sizeof(MIB_IPADDRTABLE);
743
744 if (numAddresses > 1)
745 size += (numAddresses - 1) * sizeof(MIB_IPADDRROW);
746 *ppIpAddrTable = HeapAlloc(heap, flags, size);
Juan Lang201cdcc2006-01-25 13:14:12 +0100747 if (*ppIpAddrTable) {
748 DWORD i = 0, bcast;
749 caddr_t ifPtr;
Juan Lang5cd6b342006-01-24 12:18:50 +0100750
Juan Lang201cdcc2006-01-25 13:14:12 +0100751 ret = NO_ERROR;
752 (*ppIpAddrTable)->dwNumEntries = numAddresses;
Juan Lang5cd6b342006-01-24 12:18:50 +0100753 ifPtr = ifc.ifc_buf;
Juan Lang201cdcc2006-01-25 13:14:12 +0100754 while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
755 struct ifreq *ifr = (struct ifreq *)ifPtr;
756
Mark Adams1e263e62007-01-25 20:15:58 -0500757 ifPtr += ifreq_len(ifr);
758
759 if (ifr->ifr_addr.sa_family != AF_INET)
760 continue;
761
Juan Lang201cdcc2006-01-25 13:14:12 +0100762 ret = getInterfaceIndexByName(ifr->ifr_name,
763 &(*ppIpAddrTable)->table[i].dwIndex);
764 memcpy(&(*ppIpAddrTable)->table[i].dwAddr, ifr->ifr_addr.sa_data + 2,
765 sizeof(DWORD));
766 (*ppIpAddrTable)->table[i].dwMask =
767 getInterfaceMaskByName(ifr->ifr_name);
768 /* the dwBCastAddr member isn't the broadcast address, it indicates
769 * whether the interface uses the 1's broadcast address (1) or the
770 * 0's broadcast address (0).
771 */
772 bcast = getInterfaceBCastAddrByName(ifr->ifr_name);
773 (*ppIpAddrTable)->table[i].dwBCastAddr =
774 (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
775 /* FIXME: hardcoded reasm size, not sure where to get it */
776 (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
777
778 (*ppIpAddrTable)->table[i].unused1 = 0;
779 (*ppIpAddrTable)->table[i].wType = 0;
Juan Lang201cdcc2006-01-25 13:14:12 +0100780 i++;
Juan Lang5cd6b342006-01-24 12:18:50 +0100781 }
Juan Lang5cd6b342006-01-24 12:18:50 +0100782 }
783 else
Juan Lang201cdcc2006-01-25 13:14:12 +0100784 ret = ERROR_OUTOFMEMORY;
Juan Lang5cd6b342006-01-24 12:18:50 +0100785 HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
Juan Lang5cd6b342006-01-24 12:18:50 +0100786 }
Juan Lang5cd6b342006-01-24 12:18:50 +0100787 }
788 return ret;
789}
790
Juan Lang38fa5ad2003-05-13 03:32:20 +0000791char *toIPAddressString(unsigned int addr, char string[16])
792{
793 if (string) {
794 struct in_addr iAddr;
795
796 iAddr.s_addr = addr;
797 /* extra-anal, just to make auditors happy */
Robert Shearman4fee5262005-06-13 10:01:20 +0000798 lstrcpynA(string, inet_ntoa(iAddr), 16);
Juan Lang38fa5ad2003-05-13 03:32:20 +0000799 }
800 return string;
801}