1 /*=========================================================================*\
2 * Internet domain functions
3 * LuaSocket toolkit
4 *
5 * RCS ID: $Id: inet.c,v 1.28 2005/10/07 04:40:59 diego Exp $
6 \*=========================================================================*/
7 #include <stdio.h>
8 #include <string.h>
9 
10 #include "inet.h"
11 
12 /*=========================================================================*\
13 * Internal function prototypes.
14 \*=========================================================================*/
15 static int inet_global_toip(lua_State *L);
16 static int inet_global_tohostname(lua_State *L);
17 static void inet_pushresolved(lua_State *L, struct hostent *hp);
18 static int inet_global_gethostname(lua_State *L);
19 
20 /* DNS functions */
21 static luaL_Reg func[] = {
22     { "toip", inet_global_toip },
23     { "tohostname", inet_global_tohostname },
24     { "gethostname", inet_global_gethostname},
25     { NULL, NULL}
26 };
27 
28 /*=========================================================================*\
29 * Exported functions
30 \*=========================================================================*/
31 /*-------------------------------------------------------------------------*\
32 * Initializes module
33 \*-------------------------------------------------------------------------*/
inet_open(lua_State * L)34 int inet_open(lua_State *L)
35 {
36     lua_pushstring(L, "dns");
37     lua_newtable(L);
38     luaL_openlib(L, NULL, func, 0);
39     lua_settable(L, -3);
40     return 0;
41 }
42 
43 /*=========================================================================*\
44 * Global Lua functions
45 \*=========================================================================*/
46 /*-------------------------------------------------------------------------*\
47 * Returns all information provided by the resolver given a host name
48 * or ip address
49 \*-------------------------------------------------------------------------*/
inet_gethost(const char * address,struct hostent ** hp)50 static int inet_gethost(const char *address, struct hostent **hp) {
51     struct in_addr addr;
52     if (inet_aton(address, &addr))
53         return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
54     else
55         return socket_gethostbyname(address, hp);
56 }
57 
58 /*-------------------------------------------------------------------------*\
59 * Returns all information provided by the resolver given a host name
60 * or ip address
61 \*-------------------------------------------------------------------------*/
inet_global_tohostname(lua_State * L)62 static int inet_global_tohostname(lua_State *L) {
63     const char *address = luaL_checkstring(L, 1);
64     struct hostent *hp = NULL;
65     int err = inet_gethost(address, &hp);
66     if (err != IO_DONE) {
67         lua_pushnil(L);
68         lua_pushstring(L, socket_hoststrerror(err));
69         return 2;
70     }
71     lua_pushstring(L, hp->h_name);
72     inet_pushresolved(L, hp);
73     return 2;
74 }
75 
76 /*-------------------------------------------------------------------------*\
77 * Returns all information provided by the resolver given a host name
78 * or ip address
79 \*-------------------------------------------------------------------------*/
inet_global_toip(lua_State * L)80 static int inet_global_toip(lua_State *L)
81 {
82     const char *address = luaL_checkstring(L, 1);
83     struct hostent *hp = NULL;
84     int err = inet_gethost(address, &hp);
85     if (err != IO_DONE) {
86         lua_pushnil(L);
87         lua_pushstring(L, socket_hoststrerror(err));
88         return 2;
89     }
90     lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
91     inet_pushresolved(L, hp);
92     return 2;
93 }
94 
95 
96 /*-------------------------------------------------------------------------*\
97 * Gets the host name
98 \*-------------------------------------------------------------------------*/
inet_global_gethostname(lua_State * L)99 static int inet_global_gethostname(lua_State *L)
100 {
101     char name[257];
102     name[256] = '\0';
103     if (gethostname(name, 256) < 0) {
104         lua_pushnil(L);
105         lua_pushstring(L, "gethostname failed");
106         return 2;
107     } else {
108         lua_pushstring(L, name);
109         return 1;
110     }
111 }
112 
113 
114 
115 /*=========================================================================*\
116 * Lua methods
117 \*=========================================================================*/
118 /*-------------------------------------------------------------------------*\
119 * Retrieves socket peer name
120 \*-------------------------------------------------------------------------*/
inet_meth_getpeername(lua_State * L,p_socket ps)121 int inet_meth_getpeername(lua_State *L, p_socket ps)
122 {
123     struct sockaddr_in peer;
124     socklen_t peer_len = sizeof(peer);
125     if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
126         lua_pushnil(L);
127         lua_pushstring(L, "getpeername failed");
128     } else {
129         lua_pushstring(L, inet_ntoa(peer.sin_addr));
130         lua_pushnumber(L, ntohs(peer.sin_port));
131     }
132     return 2;
133 }
134 
135 /*-------------------------------------------------------------------------*\
136 * Retrieves socket local name
137 \*-------------------------------------------------------------------------*/
inet_meth_getsockname(lua_State * L,p_socket ps)138 int inet_meth_getsockname(lua_State *L, p_socket ps)
139 {
140     struct sockaddr_in local;
141     socklen_t local_len = sizeof(local);
142     if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
143         lua_pushnil(L);
144         lua_pushstring(L, "getsockname failed");
145     } else {
146         lua_pushstring(L, inet_ntoa(local.sin_addr));
147         lua_pushnumber(L, ntohs(local.sin_port));
148     }
149     return 2;
150 }
151 
152 /*=========================================================================*\
153 * Internal functions
154 \*=========================================================================*/
155 /*-------------------------------------------------------------------------*\
156 * Passes all resolver information to Lua as a table
157 \*-------------------------------------------------------------------------*/
inet_pushresolved(lua_State * L,struct hostent * hp)158 static void inet_pushresolved(lua_State *L, struct hostent *hp)
159 {
160     char **alias;
161     struct in_addr **addr;
162     int i, resolved;
163     lua_newtable(L); resolved = lua_gettop(L);
164     lua_pushstring(L, "name");
165     lua_pushstring(L, hp->h_name);
166     lua_settable(L, resolved);
167     lua_pushstring(L, "ip");
168     lua_pushstring(L, "alias");
169     i = 1;
170     alias = hp->h_aliases;
171     lua_newtable(L);
172     if (alias) {
173         while (*alias) {
174             lua_pushnumber(L, i);
175             lua_pushstring(L, *alias);
176             lua_settable(L, -3);
177             i++; alias++;
178         }
179     }
180     lua_settable(L, resolved);
181     i = 1;
182     lua_newtable(L);
183     addr = (struct in_addr **) hp->h_addr_list;
184     if (addr) {
185         while (*addr) {
186             lua_pushnumber(L, i);
187             lua_pushstring(L, inet_ntoa(**addr));
188             lua_settable(L, -3);
189             i++; addr++;
190         }
191     }
192     lua_settable(L, resolved);
193 }
194 
195 /*-------------------------------------------------------------------------*\
196 * Tries to create a new inet socket
197 \*-------------------------------------------------------------------------*/
inet_trycreate(p_socket ps,int type)198 const char *inet_trycreate(p_socket ps, int type) {
199     return socket_strerror(socket_create(ps, AF_INET, type, 0));
200 }
201 
202 /*-------------------------------------------------------------------------*\
203 * Tries to connect to remote address (address, port)
204 \*-------------------------------------------------------------------------*/
inet_tryconnect(p_socket ps,const char * address,unsigned short port,p_timeout tm)205 const char *inet_tryconnect(p_socket ps, const char *address,
206         unsigned short port, p_timeout tm)
207 {
208     struct sockaddr_in remote;
209     int err;
210     memset(&remote, 0, sizeof(remote));
211     remote.sin_family = AF_INET;
212     remote.sin_port = htons(port);
213 	if (strcmp(address, "*")) {
214         if (!inet_aton(address, &remote.sin_addr)) {
215             struct hostent *hp = NULL;
216             struct in_addr **addr;
217             err = socket_gethostbyname(address, &hp);
218             if (err != IO_DONE) return socket_hoststrerror(err);
219             addr = (struct in_addr **) hp->h_addr_list;
220             memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
221         }
222     } else remote.sin_family = AF_UNSPEC;
223     err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm);
224     return socket_strerror(err);
225 }
226 
227 /*-------------------------------------------------------------------------*\
228 * Tries to bind socket to (address, port)
229 \*-------------------------------------------------------------------------*/
inet_trybind(p_socket ps,const char * address,unsigned short port)230 const char *inet_trybind(p_socket ps, const char *address, unsigned short port)
231 {
232     struct sockaddr_in local;
233     int err;
234     memset(&local, 0, sizeof(local));
235     /* address is either wildcard or a valid ip address */
236     local.sin_addr.s_addr = htonl(INADDR_ANY);
237     local.sin_port = htons(port);
238     local.sin_family = AF_INET;
239     if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
240         struct hostent *hp = NULL;
241         struct in_addr **addr;
242         err = socket_gethostbyname(address, &hp);
243         if (err != IO_DONE) return socket_hoststrerror(err);
244         addr = (struct in_addr **) hp->h_addr_list;
245         memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
246     }
247     err = socket_bind(ps, (SA *) &local, sizeof(local));
248     if (err != IO_DONE) socket_destroy(ps);
249     return socket_strerror(err);
250 }
251 
252 /*-------------------------------------------------------------------------*\
253 * Some systems do not provide this so that we provide our own. It's not
254 * marvelously fast, but it works just fine.
255 \*-------------------------------------------------------------------------*/
256 #ifdef INET_ATON
inet_aton(const char * cp,struct in_addr * inp)257 int inet_aton(const char *cp, struct in_addr *inp)
258 {
259     unsigned int a = 0, b = 0, c = 0, d = 0;
260     int n = 0, r;
261     unsigned long int addr = 0;
262     r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
263     if (r == 0 || n == 0) return 0;
264     cp += n;
265     if (*cp) return 0;
266     if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
267     if (inp) {
268         addr += a; addr <<= 8;
269         addr += b; addr <<= 8;
270         addr += c; addr <<= 8;
271         addr += d;
272         inp->s_addr = htonl(addr);
273     }
274     return 1;
275 }
276 #endif
277 
278 
279