Home | History | Annotate | Download | only in dropbear
      1 /*
      2  * Dropbear SSH
      3  *
      4  * Copyright (c) 2002,2003 Matt Johnston
      5  * All rights reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE. */
     24 
     25 #include "includes.h"
     26 #include "options.h"
     27 #include "dbutil.h"
     28 #include "tcpfwd.h"
     29 #include "channel.h"
     30 #include "runopts.h"
     31 #include "session.h"
     32 #include "ssh.h"
     33 
     34 #ifdef ENABLE_CLI_REMOTETCPFWD
     35 static int newtcpforwarded(struct Channel * channel);
     36 
     37 const struct ChanType cli_chan_tcpremote = {
     38 	1, /* sepfds */
     39 	"forwarded-tcpip",
     40 	newtcpforwarded,
     41 	NULL,
     42 	NULL,
     43 	NULL
     44 };
     45 #endif
     46 
     47 #ifdef ENABLE_CLI_LOCALTCPFWD
     48 static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
     49 		unsigned int remoteport);
     50 static const struct ChanType cli_chan_tcplocal = {
     51 	1, /* sepfds */
     52 	"direct-tcpip",
     53 	NULL,
     54 	NULL,
     55 	NULL,
     56 	NULL
     57 };
     58 #endif
     59 
     60 #ifdef ENABLE_CLI_LOCALTCPFWD
     61 void setup_localtcp() {
     62 
     63 	int ret;
     64 
     65 	TRACE(("enter setup_localtcp"))
     66 
     67 	if (cli_opts.localfwds == NULL) {
     68 		TRACE(("cli_opts.localfwds == NULL"))
     69 	}
     70 
     71 	while (cli_opts.localfwds != NULL) {
     72 		ret = cli_localtcp(cli_opts.localfwds->listenport,
     73 				cli_opts.localfwds->connectaddr,
     74 				cli_opts.localfwds->connectport);
     75 		if (ret == DROPBEAR_FAILURE) {
     76 			dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
     77 					cli_opts.localfwds->listenport,
     78 					cli_opts.localfwds->connectaddr,
     79 					cli_opts.localfwds->connectport);
     80 		}
     81 
     82 		cli_opts.localfwds = cli_opts.localfwds->next;
     83 	}
     84 	TRACE(("leave setup_localtcp"))
     85 
     86 }
     87 
     88 static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
     89 		unsigned int remoteport) {
     90 
     91 	struct TCPListener* tcpinfo = NULL;
     92 	int ret;
     93 
     94 	TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
     95 				remoteport));
     96 
     97 	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
     98 
     99 	tcpinfo->sendaddr = m_strdup(remoteaddr);
    100 	tcpinfo->sendport = remoteport;
    101 
    102 	if (opts.listen_fwd_all) {
    103 		tcpinfo->listenaddr = m_strdup("");
    104 	} else {
    105 		tcpinfo->listenaddr = m_strdup("localhost");
    106 	}
    107 	tcpinfo->listenport = listenport;
    108 
    109 	tcpinfo->chantype = &cli_chan_tcplocal;
    110 	tcpinfo->tcp_type = direct;
    111 
    112 	ret = listen_tcpfwd(tcpinfo);
    113 
    114 	if (ret == DROPBEAR_FAILURE) {
    115 		m_free(tcpinfo);
    116 	}
    117 	TRACE(("leave cli_localtcp: %d", ret))
    118 	return ret;
    119 }
    120 #endif /* ENABLE_CLI_LOCALTCPFWD */
    121 
    122 #ifdef  ENABLE_CLI_REMOTETCPFWD
    123 static void send_msg_global_request_remotetcp(int port) {
    124 
    125 	char* listenspec = NULL;
    126 	TRACE(("enter send_msg_global_request_remotetcp"))
    127 
    128 	CHECKCLEARTOWRITE();
    129 	buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
    130 	buf_putstring(ses.writepayload, "tcpip-forward", 13);
    131 	buf_putbyte(ses.writepayload, 0);
    132 	if (opts.listen_fwd_all) {
    133 		listenspec = "";
    134 	} else {
    135 		listenspec = "localhost";
    136 	}
    137 	/* TODO: IPv6? */;
    138 	buf_putstring(ses.writepayload, listenspec, strlen(listenspec));
    139 	buf_putint(ses.writepayload, port);
    140 
    141 	encrypt_packet();
    142 
    143 	TRACE(("leave send_msg_global_request_remotetcp"))
    144 }
    145 
    146 void setup_remotetcp() {
    147 
    148 	struct TCPFwdList * iter = NULL;
    149 
    150 	TRACE(("enter setup_remotetcp"))
    151 
    152 	if (cli_opts.remotefwds == NULL) {
    153 		TRACE(("cli_opts.remotefwds == NULL"))
    154 	}
    155 
    156 	iter = cli_opts.remotefwds;
    157 
    158 	while (iter != NULL) {
    159 		send_msg_global_request_remotetcp(iter->listenport);
    160 		iter = iter->next;
    161 	}
    162 	TRACE(("leave setup_remotetcp"))
    163 }
    164 
    165 static int newtcpforwarded(struct Channel * channel) {
    166 
    167 	unsigned int origport;
    168 	struct TCPFwdList * iter = NULL;
    169 	char portstring[NI_MAXSERV];
    170 	int sock;
    171 	int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
    172 
    173 	/* We don't care what address they connected to */
    174 	buf_eatstring(ses.payload);
    175 
    176 	origport = buf_getint(ses.payload);
    177 
    178 	/* Find which port corresponds */
    179 	iter = cli_opts.remotefwds;
    180 
    181 	while (iter != NULL) {
    182 		if (origport == iter->listenport) {
    183 			break;
    184 		}
    185 		iter = iter->next;
    186 	}
    187 
    188 	if (iter == NULL) {
    189 		/* We didn't request forwarding on that port */
    190 		dropbear_log(LOG_INFO, "Server send unrequested port, from port %d",
    191 										origport);
    192 		goto out;
    193 	}
    194 
    195 	snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
    196 	sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
    197 	if (sock < 0) {
    198 		TRACE(("leave newtcpdirect: sock failed"))
    199 		err = SSH_OPEN_CONNECT_FAILED;
    200 		goto out;
    201 	}
    202 
    203 	ses.maxfd = MAX(ses.maxfd, sock);
    204 
    205 	/* We don't set readfd, that will get set after the connection's
    206 	 * progress succeeds */
    207 	channel->writefd = sock;
    208 	channel->initconn = 1;
    209 
    210 	err = SSH_OPEN_IN_PROGRESS;
    211 
    212 out:
    213 	TRACE(("leave newtcpdirect: err %d", err))
    214 	return err;
    215 }
    216 #endif /* ENABLE_CLI_REMOTETCPFWD */
    217