Mercurial > dropbear
annotate svr-tcpfwd.c @ 447:278805938dcf
Patch from Nicolai Ehemann to try binding before going to the background,
so that if it exits early (because something's already listening etc)
then it will return an exitcode of 1.
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 19 Jul 2007 15:54:18 +0000 |
parents | b895f91c2ee6 |
children | 52a644e7b8e1 |
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 |
258
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
75 if (svr_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 |
267
7ce577234a10
* svr-tcpfwd.c: should be MAX_NAME_LEN not MAXNAMLEN
Matt Johnston <matt@ucc.asn.au>
parents:
259
diff
changeset
|
83 if (namelen > MAX_NAME_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
|
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 | |
258
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
132 return (info1->listenport == info2->listenport) |
62 | 133 && (info1->chantype == info2->chantype) |
258
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
134 && (strcmp(info1->listenaddr, info2->listenaddr) == 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 | |
258
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
156 tcpinfo.sendaddr = NULL; |
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
157 tcpinfo.sendport = 0; |
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
158 tcpinfo.listenaddr = bindaddr; |
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
159 tcpinfo.listenport = port; |
62 | 160 listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp); |
161 if (listener) { | |
162 remove_listener( listener ); | |
163 ret = DROPBEAR_SUCCESS; | |
164 } | |
165 | |
166 out: | |
167 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
|
168 TRACE(("leave cancelremotetcp")) |
62 | 169 return ret; |
170 } | |
171 | |
172 static int svr_remotetcpreq() { | |
173 | |
174 int ret = DROPBEAR_FAILURE; | |
175 unsigned char * bindaddr = NULL; | |
176 unsigned int addrlen; | |
177 struct TCPListener *tcpinfo = NULL; | |
178 unsigned int port; | |
179 | |
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
|
180 TRACE(("enter remotetcpreq")) |
62 | 181 |
182 bindaddr = buf_getstring(ses.payload, &addrlen); | |
183 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
|
184 TRACE(("addr len too long: %d", addrlen)) |
62 | 185 goto out; |
186 } | |
187 | |
188 port = buf_getint(ses.payload); | |
189 | |
190 if (port == 0) { | |
191 dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported"); | |
192 goto out; | |
193 } | |
194 | |
195 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
|
196 TRACE(("invalid port: %d", port)) |
62 | 197 goto out; |
198 } | |
199 | |
200 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
|
201 TRACE(("can't assign port < 1024 for non-root")) |
62 | 202 goto out; |
203 } | |
204 | |
205 tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); | |
258
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
206 tcpinfo->sendaddr = NULL; |
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
207 tcpinfo->sendport = 0; |
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
208 tcpinfo->listenaddr = bindaddr; |
64 | 209 tcpinfo->listenport = port; |
62 | 210 tcpinfo->chantype = &svr_chan_tcpremote; |
259
c049490e43fe
* fix -L forwarding on the client, broke last rev
Matt Johnston <matt@ucc.asn.au>
parents:
258
diff
changeset
|
211 tcpinfo->tcp_type = forwarded; |
62 | 212 |
213 ret = listen_tcpfwd(tcpinfo); | |
214 | |
215 out: | |
216 if (ret == DROPBEAR_FAILURE) { | |
217 /* we only free it if a listener wasn't created, since the listener | |
218 * has to remember it if it's to be cancelled */ | |
340 | 219 m_free(bindaddr); |
62 | 220 m_free(tcpinfo); |
221 } | |
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
|
222 TRACE(("leave remotetcpreq")) |
62 | 223 return ret; |
224 } | |
64 | 225 |
226 /* Called upon creating a new direct tcp channel (ie we connect out to an | |
227 * address */ | |
228 static int newtcpdirect(struct Channel * channel) { | |
229 | |
230 unsigned char* desthost = NULL; | |
231 unsigned int destport; | |
232 unsigned char* orighost = NULL; | |
233 unsigned int origport; | |
234 char portstring[NI_MAXSERV]; | |
235 int sock; | |
236 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
|
237 int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; |
64 | 238 |
258
306499676384
* add -g (dbclient) and -a (dropbear) options for allowing non-local
Matt Johnston <matt@ucc.asn.au>
parents:
253
diff
changeset
|
239 if (svr_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
|
240 TRACE(("leave newtcpdirect: local tcp forwarding disabled")) |
64 | 241 goto out; |
242 } | |
243 | |
244 desthost = buf_getstring(ses.payload, &len); | |
245 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
|
246 TRACE(("leave newtcpdirect: desthost too long")) |
64 | 247 goto out; |
248 } | |
249 | |
250 destport = buf_getint(ses.payload); | |
251 | |
252 orighost = buf_getstring(ses.payload, &len); | |
253 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
|
254 TRACE(("leave newtcpdirect: orighost too long")) |
64 | 255 goto out; |
256 } | |
257 | |
258 origport = buf_getint(ses.payload); | |
259 | |
260 /* best be sure */ | |
261 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
|
262 TRACE(("leave newtcpdirect: port > 65535")) |
64 | 263 goto out; |
264 } | |
265 | |
266 snprintf(portstring, sizeof(portstring), "%d", destport); | |
267 sock = connect_remote(desthost, portstring, 1, NULL); | |
268 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
|
269 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
|
270 TRACE(("leave newtcpdirect: sock failed")) |
64 | 271 goto out; |
272 } | |
273 | |
274 ses.maxfd = MAX(ses.maxfd, sock); | |
275 | |
253
84925eceeb13
* rename infd/outfd to writefd/readfd, to avoid confusion
Matt Johnston <matt@ucc.asn.au>
parents:
179
diff
changeset
|
276 /* We don't set readfd, that will get set after the connection's |
64 | 277 * progress succeeds */ |
253
84925eceeb13
* rename infd/outfd to writefd/readfd, to avoid confusion
Matt Johnston <matt@ucc.asn.au>
parents:
179
diff
changeset
|
278 channel->writefd = sock; |
64 | 279 channel->initconn = 1; |
280 | |
70
b0316ce64e4b
Merging in the changes from 0.41-0.43 main Dropbear tree
Matt Johnston <matt@ucc.asn.au>
parents:
64
diff
changeset
|
281 err = SSH_OPEN_IN_PROGRESS; |
64 | 282 |
283 out: | |
284 m_free(desthost); | |
285 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
|
286 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
|
287 return err; |
64 | 288 } |
289 | |
62 | 290 #endif |