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