Project

General

Profile

« Previous | Next » 

Revision 46245a43

Added by Reid Linnemann over 2 years ago

Make a better effort to describe an alias reference. Fixes #13539

Each of deleteAlias(), openvpnAlias(), and staticrouteAlias() are called when
deleting or modifying an alias to indicate that it is referenced by some other
configuration item, which in turn call find_alias_reference() which returns
descriptions of configuration references that can be displayed in warnings and
errors.

find_alias_reference() is refactored into find_alias_reference_by_path() which
accepts configlib paths instead of arrays, and makes a stronger attempt at
picking a descriptive text for the item, enclosed in single quotes, cascading
through descr, description, name. If none of these attributes exist, an ID
description is chosen as a last resort.

For compatibility, find_alias_reference() is retained as a wrapper around
find_alias_reference_by_path().

Each of deleteAlias(), openvpnAlias(), and staticrouteAlias() are refactored to
adapt to the path interface and for better readability, calling
find_alias_reference_by_path() in a loop over an associative array of section
paths indexing arrays of field paths (where more than onesection/field pair is
used).

View differences:

src/usr/local/pfSense/include/www/alias-utils.inc
35 35
$a_aliases = &$config['aliases']['alias'];
36 36

  
37 37
function deleteAlias($id, $apply = false) {
38
	global $config;
39

  
40 38
	/* make sure rule is not being referenced by any nat or filter rules */
41 39
	init_config_arr(array('aliases', 'alias'));
42
	$a_aliases = &$config['aliases']['alias'];
40
	$a_aliases = config_get_path('aliases/alias', []);
43 41

  
44 42
	$delete_error = "";
45 43
	$is_alias_referenced = false;
46 44
	$referenced_by = array();
47 45
	$alias_name = $a_aliases[$id]['name'];
48
	// Firewall rules
49
	find_alias_reference(array('filter', 'rule'), array('source', 'address'), $alias_name, $is_alias_referenced, $referenced_by);
50
	find_alias_reference(array('filter', 'rule'), array('destination', 'address'), $alias_name, $is_alias_referenced, $referenced_by);
51
	find_alias_reference(array('filter', 'rule'), array('source', 'port'), $alias_name, $is_alias_referenced, $referenced_by);
52
	find_alias_reference(array('filter', 'rule'), array('destination', 'port'), $alias_name, $is_alias_referenced, $referenced_by);
53
	// NAT Rules
54
	find_alias_reference(array('nat', 'rule'), array('source', 'address'), $alias_name, $is_alias_referenced, $referenced_by);
55
	find_alias_reference(array('nat', 'rule'), array('source', 'port'), $alias_name, $is_alias_referenced, $referenced_by);
56
	find_alias_reference(array('nat', 'rule'), array('destination', 'address'), $alias_name, $is_alias_referenced, $referenced_by);
57
	find_alias_reference(array('nat', 'rule'), array('destination', 'port'), $alias_name, $is_alias_referenced, $referenced_by);
58
	find_alias_reference(array('nat', 'rule'), array('target'), $alias_name, $is_alias_referenced, $referenced_by);
59
	find_alias_reference(array('nat', 'rule'), array('local-port'), $alias_name, $is_alias_referenced, $referenced_by);
60
	// NAT 1:1 Rules
61
	find_alias_reference(array('nat', 'onetoone'), array('destination', 'address'), $alias_name, $is_alias_referenced, $referenced_by);
62
	// NAT Outbound Rules
63
	find_alias_reference(array('nat', 'outbound', 'rule'), array('source', 'network'), $alias_name, $is_alias_referenced, $referenced_by);
64
	find_alias_reference(array('nat', 'outbound', 'rule'), array('sourceport'), $alias_name, $is_alias_referenced, $referenced_by);
65
	find_alias_reference(array('nat', 'outbound', 'rule'), array('destination', 'address'), $alias_name, $is_alias_referenced, $referenced_by);
66
	find_alias_reference(array('nat', 'outbound', 'rule'), array('dstport'), $alias_name, $is_alias_referenced, $referenced_by);
67
	find_alias_reference(array('nat', 'outbound', 'rule'), array('target'), $alias_name, $is_alias_referenced, $referenced_by);
68
	// Alias in an alias
69
	find_alias_reference(array('aliases', 'alias'), array('address'), $alias_name, $is_alias_referenced, $referenced_by);
70
	// Static routes
71
	find_alias_reference(array('staticroutes', 'route'), array('network'), $alias_name, $is_alias_referenced, $referenced_by);
72
	// OpenVPN
73
	find_alias_reference(array('openvpn', 'openvpn-server'), array('tunnel_network'), $alias_name, $is_alias_referenced, $referenced_by);
74
	find_alias_reference(array('openvpn', 'openvpn-server'), array('tunnel_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
75
	find_alias_reference(array('openvpn', 'openvpn-server'), array('local_network'), $alias_name, $is_alias_referenced, $referenced_by);
76
	find_alias_reference(array('openvpn', 'openvpn-server'), array('local_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
77
	find_alias_reference(array('openvpn', 'openvpn-server'), array('remote_network'), $alias_name, $is_alias_referenced, $referenced_by);
78
	find_alias_reference(array('openvpn', 'openvpn-server'), array('remote_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
79
	find_alias_reference(array('openvpn', 'openvpn-client'), array('tunnel_network'), $alias_name, $is_alias_referenced, $referenced_by);
80
	find_alias_reference(array('openvpn', 'openvpn-client'), array('tunnel_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
81
	find_alias_reference(array('openvpn', 'openvpn-client'), array('remote_network'), $alias_name, $is_alias_referenced, $referenced_by);
82
	find_alias_reference(array('openvpn', 'openvpn-client'), array('remote_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
83
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('tunnel_network'), $alias_name, $is_alias_referenced, $referenced_by);
84
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('tunnel_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
85
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('local_network'), $alias_name, $is_alias_referenced, $referenced_by);
86
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('local_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
87
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('remote_network'), $alias_name, $is_alias_referenced, $referenced_by);
88
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('remote_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
46
	$section_fields = [
47
		// Firewall rules
48
		'filter/rule' => [
49
			'source/address',
50
			'destination/address',
51
			'destination/port'
52
		],
53
		// NAT Rules
54
		'nat/rule' => [
55
			'source/address',
56
			'source/port',
57
			'destination/address',
58
			'destination/port',
59
			'target',
60
			'local-port'
61
		],
62
		// NAT 1:1 Rules
63
		'nat/onetoone' => [
64
			'destination/address'
65
		],
66
		// NAT Outbound Rules
67
		'nat/outbound/rule' => [
68
			'source/network',
69
			'sourceport',
70
			'destination/address',
71
			'dstport',
72
			'target'
73
		],
74
		// Alias in an alias
75
		'aliases/alias' => [
76
			'address'
77
		],
78
		// Static routes
79
		'staticroutes/route' => [
80
			'network'
81
		],
82
		// OpenVPN
83
		'openvpn/openvpn-server' => [
84
			'tunnel_network',
85
			'tunnel_networkv6',
86
			'local_network',
87
			'local_networkv6',
88
			'remote_network',
89
			'remote_networkv6',
90
			'tunnel_network',
91
			'tunnel_networkv6',
92
			'remote_network',
93
			'remote_networkv6'
94
		],
95
		'openvpn/openvpn-csc' => [
96
			'tunnel_network',
97
			'tunnel_networkv6',
98
			'local_network',
99
			'local_networkv6',
100
			'remote_network',
101
			'remote_networkv6'
102
		],
103
	];
104

  
105
	foreach ($section_fields as $section => $fields) {
106
		foreach ($fields as $field) {
107
			find_alias_reference_by_path($section, $field, $alias_name, $is_alias_referenced, $referenced_by);
108
		}
109
	}
110

  
89 111
	if ($is_alias_referenced == true) {
90 112
		$delete_error = sprintf(gettext("Cannot delete alias. Currently in use by %s."), htmlspecialchars(implode(", ", $referenced_by)));
91 113
	} else {
......
94 116
			unlink_if_exists("/var/db/aliastables/" . $a_aliases[$id]['name'] . ".txt");
95 117
		}
96 118
		unset($a_aliases[$id]);
119
		config_set_path('aliases/alias', $a_aliases);
97 120
		if (write_config(gettext("Deleted firewall alias " . $a_aliases[$id]['name']))) {
98 121
			if (!$apply) {
99 122
				mark_subsystem_dirty('aliases');
......
121 144
		return false;
122 145
	}
123 146

  
124
	find_alias_reference(array('openvpn', 'openvpn-server'), array('tunnel_network'), $alias_name, $is_alias_referenced, $referenced_by);
125
	find_alias_reference(array('openvpn', 'openvpn-server'), array('tunnel_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
126
	find_alias_reference(array('openvpn', 'openvpn-server'), array('local_network'), $alias_name, $is_alias_referenced, $referenced_by);
127
	find_alias_reference(array('openvpn', 'openvpn-server'), array('local_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
128
	find_alias_reference(array('openvpn', 'openvpn-server'), array('remote_network'), $alias_name, $is_alias_referenced, $referenced_by);
129
	find_alias_reference(array('openvpn', 'openvpn-server'), array('remote_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
130
	find_alias_reference(array('openvpn', 'openvpn-client'), array('tunnel_network'), $alias_name, $is_alias_referenced, $referenced_by);
131
	find_alias_reference(array('openvpn', 'openvpn-client'), array('tunnel_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
132
	find_alias_reference(array('openvpn', 'openvpn-client'), array('remote_network'), $alias_name, $is_alias_referenced, $referenced_by);
133
	find_alias_reference(array('openvpn', 'openvpn-client'), array('remote_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
134
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('tunnel_network'), $alias_name, $is_alias_referenced, $referenced_by);
135
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('tunnel_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
136
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('local_network'), $alias_name, $is_alias_referenced, $referenced_by);
137
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('local_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
138
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('remote_network'), $alias_name, $is_alias_referenced, $referenced_by);
139
	find_alias_reference(array('openvpn', 'openvpn-csc'), array('remote_networkv6'), $alias_name, $is_alias_referenced, $referenced_by);
147
	$section_fields = [
148
		'openvpn/openvpn-server' => [
149
			'tunnel_network',
150
			'tunnel_networkv6',
151
			'local_network',
152
			'local_networkv6',
153
			'remote_network',
154
			'remote_networkv6'
155
		],
156
		'openvpn/openvpn-client' => [
157
			'tunnel_network',
158
			'tunnel_networkv6',
159
			'remote_network',
160
			'remote_networkv6'
161
		],
162
		'openvpn/openvpn-csc' => [
163
			'tunnel_network',
164
			'tunnel_networkv6',
165
			'local_network',
166
			'local_networkv6',
167
			'remote_network',
168
			'remote_networkv6'
169
		]
170
	];
171

  
172
	foreach ($section_fields as $section => $fields) {
173
		foreach ($fields as $field) {
174
			find_alias_reference_by_path($section, $field, $alias_name, $is_alias_referenced, $referenced_by);
175
		}
176
	}
177

  
140 178
	if ($is_alias_referenced == true) {
141 179
		$alarm_message = sprintf(gettext("Alias is in use by OpenVPN. Pressing save will restart instances: %s."), htmlspecialchars(implode(", ", $referenced_by)));
142 180
	}
......
144 182
	return $alarm_message;
145 183
}
146 184

  
147
function find_alias_reference($section, $field, $origname, &$is_alias_referenced, &$referenced_by) {
148
	global $config;
185
/**
186
 * Find references to an alias by path.
187
 *
188
 * @param  string   $section             Section part of path, slash delimited. The section must identify an indexed array of items 
189
 * @param  string   $field               Field part of path, slash delimited. The part is appended to each element in the section to search for an alias.
190
 * @param  string   $origname            Alias name.
191
 * @param  bool	    $is_alias_referenced Set to true if a match is found.
192
 * @param  string[] $referenced_by       Array recording descriptions of paths referencing the alias.
193
 */
194
function find_alias_reference_by_path($section, $field, $origname, &$is_alias_referenced, &$referenced_by) {
149 195
	if (!$origname) {
150 196
		return;
151 197
	}
152 198

  
153
	$sectionref = &$config;
154
	foreach ($section as $sectionname) {
155
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
156
			$sectionref = &$sectionref[$sectionname];
157
		} else {
158
			return;
159
		}
160
	}
161

  
162
	if (is_array($sectionref)) {
163
		foreach ($sectionref as $itemkey => $item) {
164
			$fieldfound = true;
165
			$fieldref = &$sectionref[$itemkey];
166
			foreach ($field as $fieldname) {
167
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
168
					$fieldref = &$fieldref[$fieldname];
169
				} else {
170
					$fieldfound = false;
171
					break;
172
				}
199
	$items = config_get_path($section, []);
200

  
201
	foreach ($items as $id => $item) {
202
		if (array_get_path($item, $field) == $origname) {
203
			$is_alias_referenced = true;
204
			/* This is a bad hack to make rule descriptions more verbose,
205
			 * ideally the object should be providing its own text presentation,
206
			 * but our values are arrays at this time
207
			 */
208
			if (basename($section) == 'rule') {
209
				$descr = str_replace('/', ' ', $section) . ' ';
210
			} else {
211
				$descr = basename($section) . ' ';
173 212
			}
174
			/* explode() alias address string, see https://redmine.pfsense.org/issues/11372 */
175
			if ($fieldfound && (in_array($origname, explode(' ', $fieldref)) ||
176
			    in_array($origname, explode(',', $fieldref)))) {
177
				$is_alias_referenced = true;
178
				if (is_array($item)) {
179
					if (!empty($item['descr'])) {
180
						$referenced_by[] = $item['descr'];
181
					} elseif (!empty($item['description'])) {
182
						$referenced_by[] = $item['description'];
183
					}
184
				}
213
			if (!empty($item['descr'])) {
214
				$descr .= "'{$item['descr']}'";
215
			} elseif (!empty($item['description'])) {
216
				$descr .= "'{$item['description']}'";
217
			} elseif (!empty($item['name'])) {
218
				$descr .= "'{$item['name']}'";
219
			} else {
220
				$descr .= "id {$id}";
185 221
			}
222

  
223
			$referenced_by[] = $descr;
186 224
		}
187 225
	}
188 226
}
189 227

  
228

  
229
function find_alias_reference($section, $field, $origname, &$is_alias_referenced, &$referenced_by) {
230
	$section_path = join('/', $section);
231
	$field_path = join('/', $field);
232

  
233
	return (find_alias_reference_by_path($section_path, $field_path, $origname, $is_alias_referenced, $referenced_by));
234
}
235

  
190 236
function staticrouteAlias($id) {
191 237
	global $config;
192 238

  
......
202 248
		return false;
203 249
	}
204 250

  
205
	find_alias_reference(array('staticroutes', 'route'), array('network'), $alias_name, $is_alias_referenced, $referenced_by);
251
	find_alias_reference_by_path('staticroutes/route', 'network', $alias_name, $is_alias_referenced, $referenced_by);
206 252

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

Also available in: Unified diff