diff options
Diffstat (limited to 'cli-tcpfwd.c')
-rw-r--r-- | cli-tcpfwd.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c new file mode 100644 index 0000000..c3bfd4d --- /dev/null +++ b/cli-tcpfwd.c @@ -0,0 +1,216 @@ +/* + * Dropbear SSH + * + * Copyright (c) 2002,2003 Matt Johnston + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + +#include "includes.h" +#include "options.h" +#include "dbutil.h" +#include "tcpfwd.h" +#include "channel.h" +#include "runopts.h" +#include "session.h" +#include "ssh.h" + +#ifdef ENABLE_CLI_REMOTETCPFWD +static int newtcpforwarded(struct Channel * channel); + +const struct ChanType cli_chan_tcpremote = { + 1, /* sepfds */ + "forwarded-tcpip", + newtcpforwarded, + NULL, + NULL, + NULL +}; +#endif + +#ifdef ENABLE_CLI_LOCALTCPFWD +static int cli_localtcp(unsigned int listenport, const char* remoteaddr, + unsigned int remoteport); +static const struct ChanType cli_chan_tcplocal = { + 1, /* sepfds */ + "direct-tcpip", + NULL, + NULL, + NULL, + NULL +}; +#endif + +#ifdef ENABLE_CLI_LOCALTCPFWD +void setup_localtcp() { + + int ret; + + TRACE(("enter setup_localtcp")) + + if (cli_opts.localfwds == NULL) { + TRACE(("cli_opts.localfwds == NULL")) + } + + while (cli_opts.localfwds != NULL) { + ret = cli_localtcp(cli_opts.localfwds->listenport, + cli_opts.localfwds->connectaddr, + cli_opts.localfwds->connectport); + if (ret == DROPBEAR_FAILURE) { + dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d", + cli_opts.localfwds->listenport, + cli_opts.localfwds->connectaddr, + cli_opts.localfwds->connectport); + } + + cli_opts.localfwds = cli_opts.localfwds->next; + } + TRACE(("leave setup_localtcp")) + +} + +static int cli_localtcp(unsigned int listenport, const char* remoteaddr, + unsigned int remoteport) { + + struct TCPListener* tcpinfo = NULL; + int ret; + + TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr, + remoteport)); + + tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); + + tcpinfo->sendaddr = m_strdup(remoteaddr); + tcpinfo->sendport = remoteport; + + if (opts.listen_fwd_all) { + tcpinfo->listenaddr = m_strdup(""); + } else { + tcpinfo->listenaddr = m_strdup("localhost"); + } + tcpinfo->listenport = listenport; + + tcpinfo->chantype = &cli_chan_tcplocal; + tcpinfo->tcp_type = direct; + + ret = listen_tcpfwd(tcpinfo); + + if (ret == DROPBEAR_FAILURE) { + m_free(tcpinfo); + } + TRACE(("leave cli_localtcp: %d", ret)) + return ret; +} +#endif /* ENABLE_CLI_LOCALTCPFWD */ + +#ifdef ENABLE_CLI_REMOTETCPFWD +static void send_msg_global_request_remotetcp(int port) { + + char* listenspec = NULL; + TRACE(("enter send_msg_global_request_remotetcp")) + + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST); + buf_putstring(ses.writepayload, "tcpip-forward", 13); + buf_putbyte(ses.writepayload, 0); + if (opts.listen_fwd_all) { + listenspec = ""; + } else { + listenspec = "localhost"; + } + /* TODO: IPv6? */; + buf_putstring(ses.writepayload, listenspec, strlen(listenspec)); + buf_putint(ses.writepayload, port); + + encrypt_packet(); + + TRACE(("leave send_msg_global_request_remotetcp")) +} + +void setup_remotetcp() { + + struct TCPFwdList * iter = NULL; + + TRACE(("enter setup_remotetcp")) + + if (cli_opts.remotefwds == NULL) { + TRACE(("cli_opts.remotefwds == NULL")) + } + + iter = cli_opts.remotefwds; + + while (iter != NULL) { + send_msg_global_request_remotetcp(iter->listenport); + iter = iter->next; + } + TRACE(("leave setup_remotetcp")) +} + +static int newtcpforwarded(struct Channel * channel) { + + unsigned int origport; + struct TCPFwdList * iter = NULL; + char portstring[NI_MAXSERV]; + int sock; + int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; + + /* We don't care what address they connected to */ + buf_eatstring(ses.payload); + + origport = buf_getint(ses.payload); + + /* Find which port corresponds */ + iter = cli_opts.remotefwds; + + while (iter != NULL) { + if (origport == iter->listenport) { + break; + } + iter = iter->next; + } + + if (iter == NULL) { + /* We didn't request forwarding on that port */ + dropbear_log(LOG_INFO, "Server send unrequested port, from port %d", + origport); + goto out; + } + + snprintf(portstring, sizeof(portstring), "%d", iter->connectport); + sock = connect_remote(iter->connectaddr, portstring, 1, NULL); + if (sock < 0) { + TRACE(("leave newtcpdirect: sock failed")) + err = SSH_OPEN_CONNECT_FAILED; + goto out; + } + + ses.maxfd = MAX(ses.maxfd, sock); + + /* We don't set readfd, that will get set after the connection's + * progress succeeds */ + channel->writefd = sock; + channel->initconn = 1; + + err = SSH_OPEN_IN_PROGRESS; + +out: + TRACE(("leave newtcpdirect: err %d", err)) + return err; +} +#endif /* ENABLE_CLI_REMOTETCPFWD */ |