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\*=========================================================================*/
18static int inet_global_toip(lua_State *L);
19static int inet_global_getaddrinfo(lua_State *L);
20static int inet_global_tohostname(lua_State *L);
21static int inet_global_getnameinfo(lua_State *L);
22static void inet_pushresolved(lua_State *L, struct hostent *hp);
23static int inet_global_gethostname(lua_State *L);
24
25/* DNS functions */
26static 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\*-------------------------------------------------------------------------*/
41int 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\*-------------------------------------------------------------------------*/
57static 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\*-------------------------------------------------------------------------*/
69static 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
83static 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\*-------------------------------------------------------------------------*/
131static 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
146int 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
154int 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
162static 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\*-------------------------------------------------------------------------*/
225static 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\*-------------------------------------------------------------------------*/
245int 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_strerror(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\*-------------------------------------------------------------------------*/
279int 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_strerror(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\*-------------------------------------------------------------------------*/
315static 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\*-------------------------------------------------------------------------*/
355const 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\*-------------------------------------------------------------------------*/
367const 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\*-------------------------------------------------------------------------*/
394const 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\*-------------------------------------------------------------------------*/
440const 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\*-------------------------------------------------------------------------*/
456const 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
500int 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
522int 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