Project

General

Profile

Feature #3718 » radvd-routes-enhancment.patch

Marc Posch, 07/23/2016 09:23 AM

View differences:

/etc/inc/services.inc Sat Jul 23 14:57:51 2016
167 167
			case "stateless_dhcp":
168 168
				$radvdconf .= "\tAdvManagedFlag off;\n";
169 169
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
170 170
				break;
171 171
		}
172
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
173
		if ($racarpif == true) {
174
			$radvdconf .= "\t\tDeprecatePrefix off;\n";
175
		} else {
176
			$radvdconf .= "\t\tDeprecatePrefix on;\n";
177
		}
178
		switch ($dhcpv6ifconf['ramode']) {
179
			case "managed":
180
				$radvdconf .= "\t\tAdvOnLink on;\n";
181
				$radvdconf .= "\t\tAdvAutonomous off;\n";
182
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
183
				break;
184
			case "router":
185
				$radvdconf .= "\t\tAdvOnLink off;\n";
186
				$radvdconf .= "\t\tAdvAutonomous off;\n";
187
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
188
				break;
189
			case "stateless_dhcp":
190
			case "assist":
191
				$radvdconf .= "\t\tAdvOnLink on;\n";
192
				$radvdconf .= "\t\tAdvAutonomous on;\n";
193
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
194
				break;
195
			case "unmanaged":
196
				$radvdconf .= "\t\tAdvOnLink on;\n";
197
				$radvdconf .= "\t\tAdvAutonomous on;\n";
198
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
199
				break;
200
		}
172
		/* If there are subnets defined, do not generate prefix for interface subnet, but use the user-specified subnets instead */
173
		if (is_array($dhcpv6ifconf['subnets']['item'])) {
174
		foreach ($dhcpv6ifconf['subnets']['item'] as $dhcpv6subnet) {
175
				$radvdconf .= "\tprefix {$dhcpv6subnet} {\n";
176
				if ($racarpif == true) {
177
					$radvdconf .= "\t\tDeprecatePrefix off;\n";
178
				} else {
179
					$radvdconf .= "\t\tDeprecatePrefix on;\n";
180
				}
181
				switch($dhcpv6ifconf['ramode']) {
182
					case "managed":
183
						$radvdconf .= "\t\tAdvOnLink on;\n";
184
						$radvdconf .= "\t\tAdvAutonomous off;\n";
185
						$radvdconf .= "\t\tAdvRouterAddr on;\n";
186
						break;
187
					case "router":
188
						$radvdconf .= "\t\tAdvOnLink off;\n";
189
						$radvdconf .= "\t\tAdvAutonomous off;\n";
190
						$radvdconf .= "\t\tAdvRouterAddr on;\n";
191
						break;
192
					case "stateless_dhcp":
193
					case "assist":
194
						$radvdconf .= "\t\tAdvOnLink on;\n";
195
						$radvdconf .= "\t\tAdvAutonomous on;\n";
196
						$radvdconf .= "\t\tAdvRouterAddr on;\n";
197
						break;
198
					case "unmanaged":
199
						$radvdconf .= "\t\tAdvOnLink on;\n";
200
						$radvdconf .= "\t\tAdvAutonomous on;\n";
201
						$radvdconf .= "\t\tAdvRouterAddr on;\n";
202
						break;
203
						
204
				}
205
				if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
206
				  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
207
				} else {
208
				  $radvdconf .= "\t\tAdvValidLifetime 86400;\n";
209
				}
201 210

  
202
		if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
203
		  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
204
		} else {
205
		  $radvdconf .= "\t\tAdvValidLifetime 86400;\n";
211
				if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
212
				  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
213
				} else {
214
				  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
215
				}
216
				$radvdconf .= "\t};\n";
217
			}
206 218
		}
207 219

  
208
		if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
209
		  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
210
		} else {
211
		  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
220
		/* There are no user-specified subnets, so generate prefix for the interface subnet only */
221
		else {
222
			$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
223
			if ($racarpif == true) {
224
				$radvdconf .= "\t\tDeprecatePrefix off;\n";
225
			} else {
226
				$radvdconf .= "\t\tDeprecatePrefix on;\n";
227
			}
228
			switch ($dhcpv6ifconf['ramode']) {
229
				case "managed":
230
					$radvdconf .= "\t\tAdvOnLink on;\n";
231
					$radvdconf .= "\t\tAdvAutonomous off;\n";
232
					$radvdconf .= "\t\tAdvRouterAddr on;\n";
233
					break;
234
				case "router":
235
					$radvdconf .= "\t\tAdvOnLink off;\n";
236
					$radvdconf .= "\t\tAdvAutonomous off;\n";
237
					$radvdconf .= "\t\tAdvRouterAddr on;\n";
238
					break;
239
				case "stateless_dhcp":
240
				case "assist":
241
					$radvdconf .= "\t\tAdvOnLink on;\n";
242
					$radvdconf .= "\t\tAdvAutonomous on;\n";
243
					$radvdconf .= "\t\tAdvRouterAddr on;\n";
244
					break;
245
				case "unmanaged":
246
					$radvdconf .= "\t\tAdvOnLink on;\n";
247
					$radvdconf .= "\t\tAdvAutonomous on;\n";
248
					$radvdconf .= "\t\tAdvRouterAddr on;\n";
249
					break;
250
			}
251
			if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
252
			  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
253
			} else {
254
			  $radvdconf .= "\t\tAdvValidLifetime 86400;\n";
255
			}
256
			if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
257
			  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
258
			} else {
259
			  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
260
			}
261
			$radvdconf .= "\t};\n";
212 262
		}
213

  
214
		$radvdconf .= "\t};\n";
215

  
216
		if (is_array($dhcpv6ifconf['subnets']['item'])) {
217
			foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) {
218
				if (is_subnetv6($subnet)) {
219
					$radvdconf .= "\tprefix {$subnet} {\n";
220
					$radvdconf .= "\t\tDeprecatePrefix on;\n";
221
					switch ($dhcpv6ifconf['ramode']) {
222
						case "managed":
223
							$radvdconf .= "\t\tAdvOnLink on;\n";
224
							$radvdconf .= "\t\tAdvAutonomous off;\n";
225
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
226
							break;
227
						case "router":
228
							$radvdconf .= "\t\tAdvOnLink off;\n";
229
							$radvdconf .= "\t\tAdvAutonomous off;\n";
230
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
231
							break;
232
						case "assist":
233
							$radvdconf .= "\t\tAdvOnLink on;\n";
234
							$radvdconf .= "\t\tAdvAutonomous on;\n";
235
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
236
							break;
237
						case "unmanaged":
238
							$radvdconf .= "\t\tAdvOnLink on;\n";
239
							$radvdconf .= "\t\tAdvAutonomous on;\n";
240
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
241
							break;
242
					}
243
					$radvdconf .= "\t};\n";
244
				}
263
		/* If there are routes defined, do not generate a default route, but use the user-specified routes instead */
264
		if (is_array($dhcpv6ifconf['routes']['item'])) {
265
			foreach ($dhcpv6ifconf['routes']['item'] as $dhcpv6route) {
266
				$radvdconf .= "\troute " . $dhcpv6route['destination'] . " {\n";
267
				$radvdconf .= "\t\tRemoveRoute on;\n";
268
				$radvdconf .= "\t\tAdvRoutePreference " . $dhcpv6route['priority'] . ";\n";
269
				$radvdconf .= "\t};\n";
245 270
			}
246 271
		}
247
		$radvdconf .= "\troute ::/0 {\n";
248
		$radvdconf .= "\t\tRemoveRoute on;\n";
249
		$radvdconf .= "\t};\n";
272
		/* There are no user-specified routes, so generate a default route entry */
273
		else {
274
			$radvdconf .= "\troute ::/0 {\n";
275
			$radvdconf .= "\t\tRemoveRoute on;\n";
276
			$radvdconf .= "\t};\n";
277
		}
250 278

  
251 279
		/* add DNS servers */
252 280
		$dnslist = array();
253 281
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
254 282
			foreach ($dhcpv6ifconf['dnsserver'] as $server) {
255
-- /usr/local/www/services_router_advertisements.php.orig	Mon May 16 23:22:25 2016
283
++ /usr/local/www/services_router_advertisements.php	Sat Jul 23 15:10:12 2016
......
131 131
	$pconfig['radomainsearchlist'] = $config['dhcpdv6'][$if]['radomainsearchlist'];
132 132
	list($pconfig['radns1'], $pconfig['radns2'], $pconfig['radns3']) = $config['dhcpdv6'][$if]['radnsserver'];
133 133
	$pconfig['rasamednsasdhcp6'] = isset($config['dhcpdv6'][$if]['rasamednsasdhcp6']);
134 134

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

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

  
160 169
if ($_POST) {
161 170
	unset($input_errors);
162 171

  
163 172
	$pconfig = $_POST;
......
183 192
			if (!is_ipaddrv6($address)) {
184 193
				$input_errors[] = sprintf(gettext("An invalid subnet or alias was specified. [%s/%s]"), $address, $bits);
185 194
			}
186 195
		}
187 196
	}
197
	$pconfig['routes'] = array();
198
	for ($x = 0; $x < 5000; $x += 1) {
199
		$address = trim($_POST['route_address' . $x]);
200
		if ($address === "") {
201
			continue;
202
		}
203
		$bits = trim($_POST['route_bits' . $x]);
204
		if ($bits === "") {
205
			$bits = "128";
206
		}
207
		$priority = trim($_POST['route_priority' . $x]);
208
		if ($priority === "0") {
209
			$priority = "medium";
210
		}
211
		if (is_alias($address)) {
212
			$pconfig['routes'][] = array('destination' => $address);
213
		} else {
214
			$pconfig['routes'][] = array('destination' => $address . "/" . $bits, 'priority' => $priority);
215
			if (!is_ipaddrv6($address)) {
216
				$input_errors[] = sprintf(gettext("An invalid route was specified. [%s/%s]"), $address, $bits);
217
			}
218
		}
219
	}
188 220

  
189 221
	if (($_POST['radns1'] && !is_ipaddrv6($_POST['radns1'])) || ($_POST['radns2'] && !is_ipaddrv6($_POST['radns2'])) || ($_POST['radns3'] && !is_ipaddrv6($_POST['radns3']))) {
190 222
		$input_errors[] = gettext("A valid IPv6 address must be specified for each of the DNS servers.");
191 223
	}
192 224
	if ($_POST['radomainsearchlist']) {
......
232 264
		if (count($pconfig['subnets'])) {
233 265
			$config['dhcpdv6'][$if]['subnets']['item'] = $pconfig['subnets'];
234 266
		} else {
235 267
			unset($config['dhcpdv6'][$if]['subnets']);
236 268
		}
269
		if (count($pconfig['routes'])) {
270
			$config['dhcpdv6'][$if]['routes']['item'] = $pconfig['routes'];
271
		} else {
272
			unset($config['dhcpdv6'][$if]['routes']);
273
		}
237 274

  
238 275
		write_config();
239 276
		$retval = services_radvd_configure();
240 277
		$savemsg = get_std_save_message($retval);
241 278
	}
......
401 438
	'addrow',
402 439
	'Add',
403 440
	null,
404 441
	'fa-plus'
405 442
))->addClass('btn-success');
443
/*-----------------------------------------------------------------------------*/
444
$section->addInput(new Form_StaticText(
445
	'Routes',
446
	$routes_help
447
));
448
$route_counter = 0;
449
$numrows = count($pconfig['routes']) - 1;
450
$route_priority_modes = $priority_modes;
451
array_unshift($route_priority_modes, '');
452
foreach ($pconfig['routes'] as $route) {
453
	$route_address_name = "route_address" . $route_counter;
454
	$route_bits_name = "route_bits" . $route_counter;
455
	$route_priority_name = "route_priority" . $route_counter;
456
	list($address, $mask) = explode("/", $route['destination']);
457
	$priority = $route['priority'];
458
	$group = new Form_Group($route_counter == 0 ? 'Routes':'');
459
	$group->add(new Form_IpAddress(
460
		$route_address_name,
461
		null,
462
		$address
463
	))->addMask($route_bits_name, $mask, 128, 0);
464
	$group->add(new Form_Select(
465
	$route_priority_name,
466
	null,
467
	$priority,
468
	$route_priority_modes
469
	));
470
	$group->add(new Form_Button(
471
		'deleterow_routes' . $route_counter,
472
		'Delete',
473
		null,
474
		'fa-trash'
475
	))->removeClass('btn-primary')->addClass('btn-warning');
476
	$group->addClass('repeatable_routes');
477
	$section->add($group);
478
	$route_counter++;
479
}
480
$section->addInput(new Form_Button(
481
	'addrow_routes',
482
	'Add',
483
	null,
484
	'fa-plus'
485
))->addClass('btn-success');
486
/*-----------------------------------------------------------------------------*/
406 487

  
407 488
$form->add($section);
408 489

  
409 490
$section = new Form_Section('DNS Configuration');
410 491

  
......
444 525

  
445 526
<script type="text/javascript">
446 527
//<![CDATA[
447 528
events.push(function() {
448 529
	// Suppress "Delete row" button if there are fewer than two rows
449
	checkLastRow();
530
	checkLastRow(this.id);
450 531

  
451 532
	// --------- Autocomplete -----------------------------------------------------------------------------------------
452 533
	var addressarray = <?= json_encode(get_alias_list(array("host", "network", "openvpn", "urltable"))) ?>;
453 534

  
454 535
	$('#radns1, #radns2, #radns3').autocomplete({
455
-- /usr/local/www/js/pfSenseHelpers.js.orig	Mon May 16 23:22:25 2016
536
++ /usr/local/www/js/pfSenseHelpers.js	Sat Jul 23 15:25:54 2016
......
262 262
  return newStr || str;
263 263
}
264 264

  
265 265
// Called after a delete so that there are no gaps in the numbering. Most of the time the config system doesn't care about
266 266
// gaps, but I do :)
267
function renumber() {
267
function renumber(element_id) {
268 268
	var idx = 0;
269
	var groupName = getRowGroupName(element_id);
269 270

  
270
	$('.repeatable').each(function() {
271
	$('.repeatable' + groupName).each(function() {
271 272

  
272 273
		$(this).find('input').each(function() {
273 274
			$(this).prop("id", this.id.replace(/\d+$/, "") + idx);
274 275
			$(this).prop("name", this.name.replace(/\d+$/, "") + idx);
275 276
		});
......
283 284

  
284 285
		idx++;
285 286
	});
286 287
}
287 288

  
289
// Return the repeatable group number, if it is defined (=added as number to the end of the control's id, e.g. "addrow2")
290
function getRowGroupName(element_id) {
291
	var groupName = ''; // Always make sure we du return an empty string, so we can use it in a concatenation without doing additional if checks
292
	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
293
	var regexResult = regexString.exec(element_id);
294
	if (regexResult != null) { // the capture inside the parentheses has succeeded, so we have successfully captured a group name
295
		groupName = regexResult[1]; // only then, assign the second value to groupName
296
	}
297
	return groupName;
298
}
299

  
288 300
function delete_row(rowDelBtn) {
289 301
	var rowLabel;
302
	var groupName = getRowGroupName(rowDelBtn);
290 303

  
291 304
	// If we are deleting row zero, we need to save/restore the label
292
	if (rowDelBtn == "deleterow0") {
305
	if (rowDelBtn == "deleterow" + groupName + "0") {
293 306
		rowLabel = $('#' + rowDelBtn).parent('div').parent('div').find('label').text();
294 307
	}
295 308

  
296 309
	$('#' + rowDelBtn).parent('div').parent('div').remove();
297
	renumber();
298
	checkLastRow();
310
	renumber(rowDelBtn);
311
	checkLastRow(rowDelBtn);
299 312

  
300
	if (rowDelBtn == "deleterow0") {
313
	if (rowDelBtn == "deleterow" + groupName + "0") {
301 314
		$('#' + rowDelBtn).parent('div').parent('div').find('label').text(rowLabel);
302 315
	}
303 316
}
304 317

  
305
function checkLastRow() {
306
	if ($('.repeatable').length <= 1) {
307
		$('#deleterow0').hide();
318
function checkLastRow(element_id) {
319
	var groupName = getRowGroupName(element_id);
320
	if($('.repeatable' + groupName).length <= 1) {
321
		$('#deleterow' + groupName + '0').hide();
308 322
	} else {
309
		$('[id^=deleterow]').show();
323
		$('[id^=deleterow' + groupName + ']').show();
310 324
	}
311 325
}
312 326

  
313
function add_row() {
327
function add_row(rowAddBtn) {
328
	var groupName = getRowGroupName(rowAddBtn);
329
	
314 330
	// Find the last repeatable group
315
	var lastRepeatableGroup = $('.repeatable:last');
331
	var lastRepeatableGroup = $('.repeatable' + groupName + ':last');
316 332

  
317 333
	// Clone it
318 334
	var newGroup = lastRepeatableGroup.clone();
319 335
	// Increment the suffix number for each input element in the new group
320 336
	$(newGroup).find('input').each(function() {
......
345 361
				}));
346 362
			}
347 363
		}
348 364
	});
349 365

  
366
	// Somehow delete button IDs did not increment, so increment the suffix number for delete buttons also
367
	$(newGroup).find('button').each(function() {
368
		$(this).prop("id", bumpStringInt(this.id));
369
		$(this).prop("name", bumpStringInt(this.name));
370
	});
371

  
350 372
	// And for "for" tags
351 373
//	$(newGroup).find('label').attr('for', bumpStringInt($(newGroup).find('label').attr('for')));
352 374

  
353 375
	$(newGroup).find('label').text(""); // Clear the label. We only want it on the very first row
354 376

  
......
361 383
			$(this).remove();
362 384
	});
363 385

  
364 386
	setMasks();
365 387

  
366
	checkLastRow();
388
	checkLastRow(rowAddBtn);
367 389

  
368 390
	// Autocomplete
369 391
	if ( typeof addressarray !== 'undefined') {
370 392
		$('[id^=address]').each(function() {
371 393
			if (this.id.substring(0, 8) != "address_") {
......
377 399
	}
378 400

  
379 401
	// Now that we are no longer cloning the event handlers, we need to remove and re-add after a new row
380 402
	// has been added to the table
381 403
	$('[id^=delete]').unbind();
382
	$('[id^=delete]').click(function(event) {
383
		if ($('.repeatable').length > 1) {
404
	$('[id^=delete]').click(function() {
405
		var groupName = getRowGroupName(this.id);
406
		if($('.repeatable' + groupName).length > 1) {
384 407
			if ((typeof retainhelp) == "undefined")
385
				moveHelpText(event.target.id);
408
				moveHelpText(this.id);
386 409

  
387
			delete_row(event.target.id);
410
			delete_row(this.id);
388 411
		} else {
389 412
			alert('The last row may not be deleted.');
390 413
		}
391 414
	});
392 415

  
......
396 419
$('[id^=addrow]').prop('type','button');
397 420
$('[id^=delete]').prop('type','button');
398 421

  
399 422
// on click . .
400 423
$('[id^=addrow]').click(function() {
401
	add_row();
424
	add_row(this.id);
402 425
});
403 426

  
404
$('[id^=delete]').click(function(event) {
405
	if ($('.repeatable').length > 1) {
427
$('[id^=delete]').click(function() {
428
	var groupName = getRowGroupName(this.id);
429
	if($('.repeatable' + groupName).length > 1) {
406 430
		if ((typeof retainhelp) == "undefined")
407
			moveHelpText(event.target.id);
431
			moveHelpText(this.id);
408 432

  
409
		delete_row(event.target.id);
433
		delete_row(this.id);
410 434
	} else {
411 435
		alert('The last row may not be deleted.');
412 436
	}
413 437
});
414 438

  
(4-4/7)