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 "ssh.h" 27 #include "tcpfwd.h" 28 #include "dbutil.h" 29 #include "session.h" 30 #include "buffer.h" 31 #include "packet.h" 32 #include "listener.h" 33 #include "runopts.h" 34 35 #ifdef DROPBEAR_TCP_ACCEPT 36 37 static void cleanup_tcp(struct Listener *listener) { 38 39 struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata); 40 41 m_free(tcpinfo->sendaddr); 42 m_free(tcpinfo->listenaddr); 43 m_free(tcpinfo); 44 } 45 46 static void tcp_acceptor(struct Listener *listener, int sock) { 47 48 int fd; 49 struct sockaddr_storage addr; 50 socklen_t len; 51 char ipstring[NI_MAXHOST], portstring[NI_MAXSERV]; 52 struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata); 53 54 len = sizeof(addr); 55 56 fd = accept(sock, (struct sockaddr*)&addr, &len); 57 if (fd < 0) { 58 return; 59 } 60 61 if (getnameinfo((struct sockaddr*)&addr, len, ipstring, sizeof(ipstring), 62 portstring, sizeof(portstring), 63 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 64 return; 65 } 66 67 if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) { 68 unsigned char* addr = NULL; 69 unsigned int port = 0; 70 71 if (tcpinfo->tcp_type == direct) { 72 /* "direct-tcpip" */ 73 /* host to connect, port to connect */ 74 addr = tcpinfo->sendaddr; 75 port = tcpinfo->sendport; 76 } else { 77 dropbear_assert(tcpinfo->tcp_type == forwarded); 78 /* "forwarded-tcpip" */ 79 /* address that was connected, port that was connected */ 80 addr = tcpinfo->listenaddr; 81 port = tcpinfo->listenport; 82 } 83 84 buf_putstring(ses.writepayload, addr, strlen(addr)); 85 buf_putint(ses.writepayload, port); 86 87 /* originator ip */ 88 buf_putstring(ses.writepayload, ipstring, strlen(ipstring)); 89 /* originator port */ 90 buf_putint(ses.writepayload, atol(portstring)); 91 92 encrypt_packet(); 93 94 } else { 95 /* XXX debug? */ 96 close(fd); 97 } 98 } 99 100 int listen_tcpfwd(struct TCPListener* tcpinfo) { 101 102 char portstring[NI_MAXSERV]; 103 int socks[DROPBEAR_MAX_SOCKS]; 104 struct Listener *listener = NULL; 105 int nsocks; 106 char* errstring = NULL; 107 /* listen_spec = NULL indicates localhost */ 108 const char* listen_spec = NULL; 109 110 TRACE(("enter listen_tcpfwd")) 111 112 /* first we try to bind, so don't need to do so much cleanup on failure */ 113 snprintf(portstring, sizeof(portstring), "%d", tcpinfo->listenport); 114 115 /* a listenaddr of "" will indicate all interfaces */ 116 if (opts.listen_fwd_all 117 && (strcmp(tcpinfo->listenaddr, "localhost") != 0) ) { 118 listen_spec = tcpinfo->listenaddr; 119 } 120 121 nsocks = dropbear_listen(listen_spec, portstring, socks, 122 DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd); 123 if (nsocks < 0) { 124 dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring); 125 m_free(errstring); 126 TRACE(("leave listen_tcpfwd: dropbear_listen failed")) 127 return DROPBEAR_FAILURE; 128 } 129 m_free(errstring); 130 131 /* new_listener will close the socks if it fails */ 132 listener = new_listener(socks, nsocks, CHANNEL_ID_TCPFORWARDED, tcpinfo, 133 tcp_acceptor, cleanup_tcp); 134 135 if (listener == NULL) { 136 TRACE(("leave listen_tcpfwd: listener failed")) 137 return DROPBEAR_FAILURE; 138 } 139 140 TRACE(("leave listen_tcpfwd: success")) 141 return DROPBEAR_SUCCESS; 142 } 143 144 #endif /* DROPBEAR_TCP_ACCEPT */ 145