• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
setup_localtcp()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 
cli_localtcp(unsigned int listenport,const char * remoteaddr,unsigned int remoteport)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
send_msg_global_request_remotetcp(int port)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 
setup_remotetcp()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 
newtcpforwarded(struct Channel * channel)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