From 44e9ae75aee88b4e85f9b1d15f85f96c1ba16931 Mon Sep 17 00:00:00 2001
From: billz
Date: Sat, 22 Aug 2020 11:41:33 +0100
Subject: [PATCH 01/79] Remove webconsole, fixes RCE via json-rpc. Thanks
@lunchb0x
---
app/css/custom.php | 15 -
app/css/lightsout.css | 10 -
includes/adblock.php | 0
includes/internetRoute.php | 0
includes/webconsole.php | 938 -----------------------------------
templates/system.php | 6 -
templates/system/console.php | 11 -
7 files changed, 980 deletions(-)
mode change 100644 => 100755 includes/adblock.php
mode change 100644 => 100755 includes/internetRoute.php
delete mode 100755 includes/webconsole.php
delete mode 100644 templates/system/console.php
diff --git a/app/css/custom.php b/app/css/custom.php
index 38415372..f6b18318 100644
--- a/app/css/custom.php
+++ b/app/css/custom.php
@@ -129,21 +129,6 @@ i.fa.fa-bars:hover{
float: left;
}
-.webconsole {
- width:100%;
- height:100%;
- border:1px solid;
-}
-
-#console {
- height:500px;
-}
-
-.systemtabcontent {
- height:100%;
- min-height:500px;
-}
-
.service-status {
border-width: 0;
}
diff --git a/app/css/lightsout.css b/app/css/lightsout.css
index e70c4fd7..55eb4b54 100644
--- a/app/css/lightsout.css
+++ b/app/css/lightsout.css
@@ -357,16 +357,6 @@ color: #d2d2d2 !important
border-color: #404040;
}
-.webconsole {
- width: 100%;
- height: 20rem;
- border: 1px solid #404040;
-}
-
-#console {
- height: 500px;
-}
-
tspan, rect {
fill: #d2d2d2;
}
diff --git a/includes/adblock.php b/includes/adblock.php
old mode 100644
new mode 100755
diff --git a/includes/internetRoute.php b/includes/internetRoute.php
old mode 100644
new mode 100755
diff --git a/includes/webconsole.php b/includes/webconsole.php
deleted file mode 100755
index 8ea74be2..00000000
--- a/includes/webconsole.php
+++ /dev/null
@@ -1,938 +0,0 @@
- 'password1', 'user2' => 'password2');
-$ACCOUNTS = array();
-
-// Password hash algorithm (password must be hashed)
-// Example: $PASSWORD_HASH_ALGORITHM = 'md5';
-// $PASSWORD_HASH_ALGORITHM = 'sha256';
-$PASSWORD_HASH_ALGORITHM = '';
-
-// Home directory (multi-user mode supported)
-// Example: $HOME_DIRECTORY = '/tmp';
-// $HOME_DIRECTORY = array('user1' => '/home/user1', 'user2' => '/home/user2');
-$HOME_DIRECTORY = '';
-
-// Code below is automatically generated from different components
-// For more information see: https://github.com/nickola/web-console
-//
-// Used components:
-// - jQuery JavaScript Library: https://github.com/jquery/jquery
-// - jQuery Terminal Emulator: https://github.com/jcubic/jquery.terminal
-// - jQuery Mouse Wheel Plugin: https://github.com/brandonaaron/jquery-mousewheel
-// - PHP JSON-RPC 2.0 Server/Client Implementation: https://github.com/sergeyfast/eazy-jsonrpc
-// - Normalize.css: https://github.com/necolas/normalize.css
-?>
- method
- */
- protected $instances = array();
-
- /**
- * Decoded Json Request
- *
- * @var object|array
- */
- protected $request;
-
- /**
- * Array of Received Calls
- *
- * @var array
- */
- protected $calls = array();
-
- /**
- * Array of Responses for Calls
- *
- * @var array
- */
- protected $response = array();
-
- /**
- * Has Calls Flag (not notifications)
- *
- * @var bool
- */
- protected $hasCalls = false;
-
- /**
- * Is Batch Call in using
- *
- * @var bool
- */
- private $isBatchCall = false;
-
- /**
- * Hidden Methods
- *
- * @var array
- */
- protected $hiddenMethods = array(
- 'execute', '__construct', 'registerinstance'
- );
-
- /**
- * Content Type
- *
- * @var string
- */
- public $ContentType = 'application/json';
-
- /**
- * Allow Cross-Domain Requests
- *
- * @var bool
- */
- public $IsXDR = true;
-
- /**
- * Max Batch Calls
- *
- * @var int
- */
- public $MaxBatchCalls = 10;
-
- /**
- * Error Messages
- *
- * @var array
- */
- protected $errorMessages = array(
- self::ParseError => 'Parse error',
- self::InvalidRequest => 'Invalid Request',
- self::MethodNotFound => 'Method not found',
- self::InvalidParams => 'Invalid params',
- self::InternalError => 'Internal error',
- );
-
-
- /**
- * Cached Reflection Methods
- *
- * @var ReflectionMethod[]
- */
- private $reflectionMethods = array();
-
-
- /**
- * Validate Request
- *
- * @return int error
- */
- private function getRequest()
- {
- $error = null;
-
- do {
- if (array_key_exists('REQUEST_METHOD', $_SERVER) && $_SERVER['REQUEST_METHOD'] != 'POST' ) {
- $error = self::InvalidRequest;
- break;
- };
-
- $request = !empty($_GET['rawRequest']) ? $_GET['rawRequest'] : file_get_contents('php://input');
- $this->request = json_decode($request, false);
- if ($this->request === null ) {
- $error = self::ParseError;
- break;
- }
-
- if ($this->request === array() ) {
- $error = self::InvalidRequest;
- break;
- }
-
- // check for batch call
- if (is_array($this->request) ) {
- if(count($this->request) > $this->MaxBatchCalls ) {
- $error = self::InvalidRequest;
- break;
- }
-
- $this->calls = $this->request;
- $this->isBatchCall = true;
- } else {
- $this->calls[] = $this->request;
- }
- } while ( false );
-
- return $error;
- }
-
-
- /**
- * Get Error Response
- *
- * @param int $code
- * @param mixed $id
- * @param null $data
- * @return array
- */
- private function getError( $code, $id = null, $data = null )
- {
- return array(
- 'jsonrpc' => '2.0',
- 'id' => $id,
- 'error' => array(
- 'code' => $code,
- 'message' => isset($this->errorMessages[$code]) ? $this->errorMessages[$code] : $this->errorMessages[self::InternalError],
- 'data' => $data,
- ),
- );
- }
-
-
- /**
- * Check for jsonrpc version and correct method
- *
- * @param object $call
- * @return array|null
- */
- private function validateCall( $call )
- {
- $result = null;
- $error = null;
- $data = null;
- $id = is_object($call) && property_exists($call, 'id') ? $call->id : null;
- do {
- if (!is_object($call) ) {
- $error = self::InvalidRequest;
- break;
- }
-
- // hack for inputEx smd tester
- if (property_exists($call, 'version') ) {
- if ($call->version == 'json-rpc-2.0' ) {
- $call->jsonrpc = '2.0';
- }
- }
-
- if (!property_exists($call, 'jsonrpc') || $call->jsonrpc != '2.0' ) {
- $error = self::InvalidRequest;
- break;
- }
-
- $fullMethod = property_exists($call, 'method') ? $call->method : '';
- $methodInfo = explode('.', $fullMethod, 2);
- $namespace = array_key_exists(1, $methodInfo) ? $methodInfo[0] : '';
- $method = $namespace ? $methodInfo[1] : $fullMethod;
- if (!$method || !array_key_exists($namespace, $this->instances) || !method_exists($this->instances[$namespace], $method) || in_array(strtolower($method), $this->hiddenMethods) ) {
- $error = self::MethodNotFound;
- break;
- }
-
- if (!array_key_exists($fullMethod, $this->reflectionMethods) ) {
- $this->reflectionMethods[$fullMethod] = new ReflectionMethod($this->instances[$namespace], $method);
- }
-
- /**
- * @var $params array
-*/
- $params = property_exists($call, 'params') ? $call->params : null;
- $paramsType = gettype($params);
- if ($params !== null && $paramsType != 'array' && $paramsType != 'object' ) {
- $error = self::InvalidParams;
- break;
- }
-
- // check parameters
- switch ( $paramsType ) {
- case 'array':
- $totalRequired = 0;
- // doesn't hold required, null, required sequence of params
- foreach ( $this->reflectionMethods[$fullMethod]->getParameters() as $param ) {
- if (!$param->isDefaultValueAvailable() ) {
- $totalRequired++;
- }
- }
-
- if (count($params) < $totalRequired ) {
- $error = self::InvalidParams;
- $data = sprintf('Check numbers of required params (got %d, expected %d)', count($params), $totalRequired);
- }
- break;
- case 'object':
- foreach ( $this->reflectionMethods[$fullMethod]->getParameters() as $param ) {
- if (!$param->isDefaultValueAvailable() && !array_key_exists($param->getName(), $params) ) {
- $error = self::InvalidParams;
- $data = $param->getName() . ' not found';
-
- break 3;
- }
- }
- break;
- case 'NULL':
- if ($this->reflectionMethods[$fullMethod]->getNumberOfRequiredParameters() > 0 ) {
- $error = self::InvalidParams;
- $data = 'Empty required params';
- break 2;
- }
- break;
- }
-
- } while ( false );
-
- if ($error ) {
- $result = array( $error, $id, $data );
- }
-
- return $result;
- }
-
-
- /**
- * Process Call
- *
- * @param $call
- * @return array|null
- */
- private function processCall( $call )
- {
- $id = property_exists($call, 'id') ? $call->id : null;
- $params = property_exists($call, 'params') ? $call->params : array();
- $result = null;
- $namespace = substr($call->method, 0, strpos($call->method, '.'));
-
- try {
- // set named parameters
- if (is_object($params) ) {
- $newParams = array();
- foreach ( $this->reflectionMethods[$call->method]->getParameters() as $param ) {
- $paramName = $param->getName();
- $defaultValue = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null;
- $newParams[] = property_exists($params, $paramName) ? $params->$paramName : $defaultValue;
- }
-
- $params = $newParams;
- }
-
- // invoke
- $result = $this->reflectionMethods[$call->method]->invokeArgs($this->instances[$namespace], $params);
- } catch ( Exception $e ) {
- return $this->getError($e->getCode(), $id, $e->getMessage());
- }
-
- if (!$id && $id !== 0 ) {
- return null;
- }
-
- return array(
- 'jsonrpc' => '2.0',
- 'result' => $result,
- 'id' => $id,
- );
- }
-
-
- /**
- * Create new Instance
- *
- * @param object $instance
- */
- public function __construct( $instance = null )
- {
- if (get_parent_class($this) ) {
- $this->RegisterInstance($this, '');
- } else if ($instance ) {
- $this->RegisterInstance($instance, '');
- }
- }
-
-
- /**
- * Register Instance
- *
- * @param object $instance
- * @param string $namespace default is empty string
- * @return $this
- */
- public function RegisterInstance( $instance, $namespace = '' )
- {
- $this->instances[$namespace] = $instance;
- $this->instances[$namespace]->errorMessages = $this->errorMessages;
-
- return $this;
- }
-
-
- /**
- * Handle Requests
- */
- public function Execute()
- {
- do {
- // check for SMD Discovery request
- if (array_key_exists('smd', $_GET) ) {
- $this->response[] = $this->getServiceMap();
- $this->hasCalls = true;
- break;
- }
-
- $error = $this->getRequest();
- if ($error ) {
- $this->response[] = $this->getError($error);
- $this->hasCalls = true;
- break;
- }
-
- foreach ( $this->calls as $call ) {
- $error = $this->validateCall($call);
- if ($error ) {
- $this->response[] = $this->getError($error[0], $error[1], $error[2]);
- $this->hasCalls = true;
- } else {
- $result = $this->processCall($call);
- if ($result ) {
- $this->response[] = $result;
- $this->hasCalls = true;
- }
- }
- }
- } while ( false );
-
- // flush response
- if ($this->hasCalls ) {
- if (!$this->isBatchCall ) {
- $this->response = reset($this->response);
- }
-
- if (!headers_sent() ) {
- // Set Content Type
- if ($this->ContentType ) {
- header('Content-Type: ' . $this->ContentType);
- }
-
- // Allow Cross Domain Requests
- if ($this->IsXDR ) {
- header('Access-Control-Allow-Origin: *');
- header('Access-Control-Allow-Headers: x-requested-with, content-type');
- }
- }
-
- echo json_encode($this->response);
- $this->resetVars();
- }
- }
-
-
- /**
- * Get Doc Comment
- *
- * @param $comment
- * @return string|null
- */
- private function getDocDescription( $comment )
- {
- $result = null;
- if (preg_match('/\*\s+([^@]*)\s+/s', $comment, $matches) ) {
- $result = str_replace('*', "\n", trim(trim($matches[1], '*')));
- }
-
- return $result;
- }
-
-
- /**
- * Get Service Map
- * Maybe not so good realization of auto-discover via doc blocks
- *
- * @return array
- */
- private function getServiceMap()
- {
- $result = array(
- 'transport' => 'POST',
- 'envelope' => 'JSON-RPC-2.0',
- 'SMDVersion' => '2.0',
- 'contentType' => 'application/json',
- 'target' => !empty($_SERVER['REQUEST_URI']) ? substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?')) : '',
- 'services' => array(),
- 'description' => '',
- );
-
- foreach( $this->instances as $namespace => $instance ) {
- $rc = new ReflectionClass($instance);
-
- // Get Class Description
- if ($rcDocComment = $this->getDocDescription($rc->getDocComment()) ) {
- $result['description'] .= $rcDocComment . PHP_EOL;
- }
-
- foreach ( $rc->getMethods() as $method ) {
- /**
- * @var ReflectionMethod $method
-*/
- if (!$method->isPublic() || in_array(strtolower($method->getName()), $this->hiddenMethods) ) {
- continue;
- }
-
- $methodName = ( $namespace ? $namespace . '.' : '' ) . $method->getName();
- $docComment = $method->getDocComment();
-
- $result['services'][$methodName] = array( 'parameters' => array() );
-
- // set description
- if ($rmDocComment = $this->getDocDescription($docComment) ) {
- $result['services'][$methodName]['description'] = $rmDocComment;
- }
-
- // @param\s+([^\s]*)\s+([^\s]*)\s*([^\s\*]*)
- $parsedParams = array();
- if (preg_match_all('/@param\s+([^\s]*)\s+([^\s]*)\s*([^\n\*]*)/', $docComment, $matches) ) {
- foreach ( $matches[2] as $number => $name ) {
- $type = $matches[1][$number];
- $desc = $matches[3][$number];
- $name = trim($name, '$');
-
- $param = array( 'type' => $type, 'description' => $desc );
- $parsedParams[$name] = array_filter($param);
- }
- };
-
- // process params
- foreach ( $method->getParameters() as $parameter ) {
- $name = $parameter->getName();
- $param = array( 'name' => $name, 'optional' => $parameter->isDefaultValueAvailable() );
- if (array_key_exists($name, $parsedParams) ) {
- $param += $parsedParams[$name];
- }
-
- if ($param['optional'] ) {
- $param['default'] = $parameter->getDefaultValue();
- }
-
- $result['services'][$methodName]['parameters'][] = $param;
- }
-
- // set return type
- if (preg_match('/@return\s+([^\s]+)\s*([^\n\*]+)/', $docComment, $matches) ) {
- $returns = array( 'type' => $matches[1], 'description' => trim($matches[2]) );
- $result['services'][$methodName]['returns'] = array_filter($returns);
- }
- }
- }
-
- return $result;
- }
-
-
- /**
- * Reset Local Class Vars after Execute
- */
- private function resetVars()
- {
- $this->response = $this->calls = array();
- $this->hasCalls = $this->isBatchCall = false;
- }
-
-}
-?>
-= 1) ? true : false;
-
-// Utilities
-function is_empty_string($string)
-{
- return strlen($string) <= 0;
-}
-
-function is_equal_strings($string1, $string2)
-{
- return strcmp($string1, $string2) == 0;
-}
-
-function get_hash($algorithm, $string)
-{
- return hash($algorithm, trim((string) $string));
-}
-
-// Command execution
-function execute_command($command)
-{
- $descriptors = array(
- 0 => array('pipe', 'r'), // STDIN
- 1 => array('pipe', 'w'), // STDOUT
- 2 => array('pipe', 'w') // STDERR
- );
-
- $process = proc_open($command . ' 2>&1', $descriptors, $pipes);
- if (!is_resource($process)) { die("Can't execute command.");
- }
-
- // Nothing to push to STDIN
- fclose($pipes[0]);
-
- $output = stream_get_contents($pipes[1]);
- fclose($pipes[1]);
-
- $error = stream_get_contents($pipes[2]);
- fclose($pipes[2]);
-
- // All pipes must be closed before "proc_close"
- $code = proc_close($process);
-
- return $output;
-}
-
-// Command parsing
-function parse_command($command)
-{
- $value = ltrim((string) $command);
-
- if (!is_empty_string($value)) {
- $values = explode(' ', $value);
- $values_total = count($values);
-
- if ($values_total > 1) {
- $value = $values[$values_total - 1];
-
- for ($index = $values_total - 2; $index >= 0; $index--) {
- $value_item = $values[$index];
-
- if (substr($value_item, -1) == '\\') { $value = $value_item . ' ' . $value;
- } else { break;
- }
- }
- }
- }
-
- return $value;
-}
-
-// RPC Server
-class WebConsoleRPCServer extends BaseJsonRpcServer
-{
- protected $home_directory = '';
-
- private function error($message)
- {
- throw new Exception($message);
- }
-
- // Authentication
- private function authenticate_user($user, $password)
- {
- $user = trim((string) $user);
- $password = trim((string) $password);
-
- if ($user && $password) {
- global $ACCOUNTS, $PASSWORD_HASH_ALGORITHM;
-
- if (isset($ACCOUNTS[$user]) && !is_empty_string($ACCOUNTS[$user])) {
- if ($PASSWORD_HASH_ALGORITHM) { $password = get_hash($PASSWORD_HASH_ALGORITHM, $password);
- }
-
- if (is_equal_strings($password, $ACCOUNTS[$user])) {
- return $user . ':' . get_hash('sha256', $password);
- }
- }
- }
-
- throw new Exception("Incorrect user or password");
- }
-
- private function authenticate_token($token)
- {
- global $NO_LOGIN;
- if ($NO_LOGIN) { return true;
- }
-
- $token = trim((string) $token);
- $token_parts = explode(':', $token, 2);
-
- if (count($token_parts) == 2) {
- $user = trim((string) $token_parts[0]);
- $password_hash = trim((string) $token_parts[1]);
-
- if ($user && $password_hash) {
- global $ACCOUNTS;
-
- if (isset($ACCOUNTS[$user]) && !is_empty_string($ACCOUNTS[$user])) {
- $real_password_hash = get_hash('sha256', $ACCOUNTS[$user]);
- if (is_equal_strings($password_hash, $real_password_hash)) { return $user;
- }
- }
- }
- }
-
- throw new Exception("Incorrect user or password");
- }
-
- private function get_home_directory($user)
- {
- global $HOME_DIRECTORY;
-
- if (is_string($HOME_DIRECTORY)) {
- if (!is_empty_string($HOME_DIRECTORY)) { return $HOME_DIRECTORY;
- }
- }
- else if (is_string($user) && !is_empty_string($user) && isset($HOME_DIRECTORY[$user]) && !is_empty_string($HOME_DIRECTORY[$user])) {
- return $HOME_DIRECTORY[$user];
- }
-
- return getcwd();
- }
-
- // Environment
- private function get_environment()
- {
- $hostname = function_exists('gethostname') ? gethostname() : null;
- return array('path' => getcwd(), 'hostname' => $hostname);
- }
-
- private function set_environment($environment)
- {
- $environment = !empty($environment) ? (array) $environment : array();
- $path = (isset($environment['path']) && !is_empty_string($environment['path'])) ? $environment['path'] : $this->home_directory;
-
- if (!is_empty_string($path)) {
- if (is_dir($path)) {
- if (!@chdir($path)) { return array('output' => "Unable to change directory to current working directory, updating current directory",
- 'environment' => $this->get_environment());
- }
- }
- else { return array('output' => "Current working directory not found, updating current directory",
- 'environment' => $this->get_environment());
- }
- }
- }
-
- // Initialization
- private function initialize($token, $environment)
- {
- $user = $this->authenticate_token($token);
- $this->home_directory = $this->get_home_directory($user);
- $result = $this->set_environment($environment);
-
- if ($result) { return $result;
- }
- }
-
- // Methods
- public function login($user, $password)
- {
- $result = array('token' => $this->authenticate_user($user, $password),
- 'environment' => $this->get_environment());
-
- $home_directory = $this->get_home_directory($user);
- if (!is_empty_string($home_directory)) {
- if (is_dir($home_directory)) { $result['environment']['path'] = $home_directory;
- } else { $result['output'] = "Home directory not found: ". $home_directory;
- }
- }
-
- return $result;
- }
-
- public function cd($token, $environment, $path)
- {
- $result = $this->initialize($token, $environment);
- if ($result) { return $result;
- }
-
- $path = trim((string) $path);
- if (is_empty_string($path)) { $path = $this->home_directory;
- }
-
- if (!is_empty_string($path)) {
- if (is_dir($path)) {
- if (!@chdir($path)) { return array('output' => "cd: ". $path . ": Unable to change directory");
- }
- }
- else { return array('output' => "cd: ". $path . ": No such directory");
- }
- }
-
- return array('environment' => $this->get_environment());
- }
-
- public function completion($token, $environment, $pattern, $command)
- {
- $result = $this->initialize($token, $environment);
- if ($result) { return $result;
- }
-
- $scan_path = '';
- $completion_prefix = '';
- $completion = array();
-
- if (!empty($pattern)) {
- if (!is_dir($pattern)) {
- $pattern = dirname($pattern);
- if ($pattern == '.') { $pattern = '';
- }
- }
-
- if (!empty($pattern)) {
- if (is_dir($pattern)) {
- $scan_path = $completion_prefix = $pattern;
- if (substr($completion_prefix, -1) != '/') { $completion_prefix .= '/';
- }
- }
- }
- else { $scan_path = getcwd();
- }
- }
- else { $scan_path = getcwd();
- }
-
- if (!empty($scan_path)) {
- // Loading directory listing
- $completion = array_values(array_diff(scandir($scan_path), array('..', '.')));
- natsort($completion);
-
- // Prefix
- if (!empty($completion_prefix) && !empty($completion)) {
- foreach ($completion as &$value) { $value = $completion_prefix . $value;
- }
- }
-
- // Pattern
- if (!empty($pattern) && !empty($completion)) {
- // For PHP version that does not support anonymous functions (available since PHP 5.3.0)
- function filter_pattern($value)
- {
- global $pattern;
- return !strncmp($pattern, $value, strlen($pattern));
- }
-
- $completion = array_values(array_filter($completion, 'filter_pattern'));
- }
- }
-
- return array('completion' => $completion);
- }
-
- public function run($token, $environment, $command)
- {
- $result = $this->initialize($token, $environment);
- if ($result) { return $result;
- }
-
- $output = ($command && !is_empty_string($command)) ? execute_command($command) : '';
- if ($output && substr($output, -1) == "\n") { $output = substr($output, 0, -1);
- }
-
- return array('output' => $output);
- }
-}
-
-// Processing request
-if (array_key_exists('REQUEST_METHOD', $_SERVER) && $_SERVER['REQUEST_METHOD'] == 'POST') {
- $rpc_server = new WebConsoleRPCServer();
- $rpc_server->Execute();
-}
-else if (!$IS_CONFIGURED) {
- ?>
-
-
-
-
-
- Web Console
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Web Console
-
-
-
-
-
-
-
-
-
-
diff --git a/templates/system.php b/templates/system.php
index 902b6953..0e983186 100755
--- a/templates/system.php
+++ b/templates/system.php
@@ -16,19 +16,13 @@
-
-
-
-
diff --git a/templates/system/console.php b/templates/system/console.php
deleted file mode 100644
index 009af68d..00000000
--- a/templates/system/console.php
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
From 6ca12a184b525be9bfdccb0068815e31c1f63e2a Mon Sep 17 00:00:00 2001
From: billz
Date: Wed, 4 Nov 2020 01:05:35 +0000
Subject: [PATCH 02/79] Add DHCP for eth0 option to advanced tab
---
templates/dhcp/advanced.php | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/templates/dhcp/advanced.php b/templates/dhcp/advanced.php
index 6366977c..eeec4a2d 100644
--- a/templates/dhcp/advanced.php
+++ b/templates/dhcp/advanced.php
@@ -4,7 +4,6 @@
-
From 06af0795f62f0bb2534081fbe65e1dddd1410466 Mon Sep 17 00:00:00 2001
From: billz
Date: Fri, 6 Nov 2020 09:01:33 +0000
Subject: [PATCH 03/79] Add /bin/cp for 090_eth0.conf to sudoers
---
installers/raspap.sudoers | 1 +
1 file changed, 1 insertion(+)
diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers
index ae42393c..2109bece 100644
--- a/installers/raspap.sudoers
+++ b/installers/raspap.sudoers
@@ -21,6 +21,7 @@ www-data ALL=(ALL) NOPASSWD:/bin/systemctl disable openvpn-client@client
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/ovpnclient.ovpn /etc/openvpn/client/client.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/authdata /etc/openvpn/client/login.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_raspap.conf
+www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_eth0.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dhcpddata /etc/dhcpcd.conf
www-data ALL=(ALL) NOPASSWD:/sbin/shutdown -h now
www-data ALL=(ALL) NOPASSWD:/sbin/reboot
From a20877c377e6ed67af56bc523bf8e9c1ced13d87 Mon Sep 17 00:00:00 2001
From: billz
Date: Fri, 6 Nov 2020 09:04:22 +0000
Subject: [PATCH 04/79] Add RASPI_DNSMASQ_ETH0 to default config
---
config/config.php | 1 +
includes/defaults.php | 1 +
2 files changed, 2 insertions(+)
diff --git a/config/config.php b/config/config.php
index 030df874..90b96247 100755
--- a/config/config.php
+++ b/config/config.php
@@ -11,6 +11,7 @@ define('RASPI_CACHE_PATH', sys_get_temp_dir() . '/raspap');
// These are typical for default RPi installs. Modify if needed.
define('RASPI_DNSMASQ_CONFIG', '/etc/dnsmasq.d/090_raspap.conf');
define('RASPI_DNSMASQ_LEASES', '/var/lib/misc/dnsmasq.leases');
+define('RASPI_DNSMASQ_ETH0', '/etc/dnsmasq.d/090_eth0.conf');
define('RASPI_ADBLOCK_LISTPATH', '/etc/raspap/adblock/');
define('RASPI_ADBLOCK_CONFIG', '/etc/dnsmasq.d/090_adblock.conf');
define('RASPI_HOSTAPD_CONFIG', '/etc/hostapd/hostapd.conf');
diff --git a/includes/defaults.php b/includes/defaults.php
index fb543d43..b69ef2aa 100755
--- a/includes/defaults.php
+++ b/includes/defaults.php
@@ -16,6 +16,7 @@ $defaults = [
// These are typical for default RPi installs. Modify if needed.
'RASPI_DNSMASQ_CONFIG' => '/etc/dnsmasq.d/090_raspap.conf',
'RASPI_DNSMASQ_LEASES' => '/var/lib/misc/dnsmasq.leases',
+ 'RASPI_DNSMASQ_ETH0' => '/etc/dnsmasq.d/090_eth0.conf',
'RASPI_ADBLOCK_LISTPATH' => '/etc/raspap/adblock/',
'RASPI_ADBLOCK_CONFIG' => '/etc/dnsmasq.d/090_adblock.conf',
'RASPI_HOSTAPD_CONFIG' => '/etc/hostapd/hostapd.conf',
From ab05bf15c79c3d1f61748d74d99e5d3143ae2220 Mon Sep 17 00:00:00 2001
From: billz
Date: Fri, 6 Nov 2020 09:05:43 +0000
Subject: [PATCH 05/79] Use dchp_eth0 to set toggle state
---
templates/dhcp/advanced.php | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/templates/dhcp/advanced.php b/templates/dhcp/advanced.php
index eeec4a2d..6d507416 100644
--- a/templates/dhcp/advanced.php
+++ b/templates/dhcp/advanced.php
@@ -52,17 +52,14 @@
-
-
-
From 3e101e4c55437ef0c8ee5f040196db1b7655a71a Mon Sep 17 00:00:00 2001
From: billz
Date: Mon, 9 Nov 2020 17:46:19 +0000
Subject: [PATCH 06/79] Add /bin/rm 090_eth0.conf to sudoers
---
installers/raspap.sudoers | 1 +
1 file changed, 1 insertion(+)
diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers
index 2109bece..21ed9371 100644
--- a/installers/raspap.sudoers
+++ b/installers/raspap.sudoers
@@ -22,6 +22,7 @@ www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/ovpnclient.ovpn /etc/openvpn/client/cli
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/authdata /etc/openvpn/client/login.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_raspap.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_eth0.conf
+www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/dnsmasq.d/090_eth0.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dhcpddata /etc/dhcpcd.conf
www-data ALL=(ALL) NOPASSWD:/sbin/shutdown -h now
www-data ALL=(ALL) NOPASSWD:/sbin/reboot
From 0049518769e95d5dd35f6c3cd227b250e858f5be Mon Sep 17 00:00:00 2001
From: billz
Date: Mon, 9 Nov 2020 17:46:55 +0000
Subject: [PATCH 07/79] Minor: update label
---
templates/dhcp/advanced.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/dhcp/advanced.php b/templates/dhcp/advanced.php
index 6d507416..bd158f27 100644
--- a/templates/dhcp/advanced.php
+++ b/templates/dhcp/advanced.php
@@ -57,7 +57,7 @@
-
eth0 configuration to DHCP and dnsmasq.") ?>
+
eth0 configuration for DHCP and dnsmasq.") ?>
From 6d14cbaee57cad280b1b921a274fea3cc432ccdc Mon Sep 17 00:00:00 2001
From: billz
Date: Mon, 9 Nov 2020 17:48:32 +0000
Subject: [PATCH 08/79] Handle dhcp for eth0, udpdate dhcpcd + dnsmasq.conf
---
includes/dhcp.php | 44 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 39 insertions(+), 5 deletions(-)
diff --git a/includes/dhcp.php b/includes/dhcp.php
index b1838214..4af64bce 100755
--- a/includes/dhcp.php
+++ b/includes/dhcp.php
@@ -81,15 +81,46 @@ function DisplayDHCPConfig()
$config .= "log-facility=/tmp/dnsmasq.log".PHP_EOL;
$config .= "conf-dir=/etc/dnsmasq.d".PHP_EOL;
-
file_put_contents("/tmp/dnsmasqdata", $config);
- system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_CONFIG, $return);
+
+ // handle DHCP for eth0 option
+ if ($_POST['dhcp-eth0'] == "1" && $_POST['interface'] == "eth0") {
+ $dhcp_cfg = file_get_contents(RASPI_DHCPCD_CONFIG);
+ if (!preg_match('/inteface eth0/', $dhcp_cnf)) {
+ // set dhcp values from ini, fallback to default if undefined
+ $eth0_cfg = parse_ini_file(RASPI_CONFIG_NETWORKING.'/eth0.ini', false, INI_SCANNER_RAW);
+ $ip_address = ($eth0_cfg['ip_address'] == '') ? '172.16.10.1/24' : $eth0_cfg['ip_address'];
+ $domain_name_server = ($eth0_cfg['domain_name_server'] =='') ? '1.1.1.1 8.8.8.8' : $eth0_cfg['domain_name_server'];
+
+ // append eth0 config to dhcpcd.conf
+ $cfg = $dhcp_conf;
+ $cfg[] = '# RaspAP '.$_POST['interface'].' configuration';
+ $cfg[] = 'interface '.$_POST['interface'];
+ $cfg[] = 'static ip_address='.$ip_address;
+ $cfg[] = 'static domain_name_server='.$domain_name_server;
+ $cfg[] = PHP_EOL;
+ $cfg = join(PHP_EOL, $cfg);
+ $dhcp_cfg .= $cfg;
+ file_put_contents("/tmp/dhcpddata", $dhcp_cfg);
+ system('sudo cp /tmp/dhcpddata '.RASPI_DHCPCD_CONFIG, $return);
+ $status->addMessage('DHCP configuration for eth0 added.', 'success');
+ }
+ system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_ETH0, $return);
+ $status->addMessage('Dnsmasq configuration for eth0 added.', 'success');
+ } elseif (!isset($_POST['dhcp-eth0']) && file_exists(RASPI_DNSMASQ_ETH0)) {
+ // todo: remove dhcpcd eth0 conf
+ system('sudo rm '.RASPI_DNSMASQ_ETH0, $return);
+ $status->addMessage('Dnsmasq configuration for eth0 removed.', 'success');
+ } else {
+ system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_CONFIG, $return);
+ }
+
} else {
$status->addMessage($errors, 'danger');
}
if ($return == 0) {
- $status->addMessage('Dnsmasq configuration updated successfully', 'success');
+ $status->addMessage('Dnsmasq configuration updated successfully.', 'success');
} else {
$status->addMessage('Dnsmasq configuration failed to be updated.', 'danger');
}
@@ -176,7 +207,9 @@ function DisplayDHCPConfig()
break;
}
}
-
+ if (file_exists(RASPI_DNSMASQ_ETH0)) {
+ $dhcp_eth0 = 1;
+ }
exec("ip -o link show | awk -F': ' '{print $2}'", $interfaces);
exec('cat ' . RASPI_DNSMASQ_LEASES, $leases);
@@ -198,7 +231,8 @@ function DisplayDHCPConfig()
"conf",
"dhcpHost",
"interfaces",
- "leases"
+ "leases",
+ "dhcp_eth0"
)
);
}
From e5f1d4ed0eef98376574f43358ce0af75c60586a Mon Sep 17 00:00:00 2001
From: billz
Date: Wed, 11 Nov 2020 12:40:22 +0000
Subject: [PATCH 09/79] Safe write dhcpcd.conf, validate static IP, handle
revert cfg
---
includes/dhcp.php | 56 +++++++++++++++++++++++++++++------------------
1 file changed, 35 insertions(+), 21 deletions(-)
diff --git a/includes/dhcp.php b/includes/dhcp.php
index 4af64bce..ff5505f0 100755
--- a/includes/dhcp.php
+++ b/includes/dhcp.php
@@ -85,30 +85,44 @@ function DisplayDHCPConfig()
// handle DHCP for eth0 option
if ($_POST['dhcp-eth0'] == "1" && $_POST['interface'] == "eth0") {
- $dhcp_cfg = file_get_contents(RASPI_DHCPCD_CONFIG);
- if (!preg_match('/inteface eth0/', $dhcp_cnf)) {
- // set dhcp values from ini, fallback to default if undefined
- $eth0_cfg = parse_ini_file(RASPI_CONFIG_NETWORKING.'/eth0.ini', false, INI_SCANNER_RAW);
- $ip_address = ($eth0_cfg['ip_address'] == '') ? '172.16.10.1/24' : $eth0_cfg['ip_address'];
- $domain_name_server = ($eth0_cfg['domain_name_server'] =='') ? '1.1.1.1 8.8.8.8' : $eth0_cfg['domain_name_server'];
+ if (!file_exists(RASPI_CONFIG_NETWORKING.'/eth0.ini') || filesize(RASPI_CONFIG_NETWORKING.'/eth0.ini') ==0 ) {
+ $status->addMessage('Static IP address for eth0 not found.', 'danger');
+ $status->addMessage('Configure this interface in Networking > eth0.', 'danger');
+ $return = 1;
+ } else {
+ $dhcp_cfg = file_get_contents(RASPI_DHCPCD_CONFIG);
+ if (!preg_match('/^interface\seth0$/m', $dhcp_cfg)) {
+ // set dhcp values from ini
+ $eth0_cfg = parse_ini_file(RASPI_CONFIG_NETWORKING.'/eth0.ini', false, INI_SCANNER_RAW);
+ $ip_address = $eth0_cfg['ip_address'];
+ $domain_name_server = ($eth0_cfg['domain_name_server'] =='') ? '1.1.1.1 8.8.8.8' : $eth0_cfg['domain_name_server'];
- // append eth0 config to dhcpcd.conf
- $cfg = $dhcp_conf;
- $cfg[] = '# RaspAP '.$_POST['interface'].' configuration';
- $cfg[] = 'interface '.$_POST['interface'];
- $cfg[] = 'static ip_address='.$ip_address;
- $cfg[] = 'static domain_name_server='.$domain_name_server;
- $cfg[] = PHP_EOL;
- $cfg = join(PHP_EOL, $cfg);
- $dhcp_cfg .= $cfg;
- file_put_contents("/tmp/dhcpddata", $dhcp_cfg);
- system('sudo cp /tmp/dhcpddata '.RASPI_DHCPCD_CONFIG, $return);
- $status->addMessage('DHCP configuration for eth0 added.', 'success');
+ // append eth0 config to dhcpcd.conf
+ $cfg = $dhcp_conf;
+ $cfg[] = '# RaspAP '.$_POST['interface'].' configuration';
+ $cfg[] = 'interface '.$_POST['interface'];
+ $cfg[] = 'static ip_address='.$ip_address;
+ $cfg[] = 'static domain_name_server='.$domain_name_server;
+ $cfg[] = PHP_EOL;
+ $cfg = join(PHP_EOL, $cfg);
+ $dhcp_cfg .= $cfg;
+ file_put_contents("/tmp/dhcpddata", $dhcp_cfg);
+ system('sudo cp /tmp/dhcpddata '.RASPI_DHCPCD_CONFIG, $return);
+ $status->addMessage('DHCP configuration for eth0 added.', 'success');
+ system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_ETH0, $return);
+ $status->addMessage('Dnsmasq configuration for eth0 added.', 'success');
+ } else {
+ $status->addMessage('DHCP for '.$_POST['interface'].' already enabled.', 'danger');
+ }
}
- system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_ETH0, $return);
- $status->addMessage('Dnsmasq configuration for eth0 added.', 'success');
} elseif (!isset($_POST['dhcp-eth0']) && file_exists(RASPI_DNSMASQ_ETH0)) {
- // todo: remove dhcpcd eth0 conf
+ // remove dhcpcd eth0 conf
+ $dhcp_cfg = file_get_contents(RASPI_DHCPCD_CONFIG);
+ $dhcp_cfg = preg_replace('/^#\sRaspAP\seth0.*(\n.*){3,}/m', '', $dhcp_cfg);
+ file_put_contents("/tmp/dhcpddata", $dhcp_cfg);
+ system('sudo cp /tmp/dhcpddata '.RASPI_DHCPCD_CONFIG, $return);
+ $status->addMessage('DHCP configuration for eth0 removed.', 'success');
+ // remove dnsmasq eth0 conf
system('sudo rm '.RASPI_DNSMASQ_ETH0, $return);
$status->addMessage('Dnsmasq configuration for eth0 removed.', 'success');
} else {
From e54e8b5bc0999ef391412ff0383bba9733fbcc57 Mon Sep 17 00:00:00 2001
From: billz
Date: Sun, 15 Nov 2020 10:51:09 +0000
Subject: [PATCH 10/79] Update const RASPI_DNSMASQ_PREFIX
---
config/config.php | 2 +-
includes/defaults.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/config/config.php b/config/config.php
index 90b96247..d80c8038 100755
--- a/config/config.php
+++ b/config/config.php
@@ -11,7 +11,7 @@ define('RASPI_CACHE_PATH', sys_get_temp_dir() . '/raspap');
// These are typical for default RPi installs. Modify if needed.
define('RASPI_DNSMASQ_CONFIG', '/etc/dnsmasq.d/090_raspap.conf');
define('RASPI_DNSMASQ_LEASES', '/var/lib/misc/dnsmasq.leases');
-define('RASPI_DNSMASQ_ETH0', '/etc/dnsmasq.d/090_eth0.conf');
+define('RASPI_DNSMASQ_PREFIX', '/etc/dnsmasq.d/090_');
define('RASPI_ADBLOCK_LISTPATH', '/etc/raspap/adblock/');
define('RASPI_ADBLOCK_CONFIG', '/etc/dnsmasq.d/090_adblock.conf');
define('RASPI_HOSTAPD_CONFIG', '/etc/hostapd/hostapd.conf');
diff --git a/includes/defaults.php b/includes/defaults.php
index b69ef2aa..e6ecab74 100755
--- a/includes/defaults.php
+++ b/includes/defaults.php
@@ -16,7 +16,7 @@ $defaults = [
// These are typical for default RPi installs. Modify if needed.
'RASPI_DNSMASQ_CONFIG' => '/etc/dnsmasq.d/090_raspap.conf',
'RASPI_DNSMASQ_LEASES' => '/var/lib/misc/dnsmasq.leases',
- 'RASPI_DNSMASQ_ETH0' => '/etc/dnsmasq.d/090_eth0.conf',
+ 'RASPI_DNSMASQ_PREFIX' => '/etc/dnsmasq.d/090_',
'RASPI_ADBLOCK_LISTPATH' => '/etc/raspap/adblock/',
'RASPI_ADBLOCK_CONFIG' => '/etc/dnsmasq.d/090_adblock.conf',
'RASPI_HOSTAPD_CONFIG' => '/etc/hostapd/hostapd.conf',
From 17da7cfcab0c6130a6a5ebe744107683b8d39623 Mon Sep 17 00:00:00 2001
From: billz
Date: Sun, 15 Nov 2020 10:51:51 +0000
Subject: [PATCH 11/79] Move enable DHCP option to general tab
---
templates/dhcp/advanced.php | 13 -------------
templates/dhcp/general.php | 16 ++++++++++++++++
2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/templates/dhcp/advanced.php b/templates/dhcp/advanced.php
index bd158f27..fda2eb00 100644
--- a/templates/dhcp/advanced.php
+++ b/templates/dhcp/advanced.php
@@ -47,19 +47,6 @@
-
-
-
diff --git a/templates/dhcp/general.php b/templates/dhcp/general.php
index e4023392..45b01c64 100644
--- a/templates/dhcp/general.php
+++ b/templates/dhcp/general.php
@@ -12,6 +12,22 @@
+
+
+
@@ -31,29 +25,29 @@
@@ -61,14 +55,14 @@
From 209d74136373c462ad70aa38569f21f189243c17 Mon Sep 17 00:00:00 2001
From: billz
Date: Mon, 16 Nov 2020 18:21:31 +0000
Subject: [PATCH 17/79] Remove parse DHCP, moved to AJAX handler
---
includes/dhcp.php | 64 +----------------------------------------------
1 file changed, 1 insertion(+), 63 deletions(-)
diff --git a/includes/dhcp.php b/includes/dhcp.php
index 449cdad1..e498b962 100755
--- a/includes/dhcp.php
+++ b/includes/dhcp.php
@@ -176,57 +176,6 @@ function DisplayDHCPConfig()
}
$serviceStatus = $dnsmasq_state ? "up" : "down";
-
- exec('cat '. RASPI_DNSMASQ_CONFIG, $return);
- $conf = ParseConfig($return);
- $arrRange = explode(",", $conf['dhcp-range']);
- $RangeStart = $arrRange[0];
- $RangeEnd = $arrRange[1];
- $RangeMask = $arrRange[2];
- $leaseTime = $arrRange[3];
- $dhcpHost = $conf["dhcp-host"];
- $dhcpHost = empty($dhcpHost) ? [] : $dhcpHost;
- $dhcpHost = is_array($dhcpHost) ? $dhcpHost : [ $dhcpHost ];
- $upstreamServers = is_array($conf['server']) ? $conf['server'] : [ $conf['server'] ];
- $upstreamServers = array_filter($upstreamServers);
-
- $DNS1 = '';
- $DNS2 = '';
- if (isset($conf['dhcp-option'])) {
- $arrDns = explode(",", $conf['dhcp-option']);
- if ($arrDns[0] == '6') {
- if (count($arrDns) > 1) {
- $DNS1 = $arrDns[1];
- }
- if (count($arrDns) > 2) {
- $DNS2 = $arrDns[2];
- }
- }
- }
-
- $hselected = '';
- $mselected = '';
- $dselected = '';
- $infiniteselected = '';
- preg_match('/([0-9]*)([a-z])/i', $leaseTime, $arrRangeLeaseTime);
- if ($leaseTime === 'infinite') {
- $infiniteselected = ' selected="selected"';
- } else {
- switch ($arrRangeLeaseTime[2]) {
- case 'h':
- $hselected = ' selected="selected"';
- break;
- case 'm':
- $mselected = ' selected="selected"';
- break;
- case 'd':
- $dselected = ' selected="selected"';
- break;
- }
- }
- if (file_exists(RASPI_DNSMASQ_PREFIX.$iface.'.conf')) {
- $dhcp_iface_enable = 1;
- }
exec("ip -o link show | awk -F': ' '{print $2}'", $interfaces);
exec('cat ' . RASPI_DNSMASQ_LEASES, $leases);
@@ -234,22 +183,11 @@ function DisplayDHCPConfig()
"dhcp", compact(
"status",
"serviceStatus",
- "RangeStart",
- "RangeEnd",
- "DNS1",
- "DNS2",
- "upstreamServers",
- "arrRangeLeaseTime",
- "mselected",
- "hselected",
- "dselected",
- "infiniteselected",
"dnsmasq_state",
"conf",
"dhcpHost",
"interfaces",
- "leases",
- "dhcp_iface_enable"
+ "leases"
)
);
}
From e4856484d9fe681b3f852c1db32eece737eca05e Mon Sep 17 00:00:00 2001
From: billz
Date: Tue, 17 Nov 2020 11:18:10 +0000
Subject: [PATCH 18/79] Add advanced fields to JSON response
---
ajax/networking/get_netcfg.php | 2 +-
app/js/custom.js | 2 ++
templates/dhcp/advanced.php | 2 +-
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/ajax/networking/get_netcfg.php b/ajax/networking/get_netcfg.php
index f2e735a4..c2710011 100644
--- a/ajax/networking/get_netcfg.php
+++ b/ajax/networking/get_netcfg.php
@@ -21,7 +21,7 @@ if (isset($interface)) {
$dhcpdata['dhcpHost'] = is_array($dhcpHost) ? $dhcpHost : [ $dhcpHost ];
$upstreamServers = is_array($conf['server']) ? $conf['server'] : [ $conf['server'] ];
$dhcpdata['upstreamServers'] = array_filter($upstreamServers);
-
+ $dhcpdata['upstreamServersEnabled'] = empty($conf['server']) ? false: true;
preg_match('/([0-9]*)([a-z])/i', $dhcpdata['leaseTime'], $arrRangeLeaseTime);
$dhcpdata['leaseTime'] = $arrRangeLeaseTime[1];
$dhcpdata['leaseTimeInterval'] = $arrRangeLeaseTime[2];
diff --git a/app/js/custom.js b/app/js/custom.js
index 0d8ce7f6..38d8e9f9 100644
--- a/app/js/custom.js
+++ b/app/js/custom.js
@@ -255,6 +255,8 @@ function loadInterfaceDHCPSelect() {
$('#txtdns1').val(jsonData.DNS1);
$('#txtdns2').val(jsonData.DNS2);
$('#cbxrangeleasetimeunits').val(jsonData.leaseTimeInterval);
+ $('#no-resolv')[0].checked = jsonData.upstreamServersEnabled;
+ $('#cbxdhcpupstreamserver').val(jsonData.upstreamServers[0]);
});
}
diff --git a/templates/dhcp/advanced.php b/templates/dhcp/advanced.php
index fda2eb00..69804d86 100644
--- a/templates/dhcp/advanced.php
+++ b/templates/dhcp/advanced.php
@@ -41,7 +41,7 @@
]/[domain/]][[#][@|[#]]"); ?>
-