lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi,

I want to write a software that execute lua networking code. My goal was to
sandbox Luasocket to put restrictions on what hosts are allowed or not,
maximum amout of bandwith, number of sockets opened, ... Initially, I thinked
that I could easily do that in pure lua using closure. But after a
promising start, wrapping socket objects into an array, I discover a major
problem, the socket.select() function. This function cannot take my array
and need 'pure' socket to use them. So, now, I have implemented that the
listen() and connect() method return a pure socket rather than an array.
That break the Luasocket protocol and permit only to put restriction on
hosts but no other ones like bandwith management.

Do you think there is a good (and secure) solution in Lua or I must do some
change in C ? If I must change C, where and how do you advise me to change
to be as clean as possible ? Some of you as already a socket sandbox ready
? :-)

Thank you, reguards.

Leo

PS: Here is my socket sandbox code:

do
        local s_ori = socket

        socket = {}

        -- socket.tcp() is originally a 'master' object, transformed in 'server'
        -- object by a call to listen() or transformed in a 'client' object by a call
        -- to connect(). At this point select() need an array of 'client' or
        -- 'server' objects. So after a call to listen() or connect(), we must
        -- return a new object because we can't change our object wrapper (array) in
        -- the final object. This way break lightly the luasocket syntax. Anyway,
        -- this solution permit only host filtering and not socket and bandwith
        -- limitations. One more problem is that you can normally use a 'master'
        -- object in select but not in this solution, because 'master' object is
        -- always wrapped in a table.

        socket.tcp = function()
                local stcp = s_ori.tcp()
                local sock = {}

                -- We must break the protocol here, because socket.select() need pure
                -- socket{client|master} objects and no tables.
                sock.connect = function(self, host, ...)
                        if host ~= "this.denied.host" then
                                local s, msg = stcp.connect(stcp, host, unpack(arg))
                                if s ~= nil then
                                        return stcp
                                else
                                        return s, msg
                                end
                        else
                                return nil, "sandbox"
                        end
                end

                -- We must break the protocol here, because socket.select() need pure
                -- socket{client|master} objects and no tables.
                sock.listen = function(self, ...)
                        local s = stcp.listen(stcp, unpack(arg))
                        if s == nil then
                                return nil
                        else
                                return stcp
                        end
                end
                sock.bind = function(self, ...)
                        return stcp.bind(stcp, unpack(arg))
                end

                sock.close = function(self, ...)
                        return stcp.close(stcp, unpack(arg))
                end
                sock.getsockname = function(self, ...)
                        return stcp.getsockname(stcp, unpack(arg))
                end
                sock.getstats = function(self, ...)
                        return stcp.getstats(stcp, unpack(arg))
                end
                sock.setstats = function(self, ...)
                        return stcp.setstats(stcp, unpack(arg))
                end
                sock.settimeout = function(self, ...)
                        return stcp.settimeout(stcp, unpack(arg))
                end

                -- metatable (didn't work ..., not important implemented above)
--[[
                local sock_meta = {}
                sock_meta['__index'] = function (table, func)
                        return stcp[func]
                end
                sock_meta['__newindex'] = function (table, func) end
                setmetatable(sock, sock_meta)
]]--

                return sock
        end

        socket.udp = function()
                local sudp = s_ori.udp()
                local sock = {}
                sock.close = function(self, ...)
                        return sudp.close(sudp, unpack(arg))
                end
                sock.getpeername = function(self, ...)
                        return sudp.getpeername(sudp, unpack(arg))
                end
                sock.getsockname = function(self, ...)
                        return sudp.getsockname(sudp, unpack(arg))
                end
                sock.receive = function(self, ...)
                        return sudp.receive(sudp, unpack(arg))
                end
                sock.receivefrom = function(self, ...)
                        return sudp.receivefrom(sudp, unpack(arg))
                end
                sock.send = function(self, ...)
                        return sudp.send(sudp, unpack(arg))
                end
                sock.sendto = function(self, ...)
                        return sudp.sendto(sudp, unpack(arg))
                end
                sock.setpeername = function(self, ...)
                        return sudp.setpeername(sudp, unpack(arg))
                end
                sock.setsockname = function(self, ...)
                        return sudp.setsockname(sudp, unpack(arg))
                end
                sock.setoption = function(self, ...)
                        return sudp.setoption(sudp, unpack(arg))
                end
                sock.settimeout = function(self, ...)
                        return sudp.settimeout(sudp, unpack(arg))
                end

                return sock
        end

        socket.bind = function(...)
                return s_ori.bind(unpack(arg))
        end
        socket.connect = function(...)
                return s_ori.connect(unpack(arg))
        end
        socket._DEBUG = s_ori._DEBUG
        socket.newtry = function(...)
                return s_ori.newtry(unpack(arg))
        end
        socket.protect = function(...)
                return s_ori.protect(unpack(arg))
        end
        socket.select = function(...)
                return s_ori.select(unpack(arg))
        end
        socket.sink = function(...)
                return s_ori.sink(unpack(arg))
        end
        socket.skip = function(...)
                return s_ori.skip(unpack(arg))
        end
        socket.sleep = function(...)
                return s_ori.sleep(unpack(arg))
        end
        socket.source = function(...)
                return s_ori.source(unpack(arg))
        end
        socket.gettime = function(...)
                return s_ori.gettime(unpack(arg))
        end
        socket.try = function(...)
                return s_ori.try(unpack(arg))
        end
        socket._VERSION = s_ori._VERSION

        socket.dns = {}

        socket.dns.gethostname = function(...)
                return s_ori.dns.gethostname(unpack(arg))
        end
        socket.dns.tohostname = function(...)
                return s_ori.dns.tohostname(unpack(arg))
        end
        socket.dns.toip = function(...)
                return s_ori.dns.toip(unpack(arg))
        end
end