|
Lines 19-24
Link Here
|
| 19 |
#include <sys/socket.h> |
19 |
#include <sys/socket.h> |
| 20 |
#include <sys/time.h> |
20 |
#include <sys/time.h> |
| 21 |
|
21 |
|
|
|
22 |
#include <net/if.h> |
| 22 |
#include <netinet/in.h> |
23 |
#include <netinet/in.h> |
| 23 |
|
24 |
|
| 24 |
#include <ctype.h> |
25 |
#include <ctype.h> |
|
Lines 33-38
Link Here
|
| 33 |
#include <stdlib.h> |
34 |
#include <stdlib.h> |
| 34 |
#include <string.h> |
35 |
#include <string.h> |
| 35 |
#include <unistd.h> |
36 |
#include <unistd.h> |
|
|
37 |
#include <ifaddrs.h> |
| 36 |
|
38 |
|
| 37 |
#include "xmalloc.h" |
39 |
#include "xmalloc.h" |
| 38 |
#include "ssh.h" |
40 |
#include "ssh.h" |
|
Lines 258-271
ssh_kill_proxy_command(void)
Link Here
|
| 258 |
kill(proxy_command_pid, SIGHUP); |
260 |
kill(proxy_command_pid, SIGHUP); |
| 259 |
} |
261 |
} |
| 260 |
|
262 |
|
|
|
263 |
/* |
| 264 |
* Search a interface address list (returned from getifaddrs(3)) for an |
| 265 |
* address that matches the desired address family on the specifed interface. |
| 266 |
* Returns 0 and fills in *resultp and *rlenp on success. Returns -1 on failure. |
| 267 |
*/ |
| 268 |
static int |
| 269 |
check_ifaddrs(const char *ifname, int af, const struct ifaddrs *ifaddrs, |
| 270 |
struct sockaddr_storage *resultp, socklen_t *rlenp) |
| 271 |
{ |
| 272 |
struct sockaddr_in6 *sa6; |
| 273 |
struct sockaddr_in *sa; |
| 274 |
struct in6_addr *v6addr; |
| 275 |
const struct ifaddrs *ifa; |
| 276 |
int allow_local; |
| 277 |
|
| 278 |
/* |
| 279 |
* Prefer addresses that are not loopback or linklocal, but use them |
| 280 |
* if nothing else matches. |
| 281 |
*/ |
| 282 |
for (allow_local = 0; allow_local < 2; allow_local++) { |
| 283 |
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { |
| 284 |
if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL || |
| 285 |
(ifa->ifa_flags & IFF_UP) == 0 || |
| 286 |
ifa->ifa_addr->sa_family != af || |
| 287 |
strcmp(ifa->ifa_name, options.bind_interface) != 0) |
| 288 |
continue; |
| 289 |
switch (ifa->ifa_addr->sa_family) { |
| 290 |
case AF_INET: |
| 291 |
sa = (struct sockaddr_in *)ifa->ifa_addr; |
| 292 |
if (!allow_local && sa->sin_addr.s_addr == |
| 293 |
htonl(INADDR_LOOPBACK)) |
| 294 |
continue; |
| 295 |
if (*rlenp < sizeof(struct sockaddr_in)) { |
| 296 |
error("%s: v4 addr doesn't fit", |
| 297 |
__func__); |
| 298 |
return -1; |
| 299 |
} |
| 300 |
*rlenp = sizeof(struct sockaddr_in); |
| 301 |
memcpy(resultp, sa, *rlenp); |
| 302 |
return 0; |
| 303 |
case AF_INET6: |
| 304 |
sa6 = (struct sockaddr_in6 *)ifa->ifa_addr; |
| 305 |
v6addr = &sa6->sin6_addr; |
| 306 |
if (!allow_local && |
| 307 |
(IN6_IS_ADDR_LINKLOCAL(v6addr) || |
| 308 |
IN6_IS_ADDR_LOOPBACK(v6addr))) |
| 309 |
continue; |
| 310 |
if (*rlenp < sizeof(struct sockaddr_in6)) { |
| 311 |
error("%s: v6 addr doesn't fit", |
| 312 |
__func__); |
| 313 |
return -1; |
| 314 |
} |
| 315 |
*rlenp = sizeof(struct sockaddr_in6); |
| 316 |
memcpy(resultp, sa6, *rlenp); |
| 317 |
return 0; |
| 318 |
} |
| 319 |
} |
| 320 |
} |
| 321 |
return -1; |
| 322 |
} |
| 323 |
|
| 261 |
/* |
324 |
/* |
| 262 |
* Creates a (possibly privileged) socket for use as the ssh connection. |
325 |
* Creates a (possibly privileged) socket for use as the ssh connection. |
| 263 |
*/ |
326 |
*/ |
| 264 |
static int |
327 |
static int |
| 265 |
ssh_create_socket(int privileged, struct addrinfo *ai) |
328 |
ssh_create_socket(int privileged, struct addrinfo *ai) |
| 266 |
{ |
329 |
{ |
| 267 |
int sock, r, gaierr; |
330 |
int sock, r, oerrno; |
|
|
331 |
struct sockaddr_storage bindaddr; |
| 332 |
socklen_t bindaddrlen = 0; |
| 268 |
struct addrinfo hints, *res = NULL; |
333 |
struct addrinfo hints, *res = NULL; |
|
|
334 |
struct ifaddrs *ifaddrs = NULL; |
| 335 |
char ntop[NI_MAXHOST]; |
| 269 |
|
336 |
|
| 270 |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
337 |
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
| 271 |
if (sock < 0) { |
338 |
if (sock < 0) { |
|
Lines 275-296
ssh_create_socket(int privileged, struct addrinfo *ai)
Link Here
|
| 275 |
fcntl(sock, F_SETFD, FD_CLOEXEC); |
342 |
fcntl(sock, F_SETFD, FD_CLOEXEC); |
| 276 |
|
343 |
|
| 277 |
/* Bind the socket to an alternative local IP address */ |
344 |
/* Bind the socket to an alternative local IP address */ |
| 278 |
if (options.bind_address == NULL && !privileged) |
345 |
if (options.bind_address == NULL && options.bind_interface == NULL && |
|
|
346 |
!privileged) |
| 279 |
return sock; |
347 |
return sock; |
| 280 |
|
348 |
|
| 281 |
if (options.bind_address) { |
349 |
if (options.bind_address != NULL) { |
| 282 |
memset(&hints, 0, sizeof(hints)); |
350 |
memset(&hints, 0, sizeof(hints)); |
| 283 |
hints.ai_family = ai->ai_family; |
351 |
hints.ai_family = ai->ai_family; |
| 284 |
hints.ai_socktype = ai->ai_socktype; |
352 |
hints.ai_socktype = ai->ai_socktype; |
| 285 |
hints.ai_protocol = ai->ai_protocol; |
353 |
hints.ai_protocol = ai->ai_protocol; |
| 286 |
hints.ai_flags = AI_PASSIVE; |
354 |
hints.ai_flags = AI_PASSIVE; |
| 287 |
gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res); |
355 |
if ((r = getaddrinfo(options.bind_address, NULL, |
| 288 |
if (gaierr) { |
356 |
&hints, &res)) != 0) { |
| 289 |
error("getaddrinfo: %s: %s", options.bind_address, |
357 |
error("getaddrinfo: %s: %s", options.bind_address, |
| 290 |
ssh_gai_strerror(gaierr)); |
358 |
ssh_gai_strerror(r)); |
| 291 |
close(sock); |
359 |
goto fail; |
| 292 |
return -1; |
|
|
| 293 |
} |
360 |
} |
|
|
361 |
if (res == NULL) |
| 362 |
error("getaddrinfo: no addrs"); |
| 363 |
goto fail; |
| 364 |
if (res->ai_addrlen > sizeof(bindaddr)) { |
| 365 |
error("%s: addr doesn't fit", __func__); |
| 366 |
goto fail; |
| 367 |
} |
| 368 |
memcpy(&bindaddr, res->ai_addr, res->ai_addrlen); |
| 369 |
bindaddrlen = res->ai_addrlen; |
| 370 |
} else if (options.bind_interface != NULL) { |
| 371 |
if ((r = getifaddrs(&ifaddrs)) != 0) { |
| 372 |
error("getifaddrs: %s: %s", options.bind_interface, |
| 373 |
strerror(errno)); |
| 374 |
goto fail; |
| 375 |
} |
| 376 |
bindaddrlen = sizeof(bindaddr); |
| 377 |
if (check_ifaddrs(options.bind_interface, ai->ai_family, |
| 378 |
ifaddrs, &bindaddr, &bindaddrlen) != 0) { |
| 379 |
logit("getifaddrs: %s: no suitable addresses", |
| 380 |
options.bind_interface); |
| 381 |
goto fail; |
| 382 |
} |
| 383 |
} |
| 384 |
if ((r = getnameinfo((struct sockaddr *)&bindaddr, bindaddrlen, |
| 385 |
ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST)) != 0) { |
| 386 |
error("%s: getnameinfo failed: %s", __func__, |
| 387 |
ssh_gai_strerror(r)); |
| 388 |
goto fail; |
| 294 |
} |
389 |
} |
| 295 |
/* |
390 |
/* |
| 296 |
* If we are running as root and want to connect to a privileged |
391 |
* If we are running as root and want to connect to a privileged |
|
Lines 298-322
ssh_create_socket(int privileged, struct addrinfo *ai)
Link Here
|
| 298 |
*/ |
393 |
*/ |
| 299 |
if (privileged) { |
394 |
if (privileged) { |
| 300 |
PRIV_START; |
395 |
PRIV_START; |
| 301 |
r = bindresvport_sa(sock, res ? res->ai_addr : NULL); |
396 |
r = bindresvport_sa(sock, |
|
|
397 |
bindaddrlen == 0 ? NULL : (struct sockaddr *)&bindaddr); |
| 398 |
oerrno = errno; |
| 302 |
PRIV_END; |
399 |
PRIV_END; |
| 303 |
if (r < 0) { |
400 |
if (r < 0) { |
| 304 |
error("bindresvport_sa: af=%d %s", ai->ai_family, |
401 |
error("bindresvport_sa %s: %s", ntop, |
| 305 |
strerror(errno)); |
402 |
strerror(oerrno)); |
| 306 |
goto fail; |
403 |
goto fail; |
| 307 |
} |
404 |
} |
| 308 |
} else { |
405 |
} else if (bind(sock, (struct sockaddr *)&bindaddr, bindaddrlen) != 0) { |
| 309 |
if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { |
406 |
error("bind %s: %s", ntop, strerror(errno)); |
| 310 |
error("bind: %s: %s", options.bind_address, |
407 |
goto fail; |
| 311 |
strerror(errno)); |
|
|
| 312 |
fail: |
| 313 |
close(sock); |
| 314 |
freeaddrinfo(res); |
| 315 |
return -1; |
| 316 |
} |
| 317 |
} |
408 |
} |
|
|
409 |
debug("%s: bound to %s", __func__, ntop); |
| 410 |
/* success */ |
| 411 |
goto out; |
| 412 |
fail: |
| 413 |
close(sock); |
| 414 |
sock = -1; |
| 415 |
out: |
| 318 |
if (res != NULL) |
416 |
if (res != NULL) |
| 319 |
freeaddrinfo(res); |
417 |
freeaddrinfo(res); |
|
|
418 |
if (ifaddrs != NULL) |
| 419 |
freeifaddrs(ifaddrs); |
| 320 |
return sock; |
420 |
return sock; |
| 321 |
} |
421 |
} |
| 322 |
|
422 |
|