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(unsigned int listenport
, const char* remoteaddr
,
49 unsigned int remoteport
);
50 static const struct ChanType cli_chan_tcplocal
= {
60 #ifdef ENABLE_CLI_LOCALTCPFWD
61 void setup_localtcp() {
65 TRACE(("enter setup_localtcp"))
67 if (cli_opts
.localfwds
== NULL
) {
68 TRACE(("cli_opts.localfwds == NULL"))
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
);
82 cli_opts
.localfwds
= cli_opts
.localfwds
->next
;
84 TRACE(("leave setup_localtcp"))
88 static int cli_localtcp(unsigned int listenport
, const char* remoteaddr
,
89 unsigned int remoteport
) {
91 struct TCPListener
* tcpinfo
= NULL
;
94 TRACE(("enter cli_localtcp: %d %s %d", listenport
, remoteaddr
,
97 tcpinfo
= (struct TCPListener
*)m_malloc(sizeof(struct TCPListener
));
99 tcpinfo
->sendaddr
= m_strdup(remoteaddr
);
100 tcpinfo
->sendport
= remoteport
;
102 if (opts
.listen_fwd_all
) {
103 tcpinfo
->listenaddr
= m_strdup("");
105 tcpinfo
->listenaddr
= m_strdup("localhost");
107 tcpinfo
->listenport
= listenport
;
109 tcpinfo
->chantype
= &cli_chan_tcplocal
;
110 tcpinfo
->tcp_type
= direct
;
112 ret
= listen_tcpfwd(tcpinfo
);
114 if (ret
== DROPBEAR_FAILURE
) {
117 TRACE(("leave cli_localtcp: %d", ret
))
120 #endif /* ENABLE_CLI_LOCALTCPFWD */
122 #ifdef ENABLE_CLI_REMOTETCPFWD
123 static void send_msg_global_request_remotetcp(int port
) {
125 char* listenspec
= NULL
;
126 TRACE(("enter send_msg_global_request_remotetcp"))
129 buf_putbyte(ses
.writepayload
, SSH_MSG_GLOBAL_REQUEST
);
130 buf_putstring(ses
.writepayload
, "tcpip-forward", 13);
131 buf_putbyte(ses
.writepayload
, 1); /* want_reply */
132 if (opts
.listen_fwd_all
) {
135 listenspec
= "localhost";
138 buf_putstring(ses
.writepayload
, listenspec
, strlen(listenspec
));
139 buf_putint(ses
.writepayload
, port
);
143 TRACE(("leave send_msg_global_request_remotetcp"))
146 /* The only global success/failure messages are for remotetcp.
147 * Since there isn't any identifier in these messages, we have to rely on them
148 * being in the same order as we sent the requests. This is the ordering
149 * of the cli_opts.remotefwds list */
150 void cli_recv_msg_request_success() {
152 /* Nothing in the packet. We just mark off that we have received the reply,
153 * so that we can report failure for later ones. */
154 struct TCPFwdList
* iter
= NULL
;
156 iter
= cli_opts
.remotefwds
;
157 while (iter
!= NULL
) {
158 if (!iter
->have_reply
)
160 iter
->have_reply
= 1;
167 void cli_recv_msg_request_failure() {
168 struct TCPFwdList
* iter
= NULL
;
170 iter
= cli_opts
.remotefwds
;
171 while (iter
!= NULL
) {
172 if (!iter
->have_reply
)
174 iter
->have_reply
= 1;
175 dropbear_log(LOG_WARNING
, "Remote TCP forward request failed (port %d -> %s:%d)", iter
->listenport
, iter
->connectaddr
, iter
->connectport
);
182 void setup_remotetcp() {
184 struct TCPFwdList
* iter
= NULL
;
186 TRACE(("enter setup_remotetcp"))
188 if (cli_opts
.remotefwds
== NULL
) {
189 TRACE(("cli_opts.remotefwds == NULL"))
192 iter
= cli_opts
.remotefwds
;
194 while (iter
!= NULL
) {
195 send_msg_global_request_remotetcp(iter
->listenport
);
198 TRACE(("leave setup_remotetcp"))
201 static int newtcpforwarded(struct Channel
* channel
) {
203 unsigned int origport
;
204 struct TCPFwdList
* iter
= NULL
;
205 char portstring
[NI_MAXSERV
];
207 int err
= SSH_OPEN_ADMINISTRATIVELY_PROHIBITED
;
209 /* We don't care what address they connected to */
210 buf_eatstring(ses
.payload
);
212 origport
= buf_getint(ses
.payload
);
214 /* Find which port corresponds */
215 iter
= cli_opts
.remotefwds
;
217 while (iter
!= NULL
) {
218 if (origport
== iter
->listenport
) {
225 /* We didn't request forwarding on that port */
226 dropbear_log(LOG_INFO
, "Server send unrequested port, from port %d",
231 snprintf(portstring
, sizeof(portstring
), "%d", iter
->connectport
);
232 sock
= connect_remote(iter
->connectaddr
, portstring
, 1, NULL
);
234 TRACE(("leave newtcpdirect: sock failed"))
235 err
= SSH_OPEN_CONNECT_FAILED
;
239 ses
.maxfd
= MAX(ses
.maxfd
, sock
);
241 /* We don't set readfd, that will get set after the connection's
242 * progress succeeds */
243 channel
->writefd
= sock
;
244 channel
->initconn
= 1;
246 err
= SSH_OPEN_IN_PROGRESS
;
249 TRACE(("leave newtcpdirect: err %d", err
))
252 #endif /* ENABLE_CLI_REMOTETCPFWD */