local l,n=ngx,require
local v=n("datamodel")local e=n("io")local m=n("bit")local h=n("tch.inet")local i=n("web.content_helper")local o=n("web.uimessage_helper")local c,r,a,u,b,x=pairs,ipairs,tonumber,type,setmetatable,next
local s=math.floor
local Q=e.open
local w,S=math.random,math.huge
local y,d,f,O,F,I,g=string.istainted,string.format,string.match,string.find,string.sub,string.untaint,string.lower
local W,H=string.gsub,string.upper
local A,D=table.concat,table.remove
local P=n("web.taint").untaint_mt
local K=math.min
local X=math.max
local U=n'tch.posix'local j=U.inet_pton
local e=n("web.intl")local function t(n)l.log(l.NOTICE,n)end
local e=e.load_gettext(t)local n=e.gettext
local t=e.ngettext
local function p()e.language(l.header['Content-Language'])end
local function C()checkUiMessages=false
local n=l.ctx.session
local n=n:retrieve("uimessages")for e,n in r(n or{})do
if n.level=="error"then
checkUiMessages=true
end
end
return checkUiMessages
end
e.textdomain('web-framework-tch')local e={}function e.getAllNonWirelessInterfaces(n)local t={}for e,n in r(n)do
if n.type=="lan"then
local e
if n.name and n.name~=""then
e=n.name
else
e=n.paramindex
end
t[#t+1]={name=e,index=n.paramindex}end
end
return t
end
function e.handleQuery(t,s)p()local e={}local a={}for t,n in c(t)do
e[t]=n
end
local u,d=i.getExactContent(e)if not u then
o.pushMessage(d,"error")return e,a
end
if l.var.request_method=="POST"and l.var.content_type and f(l.var.content_type,"application/x%-www%-form%-urlencoded")then
local d=l.req.get_post_args()if(d["action"]=="SAVE")then
local u={}for n,e in c(e)do
u[n]=e
end
for n,r in c(d)do
if t[n]and not s[n]then
o.pushMessage("Validation missing for "..n,"error")l.log(l.ERR,"Validation missing for "..n)return e,a
end
e[n]=r
end
local d
d,a=i.validateObject(e,s)if d and not C()then
for n,t in c(e)do
if t==u[n]then
e[n]=nil
end
end
local a,d=i.setObject(e,t)if a then
if x(e)then
a,d=v.apply()end
for n in c(t)do
if not e[n]then
e[n]=u[n]end
end
if not a then
l.log(l.ERR,"apply failed: "..d)o.pushMessage(n"Error while applying changes","error")else
o.pushMessage(n"Changes saved successfully","success")end
else
for e,n in r(d)do
l.log(l.ERR,"setObject failed on "..n.path..": "..n.errcode.." "..n.errmsg)end
o.pushMessage(n"Error while saving changes","error")for n,t in c(t)do
e[n]=t
end
i.getExactContent(e)end
else
local e={}e[#e+1]=n"Some parameters failed validation"e[#e+1]="<br/>"for n,t in c(a)do
e[#e+1]="<strong>"..n.."</strong>"..": "..t.."<br/>"end
o.pushMessage(table.concat(e),"error")end
end
end
return e,a
end
function e.mergeTables(n,e)if n==nil then
n={}end
if e==nil then
return
end
for t,e in r(e)do
n[e.param]=e.value
end
end
local function x(n,t)local e={}for i,n in r(n)do
if n.type=="aggregate"then
for r,n in r(n.subcolumns)do
if t or not n.readonly then
e[n.name]=n.param
end
end
else
if t or not n.readonly then
e[n.name]=n.param
end
end
end
return e
end
function e.secondsToTime(e)p()local e=a(e)if(e and e>=0)then
local e={s(e/86400),s(e/3600)%24,s(e/60)%60,s(e)%60}local r=4
local n=e[4]e[4]=d(t("%d second","%d seconds",n),n)n=e[3]if n>0 then
r=3
end
e[3]=d(t("%d minute","%d minutes",n),n)n=e[2]if n>0 then
r=2
end
e[2]=d(t("%d hour","%d hours",n),n)n=e[1]if n>0 then
r=1
end
e[1]=d(t("%d day","%d days",n),n)return A(e," ",r)end
return nil,n"Positive number expected."end
function e.secondsToTimeShort(e)p()local e=a(e)if(e and e>=0)then
local e={s(e/86400),s(e/3600)%24,s(e/60)%60,s(e)%60}local r=4
local n=e[4]e[4]=d(t("%ds","%ds",n),n)n=e[3]if n>0 then
r=3
end
e[3]=d(t("%dm","%dm",n),n)n=e[2]if n>0 then
r=2
end
e[2]=d(t("%dh","%dh",n),n)n=e[1]if n>0 then
r=1
end
e[1]=d(t("%dd","%dd",n),n)return A(e," ",r)end
return nil,n"Positive number expected."end
local function B()return"stateid."..w()end
local function T(e,n)if e==nil and n==""then
return true
end
if e==n then
return true
end
return false
end
local E="Changes not allowed."local M="Changes were made to this table which require you to start again."local V="You tried to access an invalid line."local t="An error occured while saving your changes."local o="An error occured while applying your changes."local function _(i,r,e)if i then
if r==true then
v.apply()end
else
e.errmsg=n(t)end
end
local function G(d,a,n,t,r)local e={}for t,r in c(t)do
if not n[t]then
e[t]=d..a.."."..r
end
end
local t=i.getExactContent(e)if t then
for e,t in c(e)do
n[e]=t
end
end
return i.validateObject(n,r)end
local function Z(n,e,t)for e,t in c(e)do
if not n[e]then
n[e]=""end
end
return i.validateObject(n,t)end
local function z(t,a,e,o)local d=true
local l={}for u,e in r(e)do
if e.unique then
local o=string.untaint(o[e.name])local t=i.getMatchedContent(t,{[e.param]=o})if a then
for n,e in r(t)do
if e.path==a then
D(t,n)break
end
end
end
if#t>0 then
d=nil
l[e.name]=n"duplicate value"end
end
end
return d,l
end
local function o(e,t)local n={}for r,e in r(e)do
if e.type=="aggregate"then
n[#n+1]=o(e.subcolumns,t)else
n[#n+1]=t[e.name]end
end
return n
end
local function N(n,a,e,t,d,l,u)if l then
local e,i=i.loadTableData(n,a,e,u)local n
if t then
for e,r in r(i)do
if t==r.paramindex then
n=e
end
end
if not n then
return nil
end
else
n=#e+1
end
if d==nil then
D(e,n)else
e[n]=o(a,d)end
return l(e)else
return true
end
end
function e.handleTableQuery(h,e,w,R,j)p()local p,o
local g={}local t={}local b=x(h)local m=e.basepath or""local s,P,s=i.getPaths(m)local I=l.ctx.session
if e==nil then
e={}end
local O=e and not(e.canEdit==false)or true
local D=e and not(e.canAdd==false)or true
local Y=e and not(e.canDelete==false)or true
local W=e and(e.addNamedObject==true)local L=e and not(e.canApply==false)local s=e and a(e.editing)or 0
local s=e and a(e.minEntries)or 0
local s=e and e.maxEntries or S
local k=e and e.newList
local S=e and e.sorted
local x=e.tableid..".stateid"local F=e.tableid..".allowedindexes"local y=e.valid
local A=false
local c
local s
if l.var.request_method=="POST"and l.var.content_type and f(l.var.content_type,"application/x%-www%-form%-urlencoded")then
t=l.req.get_post_args()local f=t.action
local l=a(t.index)or-1
local U=e.tableid
local q=t.tableid
local p=I:retrieve(x)local C=t.stateid
o=I:retrieve(F)or{}if o[l]then
e.changesessionindex=o[l].paramindex
end
if(U~=nil and U==q)then
if f=="TABLE-DELETE"and Y then
if T(p,C)==true then
if l and o[l]then
if o[l].canDelete then
s,g=N(m,h,w,o[l].paramindex,nil,y,S)if s==true then
c=v.del(P..o[l].paramindex..".")if u(e.onDelete)=="function"and c then
e.onDelete(o[l].paramindex)end
_(c,L,e)I:store(x,B())end
else
e.errmsg=n(E)end
else
e.errmsg=n(V);end
else
e.errmsg=n(M)end
elseif f=="TABLE-EDIT"and O then
if T(p,C)==true then
if l and o[l]then
if o[l].canEdit then
e.editing=l
else
e.errmsg=n(E)end
else
e.errmsg=n(V);end
else
e.errmsg=n(M)end
elseif f=="TABLE-MODIFY"and O then
if T(p,C)==true then
if l and o[l]then
if o[l].canEdit then
s,g=G(P,o[l].paramindex,t,b,j)if s==true then
s,g=z(m,P..o[l].paramindex..".",h,t)end
if s==true then
s,g=N(m,h,w,o[l].paramindex,t,y,S)end
if s==true then
c=i.setObject(t,b,P..o[l].paramindex..".",R)if u(e.onModify)=="function"and c then
e.onModify(o[l].paramindex,t)end
_(c,L,e)I:store(x,B())else
e.editing=l
A=true
end
else
e.errmsg=n(E)end
else
e.errmsg=n(V);end
else
e.errmsg=n(M)end
elseif f=="TABLE-CANCEL"then
e.editing=0
elseif f=="TABLE-ADD"and D then
s,g=Z(t,b,j)if s==true then
s,g=z(m,nil,h,t)end
if s==true then
s,g=N(m,h,w,nil,t,y,S)end
if s==true then
if W==true then
local n=d("%s",t[h[1].name])local n=e.objectName or n
c=i.addNewObject(m,t,b,R,n)else
c=i.addNewObject(m,t,b,R)end
if u(e.onAdd)=="function"and c then
e.onAdd(c,t)end
_(c,L,e)e.editing=0
else
A=true
e.editing=-1
end
elseif f=="TABLE-NEW"and D then
e.editing=-1
elseif f=="TABLE-NEW-LIST"and D then
local n=a(t.listid)e.editing=-1
if k~=nil and n~=nil and n then
if k[n]~=nil then
local e=k[n].values
for t,n in r(h)do
n.default=e[n.name]or n.default or""end
end
end
end
end
end
e.stateid=I:retrieve(x)or""p,o=i.loadTableData(m,h,w,S)I:store(F,o)if A==true then
if e.editing==-1 then
for e,n in r(h)do
if n.type=="aggregate"then
for e,n in r(n.subcolumns)do
n.default=t[n.name]or n.default or""end
else
n.default=t[n.name]or n.default or""end
end
else
local n={}for i,a in r(h)do
if a.type=="aggregate"then
local i={}for a,r in r(a.subcolumns)do
i[#i+1]=t[r.name]or p[e.editing][#i+1]or""end
n[#n+1]=i
else
n[#n+1]=t[a.name]or p[e.editing][#n+1]or""end
end
p[e.editing]=n
end
end
return p,g
end
local function l()return true
end
local function t()return false,""end
function e.validateNonEmptyString(e)if u(e)~="string"and not y(e)then
return nil,n"Received a non string value."end
if#e==0 then
return nil,n"String cannot be empty."end
return true
end
function e.GetIPType(n)n=string.untaint(n)if n and h.isValidIPv4(n)then
return 4
elseif n and h.isValidIPv6(n)then
return 6
end
return 0
end
local x=e.GetIPType
function e.validateStringIsIP(e)local e=x(e)if e==4 or e==6 then
return true
end
return nil,n"Invalid IP address."end
local o="^%x%x:%x%x:%x%x:%x%x:%x%x:%x%x$"local w="^%x%x%-%x%x%-%x%x%-%x%x%-%x%x%-%x%x$"function e.validateStringIsMAC(t)local e
if not t then
return nil,n"Invalid input"end
if t:match(o)then
e=W(t,":","")elseif t:match(w)then
e=W(t,"-","")else
return nil,n"Invalid MAC address, it must be of the form 00:11:22:33:44:55 or 00-11-22-33-44-55"end
e=H(e)if e=="000000000000"or e=="FFFFFFFFFFFF"then
return nil,n"Invalid MAC address"end
if(f(e,"^0[01]005E"))or(F(e,1,4)=="3333")or(F(e,1,2)=="CF")then
return nil,n"Reserved MAC address"end
return true
end
function e.validateStringIsDomainName(e)if u(e)~="string"and not y(e)then
return nil,n"Received a non string value."end
if#e==0 then
return nil,n"Domain name cannot be empty."end
if#e>255 then
return nil,n"Received domain name is too long."end
local t=0
local r=0
repeat
t=t+1
r=O(e,".",t,true)local e=F(e,t,r)local e=f(e,"[^%.]*")if e~=nil then
if#e==0 then
return nil,n"Empty label not allowed."end
if#e>63 then
return nil,n"Domain name contains a label that is longer than 63 characters."end
local t=f(e,"^[a-zA-z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]")if#e==1 then
if not f(e,"[a-zA-Z0-9]")then
return nil,n"Label within domain name has invalid syntax."end
elseif e~=t then
return nil,n"Label within domain name has invalid syntax."end
end
t=r
until not r
return true
end
function e.validateBoolean(e)e=a(e)if e==1 or e==0 then
return true
end
return nil,n"0 or 1 expected."end
function e.validateStringIsPort(e,r,i)e=e and f(e,"^[%s0]*(%d+)%s*$")local t=e and a(e)if t and(s(t)==t)and t>=1 and t<65536 then
if r and i then
r[i]=e
end
return true
end
return nil,n"Port is invalid. It should be between 1 and 65535 or it must be of format port1:port2 with port1 <= port2."end
local t="^[%s0]*(%d+)%s*%:[%s0]*(%d+)%s*$"function e.validateStringIsPortRange(i,l,d)if not i then
return nil,n"Invalid port range."end
local t,r=f(i,t)if t then
local o,i=e.validateStringIsPort(t)local u,e=e.validateStringIsPort(r)if i then
return nil,i
elseif e then
return nil,e
end
if o and u and a(t)<=a(r)then
l[d]=t..":"..r
return true
else
return nil,n"Port range is invalid, it must be of format port1:port2 with port1 <= port2."end
else
return e.validateStringIsPort(i,l,d)end
end
function e.validatePositiveNum(e)local e=a(e)if(e and e>=0)then
return true
end
return nil,n"Positive number expected."end
function e.getValidateNumberInRange(e,t)local r=n"Input must be a number."if e and t then
r=d(n"Input must be a number between %d and %d included.",e,t)elseif not e and not t then
r=n"Input must be a number."elseif not e then
r=d(n"Input must be a number smaller than %d included.",t)elseif not t then
r=d(n"Input must be a number greater than %d included.",e)end
return function(n)local n=a(n)if not n then
return nil,r
end
if e and n<e then
return nil,r
end
if t and n>t then
return nil,r
end
return true
end
end
function e.getValidateWholeNumber(e)local n=n"Input must be a whole number."if not(e and e:match("^%d+$"))then
return nil,n
end
return true
end
function e.validateRegExpire(r)local t=a(r)if t and t>=60 and t<=600000 and e.getValidateWholeNumber(r)then
return true
end
return nil,n"Expire Time is invalid. It should be a whole number, between 60 and 600000."end
function e.getValidateInCheckboxgroup(e)local a=b({},P)for e,n in r(e)do
a[n[1]]=true
end
return function(t,d,l)local e
local i
local o=""if not t then
return nil,n"Invalid input."end
if u(t)=="table"then
e=t
else
e={t}end
d[l]=e
for t,e in r(e)do
if e==o then
i=t
elseif not a[e]then
return nil,n"Invalid value."end
end
if i then
D(e,i)end
return true
end
end
function e.getValidateCheckboxSwitch()return function(e,t,r)if not e then
return nil,n"Invalid input."end
if u(e)=="table"then
for r,e in c(e)do
if(e~="_DUMMY_"and e~="_TRUE_")then
return nil,n"Invalid value."end
end
t[r]="1"return true
else
if(e=="_DUMMY_")then
t[r]="0"return true
else
return nil,n"Invalid value."end
end
end
end
function e.getValidateInEnumSelect(t)local e=b({},P)for t,n in r(t)do
e[n[1]]=true
end
return function(t)return e[t],n"Invalid value."end
end
function e.getValidateStringLength(t)return function(e)if u(e)~="string"and not y(e)then
return nil,n"Received a non string value."end
if#e<t then
return nil,d(n"String must be at least %d characters long.",t)end
return true
end
end
function e.getValidateStringLengthInRange(t,r)return function(e)if u(e)~="string"and not y(e)then
return nil,n"Received a non string value."end
if#e<t or#e>r then
return nil,d(n"String must be between %1$d and %2$d characters long.",t,r)end
return true
end
end
function e.getValidationIfPropInList(a,i,n)local t=b({},P)for e,n in r(n)do
t[n]=true
end
return function(r,n,e)if not n then
return true
end
if n[i]and t[n[i]]then
return a(r,n,e)end
n[e]=nil
return true
end
end
function e.getValidationIfCheckboxSwitchPropInList(a,e,t)local i=b({},P)for e,n in r(t)do
i[n]=true
end
return function(d,t,r)if not t then
return true
end
if t[e]then
local e=t[e]if u(e)=="table"then
for r,t in c(e)do
if(t~="_DUMMY_"and t~="_TRUE_")then
return nil,n"Invalid value."end
end
e="1"elseif(e=="_DUMMY_")then
e="0"end
if i[e]then
return a(d,t,r)end
end
t[r]=nil
return true
end
end
function e.validateStringIsLeaseTime(e)if not e then
return nil,n"Invalid value."end
local t="^(%d+)([wdhms])$"local r=b({s=1814400,m=30240,h=504,d=21,w=3,},P)local e,t=e:match(t)e=e and a(e)if not e or e<1 then
return nil,n"Invalid value; enter 'infinite' for infinite time or a number greater than 0, followed by 's' for seconds or 'm' for minutes or 'h' for hours or 'd' for days or 'w' for weeks. No spaces."end
if(((t=="s")and(e<120))or((t=="m")and(e<2)))then
return nil,n"The minimum leasetime must be 120 seconds or 2 minutes."elseif r[t]and e>r[t]then
return nil,n"The Maximum leasetime must be 3 weeks or 21 days or 504 hours or 30240 minutes or 1814400 seconds."end
return true
end
function e.getValidationPassword(t)return function(e,n,r)if e=="********"then
n[r]=nil
return true
end
if u(t)=="function"then
return t(e,n,r)end
return true
end
end
function e.getOptionalValidation(n)local n=n
if u(n)~="function"then
n=l
end
return function(e,t,r)if not e or e==""then
return true
end
return n(e,t,r)end
end
function e.getConditionalValidation(a,e,n)local e,n=e,n
if u(e)~="function"then
e=l
end
if u(n)~="function"then
n=l
end
return function(t,r,i)if u(a)=="function"then
if a(t,r,i)then
return e(t,r,i)else
return n(t,r,i)end
end
return true
end
end
local function t(e)local n={}for t,e in c(e)do
if u(e)=="function"then
n[#n+1]=e
end
end
return n
end
function e.getAndValidation(...)local t=t{...}return function(i,a,d)local n={}local e=true
for r,t in r(t)do
local t,r=t(i,a,d)e=e and t
if not t then
n[#n+1]=r
end
end
return e,A(n," ")end
end
function e.getOrValidation(...)local t=t{...}return function(d,i,a)local e={}local n
for r,t in r(t)do
local t,r=t(d,i,a)n=n or t
if not t then
e[#e+1]=r
end
end
return n,A(e," ")end
end
local t=e.getValidateStringLengthInRange(8,63)local l="^[ -~]+$"function e.validatePSK(e)if e and#e==64 and e:match("^[%x]+$")then
return true
else
local n,e=t(e)if not n then
return n,e
end
end
if not f(e,l)then
return nil,n"The wireless key contains invalid characters, only space, letters, numbers and the following characters !\"'`#$%&()*+,-./:;<=>?@[\\]^_{|}~ are allowed."end
return true
end
local function t(e)if e then
local n=0
n=n+3*(s(e/10000000)%10)n=n+(s(e/1000000)%10)n=n+3*(s(e/100000)%10)n=n+(s(e/10000)%10)n=n+3*(s(e/1000)%10)n=n+(s(e/100)%10)n=n+3*(s(e/10)%10)n=n+(e%10)if 0==(n%10)then
return true
end
end
return nil,n"Invalid Pin."end
function e.validateWPSPIN(e)local r=n"PIN code must be 4 or 8 digits with potentially a dash or space in the middle."if e==nil or#e==0 then
return true
end
local i=e:match("^(%d%d%d%d)$")local n,e=e:match("^(%d%d%d%d)[%-%s]?(%d%d%d%d)$")if i then
return true
end
if n and e then
local n=a(n..e)return t(n)end
return nil,r
end
function e.validateWEP(e)if e==nil or(#e~=5 and#e~=10 and#e~=13 and#e~=26)then
return nil,n"Invalid length, a WEP key must be 5, 10, 13 or 26 characters long, length of 10 and 26 can only contain the letters A to F or digits"end
if(#e==10 or#e==26)and(not e:match("^[%x]+$"))then
return nil,n"A WEP key of length 10 or 26 can only contain the letters A to F or digits"end
return true
end
local function t(n)if n then
n=string.untaint(n)local n=j and j(U.AF_INET,n)or nil
if not n then
return nil
end
local r,t,e,n=n:byte(1,4)return m.tobit((r*16777216)+(t*65536)+(e*256)+n)end
end
local function o(e,n)local n=m.bor(e,m.bnot(n))return n
end
local function l(t,n)local n=m.band(t,n)return n
end
e.ipv42num=t
function e.validateIPv4Netmask(e)p()e=string.untaint(e)local e,t=h.validateIPv4Netmask(e)if not e then
return e,n"Invalid netmask."end
return e
end
function e.validateDestinationIP(i,a)local t,r=e.validateStringIsIP(i)if not t then
return nil,r
end
t,r=e.reservedIPValidation(i)if not t then
return nil,r
end
t,r=e.getValidateStringIsIPv4InNetwork(a.Gateway,a.Mask)if not t then
return nil,r
end
t,r=t(i)if not t then
return nil,n"Destination is not in the Gateway network"end
return t
end
function e.getValidateStringIsIPv4InNetwork(r,e)local i=t(r)local e=t(e)if i and e then
local a=l(i,e)return function(i)if(x(i)~=4)then
return nil,n"String is not an IPv4 address."end
local t=t(i)if a~=l(t,e)then
return nil,d(n"IP is not in the same network as the gateway %s.",r)end
return true
end
end
end
function e.getValidateStringIsDeviceIPv4(d,u)local r=t(d)local i=t(u)if r and i then
local a=l(r,i)local l=o(a,i)local i=e.getValidateStringIsIPv4InNetwork(d,u)return function(e)local i,d=i(e)if i==nil then
return i,d
end
local e=t(e)if r==e then
return nil,n"Cannot use the GW IP."end
if l==e then
return nil,n"Cannot use the broadcast address."end
if a==e then
return nil,n"Cannot use the network address."end
return true
end
end
return nil,n"Invalid IP address."end
local function s(n)local n=a(n,16)if n and n<=65535 then
return true
end
return false
end
function e.validateStringIsIPv6(e)e=string.untaint(e)if e and h.isValidIPv6(e)then
return true
else
return nil,n"Invalid IPv6 Address, address group is invalid."end
end
local b=t("127.0.0.0")local s=t("127.255.255.255")local P=t("224.0.0.0")local w=t("239.255.255.255")local S=t("255.255.255.255")local y=t("240.0.0.0")local k=t("255.255.255.254")local C=t("0.0.0.1")local A=t("0.255.255.255")function e.publicIPValidation(r,i,t)if r~=""then
if not e.isPublicIP(r)then
return nil,n"Not a Public address"end
local t=e.ipv42num(r)if y<=t and k>=t then
return nil,n"Cannot use a reserved IP address."end
if C<=t and A>=t then
return nil,n"Cannot use software address range."end
if b<=t and t<=s then
return nil,n"Cannot use IPv4 loopback address range."end
if P<=t and w>=t then
return nil,n"Cannot use a multicast address."end
if i.localpublicmask then
local r=e.isNetworkAddress(r,i.localpublicmask)if r then
return nil,n"Cannot use the network address"end
local e=e.isBroadcastAddress(t,i.localpublicmask)if e then
return nil,n"Cannot use the broadcast address"end
end
return true
end
end
function e.advancedIPValidation(a,i,r)if not a then
return nil,n"Invalid IP Address."end
local r=e.ipv42num(a)if not r then
return nil,n"Invalid IP Address."end
if b<=r and r<=s then
return nil,n"Cannot use IPv4 loopback address range."end
local d="127.255.255.255"local o="10.0.0.0"local l="10.255.255.255"if i.localdevmask then
if 0<r and e.ipv42num(d)>=r then
if t(o)>=r or t(l)<=r then
return nil,n"Cannot use an address in this address range."end
end
end
if r==0 then
return nil,n"Cannot use an address in this address range."end
if P<=r and w>=r then
return nil,n"Cannot use a multicast address."end
if S==r then
return nil,n"Cannot use the limited broadcast destination address."end
if i.localdevmask then
local t,a=e.isNetworkAddress(a,i.localdevmask)if t then
return nil,n"Cannot use the network address"end
local e,t=e.isBroadcastAddress(r,i.localdevmask)if e then
return nil,n"Cannot use the broadcast address"end
end
return true
end
local C=t("10.0.0.0")local E=t("10.255.255.255")local N=t("172.16.0.0")local k=t("172.31.255.255")local A=t("192.168.0.0")local y=t("192.168.255.255")function e.isPublicIP(e)if not e then
return nil,n"Invalid IP Address."end
local e=t(e)if not e then
return nil,n"Invalid IP Address"end
if(C<=e and e<=E)or(N<=e and e<=k)or(A<=e and e<=y)then
return nil,n"Not a Public Address"end
return true
end
function e.DNSIPValidation(i,r)local t=t(i)if not t then
return nil,n"Invalid IP Address."end
if b<=t and t<=s then
return nil,n"Cannot use IPv4 loopback address range"end
if P<=t and w>=t then
return nil,n"Cannot use a multicast address"end
if S==t then
return nil,n"Cannot use the limited broadcast destination address"end
local i,a=e.isNetworkAddress(i,r.localdevmask)if i then
return nil,n"Cannot use the network address"end
local e,t=e.isBroadcastAddress(t,r.localdevmask)if e then
return nil,n"Cannot use the broadcast address"end
return true
end
function e.isWANIP(i,e)local i=t(i)if not i then
return nil,n"Invalid input"end
for r,e in r(e)do
local r,d
if e.type=="wan"and e.ipaddr~=""then
local u=t(e.ipaddr)local t=h.netmaskToNumber(a(e.ipmask))if not t then
return nil,n"Invalid netmask"end
if u and t then
r=l(u,t)d=o(r,t)end
if r and d then
if r<=i and i<=d then
return true,e.paramindex
end
end
end
end
end
function e.isLANIP(e,s,c)local d=t(e)if not d then
return nil,n"Invalid input"end
local u={}local e=v.get("uci.firewall.zone.")local e=i.convertResultToObject("uci.firewall.zone.",e)for e,n in r(e)do
if n.wan=="1"and n.name=="wan"then
local n=i.convertResultToObject("uci.firewall.zone.@"..n.name..".network.",n)for e,n in r(n)do
u[I(n.value)]=true
end
end
end
for r,e in r(s)do
if not u[e.paramindex]and e.ipaddr~=""and e.paramindex~=c then
local r,i
local u=t(e.ipaddr)local t=h.netmaskToNumber(a(e.ipmask))if not t then
return nil,n"Invalid netmask"end
if u and t then
r=l(u,t)i=o(r,t)end
if r and i then
if r<=d and d<=i then
return true,e.paramindex
end
end
end
end
end
function e.cidr2mask(e)if not e then
return nil,n"Invalid CIDR number."end
e=a(e)if not e or e<0 or e>32 then
return nil,n"Invalid CIDR number."end
local n=""for t=1,4 do
n=n..tostring(256-2^(8-K(8,e)))if(t<4)then
n=n.."."end
e=X(0,e-8)end
return n
end
function e.validateIPAndSubnet(r)return function(e)local i=n"Invalid data format detected"if not e or e==""then
return nil,i
end
local t,l=f(I(e),"^([^/]+)/?(%d*)$")if not t or t==""or I(e):match("/$")=="/"then
return nil,i
end
local i=x(t)if r~=i then
return nil,d("%s%d",n"Please enter valid IPv",r)end
if l~=""then
local r,t,e
if i==4 then
t,e=1,32
elseif i==6 then
t,e=8,128
end
r=a(l)if not r or r<t or r>e then
return nil,d(n"Subnet must be between %d and %d (inclusive)",t,e)end
end
return true
end
end
function e.validateURL(i,a)if i then
local r,t=f(i,"([%w]+)://([^/]*)/?")if r and r~=a then
return nil,n"Invalid URL"end
if not r then
t=f(i,"([^/]*)/?")end
local n,r=string.match(t,"%[(.+)%]%:(%d+)$")if n and r then
if e.validateStringIsPort(r)and(e.validateStringIsIP(n)or e.validateStringIsDomainName(n))then
return true
end
else
if(e.validateStringIsIP(t)or e.validateStringIsDomainName(t))then
return true
end
end
end
return nil,n"Invalid URL"end
function e.validateQTN(t)local a={mac="uci.env.var.qtn_eth_mac"}local l=i.getExactContent(a)if not l then
return true
end
if not t then
return nil,"Invalid input"end
t=I(t)if e.validateStringIsMAC(t)then
if g(a.mac)==g(t)then
return nil,d(n"Cannot assign, %s in use by system.",t)end
return true
elseif h.isValidIPv4(t)==true then
local e=i.getMatchedContent("sys.proc.net.arp.",{hw_address=g(a.mac)})if#e>0 then
for r,e in r(e)do
if e.ip_address==t then
return nil,d(n"Cannot assign, %s in use by system.",t)end
end
end
return true
end
return nil,n"Invalid input."end
function e.isBroadcastAddress(e,n)local n=t(n)if n then
local t=l(e,n)local n=o(t,n)return n==e
end
end
function e.isNetworkAddress(r,i)local t=t(i)if t then
local e=e.ipv42num(r)if not e then
return nil,n"Invalid IP Address."end
if l(e,t)==e then
return true
end
return nil,n"Invalid Network Address."end
end
function e.getDefaultSubnetMask(i)local r
if not i then
return nil,n"Invalid IP Address."end
local e=e.ipv42num(i)if not e then
return nil,n"Invalid IP Address."end
if t("10.0.0.0")<=e and e<=t("127.255.255.255")then
r="8"elseif t("128.0.0.0")<=e and e<=t("191.255.255.255")then
r="16"elseif t("192.0.0.0")<=e and e<=t("223.255.255.255")then
r="24"else
return nil,n"IP Address does not belong to Class A, B or C."end
return r
end
function e.getPossibleHostsInSubnet(e)p()e=string.untaint(e)local e=h.getPossibleHostsInIPv4Subnet(e)if not e then
return nil,n"Invalid subnet."end
return e
end
function e.staticLeaseIPValidation(t,n)local r,i=e.advancedIPValidation(t,n)if not r then
return nil,i
end
local n=e.getValidateStringIsDeviceIPv4(n.localdevIP,n.localdevmask)local n,e=n(t)if not n then
return n,e
end
return true
end
function e.reservedIPValidation(t)if h.isValidIPv4(I(t))then
local e=v.get("uci.dhcp.host.")e=i.convertResultToObject("uci.dhcp.host.",e)or{}for r,e in r(e)do
if f(e.name,"^ReservedStatic")and e.mac==""then
if t==e.ip then
return nil,n"The IP is internally used for other services."end
end
end
return true
end
return nil,n"Invalid input."end
function e.getRandomKey()local e
local t=("%02X"):rep(16)local n=Q("/dev/urandom","r")if n then
e=n:read(16)n:close()end
return t:format(e:byte(1,16))end
function e.validateSSID(e)local t='^[^?"$%[%]+\\]*$'local r="^[^%s#!;]"if not e then
return nil,n"SSID should not be empty"elseif not e:match(r)then
return nil,n"SSID should not start with ; # !"elseif not e:match(t)then
return nil,n'SSID should not contain ?, ", $, [, \\, ],and + special characters'end
return true
end
function e.validateDHCPIgnore(r,t)if not e.getOptionalValidation(e.validateBoolean)(r)then
return nil,n"Invalid value."end
if t.dhcpv4State==""or t.dhcpv4State=="server"then
if t.dhcpIgnore=="1"then
t.dhcpIgnore="0"end
end
return true
end
function e.num2ipv4(e)if u(e)~="number"then
return nil,n"Invalid Number"end
if e<0 then
e=(2^32)+e
end
local e=h.numberToIpv4(e)if not e then
return nil,n"Invalid Number"end
return e
end
function e.validateTime(e)if not e then
return nil,n"Invalid input"end
local t="^(%d+):(%d+)$"local t,e=e:match(t)if e then
t=a(t)e=a(e)if t<0 or 23<t then
return nil,n"Invalid hour, must be between 0 and 23"end
if e<0 or 59<e then
return nil,n"Invalid minutes, must be between 0 and 59"end
return true
end
return nil,n"Invalid time (must be hh:mm)"end
local function a(n,e,t)return d("%s%s%s%s%s",e or"",t or"",(e or t)and" "or"",n,(n=="N/A")and""or" dB")end
local function l(e)local n=0
if e=="DS"then
n=1
end
return n
end
function e.populateAttenuation(n,t)if not n then
return
end
if O(n,"[,%s]")then
local e={}local i=l(t)for r in n:gmatch('([^,%s]+)')do
local n=#e
e[n+1]=a(r,t,n+i)end
return table.concat(e,", ")else
return a(n)end
end
function e.validateStringIsIPv4(e)if not e then
return nil,n"Invalid input"end
e=I(e)if h.isValidIPv4(e)then
return true
end
return nil,n"String is not an IPv4 address."end
function e.stringToTable(t,e)local n={}if t and e then
for e in t:gmatch(e)do
n[#n+1]=e
end
end
return n
end
function e.compareMACAddresses(t,r)if not(e.validateStringIsMAC(t)or e.validateStringIsMAC(r))then
return nil,n"Invalid MAC Address"end
if g(t:gsub("[:-]",""))==g(r:gsub("[:-]",""))then
return true
end
end
function e.valueInList(e,t,n)if e then
for r,e in c(e)do
if u(n)=="function"then
if n(e.value,t)then
return true
end
elseif e.value==t then
return true
end
end
end
end
function e.validateDMZ(r,t)local n={gateway_ip="uci.network.interface.@lan.ipaddr",netmask="uci.network.interface.@lan.netmask",}i.getExactContent(n)if t.DMZ_enable~="1"and r==""then
return true
end
local t,n=e.getValidateStringIsDeviceIPv4(n.gateway_ip,n.netmask)(r)if not t then
return nil,n
end
t,n=e.reservedIPValidation(r)if not t then
return nil,n
end
t,n=e.validateQTN(r)if not t then
return nil,n
end
return true
end
function e.isUpgradeAllowed(n,e)if n~="1"then
return
end
local n=v.get("uci.web.uiconfig.@uidefault.upgradefw_role.")or{}if#n==0 then
return true
end
for t,n in r(n)do
if n.value==e then
return true
end
end
end
function e.isSpaceInString(e)if e:match("%s")then
return nil,n"space is not allowed"end
return true
end
function e.DHCPStartAndLimitAddress(i,r,d,a)if d and a and i and r then
i=t(i)r=t(r)if not i or not r then
return nil,n"Invalid IP Address."end
local n=m.band(i,r)local i=m.bor(n,m.bnot(r))-1
local r=m.bor(n,m.band(d,m.bnot(r)))local t=r+a-1
r=e.num2ipv4(r)if t>i then
t=i
end
t=e.num2ipv4(t)n=e.num2ipv4(n)return r,t,n
end
end
function e.isFeatureEnabled(n,e)local n=v.get("uci.web.feature.@"..n..".")if not n then
return true
end
for t,n in r(n)do
if n.value==e then
return true
end
end
end
function e.validateUciName(e)if not f(e,"^[%w_]+$")or#e>63 then
return nil,n"Invalid input."end
return true
end
function e.validateLXC(t)if not t then
return nil,"Invalid input"end
local a={mac="uci.env.var.local_eth_mac_lxc"}local l=i.getExactContent(a)if not l then
return true
end
if e.validateStringIsMAC(t)then
if g(a.mac)==g(t)then
return nil,d(n"Cannot assign, %s in use by system.",t)end
return true
elseif h.isValidIPv4(I(t))then
local e=i.getMatchedContent("sys.proc.net.arp.",{hw_address=g(a.mac)})for r,e in r(e)do
if e.ip_address==t then
return nil,d(n"Cannot assign, %s in use by system.",t)end
end
return true
end
return nil,n"Invalid input."end
return e