mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
net/haproxy: add support for maps, closes #180
This commit is contained in:
+98
@@ -1005,4 +1005,102 @@ class SettingsController extends ApiControllerBase
|
||||
"name"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve mapfile settings or return defaults
|
||||
* @param $uuid item unique id
|
||||
* @return array
|
||||
*/
|
||||
public function getMapfileAction($uuid = null)
|
||||
{
|
||||
$mdlCP = new HAProxy();
|
||||
if ($uuid != null) {
|
||||
$node = $mdlCP->getNodeByReference('mapfiles.mapfile.'.$uuid);
|
||||
if ($node != null) {
|
||||
// return node
|
||||
return array("mapfile" => $node->getNodes());
|
||||
}
|
||||
} else {
|
||||
// generate new node, but don't save to disc
|
||||
$node = $mdlCP->mapfiles->mapfile->add();
|
||||
return array("mapfile" => $node->getNodes());
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* update mapfile with given properties
|
||||
* @param $uuid item unique id
|
||||
* @return array
|
||||
*/
|
||||
public function setMapfileAction($uuid)
|
||||
{
|
||||
if ($this->request->isPost() && $this->request->hasPost("mapfile")) {
|
||||
$mdlCP = new HAProxy();
|
||||
if ($uuid != null) {
|
||||
$node = $mdlCP->getNodeByReference('mapfiles.mapfile.'.$uuid);
|
||||
if ($node != null) {
|
||||
$node->setNodes($this->request->getPost("mapfile"));
|
||||
return $this->save($mdlCP, $node, "mapfile");
|
||||
}
|
||||
}
|
||||
}
|
||||
return array("result"=>"failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* add new mapfile and set with attributes from post
|
||||
* @return array
|
||||
*/
|
||||
public function addMapfileAction()
|
||||
{
|
||||
$result = array("result"=>"failed");
|
||||
if ($this->request->isPost() && $this->request->hasPost("mapfile")) {
|
||||
$mdlCP = new HAProxy();
|
||||
$node = $mdlCP->mapfiles->mapfile->Add();
|
||||
$node->setNodes($this->request->getPost("mapfile"));
|
||||
return $this->save($mdlCP, $node, "mapfile");
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete mapfile by uuid
|
||||
* @param $uuid item unique id
|
||||
* @return array status
|
||||
*/
|
||||
public function delMapfileAction($uuid)
|
||||
{
|
||||
$result = array("result"=>"failed");
|
||||
if ($this->request->isPost()) {
|
||||
$mdlCP = new HAProxy();
|
||||
if ($uuid != null) {
|
||||
if ($mdlCP->mapfiles->mapfile->del($uuid)) {
|
||||
// if item is removed, serialize to config and save
|
||||
$mdlCP->serializeToConfig();
|
||||
Config::getInstance()->save();
|
||||
$result['result'] = 'deleted';
|
||||
} else {
|
||||
$result['result'] = 'not found';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* search mapfiles
|
||||
* @return array
|
||||
*/
|
||||
public function searchMapfilesAction()
|
||||
{
|
||||
$this->sessionClose();
|
||||
$mdlCP = new HAProxy();
|
||||
$grid = new UIModelGrid($mdlCP->mapfiles->mapfile);
|
||||
return $grid->fetchBindRequest(
|
||||
$this->request,
|
||||
array("name", "description"),
|
||||
"name"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ class IndexController extends \OPNsense\Base\IndexController
|
||||
$this->view->formDialogAcl = $this->getForm("dialogAcl");
|
||||
$this->view->formDialogLua = $this->getForm("dialogLua");
|
||||
$this->view->formDialogErrorfile = $this->getForm("dialogErrorfile");
|
||||
$this->view->formDialogMapfile = $this->getForm("dialogMapfile");
|
||||
// set additional view parameters
|
||||
$mdlHAProxy = new \OPNsense\HAProxy\HAProxy();
|
||||
$this->view->showIntro = (string)$mdlHAProxy->general->showIntro;
|
||||
|
||||
@@ -354,4 +354,21 @@
|
||||
<type>textbox</type>
|
||||
<help><![CDATA[Specify a HAProxy rule/ACL that is currently not supported by the GUI.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<label>Parameters</label>
|
||||
<type>header</type>
|
||||
<style>type_table table_map_use_backend</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>action.map_use_backend_file</id>
|
||||
<label>Map file</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[HAProxy will extract the Host header from the HTTP request and search the map file for a match. If a match is found, the backend pool from the map file will be used.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<id>action.map_use_backend_default</id>
|
||||
<label>Default backend pool</label>
|
||||
<type>dropdown</type>
|
||||
<help><![CDATA[HAProxy will use this backend pool if no match is found in the map file.]]></help>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<form>
|
||||
<field>
|
||||
<id>mapfile.name</id>
|
||||
<label>Name</label>
|
||||
<type>text</type>
|
||||
<help>Name to identify this map file.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>mapfile.description</id>
|
||||
<label>Description</label>
|
||||
<type>text</type>
|
||||
<help>Description for this map file.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>mapfile.content</id>
|
||||
<label>Content</label>
|
||||
<type>textbox</type>
|
||||
<help><![CDATA[Paste the content of your map file here. See the <a target="_blank" href="http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#map">HAProxy documentation</a> for a full description.]]></help>
|
||||
</field>
|
||||
</form>
|
||||
@@ -1565,6 +1565,7 @@
|
||||
<OptionValues>
|
||||
<use_backend>Use specified Backend Pool</use_backend>
|
||||
<use_server>Override server in Backend Pool</use_server>
|
||||
<map_use_backend>Map domains to backend pools using a map file</map_use_backend>
|
||||
<http-request_allow>http-request allow</http-request_allow>
|
||||
<http-request_deny>http-request deny</http-request_deny>
|
||||
<http-request_tarpit>http-request tarpit</http-request_tarpit>
|
||||
@@ -1781,6 +1782,30 @@
|
||||
<actionValue type="TextField">
|
||||
<Required>N</Required>
|
||||
</actionValue>
|
||||
<map_use_backend_file type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.HAProxy.HAProxy</source>
|
||||
<items>mapfiles.mapfile</items>
|
||||
<display>name</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Related map file item not found</ValidationMessage>
|
||||
<Multiple>N</Multiple>
|
||||
<Required>N</Required>
|
||||
</map_use_backend_file>
|
||||
<map_use_backend_default type="ModelRelationField">
|
||||
<Model>
|
||||
<template>
|
||||
<source>OPNsense.HAProxy.HAProxy</source>
|
||||
<items>backends.backend</items>
|
||||
<display>name</display>
|
||||
</template>
|
||||
</Model>
|
||||
<ValidationMessage>Related backend pool item not found</ValidationMessage>
|
||||
<Multiple>N</Multiple>
|
||||
<Required>N</Required>
|
||||
</map_use_backend_default>
|
||||
</action>
|
||||
</actions>
|
||||
<luas>
|
||||
@@ -1843,5 +1868,25 @@
|
||||
</content>
|
||||
</errorfile>
|
||||
</errorfiles>
|
||||
<mapfiles>
|
||||
<mapfile type="ArrayField">
|
||||
<id type="UniqueIdField">
|
||||
<Required>Y</Required>
|
||||
</id>
|
||||
<name type="TextField">
|
||||
<mask>/^[^\t^,^;^\.^\[^\]^\{^\}]{1,255}$/u</mask>
|
||||
<ValidationMessage>Should be a string between 1 and 255 characters.</ValidationMessage>
|
||||
<Required>Y</Required>
|
||||
</name>
|
||||
<description type="TextField">
|
||||
<mask>/^.{1,255}$/u</mask>
|
||||
<ValidationMessage>Should be a string between 1 and 255 characters.</ValidationMessage>
|
||||
<Required>N</Required>
|
||||
</description>
|
||||
<content type="TextField">
|
||||
<Required>Y</Required>
|
||||
</content>
|
||||
</mapfile>
|
||||
</mapfiles>
|
||||
</items>
|
||||
</model>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<Acls VisibleName="ACLs" url="/ui/haproxy#acls"/>
|
||||
<Luas VisibleName="Lua Scripts" url="/ui/haproxy#luas"/>
|
||||
<Errorfiles VisibleName="Error Files" url="/ui/haproxy#errorfiles"/>
|
||||
<Mapfiles VisibleName="Map Files" url="/ui/haproxy#mapfiles"/>
|
||||
</Settings>
|
||||
<Statistics order="20" url="/ui/haproxy/statistics">
|
||||
<Overview VisibleName="Overview" url="/ui/haproxy/statistics#info"/>
|
||||
|
||||
@@ -146,6 +146,18 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
);
|
||||
|
||||
$("#grid-mapfiles").UIBootgrid(
|
||||
{ search:'/api/haproxy/settings/searchMapfiles',
|
||||
get:'/api/haproxy/settings/getMapfile/',
|
||||
set:'/api/haproxy/settings/setMapfile/',
|
||||
add:'/api/haproxy/settings/addMapfile/',
|
||||
del:'/api/haproxy/settings/delMapfile/',
|
||||
options: {
|
||||
rowCount:[10,25,50,100,500,1000]
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// hook into on-show event for dialog to extend layout.
|
||||
$('#DialogAcl').on('shown.bs.modal', function (e) {
|
||||
$("#acl\\.expression").change(function(){
|
||||
@@ -463,6 +475,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endif %}
|
||||
<li><a data-toggle="tab" id="errorfiles-tab" href="#errorfiles">{{ lang._('Error Messages') }}</a></li>
|
||||
<li><a data-toggle="tab" href="#luas">{{ lang._('Lua Scripts') }}</a></li>
|
||||
<li><a data-toggle="tab" href="#mapfiles">{{ lang._('Map Files') }}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -535,8 +548,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
<ul>
|
||||
<li>{{ lang._("%sError Messages:%s Return a custom message instead of errors generated by HAProxy. Useful to overwrite HAProxy's internal error messages. The message must represent the full HTTP response and include required HTTP headers.") | format('<b>', '</b>') }}</li>
|
||||
<li>{{ lang._("%sLua scripts:%s Include your own Lua code/scripts to extend HAProxy's functionality. The Lua code can be used in certain %sRules%s, for example.") | format('<b>', '</b>', '<b>', '</b>') }}</li>
|
||||
<li>{{ lang._("%sMap Files:%s A map allows to map a data in input to an other one on output. For example, this makes it possible to map a large number of domains to backend pools without using the GUI. Map files need to be used in %sRules%s, otherwise they are ignored.") | format('<b>', '</b>', '<b>', '</b>') }}</li>
|
||||
</ul>
|
||||
<p>{{ lang._("For more details visit HAProxy's official documentation regarding the %sError Messages%s and the %sLua Script%s features.") | format('<a href="http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4-errorfile" target="_blank">', '</a>', '<a href="http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#lua-load" target="_blank">', '</a>') }}</p>
|
||||
<p>{{ lang._("For more details visit HAProxy's official documentation regarding the %sError Messages%s, %sLua Script%s and the %sMap Files%s features.") | format('<a href="http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4-errorfile" target="_blank">', '</a>', '<a href="http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#lua-load" target="_blank">', '</a>', '<a href="http://cbonte.github.io/haproxy-dconv/1.8/configuration.html#map" target="_blank">', '</a>') }}</p>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -834,6 +848,40 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mapfiles" class="tab-pane fade">
|
||||
<!-- tab page "mapfiles" -->
|
||||
<table id="grid-mapfiles" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogMapfile">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-column-id="mapfileid" data-type="number" data-visible="false">{{ lang._('Map File ID') }}</th>
|
||||
<th data-column-id="name" data-type="string">{{ lang._('Map File Name') }}</th>
|
||||
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
|
||||
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
|
||||
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
|
||||
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<!-- apply button -->
|
||||
<div class="col-md-12">
|
||||
<hr/>
|
||||
<button class="btn btn-primary" id="reconfigureAct-mapfiles" type="button"><b>{{ lang._('Apply') }}</b><i id="reconfigureAct_progress" class=""></i></button>
|
||||
<button class="btn btn-primary" id="configtestAct-mapfiles" type="button"><b>{{ lang._('Test syntax') }}</b><i id="configtestAct_progress" class=""></i></button>
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# include dialogs #}
|
||||
@@ -845,3 +893,4 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogAcl,'id':'DialogAcl','label':lang._('Edit Condition')])}}
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogLua,'id':'DialogLua','label':lang._('Edit Lua Script')])}}
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogErrorfile,'id':'DialogErrorfile','label':lang._('Edit Error Message')])}}
|
||||
{{ partial("layout_partials/base_dialog",['fields':formDialogMapfile,'id':'DialogMapfile','label':lang._('Edit Map File')])}}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2016-2018 Frank Wall
|
||||
* Copyright (C) 2015 Deciso B.V.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// Use legacy code to export certificates to the filesystem.
|
||||
require_once("config.inc");
|
||||
require_once("certs.inc");
|
||||
require_once("legacy_bindings.inc");
|
||||
use OPNsense\Core\Config;
|
||||
|
||||
global $config;
|
||||
|
||||
// traverse HAProxy map files
|
||||
$configObj = Config::getInstance()->object();
|
||||
if (isset($configObj->OPNsense->HAProxy->mapfiles)) {
|
||||
foreach ($configObj->OPNsense->HAProxy->mapfiles->children() as $mapfile) {
|
||||
$mf_name = (string)$mapfile->name;
|
||||
$mf_id = (string)$mapfile->id;
|
||||
if ($mf_id != "") {
|
||||
$mf_content = htmlspecialchars_decode(str_replace("\r", "", (string)$mapfile->content));
|
||||
$mf_filename = "/var/etc/haproxy/mapfiles/" . $mf_id . ".txt";
|
||||
file_put_contents($mf_filename, $mf_content);
|
||||
chmod($mf_filename, 0600);
|
||||
echo "map file exported to " . $mf_filename . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
# NOTE: Keep /var/haproxy on this list, see GH issue opnsense/plugins #39.
|
||||
HAPROXY_DIRS="/var/haproxy /var/haproxy/var/run /var/etc/haproxy/ssl /var/etc/haproxy/lua /var/etc/haproxy/errorfiles"
|
||||
HAPROXY_DIRS="/var/haproxy /var/haproxy/var/run /var/etc/haproxy/ssl /var/etc/haproxy/lua /var/etc/haproxy/errorfiles /var/etc/haproxy/mapfiles"
|
||||
|
||||
for directory in ${HAPROXY_DIRS}; do
|
||||
mkdir -p ${directory}
|
||||
@@ -16,5 +16,6 @@ find /var/haproxy -type d -exec chmod 550 {} \;
|
||||
/usr/local/opnsense/scripts/OPNsense/HAProxy/exportCerts.php > /dev/null 2>&1
|
||||
/usr/local/opnsense/scripts/OPNsense/HAProxy/exportLuaScripts.php > /dev/null 2>&1
|
||||
/usr/local/opnsense/scripts/OPNsense/HAProxy/exportErrorFiles.php > /dev/null 2>&1
|
||||
/usr/local/opnsense/scripts/OPNsense/HAProxy/exportMapFiles.php > /dev/null 2>&1
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -306,6 +306,24 @@
|
||||
{% set action_enabled = '0' %}
|
||||
# ERROR: missing parameters
|
||||
{% endif %}
|
||||
{% elif action_data.type == 'map_use_backend' %}
|
||||
{# # First get the map file path #}
|
||||
{% if action_data.map_use_backend_file|default("") != "" %}
|
||||
{% set mapfile_data = helpers.getUUID(action_data.map_use_backend_file) %}
|
||||
{% set mapfile_path = '/var/etc/haproxy/mapfiles/' ~ mapfile_data.id ~ '.txt' %}
|
||||
{# # Check if a default backend is specified #}
|
||||
{% if action_data.map_use_backend_default|default("") != "" %}
|
||||
{% set defaultbackend_data = helpers.getUUID(action_data.map_use_backend_default) %}
|
||||
{% set defaultbackend_option = ',' ~ defaultbackend_data.name %}
|
||||
{% else %}
|
||||
{% set defaultbackend_option = '' %}
|
||||
{% endif %}
|
||||
{# # Finally add map file to config #}
|
||||
{% do action_options.append('use_backend %[req.hdr(host),lower,map_dom(' ~ mapfile_path ~ defaultbackend_option ~ ')]') %}
|
||||
{% else %}
|
||||
{% set action_enabled = '0' %}
|
||||
# ERROR: missing parameters
|
||||
{% endif %}
|
||||
{% elif action_data.type == 'http-request_allow' %}
|
||||
{% do action_options.append('http-request allow') %}
|
||||
{% elif action_data.type == 'http-request_deny' %}
|
||||
|
||||
Reference in New Issue
Block a user