diff --git a/docker/routlin-dash/app/factory.py b/docker/routlin-dash/app/factory.py index efb4cd6..8cd84dc 100644 --- a/docker/routlin-dash/app/factory.py +++ b/docker/routlin-dash/app/factory.py @@ -201,7 +201,7 @@ function _checkLine(s){ if(validation&1024){t=_acc(function(){if(!s)return _par('');if(/[^0-9:]/.test(s))return _err('Digits and colon only');if(s.length<5)return _par('');return /^([01]\d|2[0-3]):[0-5]\d$/.test(s)?_ok():_err('Must be HH:MM in 24-hour format (e.g. 02:30)');}());if(t)return t;} if(validation&2048){t=_acc(function(){if(s===''||s===null||s===undefined)return _par('');if(/[^0-9]/.test(s))return _err('Digits only');var n=parseInt(s,10);var mn=(arg1!==''&&arg1!=null)?parseInt(arg1,10):0;var mx=(arg2!==''&&arg2!=null)?parseInt(arg2,10):null;if(nmx)){if(mn!=null&&mx!==null)return _err('Must be between '+mn+' and '+mx);return mn!=null?_err('Must be >= '+mn):_err('Must be <= '+mx);}return _ok();}());if(t)return t;} if(validation&4096){t=_acc(function(){if(!s)return _par('');if(/^[0-9.]+$/.test(s)){var rv=_ipv4(s);return rv==='ok'?_ok():(rv==='partial'||rv==='empty')?_par(''):_err('Invalid character');}if(s.indexOf(':')!==-1){var cc=(s.match(/:/g)||[]).length;if(cc>1){if(/:::/.test(s)||(s.match(/::/g)||[]).length>1)return _err('Invalid hostname or IP');if(/[^0-9a-fA-F:.]/.test(s))return _err('Invalid character');var col=s.replace(/[^:]/g,'').length;return(s.indexOf('::')!==-1||col===7)?_ok():_par('');}return _checkDomain(s.slice(0,s.lastIndexOf(':')));}return _checkDomain(s);}());if(t)return t;} - if(validation&8192){t=_acc(function(){if(!s)return _par('');var slash=s.indexOf('/');if(slash===-1){var rv=_ipv4(s);return(rv==='ok'||rv==='partial'||rv==='empty')?_par(''):(rv==='badchar'?_err('Invalid character'):rv==='badrange'?_err('Octet out of range'):_err('Invalid format'));}var rv=_ipv4(s.slice(0,slash));if(rv!=='ok')return rv==='badchar'?_err('Invalid character'):rv==='badrange'?_err('Octet out of range'):_par('');var pfx=s.slice(slash+1);if(!pfx)return _par('');if(/[^0-9]/.test(pfx))return _err('Invalid character');var n=parseInt(pfx,10);return(n>=0&&n<=32)?_ok():_err('Prefix must be 0-32');}());if(t)return t;} + if(validation&8192){t=_acc(function(){if(!s)return _par('');var slash=s.indexOf('/');if(slash===-1){var rv=_ipv4(s);return rv==='ok'?_ok():(rv==='partial'||rv==='empty')?_par(''):(rv==='badchar'?_err('Invalid character'):rv==='badrange'?_err('Octet out of range'):_err('Invalid format'));}var rv=_ipv4(s.slice(0,slash));if(rv!=='ok')return rv==='badchar'?_err('Invalid character'):rv==='badrange'?_err('Octet out of range'):_par('');var pfx=s.slice(slash+1);if(!pfx)return _par('');if(/[^0-9]/.test(pfx))return _err('Invalid character');var n=parseInt(pfx,10);if(n<0||n>32)return _err('Prefix must be 0-32');var ip=s.slice(0,slash).split('.').map(Number);var ipN=((ip[0]<<24)|(ip[1]<<16)|(ip[2]<<8)|ip[3])>>>0;var mB=n===0?0:((0xFFFFFFFF<<(32-n))>>>0);return((ipN&(~mB>>>0))!==0)?_err('Host bits must be zero'):_ok();}());if(t)return t;} if(validation&16384){t=_acc(function(){if(!s)return _par('');var rv=_ipv4(s);if(rv!=='ok')return _par('');if(!collisions||!collisions.length)return _ok();var ip=s.split('.').map(Number);var ipN=((ip[0]<<24)|(ip[1]<<16)|(ip[2]<<8)|ip[3])>>>0;for(var i=0;i>>0;var pfx=parseInt(sp[1],10);var mB=pfx===0?0:((0xFFFFFFFF<<(32-pfx))>>>0);if((ipN&mB)===(netN&mB))return _err('IP is on a restricted VLAN');}return _ok();}());if(t)return t;} return anyPartial?_par(''):_err(firstMsg||'Invalid'); } diff --git a/docker/routlin-dash/app/pages/intervlan/content.json b/docker/routlin-dash/app/pages/intervlan/content.json index b3a050b..59c6108 100644 --- a/docker/routlin-dash/app/pages/intervlan/content.json +++ b/docker/routlin-dash/app/pages/intervlan/content.json @@ -103,7 +103,7 @@ "label": "Source", "name": "src_ip_or_subnet", "input_type": "text", - "validate": "VALIDATION_IPV4_FORMAT|VALIDATION_IPV4_CIDR", + "validate": "VALIDATION_IPV4_CIDR", "placeholder": "e.g. 192.168.20.100 or 192.168.20.0/24", "hint": "You may allow either a single device IP or an entire subnet to contact dest." }, @@ -112,7 +112,7 @@ "label": "Destination", "name": "dst_ip_or_subnet", "input_type": "text", - "validate": "VALIDATION_IPV4_FORMAT|VALIDATION_IPV4_CIDR", + "validate": "VALIDATION_IPV4_CIDR", "placeholder": "e.g. 192.168.10.200 or 192.168.10.0/24", "hint": "You may allow either a single device IP or an entire subnet to be reached by source." } diff --git a/routlin/mod_validation.py b/routlin/mod_validation.py index 1ba2483..55e80f7 100644 --- a/routlin/mod_validation.py +++ b/routlin/mod_validation.py @@ -73,7 +73,7 @@ def ipv4_or_cidr(value): except ValueError: pass try: - ipaddress.IPv4Network(v, strict=False) + ipaddress.IPv4Network(v, strict=True) return v except ValueError: return ''