-/* $OpenBSD: channels.c,v 1.295 2009/02/12 03:00:56 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.299 2009/11/11 21:37:03 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
#include <arpa/inet.h>
#include <errno.h>
+#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
/* AF_UNSPEC or AF_INET or AF_INET6 */
static int IPv4or6 = AF_UNSPEC;
+/* Set the routing domain a.k.a. VRF */
+static int channel_rdomain = -1;
+
/* helper */
static void port_open_helper(Channel *c, char *rtype);
channel_max_fd = MAX(channel_max_fd, wfd);
channel_max_fd = MAX(channel_max_fd, efd);
- /* XXX set close-on-exec -markus */
+ if (rfd != -1)
+ fcntl(rfd, F_SETFD, FD_CLOEXEC);
+ if (wfd != -1 && wfd != rfd)
+ fcntl(wfd, F_SETFD, FD_CLOEXEC);
+ if (efd != -1 && efd != rfd && efd != wfd)
+ fcntl(efd, F_SETFD, FD_CLOEXEC);
c->rfd = rfd;
c->wfd = wfd;
c->output_filter = NULL;
c->filter_ctx = NULL;
c->filter_cleanup = NULL;
+ c->delayed = 1; /* prevent call to channel_post handler */
TAILQ_INIT(&c->status_confirms);
debug("channel %d: new [%s]", found, remote_name);
return c;
int ret;
have = buffer_len(&c->input);
- c->delayed = 0;
debug2("channel %d: pre_dynamic: have %d", c->self, have);
/* buffer_dump(&c->input); */
/* check if the fixed size part of the packet is in buffer. */
if (c->path != NULL)
nc->path = xstrdup(c->path);
- if (nextstate == SSH_CHANNEL_DYNAMIC) {
- /*
- * do not call the channel_post handler until
- * this flag has been reset by a pre-handler.
- * otherwise the FD_ISSET calls might overflow
- */
- nc->delayed = 1;
- } else {
+ if (nextstate != SSH_CHANNEL_DYNAMIC)
port_open_helper(nc, rtype);
- }
}
}
}
return -1;
}
+#ifndef BROKEN_TCGETATTR_ICANON
if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
if (tcgetattr(c->wfd, &tio) == 0 &&
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
packet_send();
}
}
+#endif
buffer_consume(&c->output, len);
if (compat20 && len > 0) {
c->local_consumed += len;
static void
channel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
{
- if (c->delayed)
- return;
channel_handle_rfd(c, readset, writeset);
channel_handle_wfd(c, readset, writeset);
if (!compat20)
channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
{
static int did_init = 0;
- u_int i;
+ u_int i, oalloc;
Channel *c;
if (!did_init) {
channel_handler_init();
did_init = 1;
}
- for (i = 0; i < channels_alloc; i++) {
+ for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
c = channels[i];
if (c == NULL)
continue;
+ if (c->delayed) {
+ if (ftab == channel_pre)
+ c->delayed = 0;
+ else
+ continue;
+ }
if (ftab[c->type] != NULL)
(*ftab[c->type])(c, readset, writeset);
channel_garbage_collect(c);
int id;
/* Reset keepalive timeout */
- keep_alive_timeouts = 0;
+ packet_set_alive_timeouts(0);
id = packet_get_int();
packet_check_eom();
IPv4or6 = af;
}
+void
+channel_set_rdomain(int rdomain)
+{
+ channel_rdomain = rdomain;
+}
+
static int
channel_setup_fwd_listener(int type, const char *listen_addr,
u_short listen_port, int *allocated_listen_port,
continue;
}
/* Create a port to listen for the host. */
- sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ sock = socket_rdomain(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol, channel_rdomain);
if (sock < 0) {
/* this is no error since kernel may not support ipv6 */
verbose("socket: %.100s", strerror(errno));
}
channel_set_reuseaddr(sock);
+ if (ai->ai_family == AF_INET6)
+ sock_set_v6only(sock);
debug("Local forwarding listening on %s port %s.",
ntop, strport);
error("connect_next: getnameinfo failed");
continue;
}
- if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
- cctx->ai->ai_protocol)) == -1) {
+ if ((sock = socket_rdomain(cctx->ai->ai_family,
+ cctx->ai->ai_socktype, cctx->ai->ai_protocol,
+ channel_rdomain)) == -1) {
if (cctx->ai->ai_next == NULL)
error("socket: %.100s", strerror(errno));
else
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
- sock = socket(ai->ai_family, ai->ai_socktype,
- ai->ai_protocol);
+ sock = socket_rdomain(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol, channel_rdomain);
if (sock < 0) {
if ((errno != EINVAL) && (errno != EAFNOSUPPORT)) {
error("socket: %.100s", strerror(errno));
continue;
}
}
-#ifdef IPV6_V6ONLY
- if (ai->ai_family == AF_INET6) {
- int on = 1;
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
- error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno));
- }
-#endif
+ if (ai->ai_family == AF_INET6)
+ sock_set_v6only(sock);
if (x11_use_localhost)
channel_set_reuseaddr(sock);
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
}
for (ai = aitop; ai; ai = ai->ai_next) {
/* Create a socket. */
- sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ sock = socket_rdomain(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol, channel_rdomain);
if (sock < 0) {
debug2("socket: %.100s", strerror(errno));
continue;