version 1.34, 1999/12/27 09:48:38 |
version 1.35, 2000/01/04 00:07:58 |
|
|
channel_after_select(fd_set * readset, fd_set * writeset) |
channel_after_select(fd_set * readset, fd_set * writeset) |
{ |
{ |
struct sockaddr addr; |
struct sockaddr addr; |
int addrlen, newsock, i, newch, len; |
int newsock, i, newch, len; |
|
socklen_t addrlen; |
Channel *ch; |
Channel *ch; |
char buf[16384], *remote_hostname; |
char buf[16384], *remote_hostname; |
|
|
|
|
* forwarded TCP/IP port. |
* forwarded TCP/IP port. |
*/ |
*/ |
if (FD_ISSET(ch->sock, readset)) { |
if (FD_ISSET(ch->sock, readset)) { |
debug("Connection to port %d forwarding to %.100s:%d requested.", |
debug("Connection to port %d forwarding to %.100s port %d requested.", |
ch->listening_port, ch->path, ch->host_port); |
ch->listening_port, ch->path, ch->host_port); |
addrlen = sizeof(addr); |
addrlen = sizeof(addr); |
newsock = accept(ch->sock, &addr, &addrlen); |
newsock = accept(ch->sock, &addr, &addrlen); |
|
|
break; |
break; |
} |
} |
remote_hostname = get_remote_hostname(newsock); |
remote_hostname = get_remote_hostname(newsock); |
snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d", |
snprintf(buf, sizeof buf, "listen port %d for %.100s port %d, connect from %.200s port %d", |
ch->listening_port, ch->path, ch->host_port, |
ch->listening_port, ch->path, ch->host_port, |
remote_hostname, get_peer_port(newsock)); |
remote_hostname, get_peer_port(newsock)); |
xfree(remote_hostname); |
xfree(remote_hostname); |
|
|
channel_request_local_forwarding(u_short port, const char *host, |
channel_request_local_forwarding(u_short port, const char *host, |
u_short host_port, int gateway_ports) |
u_short host_port, int gateway_ports) |
{ |
{ |
int ch, sock, on = 1; |
int success, ch, sock, on = 1; |
struct sockaddr_in sin; |
struct addrinfo hints, *ai, *aitop; |
|
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
struct linger linger; |
struct linger linger; |
|
|
if (strlen(host) > sizeof(channels[0].path) - 1) |
if (strlen(host) > sizeof(channels[0].path) - 1) |
packet_disconnect("Forward host name too long."); |
packet_disconnect("Forward host name too long."); |
|
|
/* Create a port to listen for the host. */ |
|
sock = socket(AF_INET, SOCK_STREAM, 0); |
|
if (sock < 0) |
|
packet_disconnect("socket: %.100s", strerror(errno)); |
|
|
|
/* Initialize socket address. */ |
|
memset(&sin, 0, sizeof(sin)); |
|
sin.sin_family = AF_INET; |
|
if (gateway_ports == 1) |
|
sin.sin_addr.s_addr = htonl(INADDR_ANY); |
|
else |
|
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
|
sin.sin_port = htons(port); |
|
|
|
/* |
/* |
* Set socket options. We would like the socket to disappear as soon |
* getaddrinfo returns a loopback address if the hostname is |
* as it has been closed for whatever reason. |
* set to NULL and hints.ai_flags is not AI_PASSIVE |
*/ |
*/ |
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); |
memset(&hints, 0, sizeof(hints)); |
linger.l_onoff = 1; |
hints.ai_family = IPv4or6; |
linger.l_linger = 5; |
hints.ai_flags = gateway_ports ? AI_PASSIVE : 0; |
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); |
hints.ai_socktype = SOCK_STREAM; |
|
snprintf(strport, sizeof strport, "%d", port); |
|
if (getaddrinfo(NULL, strport, &hints, &aitop) != 0) |
|
packet_disconnect("getaddrinfo: fatal error"); |
|
|
/* Bind the socket to the address. */ |
success = 0; |
if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) |
for (ai = aitop; ai; ai = ai->ai_next) { |
packet_disconnect("bind: %.100s", strerror(errno)); |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
|
continue; |
|
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
|
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
|
error("channel_request_local_forwarding: getnameinfo failed"); |
|
continue; |
|
} |
|
/* Create a port to listen for the host. */ |
|
sock = socket(ai->ai_family, SOCK_STREAM, 0); |
|
if (sock < 0) { |
|
/* this is no error since kernel may not support ipv6 */ |
|
verbose("socket: %.100s", strerror(errno)); |
|
continue; |
|
} |
|
/* |
|
* Set socket options. We would like the socket to disappear |
|
* as soon as it has been closed for whatever reason. |
|
*/ |
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); |
|
linger.l_onoff = 1; |
|
linger.l_linger = 5; |
|
setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); |
|
debug("Local forwarding listening on %s port %s.", ntop, strport); |
|
|
/* Start listening for connections on the socket. */ |
/* Bind the socket to the address. */ |
if (listen(sock, 5) < 0) |
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
packet_disconnect("listen: %.100s", strerror(errno)); |
/* address can be in use ipv6 address is already bound */ |
|
verbose("bind: %.100s", strerror(errno)); |
/* Allocate a channel number for the socket. */ |
close(sock); |
ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock, |
continue; |
xstrdup("port listener")); |
} |
strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); |
/* Start listening for connections on the socket. */ |
channels[ch].host_port = host_port; |
if (listen(sock, 5) < 0) { |
channels[ch].listening_port = port; |
error("listen: %.100s", strerror(errno)); |
|
close(sock); |
|
continue; |
|
} |
|
/* Allocate a channel number for the socket. */ |
|
ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock, |
|
xstrdup("port listener")); |
|
strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); |
|
channels[ch].host_port = host_port; |
|
channels[ch].listening_port = port; |
|
success = 1; |
|
} |
|
if (success == 0) |
|
packet_disconnect("cannot listen port: %d", port); |
|
freeaddrinfo(aitop); |
} |
} |
|
|
/* |
/* |
|
|
void |
void |
channel_input_port_open(int payload_len) |
channel_input_port_open(int payload_len) |
{ |
{ |
int remote_channel, sock, newch, i; |
int remote_channel, sock = 0, newch, i; |
u_short host_port; |
u_short host_port; |
struct sockaddr_in sin; |
|
char *host, *originator_string; |
char *host, *originator_string; |
struct hostent *hp; |
|
int host_len, originator_len; |
int host_len, originator_len; |
|
struct addrinfo hints, *ai, *aitop; |
|
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
|
int gaierr; |
|
|
/* Get remote channel number. */ |
/* Get remote channel number. */ |
remote_channel = packet_get_int(); |
remote_channel = packet_get_int(); |
|
|
packet_send(); |
packet_send(); |
} |
} |
} |
} |
memset(&sin, 0, sizeof(sin)); |
|
sin.sin_addr.s_addr = inet_addr(host); |
memset(&hints, 0, sizeof(hints)); |
if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) { |
hints.ai_family = IPv4or6; |
/* It was a valid numeric host address. */ |
hints.ai_socktype = SOCK_STREAM; |
sin.sin_family = AF_INET; |
snprintf(strport, sizeof strport, "%d", host_port); |
} else { |
if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { |
/* Look up the host address from the name servers. */ |
error("%.100s: unknown host (%s)", host, gai_strerror(gaierr)); |
hp = gethostbyname(host); |
goto fail; |
if (!hp) { |
} |
error("%.100s: unknown host.", host); |
|
goto fail; |
for (ai = aitop; ai; ai = ai->ai_next) { |
|
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
|
continue; |
|
if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), |
|
strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { |
|
error("channel_input_port_open: getnameinfo failed"); |
|
continue; |
} |
} |
if (!hp->h_addr_list[0]) { |
/* Create the socket. */ |
error("%.100s: host has no IP address.", host); |
sock = socket(ai->ai_family, SOCK_STREAM, 0); |
goto fail; |
if (sock < 0) { |
|
error("socket: %.100s", strerror(errno)); |
|
continue; |
} |
} |
sin.sin_family = hp->h_addrtype; |
/* Connect to the host/port. */ |
memcpy(&sin.sin_addr, hp->h_addr_list[0], |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
sizeof(sin.sin_addr)); |
error("connect %.100s port %s: %.100s", ntop, strport, |
|
strerror(errno)); |
|
close(sock); |
|
continue; /* fail -- try next */ |
|
} |
|
break; /* success */ |
|
|
} |
} |
sin.sin_port = htons(host_port); |
freeaddrinfo(aitop); |
|
|
/* Create the socket. */ |
if (!ai) { |
sock = socket(sin.sin_family, SOCK_STREAM, 0); |
error("connect %.100s port %d: failed.", host, host_port); |
if (sock < 0) { |
|
error("socket: %.100s", strerror(errno)); |
|
goto fail; |
goto fail; |
} |
} |
/* Connect to the host/port. */ |
|
if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { |
|
error("connect %.100s:%d: %.100s", host, host_port, |
|
strerror(errno)); |
|
close(sock); |
|
goto fail; |
|
} |
|
/* Successful connection. */ |
/* Successful connection. */ |
|
|
/* Allocate a channel for this connection. */ |
/* Allocate a channel for this connection. */ |
|
|
* occurs. |
* occurs. |
*/ |
*/ |
|
|
|
#define NUM_SOCKS 10 |
|
|
char * |
char * |
x11_create_display_inet(int screen_number, int x11_display_offset) |
x11_create_display_inet(int screen_number, int x11_display_offset) |
{ |
{ |
int display_number, sock; |
int display_number, sock; |
u_short port; |
u_short port; |
struct sockaddr_in sin; |
struct addrinfo hints, *ai, *aitop; |
char buf[512]; |
char strport[NI_MAXSERV]; |
|
int gaierr, n, num_socks = 0, socks[NUM_SOCKS]; |
|
char display[512]; |
char hostname[MAXHOSTNAMELEN]; |
char hostname[MAXHOSTNAMELEN]; |
|
|
for (display_number = x11_display_offset; |
for (display_number = x11_display_offset; |
display_number < MAX_DISPLAYS; |
display_number < MAX_DISPLAYS; |
display_number++) { |
display_number++) { |
port = 6000 + display_number; |
port = 6000 + display_number; |
memset(&sin, 0, sizeof(sin)); |
memset(&hints, 0, sizeof(hints)); |
sin.sin_family = AF_INET; |
hints.ai_family = IPv4or6; |
sin.sin_addr.s_addr = htonl(INADDR_ANY); |
hints.ai_flags = 0 /*AI_PASSIVE*/; /* XXX loopback only ? */ |
sin.sin_port = htons(port); |
hints.ai_socktype = SOCK_STREAM; |
|
snprintf(strport, sizeof strport, "%d", port); |
sock = socket(AF_INET, SOCK_STREAM, 0); |
if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { |
if (sock < 0) { |
error("getaddrinfo: %.100s", gai_strerror(gaierr)); |
error("socket: %.100s", strerror(errno)); |
|
return NULL; |
return NULL; |
} |
} |
if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { |
for (ai = aitop; ai; ai = ai->ai_next) { |
debug("bind port %d: %.100s", port, strerror(errno)); |
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) |
shutdown(sock, SHUT_RDWR); |
continue; |
close(sock); |
sock = socket(ai->ai_family, SOCK_STREAM, 0); |
continue; |
if (sock < 0) { |
|
error("socket: %.100s", strerror(errno)); |
|
return NULL; |
|
} |
|
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
|
debug("bind port %d: %.100s", port, strerror(errno)); |
|
shutdown(sock, SHUT_RDWR); |
|
close(sock); |
|
for (n = 0; n < num_socks; n++) { |
|
shutdown(socks[n], SHUT_RDWR); |
|
close(socks[n]); |
|
} |
|
num_socks = 0; |
|
break; |
|
} |
|
socks[num_socks++] = sock; |
|
if (num_socks == NUM_SOCKS) |
|
break; |
} |
} |
break; |
if (num_socks > 0) |
|
break; |
} |
} |
if (display_number >= MAX_DISPLAYS) { |
if (display_number >= MAX_DISPLAYS) { |
error("Failed to allocate internet-domain X11 display socket."); |
error("Failed to allocate internet-domain X11 display socket."); |
return NULL; |
return NULL; |
} |
} |
/* Start listening for connections on the socket. */ |
/* Start listening for connections on the socket. */ |
if (listen(sock, 5) < 0) { |
for (n = 0; n < num_socks; n++) { |
error("listen: %.100s", strerror(errno)); |
sock = socks[n]; |
shutdown(sock, SHUT_RDWR); |
if (listen(sock, 5) < 0) { |
close(sock); |
error("listen: %.100s", strerror(errno)); |
return NULL; |
shutdown(sock, SHUT_RDWR); |
|
close(sock); |
|
return NULL; |
|
} |
} |
} |
|
|
/* Set up a suitable value for the DISPLAY variable. */ |
/* Set up a suitable value for the DISPLAY variable. */ |
if (gethostname(hostname, sizeof(hostname)) < 0) |
if (gethostname(hostname, sizeof(hostname)) < 0) |
fatal("gethostname: %.100s", strerror(errno)); |
fatal("gethostname: %.100s", strerror(errno)); |
snprintf(buf, sizeof buf, "%.400s:%d.%d", hostname, |
snprintf(display, sizeof display, "%.400s:%d.%d", hostname, |
display_number, screen_number); |
display_number, screen_number); |
|
|
/* Allocate a channel for the socket. */ |
/* Allocate a channel for each socket. */ |
(void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock, |
for (n = 0; n < num_socks; n++) { |
xstrdup("X11 inet listener")); |
sock = socks[n]; |
|
(void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock, |
|
xstrdup("X11 inet listener")); |
|
} |
|
|
/* Return a suitable value for the DISPLAY environment variable. */ |
/* Return a suitable value for the DISPLAY environment variable. */ |
return xstrdup(buf); |
return xstrdup(display); |
} |
} |
|
|
#ifndef X_UNIX_PATH |
#ifndef X_UNIX_PATH |
|
|
void |
void |
x11_input_open(int payload_len) |
x11_input_open(int payload_len) |
{ |
{ |
int remote_channel, display_number, sock, newch; |
int remote_channel, display_number, sock = 0, newch; |
const char *display; |
const char *display; |
struct sockaddr_in sin; |
|
char buf[1024], *cp, *remote_host; |
char buf[1024], *cp, *remote_host; |
struct hostent *hp; |
|
int remote_len; |
int remote_len; |
|
struct addrinfo hints, *ai, *aitop; |
|
char strport[NI_MAXSERV]; |
|
int gaierr; |
|
|
/* Get remote channel number. */ |
/* Get remote channel number. */ |
remote_channel = packet_get_int(); |
remote_channel = packet_get_int(); |
|
|
display); |
display); |
goto fail; |
goto fail; |
} |
} |
/* Try to parse the host name as a numeric IP address. */ |
|
memset(&sin, 0, sizeof(sin)); |
|
sin.sin_addr.s_addr = inet_addr(buf); |
|
if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) { |
|
/* It was a valid numeric host address. */ |
|
sin.sin_family = AF_INET; |
|
} else { |
|
/* Not a numeric IP address. */ |
|
/* Look up the host address from the name servers. */ |
|
hp = gethostbyname(buf); |
|
if (!hp) { |
|
error("%.100s: unknown host.", buf); |
|
goto fail; |
|
} |
|
if (!hp->h_addr_list[0]) { |
|
error("%.100s: host has no IP address.", buf); |
|
goto fail; |
|
} |
|
sin.sin_family = hp->h_addrtype; |
|
memcpy(&sin.sin_addr, hp->h_addr_list[0], |
|
sizeof(sin.sin_addr)); |
|
} |
|
/* Set port number. */ |
|
sin.sin_port = htons(6000 + display_number); |
|
|
|
/* Create a socket. */ |
/* Look up the host address */ |
sock = socket(sin.sin_family, SOCK_STREAM, 0); |
memset(&hints, 0, sizeof(hints)); |
if (sock < 0) { |
hints.ai_family = IPv4or6; |
error("socket: %.100s", strerror(errno)); |
hints.ai_socktype = SOCK_STREAM; |
|
snprintf(strport, sizeof strport, "%d", 6000 + display_number); |
|
if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { |
|
error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); |
goto fail; |
goto fail; |
} |
} |
|
for (ai = aitop; ai; ai = ai->ai_next) { |
|
/* Create a socket. */ |
|
sock = socket(ai->ai_family, SOCK_STREAM, 0); |
|
if (sock < 0) { |
|
debug("socket: %.100s", strerror(errno)); |
|
continue; |
|
} |
/* Connect it to the display. */ |
/* Connect it to the display. */ |
if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { |
if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |
error("connect %.100s:%d: %.100s", buf, 6000 + display_number, |
debug("connect %.100s port %d: %.100s", buf, 6000 + display_number, |
strerror(errno)); |
strerror(errno)); |
close(sock); |
close(sock); |
|
continue; |
|
} |
|
/* Success */ |
|
break; |
|
|
|
} /* (ai = aitop, ai; ai = ai->ai_next) */ |
|
freeaddrinfo(aitop); |
|
if (!ai) { |
|
error("connect %.100s port %d: %.100s", buf, 6000 + display_number, |
|
strerror(errno)); |
goto fail; |
goto fail; |
} |
} |
success: |
success: |