v6.3.10.0

Changelog: https://roxy-wi.org/changelog#6_3_10
pull/364/head
Aidaho 2023-04-17 18:01:01 +03:00
parent db22bf0884
commit 7863fa108a
8 changed files with 202 additions and 38 deletions

View File

@ -157,13 +157,15 @@ def get_server(server_id, service):
'master': s[6],
'creds': s[7]
}
except Exception:
data = ''
except Exception as e:
data = {server_id: {"error": f"{e}"}}
return dict(error=data)
return dict(server=data)
def get_status(server_id, service):
if service != 'apache' and service != 'nginx' and service != 'haproxy':
if service not in ('apache', 'nginx', 'haproxy', 'keepalived'):
return dict(status='wrong service')
try:
servers = check_permit_to_server(server_id, service=service)
@ -240,9 +242,9 @@ def get_all_statuses():
def actions(server_id, action, service):
if action != 'start' and action != 'stop' and action != 'restart' and action != 'reload':
if action not in ('start', 'stop', 'restart', 'reload'):
return dict(status='wrong action')
if service != 'apache' and service != 'nginx' and service != 'haproxy' and service != 'keepalived':
if service not in ('apache', 'nginx', 'haproxy', 'keepalived'):
return dict(status='wrong service')
try:
@ -254,7 +256,6 @@ def actions(server_id, action, service):
cmd = ["sudo systemctl %s %s" % (action, service)]
error = server_mod.ssh_command(s[2], cmd)
done = error if error else 'done'
data = {'server_id': s[0], 'ip': s[2], 'action': action, 'hostname': s[1], 'status': done}
return dict(status=data)
@ -263,7 +264,6 @@ def actions(server_id, action, service):
def runtime(server_id):
data = {}
try:
body = request.body.getvalue().decode('utf-8')
json_loads = json.loads(body)
@ -275,7 +275,6 @@ def runtime(server_id):
for s in servers:
out = server_mod.ssh_command(s[2], cmd)
data = {server_id: {}}
sep_data = out.split('\r\n')
data = {server_id: sep_data}
@ -418,7 +417,7 @@ def edit_section(server_id, delete=0):
def upload_config(server_id, **kwargs):
service = kwargs.get('service')
if service != 'apache' and service != 'nginx' and service != 'haproxy':
if service not in ('apache', 'nginx', 'haproxy', 'keepalived'):
return dict(status='wrong service')
body = request.body.getvalue().decode('utf-8')
@ -592,7 +591,8 @@ def add_acl(server_id):
out = config_mod.get_config(server_ip, cfg)
start_line, end_line, config_read = section_mod.get_section_from_config(cfg, section_name)
except Exception as e:
status = "Cannot read section: " + str(e)
data = {server_id: {"error": f"Cannot read section: {e}"}}
return dict(error=data)
try:
config_read += acl
@ -601,9 +601,11 @@ def add_acl(server_id):
with open(cfg, "w") as conf:
conf.write(config)
except IOError as e:
status = "Cannot read import config file: " + str(e)
data = {server_id: {"error": f"Cannot read import config file: {e}"}}
return dict(error=data)
except Exception as e:
status = str(e)
data = {server_id: {"error": f"{e}"}}
return dict(error=data)
try:
out = config_mod.master_slave_upload_and_restart(server_ip, cfg, just_save=save)
@ -612,7 +614,8 @@ def add_acl(server_id):
else:
status = 'ACL has been added'
except Exception as e:
status = str(e)
data = {server_id: {"error": f"{e}"}}
return dict(error=data)
data = {'acl': status}
return dict(data)
@ -623,19 +626,18 @@ def del_acl(server_id):
json_loads = json.loads(body)
save = json_loads['action']
section_name = json_loads['section-name']
acl = generate_acl()
servers = check_permit_to_server(server_id)
status = ''
for s in servers:
cfg = '/tmp/' + s[2] + '.cfg'
server_ip = s[2]
cfg = f'/tmp/{server_ip}.cfg'
try:
out = config_mod.get_config(server_ip, cfg)
start_line, end_line, config_read = section_mod.get_section_from_config(cfg, section_name)
except Exception as e:
status = str(e)
data = {server_id: {"error": f"{e}"}}
return dict(error=data)
try:
config_new_read = ''
@ -644,7 +646,8 @@ def del_acl(server_id):
if line != '':
config_new_read += line + '\n'
except Exception as e:
status = 'Cannot delete ACL: ' + str(e)
data = {server_id: {"error": f"Cannot delete ACL: {e}"}}
return dict(error=data)
try:
config = config_mod.master_slave_upload_and_restart(start_line, end_line, cfg, config_new_read)
@ -652,9 +655,11 @@ def del_acl(server_id):
with open(cfg, "w") as conf:
conf.write(config)
except IOError as e:
status = "Cannot read import config file: " + str(e)
data = {server_id: {"error": f"Cannot read import config file: {e}"}}
return dict(error=data)
except Exception as e:
status = 'Cannot delete ACL: ' + str(e)
data = {server_id: {"error": f"Cannot delete ACL: {e}"}}
return dict(error=data)
try:
out = config_mod.master_slave_upload_and_restart(server_ip, cfg, just_save=save)
@ -663,7 +668,8 @@ def del_acl(server_id):
else:
status = 'ACL has been deleted'
except Exception as e:
status = str(e)
data = {server_id: {"error": f"{e}"}}
return dict(error=data)
return dict(acl=status)

View File

@ -82,6 +82,7 @@ elif form.getvalue('mode') is not None:
ssl = ""
ssl_check = ""
backend = ""
headers = ''
acl = ""
servers_split = ""
new_listener = form.getvalue('listener')
@ -210,6 +211,20 @@ elif form.getvalue('mode') is not None:
if form.getvalue('dynamic'):
options_split += f" dynamic-cookie-key {form.getvalue('dynamic-cookie-key')}\n"
if form.getvalue('headers_method'):
headers_res = form.getlist('headers_res')
headers_method = form.getlist('headers_method')
header_name = form.getlist('header_name')
header_value = form.getlist('header_value')
i = 0
for h in headers_method:
if headers_method[i] != 'del-header':
headers += f' {headers_res[i]} {headers_method[i]} {header_name[i]} {header_value[i]}\n'
else:
headers += f' {headers_res[i]} {headers_method[i]} {header_name[i]}\n'
i += 1
if form.getvalue('acl_if'):
acl_if = form.getlist('acl_if')
acl_value = form.getlist('acl_value')
@ -339,7 +354,7 @@ elif form.getvalue('mode') is not None:
waf += " http-request deny if { var(txn.modsec.code) -m int gt 0 }\n"
config_add = f"\n{name}\n{bind}{mode}{maxconn}{balance}{options_split}{cache_s}{filter_com}{compression_s}" \
f"{waf}{acl}{backend}{servers_split}\n{cache_set}\n"
f"{waf}{headers}{acl}{backend}{servers_split}\n{cache_set}\n"
if form.getvalue('new_userlist') is not None:
name = f"userlist {form.getvalue('new_userlist')}\n"

View File

@ -56,10 +56,17 @@ def alert_routing(
if alert_type == 'service' and setting.service_alert:
try:
telegram_send_mess(mes, level, channel_id=setting.telegram_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to Telegram: {e}', roxywi=1)
try:
slack_send_mess(mes, level, channel_id=setting.slack_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to Slack: {e}', roxywi=1)
try:
pd_send_mess(mes, level, server_ip, service_id, alert_type, channel_id=setting.pd_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message: {e}', roxywi=1)
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to PagerDuty: {e}', roxywi=1)
if setting.email:
send_email_to_server_group(subject, mes, level, group_id)
@ -67,10 +74,16 @@ def alert_routing(
if alert_type == 'backend' and setting.backend_alert:
try:
telegram_send_mess(mes, level, channel_id=setting.telegram_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to Telegram: {e}', roxywi=1)
try:
slack_send_mess(mes, level, channel_id=setting.slack_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to Slack: {e}', roxywi=1)
try:
pd_send_mess(mes, level, server_ip, service_id, alert_type, channel_id=setting.pd_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message: {e}', roxywi=1)
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to PagerDuty: {e}', roxywi=1)
if setting.email:
send_email_to_server_group(subject, mes, level, group_id)
@ -78,10 +91,16 @@ def alert_routing(
if alert_type == 'maxconn' and setting.maxconn_alert:
try:
telegram_send_mess(mes, level, channel_id=setting.telegram_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to Telegram: {e}', roxywi=1)
try:
slack_send_mess(mes, level, channel_id=setting.slack_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to Slack: {e}', roxywi=1)
try:
pd_send_mess(mes, level, server_ip, service_id, alert_type, channel_id=setting.pd_id)
except Exception as e:
roxywi_common.logging('Roxy-WI server', f'error: unable to send message: {e}', roxywi=1)
roxywi_common.logging('Roxy-WI server', f'error: unable to send message to PagerDuty: {e}', roxywi=1)
if setting.email:
send_email_to_server_group(subject, mes, level, group_id)

View File

@ -16,6 +16,8 @@
{% set observe = {'layer7':'layer7', 'layer4': 'layer4'} %}
{% set on_error = {'mark-down':'mark-down', 'fastinter': 'fastinter', 'fail-check':'fail-check',
'sudden-death':'sudden-death'} %}
{% set header_res = {'http-response': 'response', 'http-request': 'request'} %}
{% set header_params = {'add-header': 'add-header', 'set-header': 'set-header', 'del-header': 'del-header'} %}
{% set if_values = dict() %}
{% set if_values = {'1':'Host name starts with','2':'Host name ends with','3':'Path starts with','4':'Path ends with', '6': 'Src ip'} %}
@ -120,23 +122,43 @@
</span>
</td>
</tr>
<tr class="advance">
<td class="addName">{{lang.words.headers|title()}}: </td>
<td class="addOption">
<span title="{{lang.words.add|title()}} {{lang.words.headers}}" id="add_listener_header" class="link add-server"></span>
<div id="listener_header_div" style="display: none;">
<p style="border-bottom: 1px solid #ddd; padding-bottom: 10px;" id="listener_header_p">
{{ select('listener_header_res_method', name='headers_res', values=header_res, selected='response', class='force_close') }}
{{ select('listener_header_method', name='headers_method', values=header_params, selected='add-header', class='force_close') }}
<b class="padding10">{{lang.words.name}}</b>
{{ input('listener_header_name', name="header_name") }}
<b class="padding10">{{lang.words.value}}</b>
{{ input('listener_header_value', name="header_value", placeholder='Leave blank if using del-header') }}
<span class="minus minus-style" onclick="deleteId('listener_header_p')" title="{{lang.words.delete|title()}}"></span>
</p>
</div>
<span>
<a class="link add-server" id="listener_add_header" title="{{lang.words.add|title()}} {{lang.words.headers}}" style="display: none;"></a>
</span>
</td>
</tr>
<tr class="advance">
<td class="addName" title="Access control list">ACL: </td>
<td class="addOption">
<span title="Add ACL" id="add_listener_acl" class="link add-server"></span>
<span title="{{lang.words.add|title()}} ACL" id="add_listener_acl" class="link add-server"></span>
<div id="listener_acl" style="display: none;">
<p style="border-bottom: 1px solid #ddd; padding-bottom: 10px;" id="listener_acl_rule">
<b class="padding10">if</b>
<b class="padding10">{{lang.words.if|title()}}</b>
{{ select('listener_acl_if', name='acl_if', values=if_values, first='Choose if', class='force_close', disabled=false) }}
<b class="padding10">value</b>
<b class="padding10">{{lang.words.value}}</b>
{{ input('listener_acl_value', name="acl_value") }}
<b class="padding10">then</b>
<b class="padding10">{{lang.words.then}}</b>
{% set values = dict() %}
{% set values = {'2':'Redirect to','3':'Allow','4':'Deny', '6': 'Return', '7': 'Set-header'} %}
{{ select('listener_acl_then', name='acl_then', values=values, first='Choose action', class='force_close', disabled=false) }}
<b class="padding10">value</b>
<b class="padding10">{{lang.words.value}}</b>
{{ input('listener_acl_then_value', name='acl_then_value', title="Required if \'then\' is \'Use backend\' or \'Redirect\', \'Return\', or \'Set-header\'") }}
<span class="minus minus-style" onclick="deleteId('listener_acl_rule')" title="Delete this rule"></span>
<span class="minus minus-style" onclick="deleteId('listener_acl_rule')" title="{{lang.words.delete|title()}} {{lang.words.this}} ACL"></span>
</p>
</div>
<span>
@ -348,6 +370,26 @@
<div class="tooltip tooltipTop">{{lang.add_page.desc.maxconn_desc}}: 2000</div>
</td>
</tr>
<tr class="advance">
<td class="addName">{{lang.words.headers|title()}}: </td>
<td class="addOption">
<span title="{{lang.words.add|title()}} {{lang.words.headers}}" id="add_frontend_header" class="link add-server"></span>
<div id="frontend_header_div" style="display: none;">
<p style="border-bottom: 1px solid #ddd; padding-bottom: 10px;" id="frontend_header_p">
{{ select('frontend_header_res_method', name='headers_res', values=header_res, selected='response', class='force_close') }}
{{ select('frontend_header_method', name='headers_method', values=header_params, selected='add-header', class='force_close') }}
<b class="padding10">{{lang.words.name}}</b>
{{ input('frontend_header_name', name="header_name") }}
<b class="padding10">{{lang.words.value}}</b>
{{ input('frontend_header_value', name="header_value", placeholder='Leave blank if using del-header') }}
<span class="minus minus-style" onclick="deleteId('frontend_header_p')" title="{{lang.words.delete|title()}}"></span>
</p>
</div>
<span>
<a class="link add-server" id="frontend_add_header" title="{{lang.words.add|title()}} {{lang.words.headers}}" style="display: none;"></a>
</span>
</td>
</tr>
<tr class="advance">
<td class="addName" title="Access control list">ACL: </td>
<td class="addOption">
@ -523,6 +565,26 @@
</span>
</td>
</tr>
<tr class="advance">
<td class="addName">{{lang.words.headers|title()}}: </td>
<td class="addOption">
<span title="{{lang.words.add|title()}} {{lang.words.headers}}" id="add_backend_header" class="link add-server"></span>
<div id="backend_header_div" style="display: none;">
<p style="border-bottom: 1px solid #ddd; padding-bottom: 10px;" id="backend_header_p">
{{ select('backend_header_res_method', name='headers_res', values=header_res, selected='response', class='force_close') }}
{{ select('backend_header_method', name='headers_method', values=header_params, selected='add-header', class='force_close') }}
<b class="padding10">{{lang.words.name}}</b>
{{ input('backend_header_name', name="header_name") }}
<b class="padding10">{{lang.words.value}}</b>
{{ input('lbackend_header_value', name="header_value", placeholder='Leave blank if using del-header') }}
<span class="minus minus-style" onclick="deleteId('listener_header_p')" title="{{lang.words.delete|title()}}"></span>
</p>
</div>
<span>
<a class="link add-server" id="backend_add_header" title="{{lang.words.add|title()}} {{lang.words.headers}}" style="display: none;"></a>
</span>
</td>
</tr>
<tr class="advance">
<td class="addName" title="Access control list">ACL: </td>
<td class="addOption">

View File

@ -60,7 +60,7 @@
{% endif %}
</td>
{% if waf_service == 'haproxy' %}
<td style="padding-top: 2px;" class="ajaxwafstatus">
<td class="ajaxwafstatus">
{% if service.4|int() == 1 %}
<label for="metrics{{ service.0 }}"></label><input type="checkbox" id="metrics{{ service.0 }}" checked />
{% else %}

View File

@ -152,8 +152,8 @@
<table class="overview">
<tr class="overviewHead">
<td class="padding10 first-collumn">{{lang.words.server|title()}}</td>
<td class="padding10">{{lang.words.actions|title()}}</td>
<td class="padding10">WAF {{lang.words.mode}}</td>
<td>{{lang.words.actions|title()}}</td>
<td>WAF {{lang.words.mode}}</td>
{% if service == 'haproxy' %}
<td>{{lang.words.metrics|title()}}</td>
{% endif %}

View File

@ -1229,6 +1229,30 @@ $( function() {
$("#backend_checks_http_domain").removeAttr('required');
}
});
$( "#add_listener_header" ).on( "click", function() {
$( "#listener_header_div" ).show();
$( "#listener_add_header" ).show();
$( "#add_listener_header" ).hide();
} );
$( "#add_frontend_header" ).on( "click", function() {
$( "#frontend_header_div" ).show();
$( "#frontend_add_header" ).show();
$( "#add_frontend_header" ).hide();
} );
$( "#add_backend_header" ).on( "click", function() {
$( "#backend_header_div" ).show();
$( "#backend_add_header" ).show();
$( "#add_backend_header" ).hide();
} );
$("#listener_add_header").click(function(){
make_actions_for_adding_header('#listener_header_div');
});
$("#frontend_add_header").click(function(){
make_actions_for_adding_header('#frontend_header_div');
});
$("#backend_add_header").click(function(){
make_actions_for_adding_header('#backend_header_div');
});
$( "#add_listener_acl" ).on( "click", function() {
$( "#listener_acl" ).show();
$( "#listener_add_acl" ).show();
@ -1893,8 +1917,12 @@ function deleteId(id) {
$('#frontend_bind').hide();
}
}
var if_word = $('#translate').attr('data-if-title');
var then_word = $('#translate').attr('data-then');
var value_word = $('#translate').attr('data-value');
var name_word = $('#translate').attr('data-name');
var acl_option = '<p id="new_acl_p" style="border-bottom: 1px solid #ddd; padding-bottom: 10px;">\n' +
'<b class="padding10">if</b>\n' +
'<b class="padding10">'+if_word+'</b>\n' +
'<select name="acl_if">\n' +
'\t<option selected>Choose if</option>\n' +
'\t<option value="1">Host name starts with</option>\n' +
@ -1903,9 +1931,9 @@ var acl_option = '<p id="new_acl_p" style="border-bottom: 1px solid #ddd; paddin
'\t<option value="4">Path ends with</option>\n' +
'\t<option value="6">Src ip</option>\n' +
'</select> ' +
'<b class="padding10">value</b>\n' +
'<b class="padding10">'+value_word+'</b>\n' +
'<input type="text" name="acl_value" class="form-control">\n' +
'<b class="padding10">then</b>\n' +
'<b class="padding10">'+then_word+'</b>\n' +
'<select name="acl_then">\n' +
'\t<option selected>Choose then</option>\n' +
'\t<option value="5">Use backend</option>\n' +
@ -1915,7 +1943,7 @@ var acl_option = '<p id="new_acl_p" style="border-bottom: 1px solid #ddd; paddin
'\t<option value="6">Return</option>\n' +
'\t<option value="7">Set-header</option>\n' +
'</select>\n' +
'<b class="padding10">value</b>\n' +
'<b class="padding10">'+value_word+'</b>\n' +
'<input type="text" name="acl_then_value" class="form-control" value="" title="Required if\" then\" is \"Use backend\" or \"Redirect\"">\n' +
'<span class="minus minus-style" id="new_acl_rule_minus" title="Delete this ACL"></span>' +
'</p>'
@ -1931,6 +1959,36 @@ function make_actions_for_adding_acl_rule(section_id) {
$('[name=acl_if]').selectmenu({width: 180});
$('[name=acl_then]').selectmenu({width: 180});
}
var value_word = $('#translate').attr('data-value');
var name_word = $('#translate').attr('data-name');
var header_option = '<p style="border-bottom: 1px solid #ddd; padding-bottom: 10px;" id="new_header_p">\n' +
'<select name="headers_res">' +
'<option value="http-response">response</option>' +
'<option value="http-request">request</option>' +
'</select>' +
'<select name="headers_method">' +
'<option value="add-header">add-header</option>' +
'<option value="set-header">set-header</option>' +
'<option value="del-header">del-header</option>' +
'</select>' +
'\t<b class="padding10">'+name_word+'</b>' +
'\t<input name="header_name" class="form-control">' +
'\t<b class="padding10">'+value_word+'</b>' +
'\t<input name="header_value" class="form-control" placeholder="Leave blank if using del-header">' +
'\t<span class="minus minus-style" id="new_header_minus" title="Delete this header"></span>' +
'</p>'
function make_actions_for_adding_header(section_id) {
var random_id = makeid(3);
$(section_id).append(header_option);
$('#new_header_minus').attr('onclick', 'deleteId(\''+random_id+'\')');
$('#new_header_minus').attr('id', '');
$('#new_header_p').attr('id', random_id);
$('#new_header_minus').attr('id', '');
$.getScript("/inc/fontawesome.min.js");
$( "select" ).selectmenu();
$('[name=headers_method]').selectmenu({width: 180});
// $('[name=acl_then]').selectmenu({width: 180});
}
var bind_option = '<p id="new_bind_p"><input type="text" name="ip" size="15" placeholder="Any" class="form-control ui-autocomplete-input" autocomplete="off">' +
'<b>:</b> ' +
'<input type="text" name="port" size="5" style="" required="" placeholder="8080" title="Port for bind listen" class="form-control" autocomplete="off"> ' +

View File

@ -1369,3 +1369,7 @@ label {
margin-right: 10px;
margin-bottom: 20px;
}
.ajaxwafstatus {
padding-top: 2px;
padding-left: 10px;
}