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 void cli_recv_msg_request_success() {
153 /* Nothing in the packet. We just mark off that we have received the reply,
154 * so that we can report failure for later ones. */
155 m_list_elem
* iter
= NULL
;
156 for (iter
= cli_opts
.remotefwds
->first
; iter
; iter
= iter
->next
) {
157 struct TCPFwdEntry
*fwd
= (struct TCPFwdEntry
*)iter
->item
;
158 if (!fwd
->have_reply
) {
165 void cli_recv_msg_request_failure() {
167 for (iter
= cli_opts
.remotefwds
->first
; iter
; iter
= iter
->next
) {
168 struct TCPFwdEntry
*fwd
= (struct TCPFwdEntry
*)iter
->item
;
169 if (!fwd
->have_reply
) {
171 dropbear_log(LOG_WARNING
, "Remote TCP forward request failed (port %d -> %s:%d)", fwd
->listenport
, fwd
->connectaddr
, fwd
->connectport
);
177 void setup_remotetcp() {
179 TRACE(("enter setup_remotetcp"))
181 for (iter
= cli_opts
.remotefwds
->first
; iter
; iter
= iter
->next
) {
182 struct TCPFwdEntry
*fwd
= (struct TCPFwdEntry
*)iter
->item
;
183 if (!fwd
->listenaddr
)
185 // we store the addresses so that we can compare them
186 // when the server sends them back
187 if (opts
.listen_fwd_all
) {
188 fwd
->listenaddr
= m_strdup("");
190 fwd
->listenaddr
= m_strdup("localhost");
193 send_msg_global_request_remotetcp(fwd
->listenaddr
, fwd
->listenport
);
196 TRACE(("leave setup_remotetcp"))
199 static int newtcpforwarded(struct Channel
* channel
) {
201 char *origaddr
= NULL
;
202 unsigned int origport
;
203 m_list_elem
* iter
= NULL
;
204 struct TCPFwdEntry
*fwd
;
205 char portstring
[NI_MAXSERV
];
207 int err
= SSH_OPEN_ADMINISTRATIVELY_PROHIBITED
;
209 origaddr
= buf_getstring(ses
.payload
, NULL
);
210 origport
= buf_getint(ses
.payload
);
212 /* Find which port corresponds */
213 for (iter
= cli_opts
.remotefwds
->first
; iter
; iter
= iter
->next
) {
214 fwd
= (struct TCPFwdEntry
*)iter
->item
;
215 if (origport
== fwd
->listenport
216 && (strcmp(origaddr
, fwd
->listenaddr
) == 0)) {
222 /* We didn't request forwarding on that port */
224 dropbear_log(LOG_INFO
, "Server sent unrequested forward from \"%s:%d\"",
229 snprintf(portstring
, sizeof(portstring
), "%d", fwd
->connectport
);
230 sock
= connect_remote(fwd
->connectaddr
, portstring
, 1, NULL
);
232 TRACE(("leave newtcpdirect: sock failed"))
233 err
= SSH_OPEN_CONNECT_FAILED
;
237 ses
.maxfd
= MAX(ses
.maxfd
, sock
);
239 /* We don't set readfd, that will get set after the connection's
240 * progress succeeds */
241 channel
->writefd
= sock
;
242 channel
->initconn
= 1;
244 err
= SSH_OPEN_IN_PROGRESS
;
248 TRACE(("leave newtcpdirect: err %d", err
))
251 #endif /* ENABLE_CLI_REMOTETCPFWD */