Mercurial > dropbear
annotate svr-tcpfwd.c @ 206:0d56e4b80dfb
* defined USING_LISTENERS when tcp forwarding is enabled but not
X11 or agent forwarding
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 01 Jun 2005 16:15:38 +0000 |
parents | 161557a9dde8 |
children | 84925eceeb13 |
rev | line source |
---|---|
74
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
1 /* |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
2 * Dropbear SSH |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
3 * |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
4 * Copyright (c) 2002,2003 Matt Johnston |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
5 * Copyright (c) 2004 by Mihnea Stoenescu |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
6 * All rights reserved. |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
7 * |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
8 * Permission is hereby granted, free of charge, to any person obtaining a copy |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
9 * of this software and associated documentation files (the "Software"), to deal |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
10 * in the Software without restriction, including without limitation the rights |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
12 * copies of the Software, and to permit persons to whom the Software is |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
13 * furnished to do so, subject to the following conditions: |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
14 * |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
15 * The above copyright notice and this permission notice shall be included in |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
16 * all copies or substantial portions of the Software. |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
17 * |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
24 * SOFTWARE. */ |
e3adf4cf5465
License boilerplate etc, add Mihnea as an author to some of the files
Matt Johnston <matt@ucc.asn.au>
parents:
70
diff
changeset
|
25 |
62 | 26 #include "includes.h" |
27 #include "ssh.h" | |
64 | 28 #include "tcpfwd.h" |
62 | 29 #include "dbutil.h" |
30 #include "session.h" | |
31 #include "buffer.h" | |
32 #include "packet.h" | |
33 #include "listener.h" | |
34 #include "runopts.h" | |
35 | |
156
8c2b3506f112
Rearrange preprocessor parts so that compilation with various options
Matt Johnston <matt@ucc.asn.au>
parents:
74
diff
changeset
|
36 #ifdef ENABLE_SVR_REMOTETCPFWD |
62 | 37 |
38 static void send_msg_request_success(); | |
39 static void send_msg_request_failure(); | |
40 static int svr_cancelremotetcp(); | |
41 static int svr_remotetcpreq(); | |
64 | 42 static int newtcpdirect(struct Channel * channel); |
62 | 43 |
44 | |
45 const struct ChanType svr_chan_tcpdirect = { | |
46 1, /* sepfds */ | |
47 "direct-tcpip", | |
48 newtcpdirect, /* init */ | |
49 NULL, /* checkclose */ | |
50 NULL, /* reqhandler */ | |
51 NULL /* closehandler */ | |
52 }; | |
53 | |
54 static const struct ChanType svr_chan_tcpremote = { | |
55 1, /* sepfds */ | |
56 "forwarded-tcpip", | |
57 NULL, | |
58 NULL, | |
59 NULL, | |
60 NULL | |
61 }; | |
62 | |
63 /* At the moment this is completely used for tcp code (with the name reflecting | |
64 * that). If new request types are added, this should be replaced with code | |
65 * similar to the request-switching in chansession.c */ | |
66 void recv_msg_global_request_remotetcp() { | |
67 | |
68 unsigned char* reqname = NULL; | |
69 unsigned int namelen; | |
70 unsigned int wantreply = 0; | |
71 int ret = DROPBEAR_FAILURE; | |
72 | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
73 TRACE(("enter recv_msg_global_request_remotetcp")) |
62 | 74 |
75 if (opts.noremotetcp) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
76 TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled")) |
62 | 77 goto out; |
78 } | |
79 | |
80 reqname = buf_getstring(ses.payload, &namelen); | |
179
161557a9dde8
* fix longstanding bug with connections being closed on failure to
Matt Johnston <matt@ucc.asn.au>
parents:
165
diff
changeset
|
81 wantreply = buf_getbool(ses.payload); |
62 | 82 |
83 if (namelen > MAXNAMLEN) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
84 TRACE(("name len is wrong: %d", namelen)) |
62 | 85 goto out; |
86 } | |
87 | |
88 if (strcmp("tcpip-forward", reqname) == 0) { | |
89 ret = svr_remotetcpreq(); | |
90 } else if (strcmp("cancel-tcpip-forward", reqname) == 0) { | |
91 ret = svr_cancelremotetcp(); | |
92 } else { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
93 TRACE(("reqname isn't tcpip-forward: '%s'", reqname)) |
62 | 94 } |
95 | |
96 out: | |
97 if (wantreply) { | |
98 if (ret == DROPBEAR_SUCCESS) { | |
99 send_msg_request_success(); | |
100 } else { | |
101 send_msg_request_failure(); | |
102 } | |
103 } | |
104 | |
105 m_free(reqname); | |
106 | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
107 TRACE(("leave recv_msg_global_request")) |
62 | 108 } |
109 | |
110 | |
111 static void send_msg_request_success() { | |
112 | |
113 CHECKCLEARTOWRITE(); | |
114 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS); | |
115 encrypt_packet(); | |
116 | |
117 } | |
118 | |
119 static void send_msg_request_failure() { | |
120 | |
121 CHECKCLEARTOWRITE(); | |
122 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); | |
123 encrypt_packet(); | |
124 | |
125 } | |
126 | |
127 static int matchtcp(void* typedata1, void* typedata2) { | |
128 | |
129 const struct TCPListener *info1 = (struct TCPListener*)typedata1; | |
130 const struct TCPListener *info2 = (struct TCPListener*)typedata2; | |
131 | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
132 return (info1->sendport == info2->sendport) |
62 | 133 && (info1->chantype == info2->chantype) |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
134 && (strcmp(info1->sendaddr, info2->sendaddr) == 0); |
62 | 135 } |
136 | |
137 static int svr_cancelremotetcp() { | |
138 | |
139 int ret = DROPBEAR_FAILURE; | |
140 unsigned char * bindaddr = NULL; | |
141 unsigned int addrlen; | |
142 unsigned int port; | |
143 struct Listener * listener = NULL; | |
144 struct TCPListener tcpinfo; | |
145 | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
146 TRACE(("enter cancelremotetcp")) |
62 | 147 |
148 bindaddr = buf_getstring(ses.payload, &addrlen); | |
149 if (addrlen > MAX_IP_LEN) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
150 TRACE(("addr len too long: %d", addrlen)) |
62 | 151 goto out; |
152 } | |
153 | |
154 port = buf_getint(ses.payload); | |
155 | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
156 tcpinfo.sendaddr = bindaddr; |
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
157 tcpinfo.sendport = port; |
62 | 158 listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp); |
159 if (listener) { | |
160 remove_listener( listener ); | |
161 ret = DROPBEAR_SUCCESS; | |
162 } | |
163 | |
164 out: | |
165 m_free(bindaddr); | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
166 TRACE(("leave cancelremotetcp")) |
62 | 167 return ret; |
168 } | |
169 | |
170 static int svr_remotetcpreq() { | |
171 | |
172 int ret = DROPBEAR_FAILURE; | |
173 unsigned char * bindaddr = NULL; | |
174 unsigned int addrlen; | |
175 struct TCPListener *tcpinfo = NULL; | |
176 unsigned int port; | |
177 | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
178 TRACE(("enter remotetcpreq")) |
62 | 179 |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
180 /* NOTE: at this stage, we ignore bindaddr. see below and listen_tcpfwd */ |
62 | 181 bindaddr = buf_getstring(ses.payload, &addrlen); |
182 if (addrlen > MAX_IP_LEN) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
183 TRACE(("addr len too long: %d", addrlen)) |
62 | 184 goto out; |
185 } | |
186 | |
187 port = buf_getint(ses.payload); | |
188 | |
189 if (port == 0) { | |
190 dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported"); | |
191 goto out; | |
192 } | |
193 | |
194 if (port < 1 || port > 65535) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
195 TRACE(("invalid port: %d", port)) |
62 | 196 goto out; |
197 } | |
198 | |
199 if (!ses.allowprivport && port < IPPORT_RESERVED) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
200 TRACE(("can't assign port < 1024 for non-root")) |
62 | 201 goto out; |
202 } | |
203 | |
204 tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
205 tcpinfo->sendaddr = bindaddr; |
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
206 tcpinfo->sendport = port; |
64 | 207 tcpinfo->listenport = port; |
62 | 208 tcpinfo->chantype = &svr_chan_tcpremote; |
209 | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
210 /* Note: bindaddr is actually ignored by listen_tcpfwd, since |
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
211 * we only want to bind to localhost */ |
62 | 212 ret = listen_tcpfwd(tcpinfo); |
213 | |
214 out: | |
215 if (ret == DROPBEAR_FAILURE) { | |
216 /* we only free it if a listener wasn't created, since the listener | |
217 * has to remember it if it's to be cancelled */ | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
218 m_free(tcpinfo->sendaddr); |
62 | 219 m_free(tcpinfo); |
220 } | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
221 TRACE(("leave remotetcpreq")) |
62 | 222 return ret; |
223 } | |
64 | 224 |
225 /* Called upon creating a new direct tcp channel (ie we connect out to an | |
226 * address */ | |
227 static int newtcpdirect(struct Channel * channel) { | |
228 | |
229 unsigned char* desthost = NULL; | |
230 unsigned int destport; | |
231 unsigned char* orighost = NULL; | |
232 unsigned int origport; | |
233 char portstring[NI_MAXSERV]; | |
234 int sock; | |
235 int len; | |
70
b0316ce64e4b
Merging in the changes from 0.41-0.43 main Dropbear tree
Matt Johnston <matt@ucc.asn.au>
parents:
64
diff
changeset
|
236 int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; |
64 | 237 |
238 if (opts.nolocaltcp) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
239 TRACE(("leave newtcpdirect: local tcp forwarding disabled")) |
64 | 240 goto out; |
241 } | |
242 | |
243 desthost = buf_getstring(ses.payload, &len); | |
244 if (len > MAX_HOST_LEN) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
245 TRACE(("leave newtcpdirect: desthost too long")) |
64 | 246 goto out; |
247 } | |
248 | |
249 destport = buf_getint(ses.payload); | |
250 | |
251 orighost = buf_getstring(ses.payload, &len); | |
252 if (len > MAX_HOST_LEN) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
253 TRACE(("leave newtcpdirect: orighost too long")) |
64 | 254 goto out; |
255 } | |
256 | |
257 origport = buf_getint(ses.payload); | |
258 | |
259 /* best be sure */ | |
260 if (origport > 65535 || destport > 65535) { | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
261 TRACE(("leave newtcpdirect: port > 65535")) |
64 | 262 goto out; |
263 } | |
264 | |
265 snprintf(portstring, sizeof(portstring), "%d", destport); | |
266 sock = connect_remote(desthost, portstring, 1, NULL); | |
267 if (sock < 0) { | |
70
b0316ce64e4b
Merging in the changes from 0.41-0.43 main Dropbear tree
Matt Johnston <matt@ucc.asn.au>
parents:
64
diff
changeset
|
268 err = SSH_OPEN_CONNECT_FAILED; |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
269 TRACE(("leave newtcpdirect: sock failed")) |
64 | 270 goto out; |
271 } | |
272 | |
273 ses.maxfd = MAX(ses.maxfd, sock); | |
274 | |
275 /* Note that infd is actually the "outgoing" direction on the | |
276 * tcp connection, vice versa for outfd. | |
277 * We don't set outfd, that will get set after the connection's | |
278 * progress succeeds */ | |
279 channel->infd = sock; | |
280 channel->initconn = 1; | |
281 | |
70
b0316ce64e4b
Merging in the changes from 0.41-0.43 main Dropbear tree
Matt Johnston <matt@ucc.asn.au>
parents:
64
diff
changeset
|
282 err = SSH_OPEN_IN_PROGRESS; |
64 | 283 |
284 out: | |
285 m_free(desthost); | |
286 m_free(orighost); | |
165
0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
Matt Johnston <matt@ucc.asn.au>
parents:
156
diff
changeset
|
287 TRACE(("leave newtcpdirect: err %d", err)) |
70
b0316ce64e4b
Merging in the changes from 0.41-0.43 main Dropbear tree
Matt Johnston <matt@ucc.asn.au>
parents:
64
diff
changeset
|
288 return err; |
64 | 289 } |
290 | |
62 | 291 #endif |