Merge 0.9->0.10
[prosody.git] / util-src / net.c
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 --
10 */
11
12 #include <stddef.h>
13 #include <string.h>
14 #include <errno.h>
15
16 #ifndef _WIN32
17   #include <sys/ioctl.h>
18   #include <sys/types.h>
19   #include <sys/socket.h>
20   #include <net/if.h>
21   #include <ifaddrs.h>
22   #include <arpa/inet.h>
23   #include <netinet/in.h>
24 #endif
25
26 #include <lua.h>
27 #include <lauxlib.h>
28
29 /* Enumerate all locally configured IP addresses */
30
31 const char * const type_strings[] = {
32         "both",
33         "ipv4",
34         "ipv6",
35         NULL
36 };
37
38 static int lc_local_addresses(lua_State *L)
39 {
40 #ifndef _WIN32
41         /* Link-local IPv4 addresses; see RFC 3927 and RFC 5735 */
42         const long ip4_linklocal = htonl(0xa9fe0000); /* 169.254.0.0 */
43         const long ip4_mask      = htonl(0xffff0000);
44         struct ifaddrs *addr = NULL, *a;
45 #endif
46         int n = 1;
47         int type = luaL_checkoption(L, 1, "both", type_strings);
48         const char link_local = lua_toboolean(L, 2); /* defaults to 0 (false) */
49         const char ipv4 = (type == 0 || type == 1);
50         const char ipv6 = (type == 0 || type == 2);
51
52 #ifndef _WIN32
53         if (getifaddrs(&addr) < 0) {
54                 lua_pushnil(L);
55                 lua_pushfstring(L, "getifaddrs failed (%d): %s", errno,
56                 strerror(errno));
57                 return 2;
58         }
59 #endif
60         lua_newtable(L);
61
62 #ifndef _WIN32
63         for (a = addr; a; a = a->ifa_next) {
64                 int family;
65                 char ipaddr[INET6_ADDRSTRLEN];
66                 const char *tmp = NULL;
67
68                 if (a->ifa_addr == NULL || a->ifa_flags & IFF_LOOPBACK)
69                         continue;
70
71                 family = a->ifa_addr->sa_family;
72
73                 if (ipv4 && family == AF_INET) {
74                         struct sockaddr_in *sa = (struct sockaddr_in *)a->ifa_addr;
75                         if (!link_local &&((sa->sin_addr.s_addr & ip4_mask) == ip4_linklocal))
76                                 continue;
77                         tmp = inet_ntop(family, &sa->sin_addr, ipaddr, sizeof(ipaddr));
78                 } else if (ipv6 && family == AF_INET6) {
79                         struct sockaddr_in6 *sa = (struct sockaddr_in6 *)a->ifa_addr;
80                         if (!link_local && IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
81                                 continue;
82                         if (IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&sa->sin6_addr))
83                                 continue;
84                         tmp = inet_ntop(family, &sa->sin6_addr, ipaddr, sizeof(ipaddr));
85                 }
86
87                 if (tmp != NULL) {
88                         lua_pushstring(L, tmp);
89                         lua_rawseti(L, -2, n++);
90                 }
91                 /* TODO: Error reporting? */
92         }
93
94         freeifaddrs(addr);
95 #else
96         if (ipv4) {
97                 lua_pushstring(L, "0.0.0.0");
98                 lua_rawseti(L, -2, n++);
99         }
100         if (ipv6) {
101                 lua_pushstring(L, "::");
102                 lua_rawseti(L, -2, n++);
103         }
104 #endif
105         return 1;
106 }
107
108 int luaopen_util_net(lua_State* L)
109 {
110         luaL_Reg exports[] = {
111                 { "local_addresses", lc_local_addresses },
112                 { NULL, NULL }
113         };
114
115         luaL_register(L, "net",  exports);
116         return 1;
117 }