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');
|
dhcp: support simultaneous v4 dhcpd and dhcrelay, Implements #14620