f26d5c33 |
1 | #include <stdio.h> |
2 | #include <stdlib.h> |
3 | |
4 | #include "putty.h" |
5 | #include "ssh.h" |
6 | |
7 | #ifndef FALSE |
8 | #define FALSE 0 |
9 | #endif |
10 | #ifndef TRUE |
11 | #define TRUE 1 |
12 | #endif |
13 | |
14 | #define GET_32BIT_LSB_FIRST(cp) \ |
15 | (((unsigned long)(unsigned char)(cp)[0]) | \ |
16 | ((unsigned long)(unsigned char)(cp)[1] << 8) | \ |
17 | ((unsigned long)(unsigned char)(cp)[2] << 16) | \ |
18 | ((unsigned long)(unsigned char)(cp)[3] << 24)) |
19 | |
20 | #define PUT_32BIT_LSB_FIRST(cp, value) ( \ |
21 | (cp)[0] = (value), \ |
22 | (cp)[1] = (value) >> 8, \ |
23 | (cp)[2] = (value) >> 16, \ |
24 | (cp)[3] = (value) >> 24 ) |
25 | |
26 | #define GET_16BIT_LSB_FIRST(cp) \ |
27 | (((unsigned long)(unsigned char)(cp)[0]) | \ |
28 | ((unsigned long)(unsigned char)(cp)[1] << 8)) |
29 | |
30 | #define PUT_16BIT_LSB_FIRST(cp, value) ( \ |
31 | (cp)[0] = (value), \ |
32 | (cp)[1] = (value) >> 8 ) |
33 | |
34 | #define GET_32BIT_MSB_FIRST(cp) \ |
35 | (((unsigned long)(unsigned char)(cp)[0] << 24) | \ |
36 | ((unsigned long)(unsigned char)(cp)[1] << 16) | \ |
37 | ((unsigned long)(unsigned char)(cp)[2] << 8) | \ |
38 | ((unsigned long)(unsigned char)(cp)[3])) |
39 | |
40 | #define PUT_32BIT_MSB_FIRST(cp, value) ( \ |
41 | (cp)[0] = (value) >> 24, \ |
42 | (cp)[1] = (value) >> 16, \ |
43 | (cp)[2] = (value) >> 8, \ |
44 | (cp)[3] = (value) ) |
45 | |
46 | #define GET_16BIT_MSB_FIRST(cp) \ |
47 | (((unsigned long)(unsigned char)(cp)[0] << 8) | \ |
48 | ((unsigned long)(unsigned char)(cp)[1])) |
49 | |
50 | #define PUT_16BIT_MSB_FIRST(cp, value) ( \ |
51 | (cp)[0] = (value) >> 8, \ |
52 | (cp)[1] = (value) ) |
53 | |
f26d5c33 |
54 | struct pfwd_queue { |
55 | struct pfwd_queue *next; |
56 | char *buf; |
57 | }; |
58 | |
59 | struct PFwdPrivate { |
60 | struct plug_function_table *fn; |
61 | /* the above variable absolutely *must* be the first in this structure */ |
62 | void *c; /* (channel) data used by ssh.c */ |
6b78788a |
63 | void *backhandle; /* instance of SSH backend itself */ |
64 | /* Note that backhandle need not be filled in if c is non-NULL */ |
f26d5c33 |
65 | Socket s; |
66 | char hostname[128]; |
5471d09a |
67 | int throttled, throttle_override; |
f26d5c33 |
68 | int port; |
69 | int ready; |
70 | struct pfwd_queue *waiting; |
71 | }; |
72 | |
f26d5c33 |
73 | |
74 | static int pfd_closing(Plug plug, char *error_msg, int error_code, |
75 | int calling_back) |
76 | { |
77 | struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; |
78 | |
79 | /* |
80 | * We have no way to communicate down the forwarded connection, |
81 | * so if an error occurred on the socket, we just ignore it |
82 | * and treat it like a proper close. |
83 | */ |
84 | sshfwd_close(pr->c); |
85 | pfd_close(pr->s); |
86 | return 1; |
87 | } |
88 | |
89 | static int pfd_receive(Plug plug, int urgent, char *data, int len) |
90 | { |
91 | struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; |
5471d09a |
92 | if (pr->ready) { |
93 | if (sshfwd_write(pr->c, data, len) > 0) { |
94 | pr->throttled = 1; |
95 | sk_set_frozen(pr->s, 1); |
96 | } |
97 | } |
f26d5c33 |
98 | return 1; |
99 | } |
100 | |
5471d09a |
101 | static void pfd_sent(Plug plug, int bufsize) |
102 | { |
103 | struct PFwdPrivate *pr = (struct PFwdPrivate *) plug; |
104 | |
105 | sshfwd_unthrottle(pr->c, bufsize); |
106 | } |
107 | |
f26d5c33 |
108 | /* |
109 | * Called when receiving a PORT OPEN from the server |
110 | */ |
111 | char *pfd_newconnect(Socket *s, char *hostname, int port, void *c) |
112 | { |
113 | static struct plug_function_table fn_table = { |
114 | pfd_closing, |
115 | pfd_receive, |
5471d09a |
116 | pfd_sent, |
f26d5c33 |
117 | NULL |
118 | }; |
119 | |
120 | SockAddr addr; |
121 | char *err, *dummy_realhost; |
122 | struct PFwdPrivate *pr; |
123 | |
124 | /* |
125 | * Try to find host. |
126 | */ |
b7a189f3 |
127 | addr = name_lookup(hostname, port, &dummy_realhost); |
808c3834 |
128 | if ((err = sk_addr_error(addr)) != NULL) |
f26d5c33 |
129 | return err; |
130 | |
131 | /* |
132 | * Open socket. |
133 | */ |
134 | pr = (struct PFwdPrivate *) smalloc(sizeof(struct PFwdPrivate)); |
135 | pr->fn = &fn_table; |
5471d09a |
136 | pr->throttled = pr->throttle_override = 0; |
f26d5c33 |
137 | pr->ready = 1; |
138 | pr->c = c; |
6b78788a |
139 | pr->backhandle = NULL; /* we shouldn't need this */ |
f26d5c33 |
140 | |
8eebd221 |
141 | pr->s = *s = new_connection(addr, dummy_realhost, port, 0, 1, 0, (Plug) pr); |
808c3834 |
142 | if ((err = sk_socket_error(*s)) != NULL) { |
f26d5c33 |
143 | sfree(pr); |
144 | return err; |
145 | } |
146 | |
147 | sk_set_private_ptr(*s, pr); |
148 | sk_addr_free(addr); |
149 | return NULL; |
150 | } |
151 | |
152 | /* |
153 | called when someone connects to the local port |
154 | */ |
155 | |
bcce45ed |
156 | static int pfd_accepting(Plug p, void *sock) |
f26d5c33 |
157 | { |
f26d5c33 |
158 | static struct plug_function_table fn_table = { |
159 | pfd_closing, |
160 | pfd_receive, |
5471d09a |
161 | pfd_sent, |
f26d5c33 |
162 | NULL |
163 | }; |
164 | struct PFwdPrivate *pr, *org; |
f26d5c33 |
165 | Socket s; |
166 | char *err; |
167 | |
f26d5c33 |
168 | org = (struct PFwdPrivate *)p; |
169 | pr = (struct PFwdPrivate *) smalloc(sizeof(struct PFwdPrivate)); |
170 | pr->fn = &fn_table; |
171 | |
172 | pr->c = NULL; |
6b78788a |
173 | pr->backhandle = org->backhandle; |
f26d5c33 |
174 | |
175 | pr->s = s = sk_register(sock, (Plug) pr); |
808c3834 |
176 | if ((err = sk_socket_error(s)) != NULL) { |
f26d5c33 |
177 | sfree(pr); |
178 | return err != NULL; |
179 | } |
180 | |
6b78788a |
181 | pr->c = new_sock_channel(org->backhandle, s); |
f26d5c33 |
182 | |
183 | strcpy(pr->hostname, org->hostname); |
184 | pr->port = org->port; |
5471d09a |
185 | pr->throttled = pr->throttle_override = 0; |
f26d5c33 |
186 | pr->ready = 0; |
187 | pr->waiting = NULL; |
188 | |
189 | sk_set_private_ptr(s, pr); |
190 | |
191 | if (pr->c == NULL) { |
192 | sfree(pr); |
193 | return 1; |
194 | } else { |
195 | /* asks to forward to the specified host/port for this */ |
6b78788a |
196 | ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding"); |
f26d5c33 |
197 | } |
198 | |
199 | return 0; |
200 | } |
201 | |
202 | |
203 | /* Add a new forwarding from port -> desthost:destport |
6ee9b735 |
204 | sets up a listener on the local machine on (srcaddr:)port |
f26d5c33 |
205 | */ |
6ee9b735 |
206 | char *pfd_addforward(char *desthost, int destport, char *srcaddr, int port, |
207 | void *backhandle) |
f26d5c33 |
208 | { |
209 | static struct plug_function_table fn_table = { |
210 | pfd_closing, |
5471d09a |
211 | pfd_receive, /* should not happen... */ |
212 | pfd_sent, /* also should not happen */ |
f26d5c33 |
213 | pfd_accepting |
214 | }; |
215 | |
216 | char *err; |
217 | struct PFwdPrivate *pr; |
218 | Socket s; |
219 | |
220 | /* |
221 | * Open socket. |
222 | */ |
223 | pr = (struct PFwdPrivate *) smalloc(sizeof(struct PFwdPrivate)); |
224 | pr->fn = &fn_table; |
225 | pr->c = NULL; |
226 | strcpy(pr->hostname, desthost); |
227 | pr->port = destport; |
5471d09a |
228 | pr->throttled = pr->throttle_override = 0; |
f26d5c33 |
229 | pr->ready = 0; |
230 | pr->waiting = NULL; |
6b78788a |
231 | pr->backhandle = backhandle; |
f26d5c33 |
232 | |
6ee9b735 |
233 | pr->s = s = new_listener(srcaddr, port, (Plug) pr, !cfg.lport_acceptall); |
808c3834 |
234 | if ((err = sk_socket_error(s)) != NULL) { |
f26d5c33 |
235 | sfree(pr); |
236 | return err; |
237 | } |
238 | |
239 | sk_set_private_ptr(s, pr); |
240 | |
241 | return NULL; |
242 | } |
243 | |
244 | void pfd_close(Socket s) |
245 | { |
246 | struct PFwdPrivate *pr; |
247 | |
248 | if (!s) |
249 | return; |
250 | |
251 | pr = (struct PFwdPrivate *) sk_get_private_ptr(s); |
252 | |
253 | sfree(pr); |
254 | |
255 | sk_close(s); |
256 | } |
257 | |
5471d09a |
258 | void pfd_unthrottle(Socket s) |
259 | { |
260 | struct PFwdPrivate *pr; |
261 | if (!s) |
262 | return; |
263 | pr = (struct PFwdPrivate *) sk_get_private_ptr(s); |
264 | |
265 | pr->throttled = 0; |
266 | sk_set_frozen(s, pr->throttled || pr->throttle_override); |
267 | } |
268 | |
269 | void pfd_override_throttle(Socket s, int enable) |
270 | { |
271 | struct PFwdPrivate *pr; |
272 | if (!s) |
273 | return; |
274 | pr = (struct PFwdPrivate *) sk_get_private_ptr(s); |
275 | |
276 | pr->throttle_override = enable; |
277 | sk_set_frozen(s, pr->throttled || pr->throttle_override); |
278 | } |
279 | |
f26d5c33 |
280 | /* |
281 | * Called to send data down the raw connection. |
282 | */ |
5471d09a |
283 | int pfd_send(Socket s, char *data, int len) |
f26d5c33 |
284 | { |
f26d5c33 |
285 | if (s == NULL) |
5471d09a |
286 | return 0; |
287 | return sk_write(s, data, len); |
f26d5c33 |
288 | } |
289 | |
290 | |
291 | void pfd_confirm(Socket s) |
292 | { |
5f2e19fc |
293 | struct PFwdPrivate *pr; |
f26d5c33 |
294 | |
295 | if (s == NULL) |
296 | return; |
297 | |
5f2e19fc |
298 | pr = (struct PFwdPrivate *) sk_get_private_ptr(s); |
f26d5c33 |
299 | pr->ready = 1; |
300 | sk_set_frozen(s, 0); |
301 | sk_write(s, NULL, 0); |
302 | } |