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