usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / dropbear / cli-tcpfwd.c
blob0f47dcc2e8e74b9048600eccae335722c8553514
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(const char* listenaddr,
49 unsigned int listenport,
50 const char* remoteaddr,
51 unsigned int remoteport);
52 static const struct ChanType cli_chan_tcplocal = {
53 1, /* sepfds */
54 "direct-tcpip",
55 NULL,
56 NULL,
57 NULL,
58 NULL
60 #endif
62 #ifdef ENABLE_CLI_LOCALTCPFWD
63 void setup_localtcp() {
64 m_list_elem *iter;
65 int ret;
67 TRACE(("enter setup_localtcp"))
69 for (iter = cli_opts.localfwds->first; iter; iter = iter->next) {
70 struct TCPFwdEntry * fwd = (struct TCPFwdEntry*)iter->item;
71 ret = cli_localtcp(
72 fwd->listenaddr,
73 fwd->listenport,
74 fwd->connectaddr,
75 fwd->connectport);
76 if (ret == DROPBEAR_FAILURE) {
77 dropbear_log(LOG_WARNING, "Failed local port forward %s:%d:%s:%d",
78 fwd->listenaddr,
79 fwd->listenport,
80 fwd->connectaddr,
81 fwd->connectport);
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;
94 int ret;
96 TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
97 remoteport));
99 tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
101 tcpinfo->sendaddr = m_strdup(remoteaddr);
102 tcpinfo->sendport = remoteport;
104 if (listenaddr)
106 tcpinfo->listenaddr = m_strdup(listenaddr);
108 else
110 if (opts.listen_fwd_all) {
111 tcpinfo->listenaddr = m_strdup("");
112 } else {
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) {
124 m_free(tcpinfo);
126 TRACE(("leave cli_localtcp: %d", ret))
127 return 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"))
136 CHECKCLEARTOWRITE();
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);
143 encrypt_packet();
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) {
162 fwd->have_reply = 1;
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);
166 if (allocport > 0) {
167 dropbear_log(LOG_INFO, "Allocated port %d for remote forward to %s:%d",
168 allocport, fwd->connectaddr, fwd->connectport);
171 return;
176 void cli_recv_msg_request_failure() {
177 m_list_elem *iter;
178 for (iter = cli_opts.remotefwds->first; iter; iter = iter->next) {
179 struct TCPFwdEntry *fwd = (struct TCPFwdEntry*)iter->item;
180 if (!fwd->have_reply) {
181 fwd->have_reply = 1;
182 dropbear_log(LOG_WARNING, "Remote TCP forward request failed (port %d -> %s:%d)", fwd->listenport, fwd->connectaddr, fwd->connectport);
183 return;
188 void setup_remotetcp() {
189 m_list_elem *iter;
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("");
200 } else {
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];
217 int sock;
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)) {
228 break;
232 if (iter == NULL) {
233 /* We didn't request forwarding on that port */
234 cleantext(origaddr);
235 dropbear_log(LOG_INFO, "Server sent unrequested forward from \"%s:%d\"",
236 origaddr, origport);
237 goto out;
240 snprintf(portstring, sizeof(portstring), "%d", fwd->connectport);
241 sock = connect_remote(fwd->connectaddr, portstring, 1, NULL);
242 if (sock < 0) {
243 TRACE(("leave newtcpdirect: sock failed"))
244 err = SSH_OPEN_CONNECT_FAILED;
245 goto out;
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;
257 out:
258 m_free(origaddr);
259 TRACE(("leave newtcpdirect: err %d", err))
260 return err;
262 #endif /* ENABLE_CLI_REMOTETCPFWD */