2019-06-13 13:23:26 +00:00
'use strict' ;
'require ui' ;
'require rpc' ;
'require uci' ;
'require form' ;
'require tools.firewall as fwtool' ;
'require tools.widgets as widgets' ;
function fmt ( fmt /*, ...*/ ) {
var repl = [ ] , wrap = false ;
for ( var i = 1 ; i < arguments . length ; i ++ ) {
if ( L . dom . elem ( arguments [ i ] ) ) {
switch ( arguments [ i ] . nodeType ) {
case 1 :
repl . push ( arguments [ i ] . outerHTML ) ;
wrap = true ;
break ;
case 3 :
repl . push ( arguments [ i ] . data ) ;
break ;
case 11 :
var span = E ( 'span' ) ;
span . appendChild ( arguments [ i ] ) ;
repl . push ( span . innerHTML ) ;
wrap = true ;
break ;
default :
repl . push ( '' ) ;
}
}
else {
repl . push ( arguments [ i ] ) ;
}
}
var rv = fmt . format . apply ( fmt , repl ) ;
return wrap ? E ( 'span' , rv ) : rv ;
}
function forward _proto _txt ( s ) {
2019-07-17 16:19:45 +00:00
return fmt ( '%s-%s' ,
2020-01-16 12:54:22 +00:00
fwtool . fmt _family ( 'ipv4' ) ,
2019-06-13 13:23:26 +00:00
fwtool . fmt _proto ( uci . get ( 'firewall' , s , 'proto' ) ,
uci . get ( 'firewall' , s , 'icmp_type' ) ) || 'TCP+UDP' ) ;
}
function forward _src _txt ( s ) {
var z = fwtool . fmt _zone ( uci . get ( 'firewall' , s , 'src' ) , _ ( 'any zone' ) ) ,
a = fwtool . fmt _ip ( uci . get ( 'firewall' , s , 'src_ip' ) , _ ( 'any host' ) ) ,
p = fwtool . fmt _port ( uci . get ( 'firewall' , s , 'src_port' ) ) ,
m = fwtool . fmt _mac ( uci . get ( 'firewall' , s , 'src_mac' ) ) ;
if ( p && m )
return fmt ( _ ( 'From %s in %s with source %s and %s' ) , a , z , p , m ) ;
else if ( p || m )
return fmt ( _ ( 'From %s in %s with source %s' ) , a , z , p || m ) ;
else
return fmt ( _ ( 'From %s in %s' ) , a , z ) ;
}
function forward _via _txt ( s ) {
var a = fwtool . fmt _ip ( uci . get ( 'firewall' , s , 'src_dip' ) , _ ( 'any router IP' ) ) ,
p = fwtool . fmt _port ( uci . get ( 'firewall' , s , 'src_dport' ) ) ;
if ( p )
return fmt ( _ ( 'Via %s at %s' ) , a , p ) ;
else
return fmt ( _ ( 'Via %s' ) , a ) ;
}
return L . view . extend ( {
callHostHints : rpc . declare ( {
2019-10-31 13:37:07 +00:00
object : 'luci-rpc' ,
2019-08-14 15:07:55 +00:00
method : 'getHostHints' ,
expect : { '' : { } }
2019-06-13 13:23:26 +00:00
} ) ,
2020-01-16 15:30:58 +00:00
callConntrackHelpers : rpc . declare ( {
object : 'luci' ,
method : 'getConntrackHelpers' ,
expect : { result : [ ] }
} ) ,
2019-06-13 13:23:26 +00:00
load : function ( ) {
return Promise . all ( [
2020-01-16 15:30:58 +00:00
this . callHostHints ( ) ,
this . callConntrackHelpers ( )
2019-06-13 13:23:26 +00:00
] ) ;
} ,
render : function ( data ) {
var hosts = data [ 0 ] ,
2020-01-16 15:30:58 +00:00
ctHelpers = data [ 1 ] ,
2019-06-13 13:23:26 +00:00
m , s , o ;
m = new form . Map ( 'firewall' , _ ( 'Firewall - Port Forwards' ) ,
_ ( 'Port forwarding allows remote computers on the Internet to connect to a specific computer or service within the private LAN.' ) ) ;
s = m . section ( form . GridSection , 'redirect' , _ ( 'Port Forwards' ) ) ;
s . addremove = true ;
s . anonymous = true ;
s . sortable = true ;
s . tab ( 'general' , _ ( 'General Settings' ) ) ;
s . tab ( 'advanced' , _ ( 'Advanced Settings' ) ) ;
s . filter = function ( section _id ) {
return ( uci . get ( 'firewall' , section _id , 'target' ) != 'SNAT' ) ;
} ;
s . sectiontitle = function ( section _id ) {
return uci . get ( 'firewall' , section _id , 'name' ) || _ ( 'Unnamed forward' ) ;
} ;
2019-07-26 10:36:04 +00:00
s . handleAdd = function ( ev ) {
var config _name = this . uciconfig || this . map . config ,
section _id = uci . add ( config _name , this . sectiontype ) ;
uci . set ( config _name , section _id , 'target' , 'DNAT' ) ;
this . addedSection = section _id ;
this . renderMoreOptionsModal ( section _id ) ;
} ;
2019-06-13 13:23:26 +00:00
o = s . taboption ( 'general' , form . Value , 'name' , _ ( 'Name' ) ) ;
o . placeholder = _ ( 'Unnamed forward' ) ;
o . modalonly = true ;
o = s . option ( form . DummyValue , '_match' , _ ( 'Match' ) ) ;
o . modalonly = false ;
o . textvalue = function ( s ) {
return E ( 'small' , [
forward _proto _txt ( s ) , E ( 'br' ) ,
forward _src _txt ( s ) , E ( 'br' ) ,
forward _via _txt ( s )
] ) ;
} ;
o = s . option ( form . ListValue , '_dest' , _ ( 'Forward to' ) ) ;
o . modalonly = false ;
o . textvalue = function ( s ) {
var z = fwtool . fmt _zone ( uci . get ( 'firewall' , s , 'dest' ) , _ ( 'any zone' ) ) ,
a = fwtool . fmt _ip ( uci . get ( 'firewall' , s , 'dest_ip' ) , _ ( 'any host' ) ) ,
p = fwtool . fmt _port ( uci . get ( 'firewall' , s , 'dest_port' ) ) ||
fwtool . fmt _port ( uci . get ( 'firewall' , s , 'src_dport' ) ) ;
if ( p )
return fmt ( _ ( '%s, %s in %s' ) , a , p , z ) ;
else
return fmt ( _ ( '%s in %s' ) , a , z ) ;
} ;
o = s . option ( form . Flag , 'enabled' , _ ( 'Enable' ) ) ;
o . modalonly = false ;
o . default = o . enabled ;
o . editable = true ;
o = s . taboption ( 'general' , form . Value , 'proto' , _ ( 'Protocol' ) ) ;
o . modalonly = true ;
o . default = 'tcp udp' ;
o . value ( 'tcp udp' , 'TCP+UDP' ) ;
o . value ( 'tcp' , 'TCP' ) ;
o . value ( 'udp' , 'UDP' ) ;
o . value ( 'icmp' , 'ICMP' ) ;
o . cfgvalue = function ( /* ... */ ) {
var v = this . super ( 'cfgvalue' , arguments ) ;
return ( v == 'tcpudp' ) ? 'tcp udp' : v ;
} ;
o = s . taboption ( 'general' , widgets . ZoneSelect , 'src' , _ ( 'Source zone' ) ) ;
o . modalonly = true ;
o . rmempty = false ;
o . nocreate = true ;
o . default = 'wan' ;
o = s . taboption ( 'advanced' , form . Value , 'src_mac' , _ ( 'Source MAC address' ) ,
_ ( 'Only match incoming traffic from these MACs.' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
o . datatype = 'neg(macaddr)' ;
o . placeholder = E ( 'em' , _ ( 'any' ) ) ;
2019-07-07 18:11:35 +00:00
L . sortedKeys ( hosts ) . forEach ( function ( mac ) {
2019-06-13 13:23:26 +00:00
o . value ( mac , '%s (%s)' . format (
mac ,
hosts [ mac ] . name || hosts [ mac ] . ipv4 || hosts [ mac ] . ipv6 || '?'
) ) ;
} ) ;
o = s . taboption ( 'advanced' , form . Value , 'src_ip' , _ ( 'Source IP address' ) ,
_ ( 'Only match incoming traffic from this IP or range.' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
o . datatype = 'neg(ipmask4)' ;
o . placeholder = E ( 'em' , _ ( 'any' ) ) ;
2019-07-07 18:11:35 +00:00
L . sortedKeys ( hosts , 'ipv4' , 'addr' ) . forEach ( function ( mac ) {
2019-06-13 13:23:26 +00:00
o . value ( hosts [ mac ] . ipv4 , '%s (%s)' . format (
hosts [ mac ] . ipv4 ,
hosts [ mac ] . name || mac
) ) ;
} ) ;
o = s . taboption ( 'advanced' , form . Value , 'src_port' , _ ( 'Source port' ) ,
_ ( 'Only match incoming traffic originating from the given source port or port range on the client host' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
o . datatype = 'neg(portrange)' ;
o . placeholder = _ ( 'any' ) ;
o . depends ( 'proto' , 'tcp' ) ;
o . depends ( 'proto' , 'udp' ) ;
o . depends ( 'proto' , 'tcp udp' ) ;
o . depends ( 'proto' , 'tcpudp' ) ;
o = s . taboption ( 'advanced' , form . Value , 'src_dip' , _ ( 'External IP address' ) ,
_ ( 'Only match incoming traffic directed at the given IP address.' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
o . datatype = 'neg(ipmask4)' ;
o . placeholder = E ( 'em' , _ ( 'any' ) ) ;
2019-07-07 18:11:35 +00:00
L . sortedKeys ( hosts , 'ipv4' , 'addr' ) . forEach ( function ( mac ) {
2019-06-13 13:23:26 +00:00
o . value ( hosts [ mac ] . ipv4 , '%s (%s)' . format (
hosts [ mac ] . ipv4 ,
hosts [ mac ] . name || mac
) ) ;
} ) ;
o = s . taboption ( 'general' , form . Value , 'src_dport' , _ ( 'External port' ) ,
_ ( 'Match incoming traffic directed at the given destination port or port range on this host' ) ) ;
o . modalonly = true ;
o . rmempty = false ;
o . datatype = 'neg(portrange)' ;
o . depends ( 'proto' , 'tcp' ) ;
o . depends ( 'proto' , 'udp' ) ;
o . depends ( 'proto' , 'tcp udp' ) ;
o . depends ( 'proto' , 'tcpudp' ) ;
o = s . taboption ( 'general' , widgets . ZoneSelect , 'dest' , _ ( 'Internal zone' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
o . nocreate = true ;
o . default = 'lan' ;
o = s . taboption ( 'general' , form . Value , 'dest_ip' , _ ( 'Internal IP address' ) ,
_ ( 'Redirect matched incoming traffic to the specified internal host' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
o . datatype = 'ipmask4' ;
2019-07-07 18:11:35 +00:00
L . sortedKeys ( hosts , 'ipv4' , 'addr' ) . forEach ( function ( mac ) {
2019-06-13 13:23:26 +00:00
o . value ( hosts [ mac ] . ipv4 , '%s (%s)' . format (
hosts [ mac ] . ipv4 ,
hosts [ mac ] . name || mac
) ) ;
} ) ;
o = s . taboption ( 'general' , form . Value , 'dest_port' , _ ( 'Internal port' ) ,
_ ( 'Redirect matched incoming traffic to the given port on the internal host' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
o . placeholder = _ ( 'any' ) ;
o . datatype = 'portrange' ;
o . depends ( 'proto' , 'tcp' ) ;
o . depends ( 'proto' , 'udp' ) ;
o . depends ( 'proto' , 'tcp udp' ) ;
o . depends ( 'proto' , 'tcpudp' ) ;
o = s . taboption ( 'advanced' , form . Flag , 'reflection' , _ ( 'Enable NAT Loopback' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
o . default = o . enabled ;
2020-01-16 15:30:58 +00:00
o = s . taboption ( 'advanced' , form . ListValue , 'reflection_src' , _ ( 'Loopback source IP' ) , _ ( 'Specifies whether to use the external or the internal IP address for reflected traffic.' ) ) ;
o . modalonly = true ;
o . depends ( 'reflection' , '1' ) ;
o . value ( 'internal' , _ ( 'Use internal IP address' ) ) ;
o . value ( 'external' , _ ( 'Use external IP address' ) ) ;
o . write = function ( section _id , value ) {
uci . set ( 'firewall' , section _id , 'reflection_src' , ( value != 'internal' ) ? value : null ) ;
} ;
o = s . taboption ( 'advanced' , form . Value , 'helper' , _ ( 'Match helper' ) , _ ( 'Match traffic using the specified connection tracking helper.' ) ) ;
o . modalonly = true ;
o . placeholder = _ ( 'any' ) ;
for ( var i = 0 ; i < ctHelpers . length ; i ++ )
o . value ( ctHelpers [ i ] . name , '%s (%s)' . format ( ctHelpers [ i ] . description , ctHelpers [ i ] . name . toUpperCase ( ) ) ) ;
o . validate = function ( section _id , value ) {
if ( value == '' || value == null )
return true ;
value = value . replace ( /^!\s*/ , '' ) ;
for ( var i = 0 ; i < ctHelpers . length ; i ++ )
if ( value == ctHelpers [ i ] . name )
return true ;
return _ ( 'Unknown or not installed conntrack helper "%s"' ) . format ( value ) ;
} ;
2020-01-16 21:13:34 +00:00
fwtool . addMarkOption ( s , false ) ;
fwtool . addLimitOption ( s ) ;
fwtool . addLimitBurstOption ( s ) ;
2020-01-16 20:36:39 +00:00
2019-06-13 13:23:26 +00:00
o = s . taboption ( 'advanced' , form . Value , 'extra' , _ ( 'Extra arguments' ) ,
_ ( 'Passes additional arguments to iptables. Use with care!' ) ) ;
o . modalonly = true ;
o . rmempty = true ;
return m . render ( ) ;
}
} ) ;