mir3c/squashfs-root/usr/sbin/vpntool

537 lines
17 KiB
Lua
Executable File

#!/usr/bin/env lua
local posix = require "Posix"
local json = require "json"
local net_tools = require "net_tools"
local ubus = require "ubus"
local iproute = require "iproute"
local conn
local cursor
local cfg = {
['stat_file'] = "/tmp/vpn.stat.msg",
['stat_file_last'] = "/tmp/vpn.stat.msg.last",
['time_step'] = 1,
['debug'] = 0,
['daemon'] = 1,
['max_redail'] = 2,
['page_limit'] = 1000 - 1,
}
local g = {}
function exit(ret)
os.exit(ret > 255 and 255 or ret)
end
function print_json(out)
print(json.encode(out))
end
function dlog(fmt, ...)
if (cfg.debug == 1) then
posix.syslog(posix.LOG_DEBUG, string.format(fmt, unpack(arg)))
elseif (cfg.debug == 2) then
print(string.format(fmt, unpack(arg)))
end
end
function ilog(fmt, ...)
if (cfg.debug == 2) then
print(string.format(fmt, unpack(arg)))
else
posix.syslog(posix.LOG_INFO, string.format(fmt, unpack(arg)))
end
end
function elog(fmt, ...)
if (cfg.debug == 2) then
print(string.format(fmt, unpack(arg)))
else
posix.syslog(posix.LOG_ERR, string.format(fmt, unpack(arg)))
end
end
function check_ppp(interface)
g.status = conn:call("network.interface", "status", {['interface']=interface})
if not g.status.autostart then
ilog("autostart=false exit")
exit(1)
end
if g.action == "up" and g.status.up then
ilog("action=up up=true exit")
exit(1)
end
end
function get_last_msg()
local code = 0
local msg = ''
local f = io.open(cfg.stat_file_last)
if f == nil then
return nil
end
local line = f:read("*line")
while line do
_, _, code, msg = string.find(line, "^(%d+) (.*)$")
line = f:read("*line")
end
f:close()
if code then
dlog("get_last_msg code[%d] msg[%s]", tonumber(code), msg)
return {code = tonumber(code) or nil, msg = msg}
else
return nil
end
end
function init(interface)
if (g.action == "up" or g.action == "down") and cfg.daemon == 1 then
posix.daemonize()
end
posix.openlog(g.proc, "cp", posix.LOG_LOCAL7)
conn = ubus.connect()
cursor = require("luci.model.uci").cursor()
g.status = conn:call("network.interface", "status", {['interface'] = interface})
if g.status == nil then
conn:call("network", "reload", {})
dlog("ubus call network reload")
posix.sleep(1)
g.status = conn:call("network.interface", "status", {['interface'] = interface})
end
if g.status == nil then
elog("network.interface.%s does not exist", interface)
exit(1)
end
g.status.proto = cursor:get("network", interface ,"proto")
if g.status.proto ~= "l2tp" then
elog(string.format("error %s proto [%s], l2tp", interface, g.status.proto))
exit(1)
end
g.status.auth = cursor:get("network",interface,"auth")
g.status.auto = cursor:get("network",interface,"auto")
g.status.server = cursor:get("network",interface,"server")
g.l2tp_redail = 0
g.max_redail = cfg.max_redail
end
function check_redial(interface)
while posix.stat(cfg.stat_file) == nil do
check_ppp(interface)
dlog("wait %s", cfg.stat_file)
posix.sleep(cfg.time_step)
end
dlog("rename %s -> %s", cfg.stat_file, cfg.stat_file_last)
os.rename(cfg.stat_file, cfg.stat_file_last)
local m = get_last_msg()
if m ~= nil and m.code == 0 then
ilog("succeeded")
return false
end
check_ppp(interface)
if g.status.proto == "l2tp" then
g.l2tp_redail = g.l2tp_redail + 1
if g.l2tp_redail <= g.max_redail then
dlog("%s l2tp redial[%d]", interface, g.l2tp_redail)
return true
else
os.execute("ifdown " .. interface)
elog("%s l2tp max redial[%d] ifdown %s and exit", interface, g.l2tp_redail, interface)
return false
end
else
elog("error " .. interface .. " proto")
os.execute("ifdown " .. interface)
return false
end
end
function check_hostname()
if posix.gethostbyname(g.status.server) == nil then
local file,err = io.open( cfg.stat_file_last, "wb" )
if err then
elog(string.format("open %s error"), cfg.stat_file_last)
return -1
end
elog(string.format("701 Host %s not found\n", g.status.server))
file:write(string.format("701 Host %s not found\n", g.status.server))
file:close()
return -1
end
return 0
end
function pexec(cmd)
local pp = io.popen(cmd)
local data = pp:read("*all")
pp:close()
return data
end
function isStrNil(str)
return (str == nil or str == "")
end
function get_rt_tables()
local rt_tables = {}
for line in io.lines("/etc/iproute2/rt_tables") do
_, _, index, rt_table_name = string.find(line, '%s*(%S+)%s+(%S+)%s*')
index = tonumber(index)
if (index ~= nil) then
rt_tables[index] = rt_table_name
end
end
return rt_tables
end
function add_rt_tables(index, rt_table_name)
os.execute(string.format("echo '%s %s' >> /etc/iproute2/rt_tables", index, rt_table_name))
end
---------------------------------------------------------------------
local status, err = pcall(
function ()
g.proc = arg[0]
g.action = arg[1]
if g.action == "up" then
interface = arg[2]
if isStrNil(interface) then
elog("interface is nil")
exit(1)
end
init(interface)
if g.status.autostart then
elog("already start, %s down first", g.proc)
exit(1)
end
if check_hostname() ~= 0 then
exit(1)
end
dlog("rm %s", cfg.stat_file)
os.remove(cfg.stat_file)
dlog("ifup " .. interface)
os.execute("ifup " .. interface)
while check_redial(interface) do
end
exit(0)
elseif g.action == "down" then
interface = arg[2]
if isStrNil(interface) then
elog("interface is nil")
exit(1)
end
init(interface)
os.execute("ifdown " .. interface)
exit(0)
elseif g.action == "status" then
local interface = arg[2]
if isStrNil(interface) then
elog("interface is nil")
exit(1)
end
init(interface)
local s = conn:call("network.interface", "status", {['interface'] = interface})
s.stat = get_last_msg()
s.auto = cursor:get("network", interface, "auto")
print_json(s)
exit(0)
elseif g.action == 'info' then
local interface = arg[2]
if isStrNil(interface) then
elog("interface is nil")
exit(1)
end
local XQVPNUtil = require("xiaoqiang.util.XQVPNUtil")
local result = XQVPNUtil.getVPNInfo(interface)
print_json(result)
exit(0)
elseif g.action == 'set' then
local interface = arg[2]
if (interface == 'vpn') then
elog("interface vpn can't be set")
exit(1)
end
local XQVPNUtil = require("xiaoqiang.util.XQVPNUtil")
local set = XQVPNUtil.setVpn(interface, arg[3], arg[4], arg[5], arg[6], "", 0)
if set then
local fs = require "nixio.fs"
if(not fs.access(string.format("/etc/ppp/ppp.d/%s-up", interface))) then
os.execute(string.format("ln -s /etc/ppp/ppp.d/none /etc/ppp/ppp.d/%s-up", interface))
end
exit(0)
else
exit(1)
end
elseif g.action == 'flushdst' then
rt_table_name = arg[2]
if isStrNil(rt_table_name) then
elog("rt_table_name is nil")
exit(1)
end
local ret = os.execute("ip route flush table " .. rt_table_name )
exit(ret)
elseif g.action == 'listsrc' then
--ip rule list
rt_table_name = arg[2]
if isStrNil(rt_table_name) then
elog("rt_table_name is nil")
exit(1)
end
local pp = io.popen("ip rule list")
local line = pp:read("*line")
while line do
_, _, scope = string.find(line,'%S+:%s+from%s+(%S+)%s+lookup '.. rt_table_name ..'%s*')
if (scope ~= nil) then
print(scope)
end
line = pp:read("*line")
end
pp:close()
exit(0)
elseif g.action == 'listdst' then
--ip rule list
local rt_table_name = arg[2]
local page_begin = tonumber(arg[3])
local page_end = tonumber(arg[4])
local page_begin = page_begin and page_begin or 0
local page_end = page_end and page_end or page_begin + cfg.page_limit
dlog("begin %f end %f", page_begin, page_end)
if page_end >= page_begin then
page_end = (page_end - page_begin > cfg.page_limit) and (page_begin + cfg.page_limit) or page_end
else
elog("end < begin")
exit(1)
end
if page_begin < 0 then
elog("begin < 0")
exit(1)
end
if isStrNil(rt_table_name) then
elog("rt_table_name is nil")
exit(1)
end
local i = 0
local pp = io.popen("ip route list table " .. rt_table_name)
local line = pp:read("*line")
while line do
if i >= page_begin then
print(line)
end
if i >= page_end then
pp:close()
exit(0)
end
i = i + 1
line = pp:read("*line")
end
pp:close()
exit(0)
elseif g.action == 'addsrc' then
--ip rule add from 192.168.31.228 table xlacc
local ret = {['success'] = 0, ['fail'] = 0}
local n = 0
local rt_table_name = arg[2]
if isStrNil(rt_table_name) then
elog("rt_table_name is nil")
exit(1)
end
for i, v in ipairs(arg) do
if i > 2 then
if os.execute(string.format("ip rule add from %s pref 1000 table " .. rt_table_name, v)) == 0 then
ret.success = ret.success + 1
else
ret.fail = ret.fail + 1
end
end
end
print_json(ret)
exit(ret.fail)
elseif g.action == 'delsrc' then
--ip rule del from 192.168.31.228 table xlacc
local ret = {['success'] = 0, ['fail'] = 0}
local n = 0
local rt_table_name = arg[2]
if isStrNil(rt_table_name) then
elog("rt_table_name is nil")
exit(1)
end
for i, v in ipairs(arg) do
if i > 2 then
if os.execute(string.format("ip rule del from %s pref 1000 table " .. rt_table_name, v)) == 0 then
ret.success = ret.success + 1
else
ret.fail = ret.fail + 1
end
end
end
print_json(ret)
exit(ret.fail)
elseif g.action == 'change_src' then
local rt_table_name = arg[2]
if isStrNil(rt_table_name) then
elog("rt_table_name is nil")
exit(1)
end
if arg[3] and arg[4] then
os.execute(string.format("ip rule del from %s pref 1000 table " .. rt_table_name, arg[3]))
local ret = os.execute(string.format("ip rule add from %s pref 1000 table " .. rt_table_name, arg[4]))
exit(ret)
end
exit(1)
elseif g.action == 'adddst' then
local n = 0
--ip route add to 220.181.111.0/25 dev l2tp-xlacc table xlacc
local ret = {['success'] = 0, ['fail'] = 0}
local rt_table_name = arg[2]
local dev_name = arg[3]
if isStrNil(rt_table_name) or isStrNil(dev_name) then
elog("rt_table_name or dev_name is nil")
exit(1)
end
local s, err = pcall( function () iproute.init(rt_table_name, dev_name) end )
if not s then
elog(err)
exit(1)
end
for i, subnet in ipairs(arg) do
if i > 3 then
if iproute.add(subnet) == 0 then
ret.success = ret.success + 1
else
ret.fail = ret.fail + 1
end
end
end
iproute.exit()
print_json(ret)
exit(ret.fail)
elseif g.action == 'deldst' then
--ip route del to 220.181.111.0/25 dev l2tp-xlacc table xlacc
local ret = {['success'] = 0, ['fail'] = 0}
local rt_table_name = arg[2]
local dev_name = arg[3]
if isStrNil(rt_table_name) or isStrNil(dev_name) then
elog("rt_table_name or dev_name is nil")
exit(1)
end
for i, v in ipairs(arg) do
if i > 3 then
if os.execute(string.format("ip route del to %s dev %s table %s", v, dev_name, rt_table_name)) == 0 then
ret.success = ret.success + 1
else
ret.fail = ret.fail + 1
end
end
end
print_json(ret)
exit(ret.fail)
elseif g.action == 'rt_table_check' then
local rt_table_name = arg[2]
if isStrNil(rt_table_name) then
elog("rt_table_name is nil")
print(-1)
exit(1)
end
local rt_tables = get_rt_tables()
for i , v in ipairs(rt_tables) do
if rt_table_name == v then
print(i)
exit(0)
end
end
elog("rt_table_check: %s: No such rt_table_name", rt_table_name)
print(-1)
exit(1)
elseif g.action == 'rt_table_register' then
local rt_table_name = arg[2]
local i
if isStrNil(rt_table_name) then
elog("rt_table_name is nil")
print(-1)
exit(1)
end
local rt_tables = get_rt_tables()
for i , v in ipairs(rt_tables) do
if rt_table_name == v then
elog("can't register %s: item exists", rt_table_name)
print(-2)
exit(1)
end
end
i = 1
while i < 253 do
dlog("%d, %s", i, rt_tables[i] and rt_tables[i] or 'nil')
if isStrNil(rt_tables[i]) then
add_rt_tables(i, rt_table_name)
print(i)
exit(0)
end
i = i + 1
end
elog("rt_table_register: %s: No enough item on rt_tables", rt_table_name)
print(-1)
exit(1)
else
--[[
usage: vpntool {up | down | status | info} interface
vpntool {flushdst | listsrc} rt_table_name
vpntool listdst rt_table_name [begin] [end]
vpntool set 'interface' 'server' 'username' 'password' 'proto'
vpntool {adddst | deldst} rt_table_name dev_name SCOPE
vpntool {addsrc | delsrc} rt_table_name SCOPE
vpntool change_src rt_table_name { ip | network/netmask } { ip | network/netmask }
vpntool {rt_table_check | rt_table_register} rt_table_name
SCOPE := { ip | network/netmask } SCOPE
]]
print(string.format("usage: %s {up | down | status | flushdst | listsrc | info} ", arg[0]))
print(string.format(" %s {flushdst | listsrc} rt_table_name ", arg[0]))
print(string.format(" %s vpntool listdst rt_table_name [begin] [end]", arg[0]))
print(string.format(" %s set 'interface' 'server' 'username' 'password' 'proto'", arg[0]))
print(string.format(" %s {adddst | deldst} rt_table_name dev_name SCOPE", arg[0]))
print(string.format(" %s {addsrc | delsrc} rt_table_name SCOPE", arg[0]))
print(string.format(" %s change_src rt_table_name {ip | network/netmask} {ip | network/netmask}", arg[0]))
print(string.format(" %s {rt_table_check | rt_table_register} rt_table_name", arg[0]))
print("SCOPE := { ip | network/netmask } SCOPE")
exit(1)
end
end
)
if not status then
elog(err)
end