Skip to content

Commit

Permalink
Static routes handling update. Fixes #11599 #11895 #7547
Browse files Browse the repository at this point in the history
* Confirmation box to apply static routes add/route/change
* Reloading routes using aliases after changing the alias
* Correct route updates after changing destination or gateway
  • Loading branch information
vktg committed Nov 25, 2021
1 parent 47e079f commit 332052b
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 72 deletions.
72 changes: 72 additions & 0 deletions src/etc/inc/system.inc
Expand Up @@ -1041,6 +1041,32 @@ function system_staticroutes_configure($interface = "", $update_dns = false) {
}
}
unset($gateways_arr);

/* keep static routes cache,
* see https://redmine.pfsense.org/issues/11599 */
$id = 0;
foreach ($config['staticroutes']['route'] as $sroute) {
$targets = array();
if (is_subnet($sroute['network'])) {
$targets[] = $sroute['network'];
} elseif (is_alias($sroute['network'])) {
foreach (preg_split('/\s+/', $aliastable[$sroute['network']]) as $tgt) {
if (is_ipaddrv4($tgt)) {
$tgt .= "/32";
}
if (is_ipaddrv6($tgt)) {
$tgt .= "/128";
}
if (!is_subnet($tgt)) {
continue;
}
$targets[] = $tgt;
}
}
file_put_contents("{$g['tmp_path']}/staticroute_{$id}", serialize($targets));
file_put_contents("{$g['tmp_path']}/staticroute_{$id}_gw", serialize($sroute['gateway']));
$id++;
}
}
unset($static_routes);

Expand Down Expand Up @@ -1070,6 +1096,52 @@ function system_staticroutes_configure($interface = "", $update_dns = false) {
return 0;
}

function delete_static_route($id, $delete = false) {
global $g, $config, $changedesc_prefix, $a_gateways;

if (!isset($config['staticroutes']['route'][$id])) {
return;
}

if (file_exists("{$g['tmp_path']}/.system_routes.apply")) {
$toapplylist = unserialize(file_get_contents("{$g['tmp_path']}/.system_routes.apply"));
} else {
$toapplylist = array();
}

if (file_exists("{$g['tmp_path']}/staticroute_{$id}") &&
file_exists("{$g['tmp_path']}/staticroute_{$id}_gw")) {
$delete_targets = unserialize(file_get_contents("{$g['tmp_path']}/staticroute_{$id}"));
$delgw = lookup_gateway_ip_by_name(unserialize(file_get_contents("{$g['tmp_path']}/staticroute_{$id}_gw")));
if (count($delete_targets)) {
foreach ($delete_targets as $dts) {
if (is_ipaddrv6($dts)) {
$family = "-inet6";
} else {
$family = "-inet";
}
$route = route_get($dts, '', true);
if (!count($route)) {
continue;
}
$toapplylist[] = "/sbin/route delete " .
$family . " " . $dts . " " . $delgw;
}
}
}

if ($delete) {
unlink_if_exists("{$g['tmp_path']}/staticroute_{$id}");
unlink_if_exists("{$g['tmp_path']}/staticroute_{$id}_gw");
}

if (!empty($toapplylist)) {
file_put_contents("{$g['tmp_path']}/.system_routes.apply", serialize($toapplylist));
}

unset($targets);
}

function system_routing_enable() {
global $config, $g;
if (isset($config['system']['developerspew'])) {
Expand Down
57 changes: 54 additions & 3 deletions src/usr/local/pfSense/include/www/alias-utils.inc
Expand Up @@ -187,6 +187,30 @@ function find_alias_reference($section, $field, $origname, &$is_alias_referenced
}
}

function staticrouteAlias($id) {
global $config;

init_config_arr(array('aliases', 'alias'));
$a_aliases = &$config['aliases']['alias'];

$alarm_message = "";
$is_alias_referenced = false;
$referenced_by = array();
$alias_name = $a_aliases[$id]['name'];

if ($a_aliases[$id]['type'] != 'host') {
return false;
}

find_alias_reference(array('staticroutes', 'route'), array('network'), $alias_name, $is_alias_referenced, $referenced_by);

if ($is_alias_referenced) {
$alarm_message = sprintf(gettext("Alias is used in static routes. Pressing save will reload static routes: %s."), htmlspecialchars(implode(", ", $referenced_by)));
}

return $alarm_message;
}

function alias_same_type($name, $type) {
global $config;

Expand All @@ -208,7 +232,7 @@ function alias_same_type($name, $type) {
}

function saveAlias($post, $id) {
global $config, $pf_reserved_keywords, $reserved_table_names, $pconfig, $aliastable;
global $config, $g, $pf_reserved_keywords, $reserved_table_names, $pconfig, $aliastable;

$origname = $post['origname'];
$reserved_ifs = get_configured_interface_list(true);
Expand Down Expand Up @@ -625,8 +649,8 @@ function saveAlias($post, $id) {

write_config(gettext("Edited a firewall alias."));

/* restart related OpenVPN instances
* see https://redmine.pfsense.org/issues/2668 */
/* restart related OpenVPN instances, see https://redmine.pfsense.org/issues/2668
* reload related static routes, see https://redmine.pfsense.org/issues/7547 */
if (in_array($alias['type'], array('host', 'network', 'url'))) {
$config = parse_config(true);
init_config_arr(array('openvpn', 'openvpn-server'));
Expand Down Expand Up @@ -659,6 +683,33 @@ function saveAlias($post, $id) {
}
}
}

init_config_arr(array('staticroutes', 'route'));
$srid = 0;
foreach ($config['staticroutes']['route'] as $sroute) {
if (!isset($sroute['disabled']) &&
($alias['name'] == $sroute['network'])) {
delete_static_route($srid);
$reload_static_route = true;
}
$srid++;
}
if ($reload_static_route && file_exists("{$g['tmp_path']}/.system_routes.apply")) {
$toapplylist = unserialize(file_get_contents("{$g['tmp_path']}/.system_routes.apply"));
foreach ($toapplylist as $toapply) {
mwexec("{$toapply}");
}
@unlink("{$g['tmp_path']}/.system_routes.apply");

$retval |= system_routing_configure();
$retval |= filter_configure();
/* reconfigure our gateway monitor */
setup_gateways_monitor();

if ($retval == 0) {
clear_subsystem_dirty('staticroutes');
}
}
}
} else if (isset($pconfig)) {
//we received input errors, copy data to prevent retype
Expand Down
4 changes: 4 additions & 0 deletions src/usr/local/www/firewall_aliases_edit.php
Expand Up @@ -106,6 +106,7 @@
unset($id);
} else {
$openvpnuse = openvpnAlias($id);
$staticrouteuse = staticrouteAlias($id);
}

if ($_POST['save']) {
Expand Down Expand Up @@ -256,6 +257,9 @@
if ($openvpnuse) {
print_info_box($openvpnuse);
}
if ($staticrouteuse) {
print_info_box($staticrouteuse);
}

$form = new Form;

Expand Down
45 changes: 5 additions & 40 deletions src/usr/local/www/system_routes.php
Expand Up @@ -66,44 +66,13 @@
}
}

function delete_static_route($id) {
global $config, $a_routes, $changedesc_prefix, $a_gateways;

if (!isset($a_routes[$id])) {
return;
}

$targets = array();
if (is_alias($a_routes[$id]['network'])) {
foreach (filter_expand_alias_array($a_routes[$id]['network']) as
$tgt) {
if (is_ipaddrv4($tgt)) {
$tgt .= "/32";
} else if (is_ipaddrv6($tgt)) {
$tgt .= "/128";
}
if (!is_subnet($tgt)) {
continue;
}
$targets[] = $tgt;
}
} else {
$targets[] = $a_routes[$id]['network'];
}

foreach ($targets as $tgt) {
route_del($tgt);
}

unset($targets);
}

if ($_POST['act'] == "del") {
if ($a_routes[$_POST['id']]) {
$changedesc = $changedesc_prefix . sprintf(gettext("removed route to %s"), $a_routes[$_POST['id']]['network']);
delete_static_route($_POST['id']);
delete_static_route($_POST['id'], true);
unset($a_routes[$_POST['id']]);
write_config($changedesc);
mark_subsystem_dirty('staticroutes');
header("Location: system_routes.php");
exit;
}
Expand All @@ -115,21 +84,20 @@ function delete_static_route($id) {
$deleted_routes = "";
foreach ($_POST['route'] as $routei) {
$deleted_routes .= " " . $a_routes[$routei]['network'];
delete_static_route($routei);
delete_static_route($routei, true);
unset($a_routes[$routei]);
}
$changedesc = $changedesc_prefix . sprintf(gettext("removed route to%s"), $deleted_routes);
write_config($changedesc);
mark_subsystem_dirty('staticroutes');
header("Location: system_routes.php");
exit;
}

}

if ($_POST['act'] == "toggle") {
if ($a_routes[$_POST['id']]) {
$do_update_config = true;
$route_del = false;
if (isset($a_routes[$_POST['id']]['disabled'])) {
// Do not enable a route whose gateway is disabled
if (isset($a_gateways[$a_routes[$_POST['id']]['gateway']]['disabled'])) {
Expand All @@ -140,17 +108,14 @@ function delete_static_route($id) {
$changedesc = $changedesc_prefix . sprintf(gettext("enabled route to %s"), $a_routes[$_POST['id']]['network']);
}
} else {
$route_del = true;
delete_static_route($_POST['id']);
$a_routes[$_POST['id']]['disabled'] = true;
$changedesc = $changedesc_prefix . sprintf(gettext("disabled route to %s"), $a_routes[$_POST['id']]['network']);
}

if ($do_update_config) {
if (write_config($changedesc)) {
if (!$route_del) {
mark_subsystem_dirty('staticroutes');
}
mark_subsystem_dirty('staticroutes');
}
header("Location: system_routes.php");
exit;
Expand Down
53 changes: 24 additions & 29 deletions src/usr/local/www/system_routes_edit.php
Expand Up @@ -77,8 +77,9 @@

do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);

if (($_POST['network'] && !is_ipaddr($_POST['network']) && !is_alias($_POST['network']))) {
$input_errors[] = gettext("A valid IPv4 or IPv6 destination network must be specified.");
if ($_POST['network'] && !is_ipaddr($_POST['network']) &&
(!is_alias($_POST['network']) || !in_array(alias_get_type($_POST['network']), array('host', 'network', 'url')))) {
$input_errors[] = gettext("A valid IPv4 or IPv6 destination network or an alias must be specified.");
}
if (($_POST['network_subnet'] && !is_numeric($_POST['network_subnet']))) {
$input_errors[] = gettext("A valid destination network bit count must be specified.");
Expand Down Expand Up @@ -122,39 +123,28 @@
if (!is_subnet($tgt)) {
continue;
}
if (!is_subnetv6($tgt)) {
continue;
}
$new_targets[] = $tgt;
}
}
if (!isset($id)) {
$id = count($a_routes);
}
$oroute = $a_routes[$id];
$old_targets = array();
if (!empty($oroute)) {
if (is_alias($oroute['network'])) {
foreach (filter_expand_alias_array($oroute['network']) as $tgt) {
if (is_ipaddrv4($tgt)) {
$tgt .= "/32";
} else if (is_ipaddrv6($tgt)) {
$tgt .= "/128";
}
if (!is_subnet($tgt)) {
continue;
}
$old_targets[] = $tgt;
}
} else {
$old_targets[] = $oroute['network'];
if (file_exists("{$g['tmp_path']}/staticroute_{$id}")) {
$old_targets = unserialize(file_get_contents("{$g['tmp_path']}/staticroute_{$id}"));
}
if (file_exists("{$g['tmp_path']}/staticroute_{$id}_gw")) {
$old_gateway = unserialize(file_get_contents("{$g['tmp_path']}/staticroute_{$id}_gw"));
}
}

$overlaps = array_intersect($current_targets, $new_targets);
$overlaps = array_diff($overlaps, $old_targets);
if (count($overlaps)) {
$input_errors[] = gettext("A route to these destination networks already exists") . ": " . implode(", ", $overlaps);
if (!empty($old_targets)) {
$overlaps = array_intersect($current_targets, $new_targets);
$overlaps = array_diff($overlaps, $old_targets);
if (count($overlaps)) {
$input_errors[] = gettext("A route to these destination networks already exists") . ": " . implode(", ", $overlaps);
}
}

if (is_array($config['interfaces'])) {
Expand Down Expand Up @@ -194,7 +184,14 @@
$a_routes[$id] = $route;

if (!empty($oroute)) {
$delete_targets = array_diff($old_targets, $new_targets);
$rgateway = $route[0]['gateway'];
if (!empty($old_gateway) && ($rgateway != $old_gateway)) {
$delete_targets = $old_targets;
$delgw = lookup_gateway_ip_by_name($old_gateway);
} else {
$delete_targets = array_diff($old_targets, $new_targets);
$delgw = lookup_gateway_ip_by_name($rgateway);
}
if (count($delete_targets)) {
foreach ($delete_targets as $dts) {
if (is_ipaddrv6($dts)) {
Expand All @@ -204,14 +201,12 @@
if (!count($route)) {
continue;
}
$rgateway = $route[0]['gateway'];
$toapplylist[] = "/sbin/route delete " .
$family . " " . $dts . $rgateway;
$family . " " . $dts . " " . $delgw;
}
}
}
file_put_contents("{$g['tmp_path']}/.system_routes.apply",
serialize($toapplylist));
file_put_contents("{$g['tmp_path']}/.system_routes.apply", serialize($toapplylist));

mark_subsystem_dirty('staticroutes');

Expand Down

0 comments on commit 332052b

Please sign in to comment.