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

Collapse All | Expand All

(-)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 / +53 lines)
Lines 267-272 ssh_kill_proxy_command(void) Link Here
267
		kill(proxy_command_pid, SIGHUP);
267
		kill(proxy_command_pid, SIGHUP);
268
}
268
}
269
269
270
static int
271
set_v6_bindpref(int sock, const char *op)
272
{
273
#if defined(IPV6_ADDR_PREFERENCES) && defined(IPV6_PREFER_SRC_PUBLIC) && \
274
    defined(IPV6_PREFER_SRC_TMP) && defined(IPV6_PREFER_SRC_PUBTMP_DEFAULT)
275
	int val, add, del;
276
	socklen_t len = sizeof(val);
277
278
	if (strcasecmp(op, "public") == 0) {
279
		add = IPV6_PREFER_SRC_PUBLIC;
280
		del = IPV6_PREFER_SRC_TMP|IPV6_PREFER_SRC_PUBTMP_DEFAULT;
281
	} else if (strcasecmp(op, "temp") == 0) {
282
		add = IPV6_PREFER_SRC_TMP;
283
		del = IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_PUBTMP_DEFAULT;
284
	} else
285
		return 0;
286
287
	debug("%s: setting IPV6_ADDR_PREFERENCES to %s", __func__, op);
288
289
	if (getsockopt(sock, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
290
	    &val, &len) != 0) {
291
		debug("%s: getsockopt: %s", __func__, strerror(errno));
292
		return -1;
293
	}
294
	val = (val & ~del) | add;
295
	if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
296
	    &val, len) != 0) {
297
		debug("%s: getsockopt: %s", __func__, strerror(errno));
298
		return -1;
299
	}
300
	return 1;
301
#else
302
	/* Silently eat public/temp operations on hosts that lack support */
303
	if (strcasecmp(op, "public") == 0 || strcasecmp(op, "temp") == 0)
304
		return 1;
305
	return 0;
306
#endif
307
}
308
270
/*
309
/*
271
 * Creates a (possibly privileged) socket for use as the ssh connection.
310
 * Creates a (possibly privileged) socket for use as the ssh connection.
272
 */
311
 */
Lines 275-280 ssh_create_socket(int privileged, struct addrinfo *ai) Link Here
275
{
314
{
276
	int sock, r, gaierr;
315
	int sock, r, gaierr;
277
	struct addrinfo hints, *res = NULL;
316
	struct addrinfo hints, *res = NULL;
317
	const char *bind_address = options.bind_address;
278
318
279
	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
319
	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
280
	if (sock < 0) {
320
	if (sock < 0) {
Lines 283-301 ssh_create_socket(int privileged, struct addrinfo *ai) Link Here
283
	}
323
	}
284
	fcntl(sock, F_SETFD, FD_CLOEXEC);
324
	fcntl(sock, F_SETFD, FD_CLOEXEC);
285
325
326
	/* Support for IPV6_ADDR_PREFERENCES if present */
327
	if (ai->ai_family == AF_INET6 && bind_address != NULL) {
328
		if (set_v6_bindpref(sock, bind_address) != 0) {
329
			/* Skip explicit bind(2) below */
330
			bind_address = NULL;
331
		}
332
	}
333
286
	/* Bind the socket to an alternative local IP address */
334
	/* Bind the socket to an alternative local IP address */
287
	if (options.bind_address == NULL && !privileged)
335
	if (bind_address == NULL && !privileged)
288
		return sock;
336
		return sock;
289
337
290
	if (options.bind_address) {
338
	if (bind_address) {
291
		memset(&hints, 0, sizeof(hints));
339
		memset(&hints, 0, sizeof(hints));
292
		hints.ai_family = ai->ai_family;
340
		hints.ai_family = ai->ai_family;
293
		hints.ai_socktype = ai->ai_socktype;
341
		hints.ai_socktype = ai->ai_socktype;
294
		hints.ai_protocol = ai->ai_protocol;
342
		hints.ai_protocol = ai->ai_protocol;
295
		hints.ai_flags = AI_PASSIVE;
343
		hints.ai_flags = AI_PASSIVE;
296
		gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);
344
		gaierr = getaddrinfo(bind_address, NULL, &hints, &res);
297
		if (gaierr) {
345
		if (gaierr) {
298
			error("getaddrinfo: %s: %s", options.bind_address,
346
			error("getaddrinfo: %s: %s", bind_address,
299
			    ssh_gai_strerror(gaierr));
347
			    ssh_gai_strerror(gaierr));
300
			close(sock);
348
			close(sock);
301
			return -1;
349
			return -1;
Lines 316-323 ssh_create_socket(int privileged, struct addrinfo *ai) Link Here
316
		}
364
		}
317
	} else {
365
	} else {
318
		if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
366
		if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
319
			error("bind: %s: %s", options.bind_address,
367
			error("bind: %s: %s", bind_address, strerror(errno));
320
			    strerror(errno));
321
 fail:
368
 fail:
322
			close(sock);
369
			close(sock);
323
			freeaddrinfo(res);
370
			freeaddrinfo(res);

Return to bug 2606