View | Details | Raw Unified | Return to bug 2606 | Differences between
and this patch

Collapse All | Expand All

(-)a/configure.ac (+1 lines)
Lines 399-404 AC_CHECK_HEADERS([ \ Link Here
399
	inttypes.h \
399
	inttypes.h \
400
	langinfo.h \
400
	langinfo.h \
401
	limits.h \
401
	limits.h \
402
	linux/in6.h \
402
	locale.h \
403
	locale.h \
403
	login.h \
404
	login.h \
404
	maillock.h \
405
	maillock.h \
(-)a/ssh.c (-1 / +1 lines)
Lines 927-933 main(int ac, char **av) Link Here
927
			options.control_path = xstrdup(optarg);
927
			options.control_path = xstrdup(optarg);
928
			break;
928
			break;
929
		case 'b':
929
		case 'b':
930
			options.bind_address = optarg;
930
			options.bind_address = xstrdup(optarg);
931
			break;
931
			break;
932
		case 'F':
932
		case 'F':
933
			config = optarg;
933
			config = optarg;
(-)a/ssh_config.5 (+12 lines)
Lines 284-289 Note that this option does not work if Link Here
284
.Cm UsePrivilegedPort
284
.Cm UsePrivilegedPort
285
is set to
285
is set to
286
.Dq yes .
286
.Dq yes .
287
.Pp
288
Additionally, this option may be used to control the selection of IPv6
289
binding addresses on platforms that support it.
290
A
291
.Cm BindAddress
292
of
293
.Dq public
294
will cause
295
.Xr ssh 1
296
to use a stable public IPv6 address, while
297
.Dq temp
298
will prefer a randomised temporary address.
287
.It Cm CanonicalDomains
299
.It Cm CanonicalDomains
288
When
300
When
289
.Cm CanonicalizeHostname
301
.Cm CanonicalizeHostname
(-)a/sshconnect.c (-6 / +64 lines)
Lines 42-47 Link Here
42
#include <string.h>
42
#include <string.h>
43
#include <unistd.h>
43
#include <unistd.h>
44
44
45
#ifdef HAVE_LINUX_IN6_H
46
#include <linux/in6.h>
47
#endif
48
45
#include "xmalloc.h"
49
#include "xmalloc.h"
46
#include "key.h"
50
#include "key.h"
47
#include "hostfile.h"
51
#include "hostfile.h"
Lines 267-272 ssh_kill_proxy_command(void) Link Here
267
		kill(proxy_command_pid, SIGHUP);
271
		kill(proxy_command_pid, SIGHUP);
268
}
272
}
269
273
274
static int
275
set_v6_bindpref(int sock, const char *op)
276
{
277
#if defined(IPV6_ADDR_PREFERENCES) && defined(IPV6_PREFER_SRC_PUBLIC) && \
278
    defined(IPV6_PREFER_SRC_TMP) && defined(IPV6_PREFER_SRC_PUBTMP_DEFAULT)
279
	int val, add, del;
280
	socklen_t len = sizeof(val);
281
282
	if (strcasecmp(op, "%public") == 0 ||
283
	    strcasecmp(op, "%pub") == 0) {
284
		add = IPV6_PREFER_SRC_PUBLIC;
285
		del = IPV6_PREFER_SRC_TMP|IPV6_PREFER_SRC_PUBTMP_DEFAULT;
286
	} else if (strcasecmp(op, "%temporary") == 0 ||
287
		   strcasecmp(op, "%temp") == 0 ||
288
		   strcasecmp(op, "%tmp") == 0) {
289
		add = IPV6_PREFER_SRC_TMP;
290
		del = IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_PUBTMP_DEFAULT;
291
	} else
292
		return 0;
293
294
	debug("%s: setting IPV6_ADDR_PREFERENCES to %s", __func__, op+1);
295
296
	if (getsockopt(sock, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
297
	    &val, &len) != 0) {
298
		debug("%s: getsockopt: %s", __func__, strerror(errno));
299
		return -1;
300
	}
301
	val = (val & ~del) | add;
302
	if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
303
	    &val, len) != 0) {
304
		debug("%s: getsockopt: %s", __func__, strerror(errno));
305
		return -1;
306
	}
307
	return 1;
308
#else
309
	/* Silently eat operations on hosts that lack support */
310
	if (strcasecmp(op, "%public") == 0 ||
311
	    strcasecmp(op, "%pub") == 0 ||
312
	    strcasecmp(op, "%temporary") == 0 ||
313
	    strcasecmp(op, "%temp") == 0 ||
314
	    strcasecmp(op, "%tmp") == 0)
315
		return 1;
316
	return 0;
317
#endif
318
}
319
270
/*
320
/*
271
 * Creates a (possibly privileged) socket for use as the ssh connection.
321
 * Creates a (possibly privileged) socket for use as the ssh connection.
272
 */
322
 */
Lines 275-280 ssh_create_socket(int privileged, struct addrinfo *ai) Link Here
275
{
325
{
276
	int sock, r, gaierr;
326
	int sock, r, gaierr;
277
	struct addrinfo hints, *res = NULL;
327
	struct addrinfo hints, *res = NULL;
328
	const char *bind_address = options.bind_address;
278
329
279
	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
330
	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
280
	if (sock < 0) {
331
	if (sock < 0) {
Lines 283-301 ssh_create_socket(int privileged, struct addrinfo *ai) Link Here
283
	}
334
	}
284
	fcntl(sock, F_SETFD, FD_CLOEXEC);
335
	fcntl(sock, F_SETFD, FD_CLOEXEC);
285
336
337
	/* Support for IPV6_ADDR_PREFERENCES if present */
338
	if (ai->ai_family == AF_INET6 && bind_address != NULL) {
339
		if (set_v6_bindpref(sock, bind_address) != 0) {
340
			/* Skip explicit bind(2) below */
341
			bind_address = NULL;
342
		}
343
	}
344
286
	/* Bind the socket to an alternative local IP address */
345
	/* Bind the socket to an alternative local IP address */
287
	if (options.bind_address == NULL && !privileged)
346
	if (bind_address == NULL && !privileged)
288
		return sock;
347
		return sock;
289
348
290
	if (options.bind_address) {
349
	if (bind_address) {
291
		memset(&hints, 0, sizeof(hints));
350
		memset(&hints, 0, sizeof(hints));
292
		hints.ai_family = ai->ai_family;
351
		hints.ai_family = ai->ai_family;
293
		hints.ai_socktype = ai->ai_socktype;
352
		hints.ai_socktype = ai->ai_socktype;
294
		hints.ai_protocol = ai->ai_protocol;
353
		hints.ai_protocol = ai->ai_protocol;
295
		hints.ai_flags = AI_PASSIVE;
354
		hints.ai_flags = AI_PASSIVE;
296
		gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);
355
		gaierr = getaddrinfo(bind_address, NULL, &hints, &res);
297
		if (gaierr) {
356
		if (gaierr) {
298
			error("getaddrinfo: %s: %s", options.bind_address,
357
			error("getaddrinfo: %s: %s", bind_address,
299
			    ssh_gai_strerror(gaierr));
358
			    ssh_gai_strerror(gaierr));
300
			close(sock);
359
			close(sock);
301
			return -1;
360
			return -1;
Lines 316-323 ssh_create_socket(int privileged, struct addrinfo *ai) Link Here
316
		}
375
		}
317
	} else {
376
	} else {
318
		if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
377
		if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
319
			error("bind: %s: %s", options.bind_address,
378
			error("bind: %s: %s", bind_address, strerror(errno));
320
			    strerror(errno));
321
 fail:
379
 fail:
322
			close(sock);
380
			close(sock);
323
			freeaddrinfo(res);
381
			freeaddrinfo(res);

Return to bug 2606