4 * Copyright (c) 2002,2003 Matt Johnston
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
34 #ifdef ENABLE_CLI_REMOTETCPFWD
35 static int newtcpforwarded(struct Channel
* channel
);
37 const struct ChanType cli_chan_tcpremote
= {
47 #ifdef ENABLE_CLI_LOCALTCPFWD
48 static int cli_localtcp(const char* listenaddr
,
49 unsigned int listenport
,
50 const char* remoteaddr
,
51 unsigned int remoteport
);
52 static const struct ChanType cli_chan_tcplocal
= {
62 #ifdef ENABLE_CLI_LOCALTCPFWD
63 void setup_localtcp() {
67 TRACE(("enter setup_localtcp"))
69 for (iter
= cli_opts
.localfwds
->first
; iter
; iter
= iter
->next
) {
70 struct TCPFwdEntry
* fwd
= (struct TCPFwdEntry
*)iter
->item
;
76 if (ret
== DROPBEAR_FAILURE
) {
77 dropbear_log(LOG_WARNING
, "Failed local port forward %s:%d:%s:%d",
84 TRACE(("leave setup_localtcp"))
88 static int cli_localtcp(const char* listenaddr
,
89 unsigned int listenport
,
90 const char* remoteaddr
,
91 unsigned int remoteport
) {
93 struct TCPListener
* tcpinfo
= NULL
;
96 TRACE(("enter cli_localtcp: %d %s %d", listenport
, remoteaddr
,
99 tcpinfo
= (struct TCPListener
*)m_malloc(sizeof(struct TCPListener
));
101 tcpinfo
->sendaddr
= m_strdup(remoteaddr
);
102 tcpinfo
->sendport
= remoteport
;
106 tcpinfo
->listenaddr
= m_strdup(listenaddr
);
110 if (opts
.listen_fwd_all
) {
111 tcpinfo
->listenaddr
= m_strdup("");
113 tcpinfo
->listenaddr
= m_strdup("localhost");
116 tcpinfo
->listenport
= listenport
;
118 tcpinfo
->chantype
= &cli_chan_tcplocal
;
119 tcpinfo
->tcp_type
= direct
;
121 ret
= listen_tcpfwd(tcpinfo
);
123 if (ret
== DROPBEAR_FAILURE
) {
126 TRACE(("leave cli_localtcp: %d", ret
))
129 #endif /* ENABLE_CLI_LOCALTCPFWD */
131 #ifdef ENABLE_CLI_REMOTETCPFWD
132 static void send_msg_global_request_remotetcp(const char *addr
, int port
) {
134 TRACE(("enter send_msg_global_request_remotetcp"))
137 buf_putbyte(ses
.writepayload
, SSH_MSG_GLOBAL_REQUEST
);
138 buf_putstring(ses
.writepayload
, "tcpip-forward", 13);
139 buf_putbyte(ses
.writepayload
, 1); /* want_reply */
140 buf_putstring(ses
.writepayload
, addr
, strlen(addr
));
141 buf_putint(ses
.writepayload
, port
);
145 TRACE(("leave send_msg_global_request_remotetcp"))
148 /* The only global success/failure messages are for remotetcp.
149 * Since there isn't any identifier in these messages, we have to rely on them
150 * being in the same order as we sent the requests. This is the ordering
151 * of the cli_opts.remotefwds list.
152 * If the requested remote port is 0 the listen port will be
153 * dynamically allocated by the server and the port number will be returned
154 * to client and the port number reported to the user. */
155 void cli_recv_msg_request_success() {
156 /* We just mark off that we have received the reply,
157 * so that we can report failure for later ones. */
158 m_list_elem
* iter
= NULL
;
159 for (iter
= cli_opts
.remotefwds
->first
; iter
; iter
= iter
->next
) {
160 struct TCPFwdEntry
*fwd
= (struct TCPFwdEntry
*)iter
->item
;
161 if (!fwd
->have_reply
) {
163 if (fwd
->listenport
== 0) {
164 /* The server should let us know which port was allocated if we requestd port 0 */
165 int allocport
= buf_getint(ses
.payload
);
167 dropbear_log(LOG_INFO
, "Allocated port %d for remote forward to %s:%d",
168 allocport
, fwd
->connectaddr
, fwd
->connectport
);
176 void cli_recv_msg_request_failure() {
178 for (iter
= cli_opts
.remotefwds
->first
; iter
; iter
= iter
->next
) {
179 struct TCPFwdEntry
*fwd
= (struct TCPFwdEntry
*)iter
->item
;
180 if (!fwd
->have_reply
) {
182 dropbear_log(LOG_WARNING
, "Remote TCP forward request failed (port %d -> %s:%d)", fwd
->listenport
, fwd
->connectaddr
, fwd
->connectport
);
188 void setup_remotetcp() {
190 TRACE(("enter setup_remotetcp"))
192 for (iter
= cli_opts
.remotefwds
->first
; iter
; iter
= iter
->next
) {
193 struct TCPFwdEntry
*fwd
= (struct TCPFwdEntry
*)iter
->item
;
194 if (!fwd
->listenaddr
)
196 // we store the addresses so that we can compare them
197 // when the server sends them back
198 if (opts
.listen_fwd_all
) {
199 fwd
->listenaddr
= m_strdup("");
201 fwd
->listenaddr
= m_strdup("localhost");
204 send_msg_global_request_remotetcp(fwd
->listenaddr
, fwd
->listenport
);
207 TRACE(("leave setup_remotetcp"))
210 static int newtcpforwarded(struct Channel
* channel
) {
212 char *origaddr
= NULL
;
213 unsigned int origport
;
214 m_list_elem
* iter
= NULL
;
215 struct TCPFwdEntry
*fwd
;
216 char portstring
[NI_MAXSERV
];
218 int err
= SSH_OPEN_ADMINISTRATIVELY_PROHIBITED
;
220 origaddr
= buf_getstring(ses
.payload
, NULL
);
221 origport
= buf_getint(ses
.payload
);
223 /* Find which port corresponds */
224 for (iter
= cli_opts
.remotefwds
->first
; iter
; iter
= iter
->next
) {
225 fwd
= (struct TCPFwdEntry
*)iter
->item
;
226 if (origport
== fwd
->listenport
227 && (strcmp(origaddr
, fwd
->listenaddr
) == 0)) {
233 /* We didn't request forwarding on that port */
235 dropbear_log(LOG_INFO
, "Server sent unrequested forward from \"%s:%d\"",
240 snprintf(portstring
, sizeof(portstring
), "%d", fwd
->connectport
);
241 sock
= connect_remote(fwd
->connectaddr
, portstring
, 1, NULL
);
243 TRACE(("leave newtcpdirect: sock failed"))
244 err
= SSH_OPEN_CONNECT_FAILED
;
248 ses
.maxfd
= MAX(ses
.maxfd
, sock
);
250 /* We don't set readfd, that will get set after the connection's
251 * progress succeeds */
252 channel
->writefd
= sock
;
253 channel
->initconn
= 1;
255 err
= SSH_OPEN_IN_PROGRESS
;
259 TRACE(("leave newtcpdirect: err %d", err
))
262 #endif /* ENABLE_CLI_REMOTETCPFWD */