1 /*=========================================================================*\
2 * Internet domain functions
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include "lua.h"
10 #include "lauxlib.h"
11 #include "compat.h"
12 
13 #include "inet.h"
14 
15 /*=========================================================================*\
16 * Internal function prototypes.
17 \*=========================================================================*/
18 static int inet_global_toip(lua_State *L);
19 static int inet_global_getaddrinfo(lua_State *L);
20 static int inet_global_tohostname(lua_State *L);
21 static int inet_global_getnameinfo(lua_State *L);
22 static void inet_pushresolved(lua_State *L, struct hostent *hp);
23 static int inet_global_gethostname(lua_State *L);
24 
25 /* DNS functions */
26 static luaL_Reg func[] = {
27     { "toip", inet_global_toip},
28     { "getaddrinfo", inet_global_getaddrinfo},
29     { "tohostname", inet_global_tohostname},
30     { "getnameinfo", inet_global_getnameinfo},
31     { "gethostname", inet_global_gethostname},
32     { NULL, NULL}
33 };
34 
35 /*=========================================================================*\
36 * Exported functions
37 \*=========================================================================*/
38 /*-------------------------------------------------------------------------*\
39 * Initializes module
40 \*-------------------------------------------------------------------------*/
inet_open(lua_State * L)41 int inet_open(lua_State *L)
42 {
43     lua_pushstring(L, "dns");
44     lua_newtable(L);
45     luaL_setfuncs(L, func, 0);
46     lua_settable(L, -3);
47     return 0;
48 }
49 
50 /*=========================================================================*\
51 * Global Lua functions
52 \*=========================================================================*/
53 /*-------------------------------------------------------------------------*\
54 * Returns all information provided by the resolver given a host name
55 * or ip address
56 \*-------------------------------------------------------------------------*/
inet_gethost(const char * address,struct hostent ** hp)57 static int inet_gethost(const char *address, struct hostent **hp) {
58     struct in_addr addr;
59     if (inet_aton(address, &addr))
60         return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
61     else
62         return socket_gethostbyname(address, hp);
63 }
64 
65 /*-------------------------------------------------------------------------*\
66 * Returns all information provided by the resolver given a host name
67 * or ip address
68 \*-------------------------------------------------------------------------*/
inet_global_tohostname(lua_State * L)69 static int inet_global_tohostname(lua_State *L) {
70     const char *address = luaL_checkstring(L, 1);
71     struct hostent *hp = NULL;
72     int err = inet_gethost(address, &hp);
73     if (err != IO_DONE) {
74         lua_pushnil(L);
75         lua_pushstring(L, socket_hoststrerror(err));
76         return 2;
77     }
78     lua_pushstring(L, hp->h_name);
79     inet_pushresolved(L, hp);
80     return 2;
81 }
82 
inet_global_getnameinfo(lua_State * L)83 static int inet_global_getnameinfo(lua_State *L) {
84     char hbuf[NI_MAXHOST];
85     char sbuf[NI_MAXSERV];
86     int i, ret;
87     struct addrinfo hints;
88     struct addrinfo *resolved, *iter;
89     const char *host = luaL_optstring(L, 1, NULL);
90     const char *serv = luaL_optstring(L, 2, NULL);
91 
92     if (!(host || serv))
93         luaL_error(L, "host and serv cannot be both nil");
94 
95     memset(&hints, 0, sizeof(hints));
96     hints.ai_socktype = SOCK_STREAM;
97     hints.ai_family = AF_UNSPEC;
98 
99     ret = getaddrinfo(host, serv, &hints, &resolved);
100     if (ret != 0) {
101         lua_pushnil(L);
102         lua_pushstring(L, socket_gaistrerror(ret));
103         return 2;
104     }
105 
106     lua_newtable(L);
107     for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
108         getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen,
109             hbuf, host? (socklen_t) sizeof(hbuf): 0,
110             sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0);
111         if (host) {
112             lua_pushnumber(L, i);
113             lua_pushstring(L, hbuf);
114             lua_settable(L, -3);
115         }
116     }
117     freeaddrinfo(resolved);
118 
119     if (serv) {
120         lua_pushstring(L, sbuf);
121         return 2;
122     } else {
123         return 1;
124     }
125 }
126 
127 /*-------------------------------------------------------------------------*\
128 * Returns all information provided by the resolver given a host name
129 * or ip address
130 \*-------------------------------------------------------------------------*/
inet_global_toip(lua_State * L)131 static int inet_global_toip(lua_State *L)
132 {
133     const char *address = luaL_checkstring(L, 1);
134     struct hostent *hp = NULL;
135     int err = inet_gethost(address, &hp);
136     if (err != IO_DONE) {
137         lua_pushnil(L);
138         lua_pushstring(L, socket_hoststrerror(err));
139         return 2;
140     }
141     lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
142     inet_pushresolved(L, hp);
143     return 2;
144 }
145 
inet_optfamily(lua_State * L,int narg,const char * def)146 int inet_optfamily(lua_State* L, int narg, const char* def)
147 {
148     static const char* optname[] = { "unspec", "inet", "inet6", NULL };
149     static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 };
150 
151     return optvalue[luaL_checkoption(L, narg, def, optname)];
152 }
153 
inet_optsocktype(lua_State * L,int narg,const char * def)154 int inet_optsocktype(lua_State* L, int narg, const char* def)
155 {
156     static const char* optname[] = { "stream", "dgram", NULL };
157     static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
158 
159     return optvalue[luaL_checkoption(L, narg, def, optname)];
160 }
161 
inet_global_getaddrinfo(lua_State * L)162 static int inet_global_getaddrinfo(lua_State *L)
163 {
164     const char *hostname = luaL_checkstring(L, 1);
165     struct addrinfo *iterator = NULL, *resolved = NULL;
166     struct addrinfo hints;
167     int i = 1, ret = 0;
168     memset(&hints, 0, sizeof(hints));
169     hints.ai_socktype = SOCK_STREAM;
170     hints.ai_family = AF_UNSPEC;
171     ret = getaddrinfo(hostname, NULL, &hints, &resolved);
172     if (ret != 0) {
173         lua_pushnil(L);
174         lua_pushstring(L, socket_gaistrerror(ret));
175         return 2;
176     }
177     lua_newtable(L);
178     for (iterator = resolved; iterator; iterator = iterator->ai_next) {
179         char hbuf[NI_MAXHOST];
180         ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen,
181             hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
182         if (ret){
183           freeaddrinfo(resolved);
184           lua_pushnil(L);
185           lua_pushstring(L, socket_gaistrerror(ret));
186           return 2;
187         }
188         lua_pushnumber(L, i);
189         lua_newtable(L);
190         switch (iterator->ai_family) {
191             case AF_INET:
192                 lua_pushliteral(L, "family");
193                 lua_pushliteral(L, "inet");
194                 lua_settable(L, -3);
195                 break;
196             case AF_INET6:
197                 lua_pushliteral(L, "family");
198                 lua_pushliteral(L, "inet6");
199                 lua_settable(L, -3);
200                 break;
201             case AF_UNSPEC:
202                 lua_pushliteral(L, "family");
203                 lua_pushliteral(L, "unspec");
204                 lua_settable(L, -3);
205                 break;
206             default:
207                 lua_pushliteral(L, "family");
208                 lua_pushliteral(L, "unknown");
209                 lua_settable(L, -3);
210                 break;
211         }
212         lua_pushliteral(L, "addr");
213         lua_pushstring(L, hbuf);
214         lua_settable(L, -3);
215         lua_settable(L, -3);
216         i++;
217     }
218     freeaddrinfo(resolved);
219     return 1;
220 }
221 
222 /*-------------------------------------------------------------------------*\
223 * Gets the host name
224 \*-------------------------------------------------------------------------*/
inet_global_gethostname(lua_State * L)225 static int inet_global_gethostname(lua_State *L)
226 {
227     char name[257];
228     name[256] = '\0';
229     if (gethostname(name, 256) < 0) {
230         lua_pushnil(L);
231         lua_pushstring(L, socket_strerror(errno));
232         return 2;
233     } else {
234         lua_pushstring(L, name);
235         return 1;
236     }
237 }
238 
239 /*=========================================================================*\
240 * Lua methods
241 \*=========================================================================*/
242 /*-------------------------------------------------------------------------*\
243 * Retrieves socket peer name
244 \*-------------------------------------------------------------------------*/
inet_meth_getpeername(lua_State * L,p_socket ps,int family)245 int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
246 {
247     int err;
248     struct sockaddr_storage peer;
249     socklen_t peer_len = sizeof(peer);
250     char name[INET6_ADDRSTRLEN];
251     char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
252     if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
253         lua_pushnil(L);
254         lua_pushstring(L, socket_strerror(errno));
255         return 2;
256     }
257 	err = getnameinfo((struct sockaddr *) &peer, peer_len,
258         name, INET6_ADDRSTRLEN,
259         port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
260     if (err) {
261         lua_pushnil(L);
262         lua_pushstring(L, gai_strerrorA(err));
263         return 2;
264     }
265     lua_pushstring(L, name);
266     lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
267     switch (family) {
268         case AF_INET: lua_pushliteral(L, "inet"); break;
269         case AF_INET6: lua_pushliteral(L, "inet6"); break;
270         case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
271         default: lua_pushliteral(L, "unknown"); break;
272     }
273     return 3;
274 }
275 
276 /*-------------------------------------------------------------------------*\
277 * Retrieves socket local name
278 \*-------------------------------------------------------------------------*/
inet_meth_getsockname(lua_State * L,p_socket ps,int family)279 int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
280 {
281     int err;
282     struct sockaddr_storage peer;
283     socklen_t peer_len = sizeof(peer);
284     char name[INET6_ADDRSTRLEN];
285     char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
286     if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) {
287         lua_pushnil(L);
288         lua_pushstring(L, socket_strerror(errno));
289         return 2;
290     }
291 	err=getnameinfo((struct sockaddr *)&peer, peer_len,
292 		name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
293     if (err) {
294         lua_pushnil(L);
295         lua_pushstring(L, gai_strerrorA(err));
296         return 2;
297     }
298     lua_pushstring(L, name);
299     lua_pushstring(L, port);
300     switch (family) {
301         case AF_INET: lua_pushliteral(L, "inet"); break;
302         case AF_INET6: lua_pushliteral(L, "inet6"); break;
303         case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
304         default: lua_pushliteral(L, "unknown"); break;
305     }
306     return 3;
307 }
308 
309 /*=========================================================================*\
310 * Internal functions
311 \*=========================================================================*/
312 /*-------------------------------------------------------------------------*\
313 * Passes all resolver information to Lua as a table
314 \*-------------------------------------------------------------------------*/
inet_pushresolved(lua_State * L,struct hostent * hp)315 static void inet_pushresolved(lua_State *L, struct hostent *hp)
316 {
317     char **alias;
318     struct in_addr **addr;
319     int i, resolved;
320     lua_newtable(L); resolved = lua_gettop(L);
321     lua_pushstring(L, "name");
322     lua_pushstring(L, hp->h_name);
323     lua_settable(L, resolved);
324     lua_pushstring(L, "ip");
325     lua_pushstring(L, "alias");
326     i = 1;
327     alias = hp->h_aliases;
328     lua_newtable(L);
329     if (alias) {
330         while (*alias) {
331             lua_pushnumber(L, i);
332             lua_pushstring(L, *alias);
333             lua_settable(L, -3);
334             i++; alias++;
335         }
336     }
337     lua_settable(L, resolved);
338     i = 1;
339     lua_newtable(L);
340     addr = (struct in_addr **) hp->h_addr_list;
341     if (addr) {
342         while (*addr) {
343             lua_pushnumber(L, i);
344             lua_pushstring(L, inet_ntoa(**addr));
345             lua_settable(L, -3);
346             i++; addr++;
347         }
348     }
349     lua_settable(L, resolved);
350 }
351 
352 /*-------------------------------------------------------------------------*\
353 * Tries to create a new inet socket
354 \*-------------------------------------------------------------------------*/
inet_trycreate(p_socket ps,int family,int type,int protocol)355 const char *inet_trycreate(p_socket ps, int family, int type, int protocol) {
356     const char *err = socket_strerror(socket_create(ps, family, type, protocol));
357     if (err == NULL && family == AF_INET6) {
358         int yes = 1;
359         setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes));
360     }
361     return err;
362 }
363 
364 /*-------------------------------------------------------------------------*\
365 * "Disconnects" a DGRAM socket
366 \*-------------------------------------------------------------------------*/
inet_trydisconnect(p_socket ps,int family,p_timeout tm)367 const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
368 {
369     switch (family) {
370         case AF_INET: {
371             struct sockaddr_in sin;
372             memset((char *) &sin, 0, sizeof(sin));
373             sin.sin_family = AF_UNSPEC;
374             sin.sin_addr.s_addr = INADDR_ANY;
375             return socket_strerror(socket_connect(ps, (SA *) &sin,
376                 sizeof(sin), tm));
377         }
378         case AF_INET6: {
379             struct sockaddr_in6 sin6;
380             struct in6_addr addrany = IN6ADDR_ANY_INIT;
381             memset((char *) &sin6, 0, sizeof(sin6));
382             sin6.sin6_family = AF_UNSPEC;
383             sin6.sin6_addr = addrany;
384             return socket_strerror(socket_connect(ps, (SA *) &sin6,
385                 sizeof(sin6), tm));
386         }
387     }
388     return NULL;
389 }
390 
391 /*-------------------------------------------------------------------------*\
392 * Tries to connect to remote address (address, port)
393 \*-------------------------------------------------------------------------*/
inet_tryconnect(p_socket ps,int * family,const char * address,const char * serv,p_timeout tm,struct addrinfo * connecthints)394 const char *inet_tryconnect(p_socket ps, int *family, const char *address,
395         const char *serv, p_timeout tm, struct addrinfo *connecthints)
396 {
397     struct addrinfo *iterator = NULL, *resolved = NULL;
398     const char *err = NULL;
399     int current_family = *family;
400     /* try resolving */
401     err = socket_gaistrerror(getaddrinfo(address, serv,
402                 connecthints, &resolved));
403     if (err != NULL) {
404         if (resolved) freeaddrinfo(resolved);
405         return err;
406     }
407     for (iterator = resolved; iterator; iterator = iterator->ai_next) {
408         timeout_markstart(tm);
409         /* create new socket if necessary. if there was no
410          * bind, we need to create one for every new family
411          * that shows up while iterating. if there was a
412          * bind, all families will be the same and we will
413          * not enter this branch. */
414         if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
415             socket_destroy(ps);
416             err = inet_trycreate(ps, iterator->ai_family,
417                 iterator->ai_socktype, iterator->ai_protocol);
418             if (err) continue;
419             current_family = iterator->ai_family;
420             /* set non-blocking before connect */
421             socket_setnonblocking(ps);
422         }
423         /* try connecting to remote address */
424         err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
425             (socklen_t) iterator->ai_addrlen, tm));
426         /* if success or timeout is zero, break out of loop */
427         if (err == NULL || timeout_iszero(tm)) {
428             *family = current_family;
429             break;
430         }
431     }
432     freeaddrinfo(resolved);
433     /* here, if err is set, we failed */
434     return err;
435 }
436 
437 /*-------------------------------------------------------------------------*\
438 * Tries to accept a socket
439 \*-------------------------------------------------------------------------*/
inet_tryaccept(p_socket server,int family,p_socket client,p_timeout tm)440 const char *inet_tryaccept(p_socket server, int family, p_socket client,
441     p_timeout tm) {
442 	socklen_t len;
443 	t_sockaddr_storage addr;
444     switch (family) {
445         case AF_INET6: len = sizeof(struct sockaddr_in6); break;
446         case AF_INET: len = sizeof(struct sockaddr_in); break;
447         default: len = sizeof(addr); break;
448     }
449 	return socket_strerror(socket_accept(server, client, (SA *) &addr,
450         &len, tm));
451 }
452 
453 /*-------------------------------------------------------------------------*\
454 * Tries to bind socket to (address, port)
455 \*-------------------------------------------------------------------------*/
inet_trybind(p_socket ps,int * family,const char * address,const char * serv,struct addrinfo * bindhints)456 const char *inet_trybind(p_socket ps, int *family, const char *address,
457     const char *serv, struct addrinfo *bindhints) {
458     struct addrinfo *iterator = NULL, *resolved = NULL;
459     const char *err = NULL;
460     int current_family = *family;
461     /* translate luasocket special values to C */
462     if (strcmp(address, "*") == 0) address = NULL;
463     if (!serv) serv = "0";
464     /* try resolving */
465     err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
466     if (err) {
467         if (resolved) freeaddrinfo(resolved);
468         return err;
469     }
470     /* iterate over resolved addresses until one is good */
471     for (iterator = resolved; iterator; iterator = iterator->ai_next) {
472         if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
473             socket_destroy(ps);
474             err = inet_trycreate(ps, iterator->ai_family,
475                         iterator->ai_socktype, iterator->ai_protocol);
476             if (err) continue;
477             current_family = iterator->ai_family;
478         }
479         /* try binding to local address */
480         err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr,
481             (socklen_t) iterator->ai_addrlen));
482         /* keep trying unless bind succeeded */
483         if (err == NULL) {
484             *family = current_family;
485             /* set to non-blocking after bind */
486             socket_setnonblocking(ps);
487             break;
488         }
489     }
490     /* cleanup and return error */
491     freeaddrinfo(resolved);
492     /* here, if err is set, we failed */
493     return err;
494 }
495 
496 /*-------------------------------------------------------------------------*\
497 * Some systems do not provide these so that we provide our own.
498 \*-------------------------------------------------------------------------*/
499 #ifdef LUASOCKET_INET_ATON
inet_aton(const char * cp,struct in_addr * inp)500 int inet_aton(const char *cp, struct in_addr *inp)
501 {
502     unsigned int a = 0, b = 0, c = 0, d = 0;
503     int n = 0, r;
504     unsigned long int addr = 0;
505     r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
506     if (r == 0 || n == 0) return 0;
507     cp += n;
508     if (*cp) return 0;
509     if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
510     if (inp) {
511         addr += a; addr <<= 8;
512         addr += b; addr <<= 8;
513         addr += c; addr <<= 8;
514         addr += d;
515         inp->s_addr = htonl(addr);
516     }
517     return 1;
518 }
519 #endif
520 
521 #ifdef LUASOCKET_INET_PTON
inet_pton(int af,const char * src,void * dst)522 int inet_pton(int af, const char *src, void *dst)
523 {
524     struct addrinfo hints, *res;
525     int ret = 1;
526     memset(&hints, 0, sizeof(struct addrinfo));
527     hints.ai_family = af;
528     hints.ai_flags = AI_NUMERICHOST;
529     if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1;
530     if (af == AF_INET) {
531         struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
532         memcpy(dst, &in->sin_addr, sizeof(in->sin_addr));
533     } else if (af == AF_INET6) {
534         struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
535         memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr));
536     } else {
537         ret = -1;
538     }
539     freeaddrinfo(res);
540     return ret;
541 }
542 
543 #endif
544