CHANGES: Update for release
[prosody.git] / util-src / net.c
blobbb159d57dca86a4d4b88f5ef7503c2c424d05f77
1 /* Prosody IM
2 --
3 -- This project is MIT/X11 licensed. Please see the
4 -- COPYING file in the source package for more information.
5 --
6 -- Copyright (C) 2012 Paul Aurich
7 -- Copyright (C) 2013 Matthew Wild
8 -- Copyright (C) 2013 Florian Zeitz
9 --
12 #define _GNU_SOURCE
13 #include <stddef.h>
14 #include <string.h>
15 #include <errno.h>
17 #ifndef _WIN32
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <net/if.h>
22 #include <ifaddrs.h>
23 #include <arpa/inet.h>
24 #include <netinet/in.h>
25 #endif
27 #include <lua.h>
28 #include <lauxlib.h>
30 #if (LUA_VERSION_NUM == 501)
31 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
32 #endif
34 /* Enumerate all locally configured IP addresses */
36 const char *const type_strings[] = {
37 "both",
38 "ipv4",
39 "ipv6",
40 NULL
43 static int lc_local_addresses(lua_State *L) {
44 #ifndef _WIN32
45 /* Link-local IPv4 addresses; see RFC 3927 and RFC 5735 */
46 const long ip4_linklocal = htonl(0xa9fe0000); /* 169.254.0.0 */
47 const long ip4_mask = htonl(0xffff0000);
48 struct ifaddrs *addr = NULL, *a;
49 #endif
50 int n = 1;
51 int type = luaL_checkoption(L, 1, "both", type_strings);
52 const char link_local = lua_toboolean(L, 2); /* defaults to 0 (false) */
53 const char ipv4 = (type == 0 || type == 1);
54 const char ipv6 = (type == 0 || type == 2);
56 #ifndef _WIN32
58 if(getifaddrs(&addr) < 0) {
59 lua_pushnil(L);
60 lua_pushfstring(L, "getifaddrs failed (%d): %s", errno,
61 strerror(errno));
62 return 2;
65 #endif
66 lua_newtable(L);
68 #ifndef _WIN32
70 for(a = addr; a; a = a->ifa_next) {
71 int family;
72 char ipaddr[INET6_ADDRSTRLEN];
73 const char *tmp = NULL;
75 if(a->ifa_addr == NULL || a->ifa_flags & IFF_LOOPBACK) {
76 continue;
79 family = a->ifa_addr->sa_family;
81 if(ipv4 && family == AF_INET) {
82 struct sockaddr_in *sa = (struct sockaddr_in *)a->ifa_addr;
84 if(!link_local && ((sa->sin_addr.s_addr & ip4_mask) == ip4_linklocal)) {
85 continue;
88 tmp = inet_ntop(family, &sa->sin_addr, ipaddr, sizeof(ipaddr));
89 } else if(ipv6 && family == AF_INET6) {
90 struct sockaddr_in6 *sa = (struct sockaddr_in6 *)a->ifa_addr;
92 if(!link_local && IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) {
93 continue;
96 if(IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&sa->sin6_addr)) {
97 continue;
100 tmp = inet_ntop(family, &sa->sin6_addr, ipaddr, sizeof(ipaddr));
103 if(tmp != NULL) {
104 lua_pushstring(L, tmp);
105 lua_rawseti(L, -2, n++);
108 /* TODO: Error reporting? */
111 freeifaddrs(addr);
112 #else
114 if(ipv4) {
115 lua_pushstring(L, "0.0.0.0");
116 lua_rawseti(L, -2, n++);
119 if(ipv6) {
120 lua_pushstring(L, "::");
121 lua_rawseti(L, -2, n++);
124 #endif
125 return 1;
128 int luaopen_util_net(lua_State *L) {
129 #if (LUA_VERSION_NUM > 501)
130 luaL_checkversion(L);
131 #endif
132 luaL_Reg exports[] = {
133 { "local_addresses", lc_local_addresses },
134 { NULL, NULL }
137 lua_createtable(L, 0, 1);
138 luaL_setfuncs(L, exports, 0);
139 return 1;