Mercurial > dropbear
annotate svr-tcpfwd.c @ 67:86725004a0ea
fake-rfc stuff
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 12 Aug 2004 14:39:17 +0000 |
parents | efb5e0b335cf |
children | b0316ce64e4b |
rev | line source |
---|---|
62 | 1 #include "includes.h" |
2 #include "ssh.h" | |
64 | 3 #include "tcpfwd.h" |
62 | 4 #include "dbutil.h" |
5 #include "session.h" | |
6 #include "buffer.h" | |
7 #include "packet.h" | |
8 #include "listener.h" | |
9 #include "runopts.h" | |
10 | |
11 #ifndef DISABLE_SVR_REMOTETCPFWD | |
12 | |
13 static void send_msg_request_success(); | |
14 static void send_msg_request_failure(); | |
15 static int svr_cancelremotetcp(); | |
16 static int svr_remotetcpreq(); | |
64 | 17 static int newtcpdirect(struct Channel * channel); |
62 | 18 |
19 | |
20 const struct ChanType svr_chan_tcpdirect = { | |
21 1, /* sepfds */ | |
22 "direct-tcpip", | |
23 newtcpdirect, /* init */ | |
24 NULL, /* checkclose */ | |
25 NULL, /* reqhandler */ | |
26 NULL /* closehandler */ | |
27 }; | |
28 | |
29 static const struct ChanType svr_chan_tcpremote = { | |
30 1, /* sepfds */ | |
31 "forwarded-tcpip", | |
32 NULL, | |
33 NULL, | |
34 NULL, | |
35 NULL | |
36 }; | |
37 | |
38 /* At the moment this is completely used for tcp code (with the name reflecting | |
39 * that). If new request types are added, this should be replaced with code | |
40 * similar to the request-switching in chansession.c */ | |
41 void recv_msg_global_request_remotetcp() { | |
42 | |
43 unsigned char* reqname = NULL; | |
44 unsigned int namelen; | |
45 unsigned int wantreply = 0; | |
46 int ret = DROPBEAR_FAILURE; | |
47 | |
48 TRACE(("enter recv_msg_global_request_remotetcp")); | |
49 | |
50 if (opts.noremotetcp) { | |
51 TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled")); | |
52 goto out; | |
53 } | |
54 | |
55 reqname = buf_getstring(ses.payload, &namelen); | |
56 wantreply = buf_getbyte(ses.payload); | |
57 | |
58 if (namelen > MAXNAMLEN) { | |
59 TRACE(("name len is wrong: %d", namelen)); | |
60 goto out; | |
61 } | |
62 | |
63 if (strcmp("tcpip-forward", reqname) == 0) { | |
64 ret = svr_remotetcpreq(); | |
65 } else if (strcmp("cancel-tcpip-forward", reqname) == 0) { | |
66 ret = svr_cancelremotetcp(); | |
67 } else { | |
68 TRACE(("reqname isn't tcpip-forward: '%s'", reqname)); | |
69 } | |
70 | |
71 out: | |
72 if (wantreply) { | |
73 if (ret == DROPBEAR_SUCCESS) { | |
74 send_msg_request_success(); | |
75 } else { | |
76 send_msg_request_failure(); | |
77 } | |
78 } | |
79 | |
80 m_free(reqname); | |
81 | |
82 TRACE(("leave recv_msg_global_request")); | |
83 } | |
84 | |
85 | |
86 static void send_msg_request_success() { | |
87 | |
88 CHECKCLEARTOWRITE(); | |
89 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS); | |
90 encrypt_packet(); | |
91 | |
92 } | |
93 | |
94 static void send_msg_request_failure() { | |
95 | |
96 CHECKCLEARTOWRITE(); | |
97 buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); | |
98 encrypt_packet(); | |
99 | |
100 } | |
101 | |
102 static int matchtcp(void* typedata1, void* typedata2) { | |
103 | |
104 const struct TCPListener *info1 = (struct TCPListener*)typedata1; | |
105 const struct TCPListener *info2 = (struct TCPListener*)typedata2; | |
106 | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
107 return (info1->sendport == info2->sendport) |
62 | 108 && (info1->chantype == info2->chantype) |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
109 && (strcmp(info1->sendaddr, info2->sendaddr) == 0); |
62 | 110 } |
111 | |
112 static int svr_cancelremotetcp() { | |
113 | |
114 int ret = DROPBEAR_FAILURE; | |
115 unsigned char * bindaddr = NULL; | |
116 unsigned int addrlen; | |
117 unsigned int port; | |
118 struct Listener * listener = NULL; | |
119 struct TCPListener tcpinfo; | |
120 | |
121 TRACE(("enter cancelremotetcp")); | |
122 | |
123 bindaddr = buf_getstring(ses.payload, &addrlen); | |
124 if (addrlen > MAX_IP_LEN) { | |
125 TRACE(("addr len too long: %d", addrlen)); | |
126 goto out; | |
127 } | |
128 | |
129 port = buf_getint(ses.payload); | |
130 | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
131 tcpinfo.sendaddr = bindaddr; |
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
132 tcpinfo.sendport = port; |
62 | 133 listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp); |
134 if (listener) { | |
135 remove_listener( listener ); | |
136 ret = DROPBEAR_SUCCESS; | |
137 } | |
138 | |
139 out: | |
140 m_free(bindaddr); | |
141 TRACE(("leave cancelremotetcp")); | |
142 return ret; | |
143 } | |
144 | |
145 static int svr_remotetcpreq() { | |
146 | |
147 int ret = DROPBEAR_FAILURE; | |
148 unsigned char * bindaddr = NULL; | |
149 unsigned int addrlen; | |
150 struct TCPListener *tcpinfo = NULL; | |
151 unsigned int port; | |
152 | |
153 TRACE(("enter remotetcpreq")); | |
154 | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
155 /* NOTE: at this stage, we ignore bindaddr. see below and listen_tcpfwd */ |
62 | 156 bindaddr = buf_getstring(ses.payload, &addrlen); |
157 if (addrlen > MAX_IP_LEN) { | |
158 TRACE(("addr len too long: %d", addrlen)); | |
159 goto out; | |
160 } | |
161 | |
162 port = buf_getint(ses.payload); | |
163 | |
164 if (port == 0) { | |
165 dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported"); | |
166 goto out; | |
167 } | |
168 | |
169 if (port < 1 || port > 65535) { | |
170 TRACE(("invalid port: %d", port)); | |
171 goto out; | |
172 } | |
173 | |
174 if (!ses.allowprivport && port < IPPORT_RESERVED) { | |
175 TRACE(("can't assign port < 1024 for non-root")); | |
176 goto out; | |
177 } | |
178 | |
179 tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
180 tcpinfo->sendaddr = bindaddr; |
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
181 tcpinfo->sendport = port; |
64 | 182 tcpinfo->listenport = port; |
62 | 183 tcpinfo->chantype = &svr_chan_tcpremote; |
184 | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
185 /* Note: bindaddr is actually ignored by listen_tcpfwd, since |
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
186 * we only want to bind to localhost */ |
62 | 187 ret = listen_tcpfwd(tcpinfo); |
188 | |
189 out: | |
190 if (ret == DROPBEAR_FAILURE) { | |
191 /* we only free it if a listener wasn't created, since the listener | |
192 * has to remember it if it's to be cancelled */ | |
63
dcc43965928f
- A nice cleaner structure for tcp (acceptor) forwarding.
Matt Johnston <matt@ucc.asn.au>
parents:
62
diff
changeset
|
193 m_free(tcpinfo->sendaddr); |
62 | 194 m_free(tcpinfo); |
195 } | |
196 TRACE(("leave remotetcpreq")); | |
197 return ret; | |
198 } | |
64 | 199 |
200 /* Called upon creating a new direct tcp channel (ie we connect out to an | |
201 * address */ | |
202 static int newtcpdirect(struct Channel * channel) { | |
203 | |
204 unsigned char* desthost = NULL; | |
205 unsigned int destport; | |
206 unsigned char* orighost = NULL; | |
207 unsigned int origport; | |
208 char portstring[NI_MAXSERV]; | |
209 int sock; | |
210 int len; | |
211 int ret = DROPBEAR_FAILURE; | |
212 | |
213 if (opts.nolocaltcp) { | |
214 TRACE(("leave newtcpdirect: local tcp forwarding disabled")); | |
215 goto out; | |
216 } | |
217 | |
218 desthost = buf_getstring(ses.payload, &len); | |
219 if (len > MAX_HOST_LEN) { | |
220 TRACE(("leave newtcpdirect: desthost too long")); | |
221 goto out; | |
222 } | |
223 | |
224 destport = buf_getint(ses.payload); | |
225 | |
226 orighost = buf_getstring(ses.payload, &len); | |
227 if (len > MAX_HOST_LEN) { | |
228 TRACE(("leave newtcpdirect: orighost too long")); | |
229 goto out; | |
230 } | |
231 | |
232 origport = buf_getint(ses.payload); | |
233 | |
234 /* best be sure */ | |
235 if (origport > 65535 || destport > 65535) { | |
236 TRACE(("leave newtcpdirect: port > 65535")); | |
237 goto out; | |
238 } | |
239 | |
240 snprintf(portstring, sizeof(portstring), "%d", destport); | |
241 sock = connect_remote(desthost, portstring, 1, NULL); | |
242 if (sock < 0) { | |
243 TRACE(("leave newtcpdirect: sock failed")); | |
244 goto out; | |
245 } | |
246 | |
247 ses.maxfd = MAX(ses.maxfd, sock); | |
248 | |
249 /* Note that infd is actually the "outgoing" direction on the | |
250 * tcp connection, vice versa for outfd. | |
251 * We don't set outfd, that will get set after the connection's | |
252 * progress succeeds */ | |
253 channel->infd = sock; | |
254 channel->initconn = 1; | |
255 | |
256 ret = DROPBEAR_SUCCESS; | |
257 | |
258 out: | |
259 m_free(desthost); | |
260 m_free(orighost); | |
261 TRACE(("leave newtcpdirect: ret %d", ret)); | |
262 return ret; | |
263 } | |
264 | |
62 | 265 #endif |