Add local_addresses() to enumerate the local host's interface addresses (tested on all supported platforms except Windows)
This commit is contained in:
parent
d548a78e55
commit
5124888add
1 changed files with 101 additions and 2 deletions
103
src/inet.c
103
src/inet.c
|
@ -5,11 +5,27 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "inet.h"
|
||||
|
||||
typedef union {
|
||||
struct sockaddr_storage sas;
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sa4;
|
||||
struct sockaddr_in6 sa6;
|
||||
} SA_union;
|
||||
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
|
@ -17,11 +33,12 @@ static int inet_global_toip(lua_State *L);
|
|||
static int inet_global_getaddrinfo(lua_State *L);
|
||||
static int inet_global_tohostname(lua_State *L);
|
||||
static int inet_global_getnameinfo(lua_State *L);
|
||||
static int inet_global_local_addresses(lua_State *L);
|
||||
static void inet_pushresolved(lua_State *L, struct hostent *hp);
|
||||
static int inet_global_gethostname(lua_State *L);
|
||||
|
||||
/* DNS functions */
|
||||
static luaL_Reg func[] = {
|
||||
static luaL_Reg dns[] = {
|
||||
{ "toip", inet_global_toip},
|
||||
{ "getaddrinfo", inet_global_getaddrinfo},
|
||||
{ "tohostname", inet_global_tohostname},
|
||||
|
@ -30,6 +47,12 @@ static luaL_Reg func[] = {
|
|||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/* global functions */
|
||||
static luaL_Reg func[] = {
|
||||
{ "local_addresses", inet_global_local_addresses},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
|
@ -40,8 +63,11 @@ int inet_open(lua_State *L)
|
|||
{
|
||||
lua_pushstring(L, "dns");
|
||||
lua_newtable(L);
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
luaL_openlib(L, NULL, dns, 0);
|
||||
lua_settable(L, -3);
|
||||
|
||||
/* Export as global functions */
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -221,6 +247,79 @@ static int inet_global_gethostname(lua_State *L)
|
|||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Enumerate all locally configured IP addresses
|
||||
\*-------------------------------------------------------------------------*/
|
||||
|
||||
const char * const type_strings[] = {
|
||||
"both",
|
||||
"ipv4",
|
||||
"ipv6",
|
||||
NULL
|
||||
};
|
||||
|
||||
int inet_global_local_addresses(lua_State *L)
|
||||
{
|
||||
/* Link-local IPv4 addresses; see RFC 3927 and RFC 5735 */
|
||||
const long ip4_linklocal = htonl(0xa9fe0000); /* 169.254.0.0 */
|
||||
const long ip4_mask = htonl(0xffff0000);
|
||||
#ifndef _WIN32
|
||||
struct ifaddrs *addr = NULL, *a;
|
||||
int n = 1;
|
||||
#endif
|
||||
int type = luaL_checkoption(L, 1, "both", type_strings);
|
||||
const char link_local = lua_toboolean(L, 2); /* defaults to 0 (false) */
|
||||
const char ipv4 = (type == 0 || type == 1);
|
||||
const char ipv6 = (type == 0 || type == 2);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (getifaddrs(&addr) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "getifaddrs failed (%d): %s", errno,
|
||||
strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
for (a = addr; a; a = a->ifa_next) {
|
||||
int family;
|
||||
char ipaddr[INET6_ADDRSTRLEN];
|
||||
const char *tmp = NULL;
|
||||
|
||||
if (a->ifa_addr == NULL || a->ifa_flags & IFF_LOOPBACK)
|
||||
continue;
|
||||
|
||||
family = a->ifa_addr->sa_family;
|
||||
|
||||
if (ipv4 && family == AF_INET) {
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *)a->ifa_addr;
|
||||
if (!link_local &&
|
||||
((sa->sin_addr.s_addr & ip4_mask) == ip4_linklocal))
|
||||
continue;
|
||||
tmp = inet_ntop(family, &sa->sin_addr, ipaddr, sizeof(ipaddr));
|
||||
} else if (ipv6 && family == AF_INET6) {
|
||||
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)a->ifa_addr;
|
||||
if (!link_local && IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
|
||||
continue;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&sa->sin6_addr))
|
||||
continue;
|
||||
tmp = inet_ntop(family, &sa->sin6_addr, ipaddr, sizeof(ipaddr));
|
||||
}
|
||||
|
||||
if (tmp != NULL) {
|
||||
lua_pushstring(L, tmp);
|
||||
lua_rawseti(L, -2, n++);
|
||||
}
|
||||
/* TODO: Error reporting? */
|
||||
}
|
||||
|
||||
freeifaddrs(addr);
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*=========================================================================*\
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue