Add if_nameindex(3).

This commit is contained in:
Jonas 'Sortie' Termansen 2016-07-25 23:43:35 +02:00
parent 2ef6804ead
commit 3997116656
7 changed files with 256 additions and 0 deletions

View File

@ -412,6 +412,10 @@ netdb/getservent.o \
netdb/setnetent.o \
netdb/setprotoent.o \
netdb/setservent.o \
net/if/if_freenameindex.o \
net/if/if_indextoname.o \
net/if/if_nameindex.o \
net/if/if_nametoindex.o \
poll/poll.o \
poll/ppoll.o \
psctl/psctl.o \

View File

@ -74,4 +74,23 @@ struct if_config
};
#endif
struct if_nameindex
{
unsigned int if_index;
char* if_name;
};
#ifdef __cplusplus
extern "C" {
#endif
void if_freenameindex(struct if_nameindex*);
char* if_indextoname(unsigned int, char*);
struct if_nameindex* if_nameindex(void);
unsigned int if_nametoindex(const char*);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* net/if/if_freenameindex.c
* Free list of network interfaces.
*/
#include <net/if.h>
#include <stdlib.h>
void if_freenameindex(struct if_nameindex* ifs)
{
for ( size_t i = 0; ifs[i].if_name; i++ )
free(ifs[i].if_name);
free(ifs);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* net/if/if_indextoname.c
* Get name of network interface by index.
*/
#include <errno.h>
#include <net/if.h>
#include <stdlib.h>
#include <string.h>
// TODO: This is better done with a dedicated system call.
char* if_indextoname(unsigned int ifindex, char* str)
{
struct if_nameindex* ifs = if_nameindex();
if ( !ifs )
return NULL;
for ( size_t i = 0; ifs[i].if_index; i++ )
{
if ( ifs[i].if_index == ifindex )
{
strlcpy(str, ifs[i].if_name, IF_NAMESIZE);
if_freenameindex(ifs);
return str;
}
}
if_freenameindex(ifs);
return errno = ENXIO, (char*) NULL;
}

119
libc/net/if/if_nameindex.c Normal file
View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2016, 2017 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* net/if/if_nameindex.c
* Build list of network interfaces.
*/
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <net/if.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// TODO: Consider turning this into a system call to avoid a number of error
// cases and work properly in chroots.
struct if_nameindex* if_nameindex(void)
{
DIR* dir = opendir("/dev");
if ( !dir )
return NULL;
struct if_nameindex* ifs = (struct if_nameindex*)
reallocarray(NULL, sizeof(struct if_nameindex), 2);
if ( !ifs )
return closedir(dir), (struct if_nameindex*) NULL;
size_t ifs_count = 0;
size_t ifs_allocated = 2;
ifs[ifs_count].if_index = 0;
ifs[ifs_count].if_name = NULL;
struct dirent* entry;
while ( (errno = 0, entry = readdir(dir)) )
{
if ( entry->d_type != DT_UNKNOWN && entry->d_type != DT_CHR )
continue;
int fd = openat(dirfd(dir), entry->d_name, O_RDWR | O_NOFOLLOW);
if ( fd < 0 )
{
int errnum = errno;
if ( entry->d_type == DT_UNKNOWN )
{
struct stat st;
if ( fstatat(dirfd(dir), entry->d_name, &st,
AT_SYMLINK_NOFOLLOW) < 0 )
{
closedir(dir);
if_freenameindex(ifs);
return NULL;
}
if ( !S_ISCHR(st.st_mode) )
continue;
}
if ( errnum == ELOOP || errnum == EACCES || errnum == EPERM )
continue;
closedir(dir);
if_freenameindex(ifs);
return NULL;
}
int type;
struct if_info info;
if ( (type = ioctl(fd, IOCGETTYPE)) < 0 ||
IOC_TYPE(type) != IOC_TYPE_NETWORK_INTERFACE ||
ioctl(fd, NIOC_GETINFO, &info) < 0 )
{
close(fd);
continue;
}
close(fd);
if ( ifs_count + 1 == ifs_allocated )
{
size_t new_allocated = 2 * ifs_allocated;
struct if_nameindex* new_ifs = (struct if_nameindex*)
reallocarray(ifs, sizeof(struct if_nameindex), new_allocated);
if ( !new_ifs )
{
closedir(dir);
if_freenameindex(ifs);
return NULL;
}
ifs = new_ifs;
ifs_allocated = new_allocated;
}
char* name = strdup(entry->d_name);
if ( !name )
{
closedir(dir);
if_freenameindex(ifs);
return NULL;
}
ifs[ifs_count].if_index = info.linkid;
ifs[ifs_count].if_name = name;
ifs_count++;
ifs[ifs_count].if_index = 0;
ifs[ifs_count].if_name = NULL;
}
if ( errno )
{
closedir(dir);
if_freenameindex(ifs);
return NULL;
}
closedir(dir);
return ifs;
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2016 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* net/if/if_nametoindex.c
* Get index of network interface by name.
*/
#include <errno.h>
#include <net/if.h>
#include <stdlib.h>
#include <string.h>
// TODO: This is better done with a dedicated system call.
// TODO: Or at least the name can be looked up directly in /dev.
unsigned int if_nametoindex(const char* name)
{
struct if_nameindex* ifs = if_nameindex();
if ( !ifs )
return NULL;
for ( size_t i = 0; ifs[i].if_index; i++ )
{
if ( !strcmp(ifs[i].if_name, name) )
{
unsigned int result = ifs[i].if_index;
if_freenameindex(ifs);
return result;
}
}
if_freenameindex(ifs);
return 0;
}

View File

@ -330,6 +330,7 @@ temporarily fail with
.Xr getsockopt 2 ,
.Xr ioctl 2 ,
.Xr setsockopt 2 ,
.Xr if_nameindex 3 ,
.Xr arp 4 ,
.Xr ether 4 ,
.Xr inet 4 ,