]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - portfwd.c
94aec6e153a78aa62fdfcaf45b45db9232d0a0b5
[PuTTY.git] / portfwd.c
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
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 */
63     void *backhandle;                  /* instance of SSH backend itself */
64     /* Note that backhandle need not be filled in if c is non-NULL */
65     Socket s;
66     char hostname[128];
67     int throttled, throttle_override;
68     int port;
69     int ready;
70     struct pfwd_queue *waiting;
71 };
72
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;
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     }
98     return 1;
99 }
100
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
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,
116         pfd_sent,
117         NULL
118     };
119
120     SockAddr addr;
121     char *err, *dummy_realhost;
122     struct PFwdPrivate *pr;
123
124     /*
125      * Try to find host.
126      */
127     addr = name_lookup(hostname, port, &dummy_realhost);
128     if ((err = sk_addr_error(addr)) != NULL)
129         return err;
130
131     /*
132      * Open socket.
133      */
134     pr = (struct PFwdPrivate *) smalloc(sizeof(struct PFwdPrivate));
135     pr->fn = &fn_table;
136     pr->throttled = pr->throttle_override = 0;
137     pr->ready = 1;
138     pr->c = c;
139     pr->backhandle = NULL;             /* we shouldn't need this */
140
141     pr->s = *s = new_connection(addr, dummy_realhost, port, 0, 1, 0, (Plug) pr);
142     if ((err = sk_socket_error(*s)) != NULL) {
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
156 static int pfd_accepting(Plug p, void *sock)
157 {
158     static struct plug_function_table fn_table = {
159         pfd_closing,
160         pfd_receive,
161         pfd_sent,
162         NULL
163     };
164     struct PFwdPrivate *pr, *org;
165     Socket s;
166     char *err;
167
168     org = (struct PFwdPrivate *)p;
169     pr = (struct PFwdPrivate *) smalloc(sizeof(struct PFwdPrivate));
170     pr->fn = &fn_table;
171
172     pr->c = NULL;
173     pr->backhandle = org->backhandle;
174
175     pr->s = s = sk_register(sock, (Plug) pr);
176     if ((err = sk_socket_error(s)) != NULL) {
177         sfree(pr);
178         return err != NULL;
179     }
180
181     pr->c = new_sock_channel(org->backhandle, s);
182
183     strcpy(pr->hostname, org->hostname);
184     pr->port = org->port;
185     pr->throttled = pr->throttle_override = 0;
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 */
196         ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");
197     }
198
199     return 0;
200 }
201
202
203 /* Add a new forwarding from port -> desthost:destport
204  sets up a listener on the local machine on (srcaddr:)port
205  */
206 char *pfd_addforward(char *desthost, int destport, char *srcaddr, int port,
207                      void *backhandle)
208 {
209     static struct plug_function_table fn_table = {
210         pfd_closing,
211         pfd_receive,                   /* should not happen... */
212         pfd_sent,                      /* also should not happen */
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;
228     pr->throttled = pr->throttle_override = 0;
229     pr->ready = 0;
230     pr->waiting = NULL;
231     pr->backhandle = backhandle;
232
233     pr->s = s = new_listener(srcaddr, port, (Plug) pr, !cfg.lport_acceptall);
234     if ((err = sk_socket_error(s)) != NULL) {
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
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
280 /*
281  * Called to send data down the raw connection.
282  */
283 int pfd_send(Socket s, char *data, int len)
284 {
285     if (s == NULL)
286         return 0;
287     return sk_write(s, data, len);
288 }
289
290
291 void pfd_confirm(Socket s)
292 {
293     struct PFwdPrivate *pr;
294
295     if (s == NULL)
296         return;
297
298     pr = (struct PFwdPrivate *) sk_get_private_ptr(s);
299     pr->ready = 1;
300     sk_set_frozen(s, 0);
301     sk_write(s, NULL, 0);
302 }