util.encodings: Spell out all IDNA 2008 options ICU has
[prosody.git] / util-src / net.c
blob5f706d81ba7ffa7a85f0f1533430b9dbf8b624e7
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 #ifndef _GNU_SOURCE
13 #define _GNU_SOURCE
14 #endif
16 #include <stddef.h>
17 #include <string.h>
18 #include <errno.h>
20 #ifndef _WIN32
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <net/if.h>
25 #include <ifaddrs.h>
26 #include <arpa/inet.h>
27 #include <netinet/in.h>
28 #endif
30 #include <lua.h>
31 #include <lauxlib.h>
33 #if (LUA_VERSION_NUM == 501)
34 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
35 #endif
37 /* Enumerate all locally configured IP addresses */
39 const char *const type_strings[] = {
40 "both",
41 "ipv4",
42 "ipv6",
43 NULL
46 static int lc_local_addresses(lua_State *L) {
47 #ifndef _WIN32
48 /* Link-local IPv4 addresses; see RFC 3927 and RFC 5735 */
49 const long ip4_linklocal = htonl(0xa9fe0000); /* 169.254.0.0 */
50 const long ip4_mask = htonl(0xffff0000);
51 struct ifaddrs *addr = NULL, *a;
52 #endif
53 int n = 1;
54 int type = luaL_checkoption(L, 1, "both", type_strings);
55 const char link_local = lua_toboolean(L, 2); /* defaults to 0 (false) */
56 const char ipv4 = (type == 0 || type == 1);
57 const char ipv6 = (type == 0 || type == 2);
59 #ifndef _WIN32
61 if(getifaddrs(&addr) < 0) {
62 lua_pushnil(L);
63 lua_pushfstring(L, "getifaddrs failed (%d): %s", errno,
64 strerror(errno));
65 return 2;
68 #endif
69 lua_newtable(L);
71 #ifndef _WIN32
73 for(a = addr; a; a = a->ifa_next) {
74 int family;
75 char ipaddr[INET6_ADDRSTRLEN];
76 const char *tmp = NULL;
78 if(a->ifa_addr == NULL || a->ifa_flags & IFF_LOOPBACK) {
79 continue;
82 family = a->ifa_addr->sa_family;
84 if(ipv4 && family == AF_INET) {
85 struct sockaddr_in *sa = (struct sockaddr_in *)a->ifa_addr;
87 if(!link_local && ((sa->sin_addr.s_addr & ip4_mask) == ip4_linklocal)) {
88 continue;
91 tmp = inet_ntop(family, &sa->sin_addr, ipaddr, sizeof(ipaddr));
92 } else if(ipv6 && family == AF_INET6) {
93 struct sockaddr_in6 *sa = (struct sockaddr_in6 *)a->ifa_addr;
95 if(!link_local && IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) {
96 continue;
99 if(IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&sa->sin6_addr)) {
100 continue;
103 tmp = inet_ntop(family, &sa->sin6_addr, ipaddr, sizeof(ipaddr));
106 if(tmp != NULL) {
107 lua_pushstring(L, tmp);
108 lua_rawseti(L, -2, n++);
111 /* TODO: Error reporting? */
114 freeifaddrs(addr);
115 #else
117 if(ipv4) {
118 lua_pushstring(L, "0.0.0.0");
119 lua_rawseti(L, -2, n++);
122 if(ipv6) {
123 lua_pushstring(L, "::");
124 lua_rawseti(L, -2, n++);
127 #endif
128 return 1;
131 static int lc_pton(lua_State *L) {
132 char buf[16];
133 const char *ipaddr = luaL_checkstring(L, 1);
134 int errno_ = 0;
135 int family = strchr(ipaddr, ':') ? AF_INET6 : AF_INET;
137 switch(inet_pton(family, ipaddr, &buf)) {
138 case 1:
139 lua_pushlstring(L, buf, family == AF_INET6 ? 16 : 4);
140 return 1;
142 case -1:
143 errno_ = errno;
144 lua_pushnil(L);
145 lua_pushstring(L, strerror(errno_));
146 lua_pushinteger(L, errno_);
147 return 3;
149 default:
150 case 0:
151 lua_pushnil(L);
152 lua_pushstring(L, strerror(EINVAL));
153 lua_pushinteger(L, EINVAL);
154 return 3;
159 static int lc_ntop(lua_State *L) {
160 char buf[INET6_ADDRSTRLEN];
161 int family;
162 int errno_;
163 size_t l;
164 const char *ipaddr = luaL_checklstring(L, 1, &l);
166 if(l == 16) {
167 family = AF_INET6;
169 else if(l == 4) {
170 family = AF_INET;
172 else {
173 lua_pushnil(L);
174 lua_pushstring(L, strerror(EAFNOSUPPORT));
175 lua_pushinteger(L, EAFNOSUPPORT);
176 return 3;
179 if(!inet_ntop(family, ipaddr, buf, INET6_ADDRSTRLEN))
181 errno_ = errno;
182 lua_pushnil(L);
183 lua_pushstring(L, strerror(errno_));
184 lua_pushinteger(L, errno_);
185 return 3;
188 lua_pushstring(L, (const char *)(&buf));
189 return 1;
192 int luaopen_util_net(lua_State *L) {
193 #if (LUA_VERSION_NUM > 501)
194 luaL_checkversion(L);
195 #endif
196 luaL_Reg exports[] = {
197 { "local_addresses", lc_local_addresses },
198 { "pton", lc_pton },
199 { "ntop", lc_ntop },
200 { NULL, NULL }
203 lua_createtable(L, 0, 1);
204 luaL_setfuncs(L, exports, 0);
205 return 1;