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