Project

General

Profile

Feature #3718 » radvd-routes-enhancment-2.3.4.patch

Marc Posch, 08/11/2017 04:00 PM

View differences:

/etc/inc/services.inc 2017-08-11 21:59:32.000000000 +0200
185 185
			case "stateless_dhcp":
186 186
				$radvdconf .= "\tAdvManagedFlag off;\n";
187 187
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
188 188
				break;
189 189
		}
190
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
191
		if ($racarpif == true) {
192
			$radvdconf .= "\t\tDeprecatePrefix off;\n";
193
		} else {
194
			$radvdconf .= "\t\tDeprecatePrefix on;\n";
195
		}
196
		switch ($dhcpv6ifconf['ramode']) {
197
			case "managed":
198
				$radvdconf .= "\t\tAdvOnLink on;\n";
199
				$radvdconf .= "\t\tAdvAutonomous off;\n";
200
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
201
				break;
202
			case "router":
203
				$radvdconf .= "\t\tAdvOnLink off;\n";
204
				$radvdconf .= "\t\tAdvAutonomous off;\n";
205
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
206
				break;
207
			case "stateless_dhcp":
208
			case "assist":
209
				$radvdconf .= "\t\tAdvOnLink on;\n";
210
				$radvdconf .= "\t\tAdvAutonomous on;\n";
211
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
212
				break;
213
			case "unmanaged":
214
				$radvdconf .= "\t\tAdvOnLink on;\n";
215
				$radvdconf .= "\t\tAdvAutonomous on;\n";
216
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
217
				break;
218
		}
219

  
220
		if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
221
		  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
222
		} else {
223
		  $radvdconf .= "\t\tAdvValidLifetime 86400;\n";
224
		}
225

  
226
		if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
227
		  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
228
		} else {
229
		  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
230
		}
231

  
232
		$radvdconf .= "\t};\n";
233

  
190
		/* If there are subnets defined, do not generate prefix for interface subnet, but use the user-specified subnets instead */
234 191
		if (is_array($dhcpv6ifconf['subnets']['item'])) {
235
			foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) {
236
				if (is_subnetv6($subnet)) {
237
					$radvdconf .= "\tprefix {$subnet} {\n";
192
		foreach ($dhcpv6ifconf['subnets']['item'] as $dhcpv6subnet) {
193
				$radvdconf .= "\tprefix {$dhcpv6subnet} {\n";
194
				if ($racarpif == true) {
195
					$radvdconf .= "\t\tDeprecatePrefix off;\n";
196
				} else {
238 197
					$radvdconf .= "\t\tDeprecatePrefix on;\n";
239
					switch ($dhcpv6ifconf['ramode']) {
240
						case "managed":
241
							$radvdconf .= "\t\tAdvOnLink on;\n";
242
							$radvdconf .= "\t\tAdvAutonomous off;\n";
243
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
244
							break;
245
						case "router":
246
							$radvdconf .= "\t\tAdvOnLink off;\n";
247
							$radvdconf .= "\t\tAdvAutonomous off;\n";
248
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
249
							break;
250
						case "assist":
251
							$radvdconf .= "\t\tAdvOnLink on;\n";
252
							$radvdconf .= "\t\tAdvAutonomous on;\n";
253
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
254
							break;
255
						case "unmanaged":
256
							$radvdconf .= "\t\tAdvOnLink on;\n";
257
							$radvdconf .= "\t\tAdvAutonomous on;\n";
258
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
259
							break;
260
					}
261
					$radvdconf .= "\t};\n";
262 198
				}
199
				switch($dhcpv6ifconf['ramode']) {
200
					case "managed":
201
						$radvdconf .= "\t\tAdvOnLink on;\n";
202
						$radvdconf .= "\t\tAdvAutonomous off;\n";
203
						$radvdconf .= "\t\tAdvRouterAddr on;\n";
204
						break;
205
					case "router":
206
						$radvdconf .= "\t\tAdvOnLink off;\n";
207
						$radvdconf .= "\t\tAdvAutonomous off;\n";
208
						$radvdconf .= "\t\tAdvRouterAddr on;\n";
209
						break;
210
					case "stateless_dhcp":
211
					case "assist":
212
						$radvdconf .= "\t\tAdvOnLink on;\n";
213
						$radvdconf .= "\t\tAdvAutonomous on;\n";
214
						$radvdconf .= "\t\tAdvRouterAddr on;\n";
215
						break;
216
					case "unmanaged":
217
						$radvdconf .= "\t\tAdvOnLink on;\n";
218
						$radvdconf .= "\t\tAdvAutonomous on;\n";
219
						$radvdconf .= "\t\tAdvRouterAddr on;\n";
220
						break;
221
						
222
				}
223
				if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
224
				  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
225
				} else {
226
				  $radvdconf .= "\t\tAdvValidLifetime 14400;\n";
227
				}
228
				if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
229
				  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
230
				} else {
231
				  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
232
				}
233
				$radvdconf .= "\t};\n";
263 234
			}
264 235
		}
265
		$radvdconf .= "\troute ::/0 {\n";
266
		$radvdconf .= "\t\tRemoveRoute on;\n";
267
		$radvdconf .= "\t};\n";
236

  
237
		/* There are no user-specified subnets, so generate prefix for the interface subnet only */
238
		else {
239
			$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
240
			if ($racarpif == true) {
241
				$radvdconf .= "\t\tDeprecatePrefix off;\n";
242
			} else {
243
				$radvdconf .= "\t\tDeprecatePrefix on;\n";
244
			}
245
			switch ($dhcpv6ifconf['ramode']) {
246
				case "managed":
247
					$radvdconf .= "\t\tAdvOnLink on;\n";
248
					$radvdconf .= "\t\tAdvAutonomous off;\n";
249
					$radvdconf .= "\t\tAdvRouterAddr on;\n";
250
					break;
251
				case "router":
252
					$radvdconf .= "\t\tAdvOnLink off;\n";
253
					$radvdconf .= "\t\tAdvAutonomous off;\n";
254
					$radvdconf .= "\t\tAdvRouterAddr on;\n";
255
					break;
256
				case "stateless_dhcp":
257
				case "assist":
258
					$radvdconf .= "\t\tAdvOnLink on;\n";
259
					$radvdconf .= "\t\tAdvAutonomous on;\n";
260
					$radvdconf .= "\t\tAdvRouterAddr on;\n";
261
					break;
262
				case "unmanaged":
263
					$radvdconf .= "\t\tAdvOnLink on;\n";
264
					$radvdconf .= "\t\tAdvAutonomous on;\n";
265
					$radvdconf .= "\t\tAdvRouterAddr on;\n";
266
					break;
267
			}
268
			if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
269
			  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
270
			} else {
271
			  $radvdconf .= "\t\tAdvValidLifetime 86400;\n";
272
			}
273
			if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
274
			  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
275
			} else {
276
			  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
277
			}
278
			$radvdconf .= "\t};\n";
279
		}
280
		/* If there are routes defined, do not generate a default route, but use the user-specified routes instead */
281
		if (is_array($dhcpv6ifconf['routes']['item'])) {
282
			foreach ($dhcpv6ifconf['routes']['item'] as $dhcpv6route) {
283
				$radvdconf .= "\troute " . $dhcpv6route['destination'] . " {\n";
284
				$radvdconf .= "\t\tRemoveRoute on;\n";
285
				$radvdconf .= "\t\tAdvRoutePreference " . $dhcpv6route['priority'] . ";\n";
286
				$radvdconf .= "\t};\n";
287
			}
288
		}
289
		/* There are no user-specified routes, so generate a default route entry */
290
		else {
291
			$radvdconf .= "\troute ::/0 {\n";
292
			$radvdconf .= "\t\tRemoveRoute on;\n";
293
			$radvdconf .= "\t};\n";
294
		}
268 295

  
269 296
		/* add DNS servers */
270 297
		$dnslist = array();
271 298
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
272 299
			foreach ($dhcpv6ifconf['dnsserver'] as $server) {
273
-- /usr/local/www/services_router_advertisements.php.orig	2017-05-03 19:07:40.000000000 +0200
300
++ /usr/local/www/services_router_advertisements.php	2017-08-11 22:39:59.000000000 +0200
......
128 128
	$pconfig['radomainsearchlist'] = $config['dhcpdv6'][$if]['radomainsearchlist'];
129 129
	list($pconfig['radns1'], $pconfig['radns2'], $pconfig['radns3']) = $config['dhcpdv6'][$if]['radnsserver'];
130 130
	$pconfig['rasamednsasdhcp6'] = isset($config['dhcpdv6'][$if]['rasamednsasdhcp6']);
131 131

  
132 132
	$pconfig['subnets'] = $config['dhcpdv6'][$if]['subnets']['item'];
133
	$pconfig['routes'] = $config['dhcpdv6'][$if]['routes']['item'];
133 134
}
134 135
if (!is_array($pconfig['subnets'])) {
135 136
	$pconfig['subnets'] = array();
136 137
}
138
if (!is_array($pconfig['routes'])) {
139
	$pconfig['routes'] = array();
140
}
137 141

  
138 142
$advertise_modes = array(
139 143
	"disabled" => 	gettext("Disabled"),
140 144
	"router" => 	gettext("Router Only - RA Flags [none], Prefix Flags [router]"),
141 145
	"unmanaged" => 	gettext("Unmanaged - RA Flags [none], Prefix Flags [onlink, auto, router]"),
......
151 155
	gettext("Subnets are specified in CIDR format.  " .
152 156
		"Select the CIDR mask that pertains to each entry.	" .
153 157
		"/128 specifies a single IPv6 host; /64 specifies a normal IPv6 network; etc.  " .
154 158
		"If no subnets are specified here, the Router Advertisement (RA) Daemon will advertise to the subnet to which the router's interface is assigned.") .
155 159
	'</span>';
160
$routes_help = '<span class="help-block">' .
161
	gettext("Routes are specified in CIDR format. " .
162
			"Enter subnets to which routes should be advertised, and their priority. " .
163
			"If you need a default route, specify it with ::/0 here.  " .
164
			"If no routes are specified here, the Router Advertisement (RA) Daemon will advertise only the default route.");
156 165

  
157 166
// THe use of <div class="infoblock"> here causes the text to be hidden until the user clicks the "info" icon
158 167
$ramode_help = gettext('Select the Operating Mode for the Router Advertisement (RA) Daemon.') .
159 168
	'<div class="infoblock">' .
160 169
	'<dl class="dl-horizontal responsive">' .
......
194 203
			if (!is_ipaddrv6($address)) {
195 204
				$input_errors[] = sprintf(gettext("An invalid subnet or alias was specified. [%s/%s]"), $address, $bits);
196 205
			}
197 206
		}
198 207
	}
208
	$pconfig['routes'] = array();
209
	for ($x = 0; $x < 5000; $x += 1) {
210
		$address = trim($_POST['route_address' . $x]);
211
		if ($address === "") {
212
			continue;
213
		}
214
		$bits = trim($_POST['route_bits' . $x]);
215
		if ($bits === "") {
216
			$bits = "128";
217
		}
218
		$priority = trim($_POST['route_priority' . $x]);
219
		if ($priority === "0") {
220
			$priority = "medium";
221
		}
222
		if (is_alias($address)) {
223
			$pconfig['routes'][] = array('destination' => $address);
224
		} else {
225
			$pconfig['routes'][] = array('destination' => $address . "/" . $bits, 'priority' => $priority);
226
			if (!is_ipaddrv6($address)) {
227
				$input_errors[] = sprintf(gettext("An invalid route was specified. [%s/%s]"), $address, $bits);
228
			}
229
		}
230
	}
199 231

  
200 232
	if (($_POST['radns1'] && !is_ipaddrv6($_POST['radns1'])) || ($_POST['radns2'] && !is_ipaddrv6($_POST['radns2'])) || ($_POST['radns3'] && !is_ipaddrv6($_POST['radns3']))) {
201 233
		$input_errors[] = gettext("A valid IPv6 address must be specified for each of the DNS servers.");
202 234
	}
203 235
	if ($_POST['radomainsearchlist']) {
......
271 303
		if (count($pconfig['subnets'])) {
272 304
			$config['dhcpdv6'][$if]['subnets']['item'] = $pconfig['subnets'];
273 305
		} else {
274 306
			unset($config['dhcpdv6'][$if]['subnets']);
275 307
		}
308
		if (count($pconfig['routes'])) {
309
			$config['dhcpdv6'][$if]['routes']['item'] = $pconfig['routes'];
310
		} else {
311
			unset($config['dhcpdv6'][$if]['routes']);
312
		}
276 313

  
277 314
		write_config();
278 315
		$retval = services_radvd_configure();
279 316
		$savemsg = get_std_save_message($retval);
280 317
	}
......
464 501
	'addrow',
465 502
	'Add',
466 503
	null,
467 504
	'fa-plus'
468 505
))->addClass('btn-success');
506
/*-----------------------------------------------------------------------------*/
507
$section->addInput(new Form_StaticText(
508
	'Routes',
509
	$routes_help
510
));
511

  
512
if (empty($pconfig['routes'])) {
513
	$pconfig['routes'] = array('0' => '/128');
514
}
515

  
516
$route_counter = 0;
517
$numrows = count($pconfig['routes']) - 1;
518
$route_priority_modes = $priority_modes;
519
array_unshift($route_priority_modes, '');
520
foreach ($pconfig['routes'] as $route) {
521
	$route_address_name = "route_address" . $route_counter;
522
	$route_bits_name = "route_bits" . $route_counter;
523
	$route_priority_name = "route_priority" . $route_counter;
524
	list($address, $mask) = explode("/", $route['destination']);
525
	$priority = $route['priority'];
526
	$group = new Form_Group($route_counter == 0 ? 'Routes':'');
527
	$group->add(new Form_IpAddress(
528
		$route_address_name,
529
		null,
530
		$address
531
	))->addMask($route_bits_name, $mask, 128, 0);
532
	$group->add(new Form_Select(
533
	$route_priority_name,
534
	null,
535
	$priority,
536
	$route_priority_modes
537
	));
538
	$group->add(new Form_Button(
539
		'deleterow_routes' . $route_counter,
540
		'Delete',
541
		null,
542
		'fa-trash'
543
	))->removeClass('btn-primary')->addClass('btn-warning');
544
	$group->addClass('repeatable_routes');
545
	$section->add($group);
546
	$route_counter++;
547
}
548
$section->addInput(new Form_Button(
549
	'addrow_routes',
550
	'Add',
551
	null,
552
	'fa-plus'
553
))->addClass('btn-success');
554
/*-----------------------------------------------------------------------------*/
469 555

  
470 556
$form->add($section);
471 557

  
472 558
$section = new Form_Section('DNS Configuration');
473 559

  
......
508 594

  
509 595
<script type="text/javascript">
510 596
//<![CDATA[
511 597
events.push(function() {
512 598
	// Suppress "Delete row" button if there are fewer than two rows
513
	checkLastRow();
599
	checkLastRow(this.id);
514 600

  
515 601
	// --------- Autocomplete -----------------------------------------------------------------------------------------
516 602
	var addressarray = <?= json_encode(get_alias_list(array("host", "network", "openvpn", "urltable"))) ?>;
517 603

  
518 604
	$('#radns1, #radns2, #radns3').autocomplete({
519
-- /usr/local/www/js/pfSenseHelpers.js.orig	2017-05-03 19:07:40.000000000 +0200
605
++ /usr/local/www/js/pfSenseHelpers.js	2017-08-11 22:31:35.000000000 +0200
......
271 271
  return newStr || str;
272 272
}
273 273

  
274 274
// Called after a delete so that there are no gaps in the numbering. Most of the time the config system doesn't care about
275 275
// gaps, but I do :)
276
function renumber() {
276
function renumber(element_id) {
277 277
	var idx = 0;
278
	var groupName = getRowGroupName(element_id);
278 279

  
279
	$('.repeatable').each(function() {
280
	$('.repeatable' + groupName).each(function() {
280 281

  
281 282
		$(this).find('input').each(function() {
282 283
			$(this).prop("id", this.id.replace(/\d+$/, "") + idx);
283 284
			$(this).prop("name", this.name.replace(/\d+$/, "") + idx);
284 285
		});
......
297 298

  
298 299
		idx++;
299 300
	});
300 301
}
301 302

  
303
// Return the repeatable group number, if it is defined (=added as number to the end of the control's id, e.g. "addrow2")
304
function getRowGroupName(element_id) {
305
	var groupName = ''; // Always make sure we du return an empty string, so we can use it in a concatenation without doing additional if checks
306
	var regexString = /^[a-zA-Z]+(_[a-zA-Z]+)[0-9]*$/; // match any string that begins with one or more characters, has a group name after a '_' and ends with nothing or numbers
307
	var regexResult = regexString.exec(element_id);
308
	if (regexResult != null) { // the capture inside the parentheses has succeeded, so we have successfully captured a group name
309
		groupName = regexResult[1]; // only then, assign the second value to groupName
310
	}
311
	return groupName;
312
}
313

  
302 314
function delete_row(rowDelBtn) {
303 315
	var rowLabel;
316
	var groupName = getRowGroupName(rowDelBtn);
304 317

  
305 318
	// If we are deleting row zero, we need to save/restore the label
306
	if ( (rowDelBtn == "deleterow0") && ((typeof retainhelp) == "undefined")) {
319
	if ((rowDelBtn == "deleterow" + groupName + "0") && ((typeof retainhelp) == "undefined")) {
307 320
		rowLabel = $('#' + rowDelBtn).parent('div').parent('div').find('label').text();
308 321
	}
309 322

  
310 323
	$('#' + rowDelBtn).parent('div').parent('div').remove();
311 324

  
312 325
	renumber();
313 326
	checkLastRow();
327
	renumber(rowDelBtn);
328
	checkLastRow(rowDelBtn);
314 329

  
315
	if (rowDelBtn == "deleterow0") {
330
	if (rowDelBtn == "deleterow" + groupName + "0") {
316 331
		$('#' + rowDelBtn).parent('div').parent('div').find('label').text(rowLabel);
317 332
	}
318 333
}
319 334

  
320
function checkLastRow() {
321
	if ($('.repeatable').length <= 1) {
322
		$('#deleterow0').hide();
335
function checkLastRow(element_id) {
336
	var groupName = getRowGroupName(element_id);
337
	if($('.repeatable' + groupName).length <= 1) {
338
		$('#deleterow' + groupName + '0').hide();
323 339
	} else {
324
		$('[id^=deleterow]').show();
340
		$('[id^=deleterow' + groupName + ']').show();
325 341
	}
326 342
}
327 343

  
328
function add_row() {
344
function add_row(rowAddBtn) {
345
	var groupName = getRowGroupName(rowAddBtn);
346
	
329 347
	// Find the last repeatable group
330
	var lastRepeatableGroup = $('.repeatable:last');
348
	var lastRepeatableGroup = $('.repeatable' + groupName + ':last');
331 349

  
332 350
	// If the number of repeats exceeds the maximum, do not add another clone
333 351
	if ($('.repeatable').length >= lastRepeatableGroup.attr('max_repeats')) {
334 352
		// Alert user if alert message is specified
335 353
		if (typeof lastRepeatableGroup.attr('max_repeats_alert') !== 'undefined') {
......
370 388
				}));
371 389
			}
372 390
		}
373 391
	});
374 392

  
393
	// Somehow delete button IDs did not increment, so increment the suffix number for delete buttons also
394
	$(newGroup).find('button').each(function() {
395
		$(this).prop("id", bumpStringInt(this.id));
396
		$(this).prop("name", bumpStringInt(this.name));
397
	});
375 398
	// And for "for" tags
376 399
//	$(newGroup).find('label').attr('for', bumpStringInt($(newGroup).find('label').attr('for')));
377 400

  
378 401
	$(newGroup).find('label:first').text(""); // Clear the label. We only want it on the very first row
379 402

  
......
386 409
			$(this).remove();
387 410
	});
388 411

  
389 412
	setMasks();
390 413

  
391
	checkLastRow();
414
	checkLastRow(rowAddBtn);
392 415

  
393 416
	// Autocomplete
394 417
	if ( typeof addressarray !== 'undefined') {
395 418
		$('[id^=address]').each(function() {
396 419
			if (this.id.substring(0, 8) != "address_") {
......
402 425
	}
403 426

  
404 427
	// Now that we are no longer cloning the event handlers, we need to remove and re-add after a new row
405 428
	// has been added to the table
406 429
	$('[id^=delete]').unbind();
407
	$('[id^=delete]').click(function(event) {
408
		if ($('.repeatable').length > 1) {
430
	$('[id^=delete]').click(function() {
431
		var groupName = getRowGroupName(this.id);
432
		if($('.repeatable' + groupName).length > 1) {
409 433
			if ((typeof retainhelp) == "undefined")
410
				moveHelpText(event.target.id);
434
+				moveHelpText(this.id);
411 435

  
412
			delete_row(event.target.id);
436
			delete_row(this.id);
413 437
		} else {
414 438
			alert('The last row may not be deleted.');
415 439
		}
416 440
	});
417 441

  
......
421 445
$('[id^=addrow]').prop('type','button');
422 446
$('[id^=delete]').prop('type','button');
423 447

  
424 448
// on click . .
425 449
$('[id^=addrow]').click(function() {
426
	add_row();
450
	add_row(this.id);
427 451
});
428 452

  
429
$('[id^=delete]').click(function(event) {
430
	if ($('.repeatable').length > 1) {
453
$('[id^=delete]').click(function() {
454
	var groupName = getRowGroupName(this.id);
455
	if($('.repeatable' + groupName).length > 1) {
431 456
		if ((typeof retainhelp) == "undefined")
432 457
			moveHelpText($(this).attr("id"));
433 458

  
434 459
		delete_row($(this).attr("id"));
435 460
	} else {
(6-6/7)