Tomato 1.28
[tomato.git] / release / src / router / dropbear / cli-tcpfwd.c
blob0e60090bb2a296ae8b2f45efee571a20d5184a60
1 /*
2 * Dropbear SSH
3 *
4 * Copyright (c) 2002,2003 Matt Johnston
5 * All rights reserved.
6 *
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
23 * SOFTWARE. */
25 #include "includes.h"
26 #include "options.h"
27 #include "dbutil.h"
28 #include "tcpfwd.h"
29 #include "channel.h"
30 #include "runopts.h"
31 #include "session.h"
32 #include "ssh.h"
34 #ifdef ENABLE_CLI_REMOTETCPFWD
35 static int newtcpforwarded(struct Channel * channel);
37 const struct ChanType cli_chan_tcpremote = {
38 1, /* sepfds */
39 "forwarded-tcpip",
40 newtcpforwarded,
41 NULL,
42 NULL,
43 NULL
45 #endif
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 = {
51 1, /* sepfds */
52 "direct-tcpip",
53 NULL,
54 NULL,
55 NULL,
56 NULL
58 #endif
60 #ifdef ENABLE_CLI_LOCALTCPFWD
61 void setup_localtcp() {
63 int ret;
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;
92 int ret;
94 TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
95 remoteport));
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("");
104 } else {
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) {
115 m_free(tcpinfo);
117 TRACE(("leave cli_localtcp: %d", ret))
118 return 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"))
128 CHECKCLEARTOWRITE();
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) {
133 listenspec = "";
134 } else {
135 listenspec = "localhost";
137 /* TODO: IPv6? */;
138 buf_putstring(ses.writepayload, listenspec, strlen(listenspec));
139 buf_putint(ses.writepayload, port);
141 encrypt_packet();
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;
161 return;
163 iter = iter->next;
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);
176 return;
178 iter = iter->next;
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);
196 iter = iter->next;
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];
206 int sock;
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) {
219 break;
221 iter = iter->next;
224 if (iter == NULL) {
225 /* We didn't request forwarding on that port */
226 dropbear_log(LOG_INFO, "Server send unrequested port, from port %d",
227 origport);
228 goto out;
231 snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
232 sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
233 if (sock < 0) {
234 TRACE(("leave newtcpdirect: sock failed"))
235 err = SSH_OPEN_CONNECT_FAILED;
236 goto out;
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;
248 out:
249 TRACE(("leave newtcpdirect: err %d", err))
250 return err;
252 #endif /* ENABLE_CLI_REMOTETCPFWD */