WIP: Add Tor (#258)

* bootstrap tor

GUI: forms finished

add some models

add relay model

fix relay

tor: hidden acl

add controllers for General and Relay

working version of HiddenserviceController

hidden service acl is working

add socks policy

add config

* update torrc

* mark as dev preview

* update torrc

* add Fascist Mode, and some changes to relay

* update torrc: functional interface to ip; fix gui bug

* fix relation in torrc

* fix typo

* feedback from franco service file

* add transparent mode to model, form and template

* remove returns to break before service exec

* add service file

* adjust path to use the prefix, which comes from the original package

* improve call

* add exit node config

* generate a control password

* torrc: include key

* a /16 is a minimum requirement so the default should fit

* fix option values

* store key in config.xml

* add validations to Models

* add validation to hidden service

* remove _ from hostname regex

* add controller code for the query of the hostnames

* remove blocker returns

* ensure that _tor is in the pf group
This commit is contained in:
Fabian Franz
2017-09-17 12:43:34 +02:00
committed by GitHub
parent 08a1145670
commit e4be764929
39 changed files with 2371 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
PLUGIN_NAME= tor
PLUGIN_VERSION= 0.1
PLUGIN_COMMENT= The Onion Router
PLUGIN_DEPENDS= tor
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
PLUGIN_DEVEL= yes
.include "../../Mk/plugins.mk"
+65
View File
@@ -0,0 +1,65 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
function tor_enabled()
{
$model = new \OPNsense\Tor\General();
if ((string)$model->enabled == '1') {
return true;
}
return false;
}
function tor_firewall($fw)
{
if (tor_enabled()) {
}
}
function tor_services()
{
global $config;
$services = array();
if (tor_enabled()) {
$services[] = array(
'description' => gettext('The Onion Router'),
'configd' => array(
'restart' => array('tor restart'),
'start' => array('tor start'),
'stop' => array('tor stop'),
),
'name' => 'tor',
'pidfile' => '/var/run/tor/tor.pid'
);
}
return $services;
}
@@ -0,0 +1,169 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015 Jos Schellevis
* Copyright (C) 2017 Fabian Franz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Tor\Api;
use \OPNsense\Tor\ACLSocksPolicy;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
class ExitaclController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'exitpolicy';
static protected $internalModelClass = '\OPNsense\Tor\ACLExitPolicy';
public function searchaclAction()
{
$this->sessionClose();
$mdl = $this->getModel();
$grid = new UIModelGrid($mdl->policy);
return $grid->fetchBindRequest(
$this->request,
array('enabled', 'type', 'network', 'action', 'startport', 'endport')
);
}
public function getaclAction($uuid = null)
{
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference('policy.' . $uuid);
if ($node != null) {
// return node
return array('exitpolicy' => $node->getNodes());
}
} else {
$node = $mdl->policy->add();
return array('exitpolicy' => $node->getNodes());
}
return array();
}
public function addaclAction()
{
$result = array('result' => 'failed');
if ($this->request->isPost() && $this->request->hasPost('exitpolicy')) {
$result = array('result' => 'failed', 'validations' => array());
$mdl = $this->getModel();
$node = $mdl->policy->Add();
$node->setNodes($this->request->getPost('exitpolicy'));
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, 'exitpolicy', $msg->getField());
$result['validations'][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
$mdl->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result['result'] = 'saved';
}
}
return $result;
}
public function delaclAction($uuid)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
$mdl = $this->getModel();
if ($uuid != null) {
if ($mdl->policy->del($uuid)) {
$mdl->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setaclAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost('exitpolicy')) {
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference('policy.' . $uuid);
if ($node != null) {
$result = array('result' => 'failed', 'validations' => array());
$info = $this->request->getPost('exitpolicy');
$node->setNodes($info);
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, 'exitpolicy', $msg->getField());
$result['validations'][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
unset($result['validations']);
Config::getInstance()->save();
$result = array('result' => 'saved');
}
return $result;
}
}
}
return array('result' => 'failed');
}
public function toggle_handler($uuid, $element)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference($element . '.' . $uuid);
if ($node != null) {
if ($node->enabled->__toString() == '1') {
$result['result'] = 'Disabled';
$node->enabled = '0';
} else {
$result['result'] = 'Enabled';
$node->enabled = '1';
}
$mdl->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
}
public function toggleaclAction($uuid)
{
return $this->toggle_handler($uuid, 'policy');
}
}
@@ -0,0 +1,73 @@
<?php
/**
* Copyright (C) 2017 Fabian Franz
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\Tor\Api;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Core\Backend;
use \OPNsense\Core\Config;
use \OPNsense\Tor\General;
class GeneralController extends ApiMutableModelControllerBase
{
static protected $internalModelClass = '\OPNsense\Tor\General';
static protected $internalModelName = 'general';
/* override default set action */
public function setAction()
{
$result = array('result'=>'failed');
if ($this->request->isPost()) {
$mdl = new General();
$mdl->setNodes($this->request->getPost('general'));
// perform validation
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists('validations', $result)) {
$result['validations'] = array();
}
$result['validations']['general.'.$msg->getField()] = $msg->getMessage();
}
if ($valMsgs->count() == 0) {
if (empty((string)$mdl->control_port_password) || empty((string)$mdl->control_port_password_hashed)) {
$backend = new Backend();
$keys = json_decode(trim($backend->configdRun('tor genkey')), true);
$mdl->control_port_password_hashed = $keys['hashed_control_password'];
$mdl->control_port_password = $keys['control_password'];
}
$mdl->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'saved';
}
}
return $result;
}
}
@@ -0,0 +1,171 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015 Jos Schellevis
* Copyright (C) 2017 Fabian Franz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Tor\Api;
use \OPNsense\Tor\HiddenService;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
class HiddenserviceController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'hiddenservice';
static protected $internalModelClass = '\OPNsense\Tor\HiddenService';
public function searchserviceAction()
{
$this->sessionClose();
$mdl = $this->getModel();
$grid = new UIModelGrid($mdl->service);
return $grid->fetchBindRequest(
$this->request,
array('enabled', 'name')
);
}
public function getserviceAction($uuid = null)
{
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference('service.' . $uuid);
if ($node != null) {
// return node
return array('hiddenservice' => $node->getNodes());
}
} else {
$node = $mdl->service->add();
return array('hiddenservice' => $node->getNodes());
}
return array();
}
public function addserviceAction()
{
$result = array('result' => 'failed');
if ($this->request->isPost() && $this->request->hasPost('hiddenservice')) {
$result = array('result' => 'failed', 'validations' => array());
$mdl = $this->getModel();
$node = $mdl->service->Add();
$node->setNodes($this->request->getPost('hiddenservice'));
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, 'hiddenservice', $msg->getField());
$result['validations'][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result['result'] = 'saved';
}
}
return $result;
}
public function delserviceAction($uuid)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
$mdl = $this->getModel();
if ($uuid != null) {
if ($mdl->service->del($uuid)) {
$mdl->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setserviceAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost('hiddenservice')) {
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference('service.' . $uuid);
if ($node != null) {
$result = array('result' => 'failed', 'validations' => array());
$info = $this->request->getPost('hiddenservice');
$node->setNodes($info);
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, 'hiddenservice', $msg->getField());
$result['validations'][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
unset($result['validations']);
Config::getInstance()->save();
$result = array('result' => 'saved');
}
return $result;
}
}
}
return array('result' => 'failed');
}
public function toggle_handler($uuid, $element)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference($element . '.' . $uuid);
if ($node != null) {
if ($node->enabled->__toString() == '1') {
$result['result'] = 'Disabled';
$node->enabled = '0';
} else {
$result['result'] = 'Enabled';
$node->enabled = '1';
}
// if item has toggled, serialize to config and save
$mdl->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
}
public function toggleserviceAction($uuid)
{
return $this->toggle_handler($uuid, 'service');
}
}
@@ -0,0 +1,170 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015 Jos Schellevis
* Copyright (C) 2017 Fabian Franz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Tor\Api;
use \OPNsense\Tor\HiddenServiceACL;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
class HiddenserviceaclController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'hiddenserviceacl';
static protected $internalModelClass = '\OPNsense\Tor\HiddenServiceACL';
public function searchaclAction()
{
$this->sessionClose();
$mdl = $this->getModel();
$grid = new UIModelGrid($mdl->hiddenserviceacl);
return $grid->fetchBindRequest(
$this->request,
array('enabled', 'hiddenservice', 'port', 'target_host', 'target_port')
);
}
public function getaclAction($uuid = null)
{
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference('hiddenserviceacl.' . $uuid);
if ($node != null) {
// return node
return array('hiddenserviceacl' => $node->getNodes());
}
} else {
$node = $mdl->hiddenserviceacl->add();
return array('hiddenserviceacl' => $node->getNodes());
}
return array();
}
public function addaclAction()
{
$result = array('result' => 'failed');
if ($this->request->isPost() && $this->request->hasPost('hiddenserviceacl')) {
$result = array('result' => 'failed', 'validations' => array());
$mdl = $this->getModel();
$node = $mdl->hiddenserviceacl->Add();
$node->setNodes($this->request->getPost('hiddenserviceacl'));
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, 'hiddenserviceacl', $msg->getField());
$result['validations'][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result['result'] = 'saved';
}
}
return $result;
}
public function delaclAction($uuid)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
$mdl = $this->getModel();
if ($uuid != null) {
if ($mdl->hiddenserviceacl->del($uuid)) {
$mdl->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setaclAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost('hiddenserviceacl')) {
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference('hiddenserviceacl.' . $uuid);
if ($node != null) {
$result = array('result' => 'failed', 'validations' => array());
$info = $this->request->getPost('hiddenserviceacl');
$node->setNodes($info);
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, 'hiddenserviceacl', $msg->getField());
$result['validations'][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
unset($result['validations']);
Config::getInstance()->save();
$result = array('result' => 'saved');
}
return $result;
}
}
}
return array('result' => 'failed');
}
public function toggle_handler($uuid, $element)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference($element . '.' . $uuid);
if ($node != null) {
if ($node->enabled->__toString() == '1') {
$result['result'] = 'Disabled';
$node->enabled = '0';
} else {
$result['result'] = 'Enabled';
$node->enabled = '1';
}
$mdl->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
}
public function toggleaclAction($uuid)
{
return $this->toggle_handler($uuid, 'hiddenserviceacl');
}
}
@@ -0,0 +1,38 @@
<?php
/**
* Copyright (C) 2017 Fabian Franz
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\Tor\Api;
use \OPNsense\Base\ApiMutableModelControllerBase;
class RelayController extends ApiMutableModelControllerBase
{
static protected $internalModelClass = '\OPNsense\Tor\Relay';
static protected $internalModelName = 'relay';
}
@@ -0,0 +1,160 @@
<?php
/**
* Copyright (C) 2015 - 2017 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\Tor\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Core\Backend;
use \OPNsense\Tor\General;
/**
* Class ServiceController
* @package OPNsense\Tor
*/
class ServiceController extends ApiControllerBase
{
/**
* start tor service
* @return array
*/
public function startAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('tor start');
$backend->configdRun('filter reload');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* stop tor service
* @return array
*/
public function stopAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('tor stop');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* query tor hidden service hostnames
* @return array
*/
public function get_hidden_servicesAction()
{
$backend = new Backend();
$response = json_decode($backend->configdRun('tor gethostnames'));
return array('response' => $response);
}
/**
* restart tor service
* @return array
*/
public function restartAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('tor restart');
$backend->configdRun('filter reload');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* retrieve status of tor
* @return array
* @throws \Exception
*/
public function statusAction()
{
$backend = new Backend();
$general = new General();
$response = $backend->configdRun('tor status');
if (strpos($response, 'not running') > 0) {
if ($general->enabled->__toString() == 1) {
$status = 'stopped';
} else {
$status = 'disabled';
}
} elseif (strpos($response, 'is running') > 0) {
$status = 'running';
} elseif ($general->enabled->__toString() == 0) {
$status = 'disabled';
} else {
$status = 'unknown';
}
return array('status' => $status);
}
/**
* reconfigure tor, generate config and reload
*/
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$general = new General();
$backend = new Backend();
$runStatus = $this->statusAction();
// stop tor if it is running or not
$this->stopAction();
// generate template
$backend->configdRun('template reload OPNsense/Tor');
// (re)start daemon
if ($general->enabled->__toString() == 1) {
$this->startAction();
}
return array('status' => 'ok');
} else {
return array('status' => 'failed');
}
}
}
@@ -0,0 +1,169 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015 Jos Schellevis
* Copyright (C) 2017 Fabian Franz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Tor\Api;
use \OPNsense\Tor\ACLSocksPolicy;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
class SocksaclController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'policy';
static protected $internalModelClass = '\OPNsense\Tor\ACLSocksPolicy';
public function searchaclAction()
{
$this->sessionClose();
$mdl = $this->getModel();
$grid = new UIModelGrid($mdl->policy);
return $grid->fetchBindRequest(
$this->request,
array('enabled', 'type', 'network', 'action')
);
}
public function getaclAction($uuid = null)
{
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference('policy.' . $uuid);
if ($node != null) {
// return node
return array('policy' => $node->getNodes());
}
} else {
$node = $mdl->policy->add();
return array('policy' => $node->getNodes());
}
return array();
}
public function addaclAction()
{
$result = array('result' => 'failed');
if ($this->request->isPost() && $this->request->hasPost('policy')) {
$result = array('result' => 'failed', 'validations' => array());
$mdl = $this->getModel();
$node = $mdl->policy->Add();
$node->setNodes($this->request->getPost('policy'));
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, 'policy', $msg->getField());
$result['validations'][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
$mdl->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result['result'] = 'saved';
}
}
return $result;
}
public function delaclAction($uuid)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
$mdl = $this->getModel();
if ($uuid != null) {
if ($mdl->policy->del($uuid)) {
$mdl->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setaclAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost('policy')) {
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference('policy.' . $uuid);
if ($node != null) {
$result = array('result' => 'failed', 'validations' => array());
$info = $this->request->getPost('policy');
$node->setNodes($info);
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, 'policy', $msg->getField());
$result['validations'][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
unset($result['validations']);
Config::getInstance()->save();
$result = array('result' => 'saved');
}
return $result;
}
}
}
return array('result' => 'failed');
}
public function toggle_handler($uuid, $element)
{
$result = array('result' => 'failed');
if ($this->request->isPost()) {
$mdl = $this->getModel();
if ($uuid != null) {
$node = $mdl->getNodeByReference($element . '.' . $uuid);
if ($node != null) {
if ($node->enabled->__toString() == '1') {
$result['result'] = 'Disabled';
$node->enabled = '0';
} else {
$result['result'] = 'Enabled';
$node->enabled = '1';
}
$mdl->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
}
public function toggleaclAction($uuid)
{
return $this->toggle_handler($uuid, 'policy');
}
}
@@ -0,0 +1,51 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Tor;
/**
* Class IndexController
* @package OPNsense/Tor
*/
class IndexController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext("The Onion Router");
$this->view->general = $this->getForm("general");
$this->view->toracl = $this->getForm("acl_sockspolicy");
$this->view->hidden_service = $this->getForm("hidden_service");
$this->view->hidden_service_acl = $this->getForm("hidden_service_acl");
$this->view->relay = $this->getForm("relay");
$this->view->exitpolicy = $this->getForm("acl_exitpolicy");
$this->view->pick('OPNsense/Tor/general');
}
}
@@ -0,0 +1,37 @@
<form>
<field>
<id>exitpolicy.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>Enabling this will write the policy to the config file.</help>
</field>
<field>
<id>exitpolicy.type</id>
<label>Protocol</label>
<type>dropdown</type>
</field>
<field>
<id>exitpolicy.network</id>
<label>Network</label>
<type>text</type>
<help>Network on which this ACL is appied.</help>
</field>
<field>
<id>exitpolicy.startport</id>
<label>Start Port</label>
<type>text</type>
<help>Begin of the port range or the port used by this ACL.</help>
</field>
<field>
<id>exitpolicy.endport</id>
<label>End Port</label>
<type>text</type>
<help>Enter an end port if you want to use a port range.</help>
</field>
<field>
<id>exitpolicy.action</id>
<label>Action</label>
<type>dropdown</type>
<help>Reject: Do not allow the connection; Accept: Pass the connection</help>
</field>
</form>
@@ -0,0 +1,25 @@
<form>
<field>
<id>policy.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>Enabling this will write the policy to the config file.</help>
</field>
<field>
<id>policy.type</id>
<label>Protocol</label>
<type>dropdown</type>
</field>
<field>
<id>policy.network</id>
<label>Network</label>
<type>text</type>
<help>Network on which this ACL is appied.</help>
</field>
<field>
<id>policy.action</id>
<label>Action</label>
<type>dropdown</type>
<help>Reject: Do not allow the connection; Accept: Pass the connection</help>
</field>
</form>
@@ -0,0 +1,104 @@
<form>
<field>
<id>general.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>This will activate the onion router.</help>
</field>
<field>
<id>general.socks_listen_ip</id>
<label>Listen Interfaces</label>
<type>select_multiple</type>
<style>dropdownstyle</style>
<help>Add more than localhost IP addresses to listen IPs for SOCKS connections.</help>
</field>
<field>
<id>general.socks_listen_port</id>
<label>SOCKS Port Number</label>
<type>text</type>
<help>Port number on which the SOCKS server should listen. The default is 9050. You should not change this unless you need the port.</help>
<advanced>true</advanced>
</field>
<field>
<id>general.control_port</id>
<label>Control Port</label>
<type>text</type>
<help>Control Port number on which tor should listen. The default is 9051. You should not change this unless you need the port.</help>
<advanced>true</advanced>
</field>
<field>
<id>general.enablelogfile</id>
<label>Create a logfile</label>
<type>checkbox</type>
<help>If you check this, a log file will be written to disk.</help>
</field>
<field>
<id>general.logfilelevel</id>
<label>Logfile level</label>
<type>dropdown</type>
<style>dropdownstyle</style>
<help>This is the detail level of the log. A higher level means more data is logged.</help>
</field>
<field>
<id>general.enablesyslog</id>
<label>Send log messages to syslog</label>
<type>checkbox</type>
<help>Syslog is a service which is made to collect log messages from different software and maybe to a central logging server. Check this box if you have such a setup.</help>
</field>
<field>
<id>general.sysloglevel</id>
<label>Syslog level</label>
<type>dropdown</type>
<style>dropdownstyle</style>
<help>This is the detail level of the log. A higher level means more data is logged.</help>
</field>
<field>
<id>general.fascist_firewall</id>
<label>Fascist Mode</label>
<type>checkbox</type>
<help>This try to circumvent censorship. Please note that the fascist mode does not support "Hidden Services".</help>
</field>
<field>
<id>general.fascist_firewall_ports</id>
<label>Fascist Firewall Ports</label>
<type>select_multiple</type>
<help>Open ports by the fascist firewall.</help>
<allownew>true</allownew>
<style>tokenize</style>
</field>
<field>
<id>general.enable_transparent</id>
<label>Enable Transparent Proxy</label>
<type>checkbox</type>
<help>Enable this, if you want to anonymize traffic originating from a network.</help>
<advanced>true</advanced>
</field>
<field>
<id>general.transparent_port</id>
<label>Transparent Port</label>
<type>text</type>
<help>Port number on which the transparent proxy server should listen. The default is 9040. You should not change this unless you need the port.</help>
<advanced>true</advanced>
</field>
<field>
<id>general.transparent_dns</id>
<label>Transparent DNS Port</label>
<type>text</type>
<help>Port number on which the transparent DNS server should listen. The default is 9053. You should not change this unless you need the port.</help>
<advanced>true</advanced>
</field>
<field>
<id>general.transparent_ip_pool</id>
<label>Transparent IP Pool</label>
<type>text</type>
<help>Enter a network which will be used as an IP Pool to map onion Hosts.</help>
<advanced>true</advanced>
</field>
<field>
<id>general.dns_map_hosts</id>
<label>Map Host To IP Pool</label>
<type>checkbox</type>
<help>Enable this, if you want to map onion services to the IP pool configured above.</help>
<advanced>true</advanced>
</field>
</form>
@@ -0,0 +1,14 @@
<form>
<field>
<id>hiddenservice.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>Enable this hidden service.</help>
</field>
<field>
<id>hiddenservice.name</id>
<label>Name</label>
<type>text</type>
<help>Enter a directory name for the hidden service. It may consist of lowercase and uppercase characters.</help>
</field>
</form>
@@ -0,0 +1,31 @@
<form>
<field>
<id>hiddenserviceacl.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>Enable this hidden service.</help>
</field>
<field>
<id>hiddenserviceacl.hiddenservice</id>
<label>Hidden Service</label>
<type>dropdown</type>
</field>
<field>
<id>hiddenserviceacl.port</id>
<label>Port</label>
<type>text</type>
<help>The port number which is exposed in the Tor network.</help>
</field>
<field>
<id>hiddenserviceacl.target_host</id>
<label>Target Host</label>
<type>text</type>
<help>The Target host. Be careful when using localhost as some services may bypass ACLs when connecting from "127.0.0.1" or "::1".</help>
</field>
<field>
<id>hiddenserviceacl.target_port</id>
<label>Target Port</label>
<type>text</type>
<help>Enter the port of your target server.</help>
</field>
</form>
@@ -0,0 +1,62 @@
<form>
<field>
<id>relay.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>Act as a relay.</help>
</field>
<field>
<id>relay.host</id>
<label>Host</label>
<type>text</type>
<advanced>true</advanced>
</field>
<field>
<id>relay.port</id>
<label>Port</label>
<type>text</type>
</field>
<field>
<id>relay.address</id>
<label>Address</label>
<type>text</type>
<help>The external FQDN of this host.</help>
</field>
<field>
<id>relay.nick</id>
<label>Nickname</label>
<type>text</type>
<help>This may only consist of characters and numbers and is used to identifiy your host.</help>
</field>
<field>
<id>relay.bandwithrate</id>
<label>Bandwith Rate</label>
<type>text</type>
</field>
<field>
<id>relay.bandwithburst</id>
<label>Bandwith Burst</label>
<type>text</type>
</field>
<field>
<id>relay.directory_port</id>
<label>Directory Port</label>
<type>text</type>
</field>
<field>
<id>relay.exitrejectprivateip</id>
<label>Reject Private IPs</label>
<type>checkbox</type>
</field>
<field>
<id>relay.relay</id>
<label>Bridge</label>
<type>checkbox</type>
<help>A bridge is a private relay. It is not visible in the public directory. Check this if you want to become a relay (public).</help>
</field>
<field>
<id>relay.publish</id>
<label>Publish Server Descriptor</label>
<type>checkbox</type>
</field>
</form>
@@ -0,0 +1,9 @@
<acl>
<page-tor>
<name>tor</name>
<patterns>
<pattern>ui/tor/*</pattern>
<pattern>api/tor/*</pattern>
</patterns>
</page-tor>
</acl>
@@ -0,0 +1,34 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Tor;
use OPNsense\Base\BaseModel;
class ACLExitPolicy extends BaseModel
{
}
@@ -0,0 +1,43 @@
<model>
<mount>//OPNsense/tor/exitpolicy</mount>
<description>ACL for Socks port</description>
<items>
<policy type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<type type="OptionField">
<default>v6</default>
<Required>Y</Required>
<OptionValues>
<v4>IPv4</v4>
<v6>IPv6</v6>
</OptionValues>
</type>
<network type="NetworkField">
<Required>Y</Required>
</network>
<startport type="IntegerField">
<MinimumValue>1</MinimumValue>
<Required>N</Required>
<MaximumValue>65535</MaximumValue>
<ValidationMessage>A valid Port number must be specified.</ValidationMessage>
</startport>
<endport type="IntegerField">
<MinimumValue>1</MinimumValue>
<Required>N</Required>
<MaximumValue>65535</MaximumValue>
<ValidationMessage>A valid Port number must be specified.</ValidationMessage>
</endport>
<action type="OptionField">
<default>accept</default>
<Required>Y</Required>
<OptionValues>
<accept>Accept</accept>
<reject>Reject</reject>
</OptionValues>
</action>
</policy>
</items>
</model>
@@ -0,0 +1,34 @@
<?php
namespace OPNsense\Tor;
use OPNsense\Base\BaseModel;
/*
Copyright (C) 2017 Fabian Franz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
class ACLSocksPolicy extends BaseModel
{
}

Some files were not shown because too many files have changed in this diff Show More