3 -- This project is MIT/X11 licensed. Please see the
4 -- COPYING file in the source package for more information.
6 -- Copyright (C) 2012 Paul Aurich
7 -- Copyright (C) 2013 Matthew Wild
8 -- Copyright (C) 2013 Florian Zeitz
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
26 #include <arpa/inet.h>
27 #include <netinet/in.h>
33 #if (LUA_VERSION_NUM == 501)
34 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
37 /* Enumerate all locally configured IP addresses */
39 const char *const type_strings
[] = {
46 static int lc_local_addresses(lua_State
*L
) {
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
;
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);
61 if(getifaddrs(&addr
) < 0) {
63 lua_pushfstring(L
, "getifaddrs failed (%d): %s", errno
,
73 for(a
= addr
; a
; a
= a
->ifa_next
) {
75 char ipaddr
[INET6_ADDRSTRLEN
];
76 const char *tmp
= NULL
;
78 if(a
->ifa_addr
== NULL
|| a
->ifa_flags
& IFF_LOOPBACK
) {
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
)) {
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
)) {
99 if(IN6_IS_ADDR_V4MAPPED(&sa
->sin6_addr
) || IN6_IS_ADDR_V4COMPAT(&sa
->sin6_addr
)) {
103 tmp
= inet_ntop(family
, &sa
->sin6_addr
, ipaddr
, sizeof(ipaddr
));
107 lua_pushstring(L
, tmp
);
108 lua_rawseti(L
, -2, n
++);
111 /* TODO: Error reporting? */
118 lua_pushstring(L
, "0.0.0.0");
119 lua_rawseti(L
, -2, n
++);
123 lua_pushstring(L
, "::");
124 lua_rawseti(L
, -2, n
++);
131 static int lc_pton(lua_State
*L
) {
133 const char *ipaddr
= luaL_checkstring(L
, 1);
135 int family
= strchr(ipaddr
, ':') ? AF_INET6
: AF_INET
;
137 switch(inet_pton(family
, ipaddr
, &buf
)) {
139 lua_pushlstring(L
, buf
, family
== AF_INET6
? 16 : 4);
145 lua_pushstring(L
, strerror(errno_
));
146 lua_pushinteger(L
, errno_
);
152 lua_pushstring(L
, strerror(EINVAL
));
153 lua_pushinteger(L
, EINVAL
);
159 static int lc_ntop(lua_State
*L
) {
160 char buf
[INET6_ADDRSTRLEN
];
164 const char *ipaddr
= luaL_checklstring(L
, 1, &l
);
174 lua_pushstring(L
, strerror(EAFNOSUPPORT
));
175 lua_pushinteger(L
, EAFNOSUPPORT
);
179 if(!inet_ntop(family
, ipaddr
, buf
, INET6_ADDRSTRLEN
))
183 lua_pushstring(L
, strerror(errno_
));
184 lua_pushinteger(L
, errno_
);
188 lua_pushstring(L
, (const char *)(&buf
));
192 int luaopen_util_net(lua_State
*L
) {
193 #if (LUA_VERSION_NUM > 501)
194 luaL_checkversion(L
);
196 luaL_Reg exports
[] = {
197 { "local_addresses", lc_local_addresses
},
203 lua_createtable(L
, 0, 1);
204 luaL_setfuncs(L
, exports
, 0);