aboutsummaryrefslogtreecommitdiffstats
path: root/util-src/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'util-src/net.c')
-rw-r--r--util-src/net.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/util-src/net.c b/util-src/net.c
new file mode 100644
index 00000000..e307c628
--- /dev/null
+++ b/util-src/net.c
@@ -0,0 +1,117 @@
+/* Prosody IM
+--
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+-- Copyright (C) 2012 Paul Aurich
+-- Copyright (C) 2013 Matthew Wild
+-- Copyright (C) 2013 Florian Zeitz
+--
+*/
+
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+
+#ifndef _WIN32
+ #include <sys/ioctl.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <net/if.h>
+ #include <ifaddrs.h>
+ #include <arpa/inet.h>
+ #include <netinet/in.h>
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+
+/* Enumerate all locally configured IP addresses */
+
+const char * const type_strings[] = {
+ "both",
+ "ipv4",
+ "ipv6",
+ NULL
+};
+
+static int lc_local_addresses(lua_State *L)
+{
+#ifndef _WIN32
+ /* 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);
+ struct ifaddrs *addr = NULL, *a;
+#endif
+ int n = 1;
+ 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;
+ }
+#endif
+ lua_newtable(L);
+
+#ifndef _WIN32
+ 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);
+#else
+ if (ipv4) {
+ lua_pushstring(L, "0.0.0.0");
+ lua_rawseti(L, -2, n++);
+ }
+ if (ipv6) {
+ lua_pushstring(L, "::");
+ lua_rawseti(L, -2, n++);
+ }
+#endif
+ return 1;
+}
+
+int luaopen_util_net(lua_State* L)
+{
+ luaL_Reg exports[] = {
+ { "local_addresses", lc_local_addresses },
+ { NULL, NULL }
+ };
+
+ luaL_register(L, "net", exports);
+ return 1;
+}