#!/usr/bin/luaweb
json = require("json")
omg = require("omg")

dofile("/data/config.lua")

options=omg.splitCommandlineString(arg)

-- correct some config Settings
if config~=nil and config.struct_Box~=nil and config.struct_Box.struct_DChannel~=nil then
    if config.struct_Box.struct_DChannel[1]==nil then
        local t = {}
        t = config.struct_Box.struct_DChannel
        config.struct_Box.struct_DChannel = nil
        config.struct_Box.struct_DChannel = {}
        config.struct_Box.struct_DChannel[1]=t
        for k,v in ipairs(config.struct_Box.struct_DChannel) do
            if(config.struct_Box.struct_DChannel[k].struct_GateParams ~= nil) then
                if(config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTable ~= nil) then
                    if(config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTable[1] == nil) then
                        t = config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTable
                        config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTable = nil
                        config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTable = {}
                        config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTable[1]=t
                    end
                end
                if(config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTableOut ~= nil) then
                    if(config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTableOut[1] == nil) then
                        t = config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTableOut
                        config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTableOut = nil
                        config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTableOut = {}
                        config.struct_Box.struct_DChannel[k].struct_GateParams.struct_CallProcTableOut[1]=t
                    end
                end
            end
        end
    end

    ip="/sbin/iptables "
    ip6="/sbin/ip6tables "

    local f
    local isJson=false
    if io ~= nil and io.open ~= nil then
        f = io.open("/data/ipconfig.json","r")
        if f ~= nil then
            local content = f:read("*all")
            if content ~= nil and string.len(content) > 0 then
                ip_address_table = json.decode(content)
                isJson=true
            end
        else 
            f = io.open("/data/ipconfig.lua","r")
            if f ~= nil then
                dofile("/data/ipconfig.lua")
            end
        end
    end

    if options.off~=nil and p_address_table ~= nil then
       ip_address_table.disablefirewall=true
    end

    if f then
        io.close(f)

        if ip_address_table ~= nil then
            my_ip_address_table = ip_address_table["V4"]
            my_ip_address6_table = ip_address_table["V6"]
        end

        atLeastOneManagementInterfaceFound=false
        nonMatchingIpFound=false
        nonMatchingIpList=""

        ipAddressList=omg.cmd2TreeTable('let l=1; for i in $(omgsysteminfo --filter="ip.eth.*address" --val);do echo "$l=\"$i\""; let l=$l+1;done',"\.","=")
        if ipAddressList~=nil and (ip_address_table == nil or ip_address_table.disablefirewall~=true) then
            --flush
            os.execute(ip .. "-F")
            os.execute(ip .. "-X")
            os.execute(ip .. "-Z")
            os.execute(ip .. "-t nat -F")
            os.execute(ip .. "-t nat -X")
            os.execute(ip .. "-t mangle -F")
            os.execute(ip .. "-t mangle -X")
            os.execute(ip .. "-P INPUT ACCEPT")
            os.execute(ip .. "-P OUTPUT ACCEPT")
            os.execute(ip .. "-P FORWARD ACCEPT")
            
            --check for at least one management interface available
            if my_ip_address_table~=nil then
                for k1,v1 in pairs(ipAddressList) do
                    for k2,v2 in pairs(my_ip_address_table) do
                        if v2.management==true and v2.ip==v1 then
                            atLeastOneManagementInterfaceFound=true
                        end
                    end
                end
            end

            --found configured firewall rule not useable in actual ipconfig
            if my_ip_address_table~=nil then
                for k1,v1 in pairs(my_ip_address_table) do
                    local ipFound=false
                    for k2,v2 in pairs(ipAddressList) do
                        if v1.ip==v2 then
                            ipFound=true
                        end
                    end
                    if ipFound==false then
                        if string.len(nonMatchingIpList) == 0 then
                            nonMatchingIpList=v1.ip
                        else
                            nonMatchingIpList=nonMatchingIpList.." "..v1.ip
                        end
                        nonMatchingIpFound=true
                    end
                end
            end
        end

        if isJson==true then
            if ip_address_table.disablefirewall~=true then
                ip_address_table.firewallState="critical"
                ip_address_table.statusText="no management interface available"

                if atLeastOneManagementInterfaceFound==true and nonMatchingIpFound==true then
                    ip_address_table.firewallState="warning"
                    ip_address_table.statusText="some rules doesn't match IP configuration (".. (nonMatchingIpList or "") ..")"
                elseif atLeastOneManagementInterfaceFound==true and nonMatchingIpFound==false then
                    ip_address_table.firewallState="ok"
                    ip_address_table.statusText="active"
                end
            else
                ip_address_table.firewallState="ok"
                ip_address_table.statusText="inactive"
            end

            --io.write(omg.tableToJson(ip_address_table) .. "\n")
            f = io.open("/data/ipconfig.json","w")
            if f ~= nil then
                f:write(omg.tableToJson(ip_address_table) .. "\n")
                io.close(f)
            end
        end

        if atLeastOneManagementInterfaceFound==true and (ip_address_table == nil or ip_address_table.disablefirewall~=true) then
            --flush
            os.execute(ip .. "-F")
            os.execute(ip .. "-X")
            os.execute(ip .. "-Z")
            os.execute(ip .. "-t nat -F")
            os.execute(ip .. "-t nat -X")
            os.execute(ip .. "-t mangle -F")
            os.execute(ip .. "-t mangle -X")
            os.execute(ip .. "-P INPUT ACCEPT")
            os.execute(ip .. "-P OUTPUT ACCEPT")
            os.execute(ip .. "-P FORWARD ACCEPT")

            if my_ip_address_table~=nil then
                --set default policies
                os.execute(ip .. "-P INPUT DROP")
                os.execute(ip .. "-P OUTPUT DROP")
                os.execute(ip .. "-P FORWARD DROP")

                --keep established connections
                os.execute(ip .. "-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT")
                --allow loopback
                os.execute(ip .. "-A INPUT -i lo -j ACCEPT")
                --allow outbound traffic
                os.execute(ip .. "-A OUTPUT -j ACCEPT")

                --allow certain inbound connections
                for k,v in pairs(my_ip_address_table) do
                    local src
                    local additional

                    src=nil
                    additional=nil

                    if v.src and v.src~="" then
                        src=" -s " .. v.src
                    end

                    if v.additional and v.additional~="" then
                        additional=" " .. v.additional
                    end

                    if v.tlsSip then
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. config.struct_Box.string_SipTlsBindPort .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.tcpSip then
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. config.struct_Box.string_SipBindPort .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.udpSip then
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p udp --dport " .. config.struct_Box.string_SipBindPort .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.tlsSip or v.tcpSip or v.udpSip then 
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p udp --dport " .. "7004:7124" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.website then
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "80" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "8080" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.messagingServer then
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "3217:3233" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.snfs or v.management or v.messagingServer then
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "3215" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.license or v.management or v.messagingServer then
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "3214" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.management then
                        --Allows SSH connections (only 16 attempts by an IP every 1 minute, drop the rest)
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name DEFAULT --rsource" .. (src or "") .. (additional or ""))
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 16 --name DEFAULT --rsource -j DROP" .. (src or "") .. (additional or ""))
                        os.execute(ip .. "-A INPUT -d " .. v.ip .. " -p tcp -m state --state NEW --dport 22 -j ACCEPT" .. (src or "") .. (additional or ""))
                    end
                end
                --Allow ping
                os.execute(ip .. "-A INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT")
                -- Reject all other inbound - default deny unless explicitly allowed policy
                os.execute(ip .. "-A INPUT -j DROP")
                os.execute(ip .. "-A FORWARD -j DROP")
            end

            --flush
            os.execute(ip6 .. "-F")
            os.execute(ip6 .. "-X")
            os.execute(ip6 .. "-Z")
            os.execute(ip6 .. "-P INPUT ACCEPT")
            os.execute(ip6 .. "-P OUTPUT ACCEPT")
            os.execute(ip6 .. "-P FORWARD ACCEPT")

            if my_ip_address_table6~=nil then
                --set default policies
                os.execute(ip6 .. "-P INPUT DROP")
                os.execute(ip6 .. "-P OUTPUT DROP")
                os.execute(ip6 .. "-P FORWARD DROP")

                --keep established connections
                os.execute(ip6 .. "-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT")
                --allow loopback
                os.execute(ip6 .. "-A INPUT -i lo -j ACCEPT")
                --allow outbound traffic
                os.execute(ip6 .. "-A OUTPUT -j ACCEPT")

                for k,v in pairs(my_ip_address6_table) do
                    local src
                    local additional

                    src=nil
                    additional=nil

                    if v.src and v.src~="" then
                        src=" -s " .. v.src
                    end

                    if v.additional and v.additional~="" then
                        additional=" " .. v.additional
                    end

                    if v.tlsSip then
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. config.struct_Box.string_SipTlsBindPort .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.tcpSip then
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. config.struct_Box.string_SipBindPort .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.udpSip then
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p udp --dport " .. config.struct_Box.string_SipBindPort .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.tlsSip or v.tcpSip or v.udpSip then 
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p udp --dport " .. "7004:7124" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.website then
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "80" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "8080" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.messagingServer then
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "3217:3233" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.snfs or v.management or v.messagingServer then
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "3215" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.license or v.management or v.messagingServer then
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp --dport " .. "3214" .. " -j ACCEPT" .. (src or "") .. (additional or ""))
                    end

                    if v.management then
                        --Allows SSH connections (only 16 attempts by an IP every 1 minute, drop the rest)
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name DEFAULT --rsource" .. (src or "") .. (additional or ""))
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 16 --name DEFAULT --rsource -j DROP" .. (src or "") .. (additional or ""))
                        os.execute(ip6 .. "-A INPUT -d " .. v.ip .. " -p tcp -m state --state NEW --dport 22 -j ACCEPT" .. (src or "") .. (additional or ""))
                    end
                end

                --Allow ping
                os.execute(ip6 .. "-A INPUT -p icmpv6 -m ipv6-icmp --icmpv6-type echo-request -j ACCEPT")
                -- Reject all other inbound - default deny unless explicitly allowed policy
                os.execute(ip6 .. "-A INPUT -j DROP")
                os.execute(ip6 .. "-A FORWARD -j DROP")
            end
        else
            os.execute(ip .. "-F")
            os.execute(ip .. "-X")
            os.execute(ip .. "-Z")
            os.execute(ip .. "-t nat -F")
            os.execute(ip .. "-t nat -X")
            os.execute(ip .. "-t mangle -F")
            os.execute(ip .. "-t mangle -X")
            os.execute(ip .. "-P INPUT ACCEPT")
            os.execute(ip .. "-P OUTPUT ACCEPT")
            os.execute(ip .. "-P FORWARD ACCEPT")

            os.execute(ip6 .. "-F")
            os.execute(ip6 .. "-X")
            os.execute(ip6 .. "-Z")
            os.execute(ip6 .. "-P INPUT ACCEPT")
            os.execute(ip6 .. "-P OUTPUT ACCEPT")
            os.execute(ip6 .. "-P FORWARD ACCEPT")
        end

        if ip_address_table == nil or ip_address_table.disablerouting~=true then
            if my_ip_address_table~=nil then
                for k,v in pairs(my_ip_address_table) do
                    if my_ip_address_table[k].route ~= nil then
                        for k2,v2 in pairs(my_ip_address_table[k].route) do
                            local cmd,cmd2
                            if v2.net then
                                cmd="route del -net " ..  (v2.ip or "NIL") .. " netmask " .. (v2.mask or "NIL") .. " gw " .. (v2.gw or "NIL")
                                cmd2="route add -net " ..  (v2.ip or "NIL") .. " netmask " .. (v2.mask or "NIL") .. " gw " .. (v2.gw or "NIL")
                            else
                                cmd="route del " ..  (v2.ip or "NIL") .. " gw " .. (v2.gw or "NIL")
                                cmd2="route add " ..  (v2.ip or "NIL") .. " gw " .. (v2.gw or "NIL")
                            end
                            print(cmd)
                            os.execute(cmd)
                            print(cmd2)
                            os.execute(cmd2)
                        end
                    end
                end
            end
        else
            if my_ip_address_table~=nil then
                for k,v in pairs(my_ip_address_table) do
                    if my_ip_address_table[k].route ~= nil then
                        for k2,v2 in pairs(my_ip_address_table[k].route) do
                            local cmd,cmd2
                            if v2.net then
                                cmd="route del -net " ..  (v2.ip or "NIL") .. " netmask " .. (v2.mask or "NIL") .. " gw " .. (v2.gw or "NIL") .. " 2>/dev/null"
                            else
                                cmd="route del " ..  (v2.ip or "NIL") .. " gw " .. (v2.gw or "NIL") .. " 2>/dev/null"
                            end
                            print(cmd)
                            os.execute(cmd)
                        end
                    end
                end
            end
        end
    end
end
os.execute("/usr/bin/omgiptablesinfo --lua | sed -e 's/_m/ip_address_table/' > /data/ipconfig.lua")

