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 "lua.h"
11 #include "lauxlib.h"
12 
13 #include "inet.h"
14 //spring includes
15 #include "restrictions.h"
16 #include "System/Log/ILog.h"
17 
18 /*=========================================================================*\
19 * Internal function prototypes.
20 \*=========================================================================*/
21 static int inet_global_toip(lua_State *L);
22 static int inet_global_tohostname(lua_State *L);
23 static void inet_pushresolved(lua_State *L, struct hostent *hp);
24 static int inet_global_gethostname(lua_State *L);
25 
26 /* DNS functions */
27 static luaL_reg func[] = {
28     { "toip", inet_global_toip },
29     { "tohostname", inet_global_tohostname },
30     { "gethostname", inet_global_gethostname},
31     { NULL, NULL}
32 };
33 
34 /*=========================================================================*\
35 * Exported functions
36 \*=========================================================================*/
37 /*-------------------------------------------------------------------------*\
38 * Initializes module
39 \*-------------------------------------------------------------------------*/
inet_open(lua_State * L)40 int inet_open(lua_State *L)
41 {
42     lua_pushstring(L, "dns");
43     lua_newtable(L);
44     luaI_openlib(L, NULL, func, 0);
45     lua_settable(L, -3);
46     return 0;
47 }
48 
49 /*=========================================================================*\
50 * Global Lua functions
51 \*=========================================================================*/
52 /*-------------------------------------------------------------------------*\
53 * Returns all information provided by the resolver given a host name
54 * or ip address
55 \*-------------------------------------------------------------------------*/
inet_gethost(const char * address,struct hostent ** hp)56 static int inet_gethost(const char *address, struct hostent **hp) {
57     struct in_addr addr;
58     if (inet_aton(address, &addr))
59         return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
60     else
61         return socket_gethostbyname(address, hp);
62 }
63 
64 /*-------------------------------------------------------------------------*\
65 * Returns all information provided by the resolver given a host name
66 * or ip address
67 \*-------------------------------------------------------------------------*/
inet_global_tohostname(lua_State * L)68 static int inet_global_tohostname(lua_State *L) {
69     const char *address = luaL_checkstring(L, 1);
70     struct hostent *hp = NULL;
71     int err = inet_gethost(address, &hp);
72     luaSocketRestrictions->addIP(address, hp->h_name); //add resolved ip to rules
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 
83 /*-------------------------------------------------------------------------*\
84 * Returns all information provided by the resolver given a host name
85 * or ip address
86 \*-------------------------------------------------------------------------*/
inet_global_toip(lua_State * L)87 static int inet_global_toip(lua_State *L)
88 {
89     const char *address = luaL_checkstring(L, 1);
90     if (!luaSocketRestrictions->isAllowed(CLuaSocketRestrictions::ALL_RULES, address)) {
91         lua_pushnil(L);
92         LOG_L(L_ERROR, "Access to '%s' denied", address);
93         lua_pushstring(L, "hostname not in allowed list");
94         return 2;
95     }
96     struct hostent *hp = NULL;
97     int err = inet_gethost(address, &hp);
98     if (err != IO_DONE) {
99         lua_pushnil(L);
100         lua_pushstring(L, socket_hoststrerror(err));
101         return 2;
102     }
103     const char* ip = inet_ntoa(*((struct in_addr *) hp->h_addr));
104     luaSocketRestrictions->addIP(address, ip);
105     lua_pushstring(L, ip);
106     inet_pushresolved(L, hp);
107     return 2;
108 }
109 
110 
111 /*-------------------------------------------------------------------------*\
112 * Gets the host name
113 \*-------------------------------------------------------------------------*/
inet_global_gethostname(lua_State * L)114 static int inet_global_gethostname(lua_State *L)
115 {
116     char name[257];
117     name[256] = '\0';
118     if (gethostname(name, 256) < 0) {
119         lua_pushnil(L);
120         lua_pushstring(L, "gethostname failed");
121         return 2;
122     } else {
123         lua_pushstring(L, name);
124         return 1;
125     }
126 }
127 
128 
129 
130 /*=========================================================================*\
131 * Lua methods
132 \*=========================================================================*/
133 /*-------------------------------------------------------------------------*\
134 * Retrieves socket peer name
135 \*-------------------------------------------------------------------------*/
inet_meth_getpeername(lua_State * L,p_socket ps)136 int inet_meth_getpeername(lua_State *L, p_socket ps)
137 {
138     struct sockaddr_in peer;
139     socklen_t peer_len = sizeof(peer);
140     if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
141         lua_pushnil(L);
142         lua_pushstring(L, "getpeername failed");
143     } else {
144         lua_pushstring(L, inet_ntoa(peer.sin_addr));
145         lua_pushnumber(L, ntohs(peer.sin_port));
146     }
147     return 2;
148 }
149 
150 /*-------------------------------------------------------------------------*\
151 * Retrieves socket local name
152 \*-------------------------------------------------------------------------*/
inet_meth_getsockname(lua_State * L,p_socket ps)153 int inet_meth_getsockname(lua_State *L, p_socket ps)
154 {
155     struct sockaddr_in local;
156     socklen_t local_len = sizeof(local);
157     if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
158         lua_pushnil(L);
159         lua_pushstring(L, "getsockname failed");
160     } else {
161         lua_pushstring(L, inet_ntoa(local.sin_addr));
162         lua_pushnumber(L, ntohs(local.sin_port));
163     }
164     return 2;
165 }
166 
167 /*=========================================================================*\
168 * Internal functions
169 \*=========================================================================*/
170 /*-------------------------------------------------------------------------*\
171 * Passes all resolver information to Lua as a table
172 \*-------------------------------------------------------------------------*/
inet_pushresolved(lua_State * L,struct hostent * hp)173 static void inet_pushresolved(lua_State *L, struct hostent *hp)
174 {
175     char **alias;
176     struct in_addr **addr;
177     int i, resolved;
178     lua_newtable(L); resolved = lua_gettop(L);
179     lua_pushstring(L, "name");
180     lua_pushstring(L, hp->h_name);
181     lua_settable(L, resolved);
182     lua_pushstring(L, "ip");
183     lua_pushstring(L, "alias");
184     i = 1;
185     alias = hp->h_aliases;
186     lua_newtable(L);
187     if (alias) {
188         while (*alias) {
189             lua_pushnumber(L, i);
190             lua_pushstring(L, *alias);
191             lua_settable(L, -3);
192             i++; alias++;
193         }
194     }
195     lua_settable(L, resolved);
196     i = 1;
197     lua_newtable(L);
198     addr = (struct in_addr **) hp->h_addr_list;
199     if (addr) {
200         while (*addr) {
201             lua_pushnumber(L, i);
202             lua_pushstring(L, inet_ntoa(**addr));
203             lua_settable(L, -3);
204             i++; addr++;
205         }
206     }
207     lua_settable(L, resolved);
208 }
209 
210 /*-------------------------------------------------------------------------*\
211 * Tries to create a new inet socket
212 \*-------------------------------------------------------------------------*/
inet_trycreate(p_socket ps,int type)213 const char *inet_trycreate(p_socket ps, int type) {
214     return socket_strerror(socket_create(ps, AF_INET, type, 0));
215 }
216 
217 
isAllowed(p_socket ps,const char * address,unsigned short port,bool connect)218 bool isAllowed(p_socket ps, const char *address, unsigned short port, bool connect){
219     int rawtype;
220     socklen_t len = sizeof(rawtype);
221     CLuaSocketRestrictions::RestrictType type;
222     int res = getsockopt(*ps, SOL_SOCKET, SO_TYPE, (char*)&rawtype, &len);
223     #ifdef WIN32
224     if (res == SOCKET_ERROR) {
225 	LOG_L(L_ERROR, "Socket error (%d): %s", res, socket_strerror(WSAGetLastError()));
226         return false;
227     }
228     #else
229     if (res != 0) {
230         LOG_L(L_ERROR, "Socket error (%d): %s", res, socket_strerror(errno));
231         return false;
232     }
233     #endif
234     if (rawtype == SOCK_STREAM)
235 	if (connect)
236             type = CLuaSocketRestrictions::TCP_CONNECT;
237         else
238             type = CLuaSocketRestrictions::TCP_LISTEN;
239     else //SOCK_DGRAM
240         if (connect)
241             type = CLuaSocketRestrictions::UDP_CONNECT;
242         else
243             type = CLuaSocketRestrictions::UDP_LISTEN;
244     if (!luaSocketRestrictions->isAllowed(type, address, port)) {
245         LOG_L(L_ERROR, "Access to '%s:%d' denied", address, port);
246         return false;
247     }
248     return true;
249 }
250 
251 /*-------------------------------------------------------------------------*\
252 * Tries to connect to remote address (address, port)
253 \*-------------------------------------------------------------------------*/
inet_tryconnect(p_socket ps,const char * address,unsigned short port,p_timeout tm)254 const char *inet_tryconnect(p_socket ps, const char *address,
255         unsigned short port, p_timeout tm)
256 {
257     if (!isAllowed(ps, address, port, true))
258 	return "connect denied";
259 
260     struct sockaddr_in remote;
261     int err;
262     memset(&remote, 0, sizeof(remote));
263     remote.sin_family = AF_INET;
264     remote.sin_port = htons(port);
265 	if (strcmp(address, "*")) {
266         if (!inet_aton(address, &remote.sin_addr)) {
267             struct hostent *hp = NULL;
268             struct in_addr **addr;
269             err = socket_gethostbyname(address, &hp);
270             if (err != IO_DONE) return socket_hoststrerror(err);
271             addr = (struct in_addr **) hp->h_addr_list;
272             memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
273             luaSocketRestrictions->addIP(address, inet_ntoa(**addr));
274         }
275     } else remote.sin_family = AF_UNSPEC;
276     err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm);
277     return socket_strerror(err);
278 }
279 
280 /*-------------------------------------------------------------------------*\
281 * Tries to bind socket to (address, port)
282 \*-------------------------------------------------------------------------*/
inet_trybind(p_socket ps,const char * address,unsigned short port)283 const char *inet_trybind(p_socket ps, const char *address, unsigned short port)
284 {
285     if (!isAllowed(ps, address, port, false))
286 	return "bind denied";
287 
288     struct sockaddr_in local;
289     int err;
290     memset(&local, 0, sizeof(local));
291     /* address is either wildcard or a valid ip address */
292     local.sin_addr.s_addr = htonl(INADDR_ANY);
293     local.sin_port = htons(port);
294     local.sin_family = AF_INET;
295     if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
296         struct hostent *hp = NULL;
297         struct in_addr **addr;
298         err = socket_gethostbyname(address, &hp);
299         if (err != IO_DONE) return socket_hoststrerror(err);
300         addr = (struct in_addr **) hp->h_addr_list;
301         memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
302         luaSocketRestrictions->addIP(address, inet_ntoa(**addr));
303     }
304     err = socket_bind(ps, (SA *) &local, sizeof(local));
305     if (err != IO_DONE) socket_destroy(ps);
306     return socket_strerror(err);
307 }
308 
309 /*-------------------------------------------------------------------------*\
310 * Some systems do not provide this so that we provide our own. It's not
311 * marvelously fast, but it works just fine.
312 \*-------------------------------------------------------------------------*/
313 #ifdef INET_ATON
inet_aton(const char * cp,struct in_addr * inp)314 int inet_aton(const char *cp, struct in_addr *inp)
315 {
316     unsigned int a = 0, b = 0, c = 0, d = 0;
317     int n = 0, r;
318     unsigned long int addr = 0;
319     r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
320     if (r == 0 || n == 0) return 0;
321     cp += n;
322     if (*cp) return 0;
323     if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
324     if (inp) {
325         addr += a; addr <<= 8;
326         addr += b; addr <<= 8;
327         addr += c; addr <<= 8;
328         addr += d;
329         inp->s_addr = htonl(addr);
330     }
331     return 1;
332 }
333 #endif
334 
335 
336