Project

General

Profile

« Previous | Next » 

Revision e9577ebf

Added by Christian McDonald almost 2 years ago

dhcp: support simultaneous v4 dhcpd and dhcrelay, Implements #14620

View differences:

src/etc/inc/service-utils.inc
379 379
	if (config_path_enabled('dhcrelay')) {
380 380
		$pconfig = array();
381 381
		$pconfig['name'] = "dhcrelay";
382
		$pconfig['description'] = gettext("DHCP Relay");
382
		$pconfig['description'] = gettext('ISC DHCP Relay Agent');
383 383
		$pconfig['enabled'] = true;
384 384
		$pconfig['status'] = get_service_status($pconfig);
385 385
		$services[] = $pconfig;
......
388 388
	if (config_path_enabled('dhcrelay6')) {
389 389
		$pconfig = array();
390 390
		$pconfig['name'] = "dhcrelay6";
391
		$pconfig['description'] = gettext("DHCPv6 Relay");
391
		$pconfig['description'] = gettext('ISC DHCPv6 Relay Agent');
392 392
		$pconfig['enabled'] = true;
393 393
		$pconfig['status'] = get_service_status($pconfig);
394 394
		$services[] = $pconfig;
......
397 397
	if (is_dhcp_server_enabled()) {
398 398
		$pconfig = array();
399 399
		$pconfig['name'] = "dhcpd";
400
		$pconfig['description'] = gettext("DHCP Service");
400
		$pconfig['description'] = gettext('ISC DHCP Server');
401 401
		$pconfig['enabled'] = true;
402 402
		$pconfig['status'] = get_service_status($pconfig);
403 403
		$services[] = $pconfig;
......
479 479

  
480 480
function find_service_by_name($name) {
481 481
	$services = get_services();
482
	
482

  
483 483
	foreach ($services as $service) {
484 484
		if (isset($service["name"]) && ($service["name"] == $name)) {
485 485
			return $service;
src/usr/local/www/services_dhcp.php
984 984
	exit;
985 985
}
986 986

  
987
$dhcrelay_enabled = config_path_enabled('dhcrelay');
987
$dhcrelay_enabled = false;
988
if (config_path_enabled('dhcrelay')) {
989
	foreach (explode(',', config_get_path('dhcrelay/interface')) as $dhcrelayif) {
990
		if ($dhcrelayif === $if) {
991
			$dhcrelay_enabled = true;
992
			break;
993
		}
994
	}
995
}
996

  
988 997
if ($dhcrelay_enabled) {
989
	print_info_box(gettext('DHCP Relay is currently enabled. DHCP Server cannot be enabled while the DHCP Relay is enabled on any interface.'), 'danger', false);
998
	print_info_box(sprintf(gettext('DHCP Server cannot be enabled while %sDHCP Relay%s is enabled on %s interface.'),
999
	    '<a href="/services_dhcp_relay.php">', '</a>', htmlspecialchars($iflist[$if])), 'danger', false);
990 1000
}
991 1001

  
992 1002
display_top_tabs($tab_array);
993 1003

  
994 1004
$form = new Form();
995 1005

  
996
$section = new Form_Section('General Options');
1006
$section = new Form_Section(gettext('General Options'));
997 1007

  
998 1008
if (!is_numeric($pool) && !($act === 'newpool')) {
999 1009
	$input = new Form_Checkbox(
......
1013 1023
$section->addInput(new Form_Checkbox(
1014 1024
	'ignorebootp',
1015 1025
	'BOOTP',
1016
	'Ignore BOOTP queries',
1026
	gettext('Ignore BOOTP queries'),
1017 1027
	$pconfig['ignorebootp']
1018 1028
));
1019 1029

  
1020 1030
$section->addInput(new Form_Select(
1021 1031
	'denyunknown',
1022
	'Deny unknown clients',
1032
	gettext('Deny unknown clients'),
1023 1033
	$pconfig['denyunknown'],
1024 1034
	array(
1025
		"disabled" => "Allow all clients",
1026
		"enabled" => "Allow known clients from any interface",
1027
		"class" => "Allow known clients from only this interface",
1035
		"disabled" => gettext('Allow all clients'),
1036
		"enabled" => gettext('Allow known clients from any interface'),
1037
		"class" => gettext('Allow known clients from only this interface')
1028 1038
	)
1029
))->setHelp('When set to %3$sAllow all clients%4$s, any DHCP client will get an IP address within this scope/range on this interface. '.
1039
))->setHelp(gettext('When set to %3$sAllow all clients%4$s, any DHCP client will get an IP address within this scope/range on this interface. '.
1030 1040
	'If set to %3$sAllow known clients from any interface%4$s, any DHCP client with a MAC address listed in a static mapping on %1$s%3$sany%4$s%2$s scope(s)/interface(s) will get an IP address. ' .
1031
	'If set to %3$sAllow known clients from only this interface%4$s, only MAC addresses listed in static mappings on this interface will get an IP address within this scope/range.',
1041
	'If set to %3$sAllow known clients from only this interface%4$s, only MAC addresses listed in static mappings on this interface will get an IP address within this scope/range.'),
1032 1042
	'<i>', '</i>', '<b>', '</b>');
1033 1043

  
1034 1044
$section->addInput(new Form_Checkbox(
1035 1045
	'nonak',
1036
	'Ignore denied clients',
1037
	'Ignore denied clients rather than reject',
1046
	gettext('Ignore denied clients'),
1047
	gettext('Ignore denied clients rather than reject'),
1038 1048
	$pconfig['nonak']
1039
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
1049
))->setHelp(gettext('This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.'));
1040 1050

  
1041 1051
$section->addInput(new Form_Checkbox(
1042 1052
	'ignoreclientuids',
1043
	'Ignore client identifiers',
1044
	'Do not record a unique identifier (UID) in client lease data if present in the client DHCP request',
1053
	gettext('Ignore client identifiers'),
1054
	gettext('Do not record a unique identifier (UID) in client lease data if present in the client DHCP request'),
1045 1055
	$pconfig['ignoreclientuids']
1046
))->setHelp("This option may be useful when a client can dual boot using different client identifiers but the same hardware (MAC) address.  Note that the resulting server behavior violates the official DHCP specification.");
1056
))->setHelp(gettext('This option may be useful when a client can dual boot using different client identifiers but the same hardware (MAC) address.  Note that the resulting server behavior violates the official DHCP specification.'));
1047 1057

  
1048 1058

  
1049 1059
if (is_numeric($pool) || ($act == "newpool")) {
src/usr/local/www/services_dhcp_relay.php
29 29
##|*MATCH=services_dhcp_relay.php*
30 30
##|-PRIV
31 31

  
32
require_once("guiconfig.inc");
33
require_once("filter.inc");
34
$pconfig['enable'] = isset($config['dhcrelay']['enable']);
35

  
36
if (empty($config['dhcrelay']['interface'])) {
37
	$pconfig['interface'] = array();
38
} else {
39
	$pconfig['interface'] = explode(",", $config['dhcrelay']['interface']);
32
require_once('guiconfig.inc');
33
require_once('filter.inc');
34

  
35
$pconfig['enable'] = config_path_enabled('dhcrelay');
36

  
37
$pconfig['interface'] = explode(',', config_get_path('dhcrelay/interface', ''));
38

  
39
$pconfig['agentoption'] = config_path_enabled('dhcrelay', 'agentoption');
40
$pconfig['server'] = config_get_path('dhcrelay/server');
41
$pconfig['carpstatusvip'] = config_get_path('dhcrelay/carpstatusvip', 'none');
42

  
43
function has_dhcpd_enabled(string $if): bool
44
{
45
	foreach (config_get_path('dhcpd', []) as $dhcpif => $dhcpconf) {
46
		if (($dhcpif === $if) &&
47
		    isset($dhcpconf['enable']) &&
48
		    config_path_enabled('interfaces/' . $dhcpif)) {
49
			return (true);
50
		}
51
	}
52

  
53
	return (false);
40 54
}
41 55

  
42
$pconfig['agentoption'] = isset($config['dhcrelay']['agentoption']);
43
$pconfig['server'] = isset($config['dhcrelay']['server']) ? $config['dhcrelay']['server'] : null;
44
$pconfig['carpstatusvip'] = isset($config['dhcrelay']['carpstatusvip']) ? $config['dhcrelay']['carpstatusvip'] : 'none';
56
function has_valid_static_ip(string $if): bool
57
{
58
	$ifconf = config_get_path('interfaces/'.$if);
59

  
60
	return (!empty($ifconf['subnet']) && ($ifconf['subnet'] < 31) && is_ipaddrv4($ifconf['ipaddr']));
61
}
45 62

  
46 63
$iflist = array_intersect_key(
47 64
	get_configured_interface_with_descr(),
......
49 66
		array_filter(
50 67
			array_keys(get_configured_interface_with_descr()),
51 68
			function($if) {
52
				return (get_interface_ip($if) &&
69
				return (!has_dhcpd_enabled($if) && has_valid_static_ip($if) &&
53 70
				    !is_pseudo_interface(convert_friendly_interface_to_real_interface_name($if)));
54 71
			}
55 72
		)
56 73
	)
57 74
);
58 75

  
59
$carpiflist = array_merge(array('none' => 'none'), array_intersect_key(
76
$carpiflist = array_merge(['none' => 'none'], array_intersect_key(
60 77
       	get_configured_vip_list_with_descr('inet', VIP_CARP),
61 78
	array_flip(
62 79
		array_filter(
63 80
			array_keys(get_configured_vip_list_with_descr('inet', VIP_CARP)),
64 81
			function($if) {
65
				return (get_interface_ip($if) &&
82
				return (has_valid_static_ip($if) &&
66 83
				    !is_pseudo_interface(convert_friendly_interface_to_real_interface_name($if)));
67 84
			}
68 85
		)
69 86
	)
70 87
));
71 88

  
72
/*   set the enabled flag which will tell us if DHCP server is enabled
73
 *   on any interface.   We will use this to disable dhcp-relay since
74
 *   the two are not compatible with each other.
75
 */
76
$dhcpd_enabled = false;
77
if (is_array($config['dhcpd'])) {
78
	foreach ($config['dhcpd'] as $dhcpif => $dhcp) {
79
		if (empty($dhcp)) {
80
			continue;
81
		}
82
		if (isset($dhcp['enable']) && isset($config['interfaces'][$dhcpif]['enable'])) {
83
			$dhcpd_enabled = true;
84
			break;
85
		}
86
	}
87
}
88

  
89 89
if ($_POST) {
90 90

  
91 91
	unset($input_errors);
92 92

  
93 93
	$pconfig = $_POST;
94 94

  
95
	$svrlist = [];
96

  
95 97
	/* input validation */
96 98
	if ($_POST['enable']) {
97
		$reqdfields = explode(" ", "interface");
98
		$reqdfieldsn = array(gettext("Interface"));
99

  
99
		$reqdfields = ['interface'];
100
		$reqdfieldsn = [gettext('Downstream Interface(s)')];
100 101
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
102
	}
101 103

  
102
		$svrlist = '';
103

  
104
		for ($idx=0; $idx<count($_POST); $idx++) {
105
			if ($_POST['server' . $idx]) {
106
				if (!empty($_POST['server' . $idx])) { // Filter out any empties
107
					if (!is_ipaddrv4($_POST['server' . $idx])) {
108
						$input_errors[] = sprintf(gettext("Destination Server IP address %s is not a valid IPv4 address."), $_POST['server' . $idx]);
109
					}
110

  
111
					if (!empty($svrlist)) {
112
						$svrlist .= ',';
113
					}
104
	for ($idx = 0; $idx < count($_POST); $idx++) {
105
		if ($_POST['server'.$idx]) {
106
			if (empty($_POST['server'.$idx])) {
107
				continue;
108
			}
114 109

  
115
					$svrlist .= $_POST['server' . $idx];
116
				}
110
			if (!is_ipaddrv4($_POST['server'.$idx])) {
111
				$input_errors[] = sprintf(gettext('Upstream Server IPv4 address %s is not a valid IPv4 address.'), $_POST['server'.$idx]);
117 112
			}
118
		}
119 113

  
120
		// Check that the user input something in one of the Destination Server fields
121
		if (empty($svrlist)) {
122
			$input_errors[] = gettext("At least one Destination Server IP address must be specified.");
114
			$svrlist[] = $_POST['server'.$idx];
123 115
		}
124 116
	}
125 117

  
118
	// Check that the user input something in one of the Destination Server fields
119
	if (empty($svrlist) && $_POST['enable']) {
120
		$input_errors[] = gettext('At least one Upstream Server IPv4 address must be specified.');
121
	}
122

  
126 123
	// Now $svrlist is a comma separated list of servers ready to save to the config system
124
	$svrlist = implode(',', $svrlist);
127 125
	$pconfig['server'] = $svrlist;
128 126

  
129 127
	if (!$input_errors) {
130
		init_config_arr(array('dhcrelay'));
128
		init_config_arr(['dhcrelay']);
131 129
		config_set_path('dhcrelay/enable', $_POST['enable'] ? true : false);
132 130
		if (isset($_POST['interface']) &&
133 131
		    is_array($_POST['interface'])) {
......
149 147
	}
150 148
}
151 149

  
152
$pgtitle = array(gettext('Services'), gettext('DHCP Relay'));
150
$pgtitle = [gettext('Services'), gettext('DHCP Relay')];
153 151
$shortcut_section = 'dhcrelay';
154
include('head.inc');
155 152

  
156
if ($dhcpd_enabled) {
157
	print_info_box(gettext('DHCP Server is currently enabled. DHCP Relay cannot be enabled while the DHCP Server is enabled on any interface.'), 'danger', false);
158
}
153
include('head.inc');
159 154

  
160 155
if ($input_errors) {
161 156
	print_input_errors($input_errors);
......
165 160
	print_apply_result_box($retval);
166 161
}
167 162

  
168
$form = new Form(gettext('Save'), !$dhcpd_enabled);
163
$form = new Form(gettext('Save'));
169 164

  
170 165
$section = new Form_Section(gettext('DHCP Relay Configuration'));
171 166

  
......
173 168
	'enable',
174 169
	gettext('Enable'),
175 170
	gettext('Enable DHCP Relay'),
176
	$pconfig['enable']
171
	(!empty($iflist) ? $pconfig['enable'] : false)
177 172
);
178

  
179
if ($dhcpd_enabled) {
173
if (empty($iflist)) {
180 174
	$input->setAttribute('disabled', true);
181 175
}
182

  
183 176
$section->addInput($input);
184 177

  
185 178
$section->addInput(new Form_Select(
186 179
	'interface',
187
	'*Interface(s)',
180
	'*'.gettext('Downstream Interface(s)'),
188 181
	$pconfig['interface'],
189 182
	$iflist,
190 183
	true
191
))->setHelp('Interfaces without an IP address will not be shown.');
184
))->setHelp(gettext('Interface(s) from which requests from clients or other relay agents will be accepted.') . '%s' .
185
    gettext('Interfaces running DHCP Server or without a static IPv4 address will not be shown.'), '<br />');
192 186

  
193 187
$section->addInput(new Form_Select(
194 188
	'carpstatusvip',
195
	'*CARP Status VIP',
189
	'*'.gettext('CARP Status VIP'),
196 190
	$pconfig['carpstatusvip'],
197 191
	$carpiflist,
198
))->setHelp('Used to determine the HA MASTER/BACKUP status. DHCP Relay will be stopped when the ' .
199
	    'chosen VIP is in BACKUP status, and started in MASTER status.');
192
))->setHelp(gettext('DHCP Relay will be stopped when the chosen CARP VIP is in BACKUP status, and started in MASTER status.'));
200 193

  
201 194
$section->addInput(new Form_Checkbox(
202 195
	'agentoption',
203
	'',
196
	null,
204 197
	'Append circuit ID and agent ID to requests',
205 198
	$pconfig['agentoption']
206
))->setHelp(
207
	'If this is checked, the DHCP Relay will append the circuit ID (%s interface number) and the agent ID to the DHCP request.',
208
	g_get('product_label')
209
	);
210

  
211
$counter = 0;
212
foreach (explode(',', $pconfig['server']) as $server) {
213
	$group = new Form_Group($counter == 0 ? gettext("*Destination server"):'');
199
))->setHelp(gettext('If this is checked, the DHCP Relay will append the circuit ID (%s interface number) and the agent ID to the DHCP request.'),
200
    g_get('product_label'));
201

  
202
$servers = explode(',', $pconfig['server']);
203
$last = (count($servers) - 1);
204
foreach ($servers as $counter => $server) {
205
	$group = new Form_Group(($counter == 0) ? '*'.gettext('Upstream Servers') : '');
214 206
	$group->addClass('repeatable');
215 207

  
216 208
	$group->add(new Form_IpAddress(
217 209
		'server' . $counter,
218
		'Destination server',
210
		gettext('Upstream Server'),
219 211
		$server,
220 212
		'V4'
221
	))->setWidth(4)
222
	  ->setHelp('This is the IPv4 address of the server to which DHCP requests are relayed.');
213
	))->addClass('autotrim')
214
          ->setHelp(($counter == $last) ? gettext('IPv4 address of the upstream server to which requests are relayed.') : '');
223 215

  
224 216
	$group->add(new Form_Button(
225 217
		'deleterow' . $counter,
226
		'Delete',
218
		gettext('Delete'),
227 219
		null,
228 220
		'fa-trash'
229 221
	))->addClass('btn-warning');
......
232 224
	$counter++;
233 225
}
234 226

  
235
$form->add($section);
236

  
227
$group = new Form_Group(null);
237 228
$button = new Form_Button(
238 229
	'addrow',
239
	gettext('Add server'),
230
	gettext('Add Upstream Server'),
240 231
	null,
241 232
	'fa-plus'
242 233
);
243
$button->addClass('btn-success addbtn');
244
if ($dhcpd_enabled) {
245
	$button->setAttribute('disabled', true);
246
}
247
$form->addGlobal($button);
234
$button->addClass('btn-success btn-sm addbtn');
235
$group->add($button);
236
$section->add($group);
248 237

  
249
print $form;
238
$form->add($section);
239

  
240
print($form);
250 241
?>
251 242
<script type="text/javascript">
252 243
//<![CDATA[
253
	events.push(function() {
254

  
255
		function updateSection(hide) {
256
			if (hide) {
257
				$('[name="interface[]"]').parent().parent('div').addClass('hidden');
258
			} else {
259
				$('[name="interface[]"]').parent().parent('div').removeClass('hidden');
260
			}
261

  
262
			hideCheckbox('agentoption', hide);
263
			hideInput('carpstatusvip', hide);
264
			hideClass('repeatable', hide);
265
		}
266

  
267
		$('#enable').click(function () {
268
			updateSection(!this.checked);
269
    	});
270

  
271
    	updateSection(!$('#enable').prop('checked'));
244
events.push(function() {
245
	// Suppress "Delete" button if there are fewer than two rows
246
	checkLastRow();
272 247

  
273
		// Suppress "Delete row" button if there are fewer than two rows
274
		checkLastRow();
248
	// Automatically remove whitespace on changes to .autotrim elements
249
	$('body').on('change', '.autotrim', function () {
250
		$(this).val($(this).val().replace(/\s/g, ''));
275 251
	});
252
});
276 253
//]]>
277 254
</script>
278 255

  
279 256
<?php
280
include("foot.inc");
257
include('foot.inc');

Also available in: Unified diff