aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2012-05-15 21:12:04 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2012-05-15 21:12:04 +0000
commit7a1e0e0da32a6fb1028e361edd64a456fdc43ab8 (patch)
tree5186c38bfa735f51b67ad42d3a9d117a277576d5
parentc014977a343ad2c8008b4eae5c1bf2a074fad34e (diff)
downloadgnunet-7a1e0e0da32a6fb1028e361edd64a456fdc43ab8.tar.gz
gnunet-7a1e0e0da32a6fb1028e361edd64a456fdc43ab8.zip
-new proxy
-rw-r--r--src/gns/gnocksy/gnocksy.c436
1 files changed, 436 insertions, 0 deletions
diff --git a/src/gns/gnocksy/gnocksy.c b/src/gns/gnocksy/gnocksy.c
new file mode 100644
index 000000000..a7b25e30c
--- /dev/null
+++ b/src/gns/gnocksy/gnocksy.c
@@ -0,0 +1,436 @@
1/*
2 * The GNS Socks5 Proxy
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <netinet/in.h>
12#include <sys/epoll.h>
13#include <errno.h>
14#include <fcntl.h>
15#include <netdb.h>
16#include <arpa/inet.h>
17
18#define MAXEVENTS 64
19
20/* The socks phases */
21enum
22{
23 SOCKS5_INIT,
24 SOCKS5_REQUEST,
25 SOCKS5_DATA_TRANSFER
26};
27
28/* Client hello */
29struct socks5_client_hello
30{
31 uint8_t version;
32 uint8_t num_auth_methods;
33 char* auth_methods;
34};
35
36/* Client socks request */
37struct socks5_client_request
38{
39 uint8_t version;
40 uint8_t command;
41 uint8_t resvd;
42 uint8_t addr_type;
43 /*
44 * followed by either an ip4/ipv6 address
45 * or a domain name with a length field in front
46 */
47};
48
49/* Server hello */
50struct socks5_server_hello
51{
52 uint8_t version;
53 uint8_t auth_method;
54};
55
56/* Struct used to store connection
57 * information
58 */
59struct socks5_bridge
60{
61 int fd;
62 struct socks5_bridge* remote_end;
63 int status;
64};
65
66/* Server response to client requests */
67struct socks5_server_response
68{
69 uint8_t version;
70 uint8_t reply;
71 uint8_t reserved;
72 uint8_t addr_type;
73 uint8_t addr_port;
74};
75
76
77/*
78 * Create an ipv4/6 tcp socket for a given port
79 *
80 * @param port the port to bind to
81 * @return the file descriptor of the socket or -1
82 */
83static int
84create_socket (char *port)
85{
86 struct addrinfo hints;
87 struct addrinfo *result, *rp;
88 int s, sfd;
89
90 memset (&hints, 0, sizeof (struct addrinfo));
91 hints.ai_family = AF_UNSPEC;
92 hints.ai_socktype = SOCK_STREAM;
93 hints.ai_flags = AI_PASSIVE;
94
95 s = getaddrinfo (NULL, port, &hints, &result);
96 if (s != 0)
97 {
98 fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));
99 return -1;
100 }
101
102 for (rp = result; rp != NULL; rp = rp->ai_next)
103 {
104 sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
105 if (sfd == -1)
106 continue;
107
108 s = bind (sfd, rp->ai_addr, rp->ai_addrlen);
109 if (s == 0)
110 {
111 break;
112 }
113 close(sfd);
114 }
115
116 if (rp == NULL)
117 {
118 fprintf (stderr, "Could not bind\n");
119 return -1;
120 }
121
122 freeaddrinfo (result);
123
124 return sfd;
125}
126
127
128/*
129 * Make socket with fd non blocking
130 *
131 * @param fd the file descriptor of the socket
132 * @return -1 on error
133 */
134static int
135setnonblocking (int fd)
136{
137 int flags, s;
138
139 flags = fcntl (fd, F_GETFL, 0);
140 if (flags == -1)
141 {
142 perror ("fcntl");
143 return -1;
144 }
145
146 flags |= O_NONBLOCK;
147 s = fcntl (fd, F_SETFL, flags);
148 if (s == -1)
149 {
150 perror ("fcntl");
151 return -1;
152 }
153
154 return 0;
155}
156
157int main ( int argc, char *argv[] )
158{
159 int sfd, s;
160 int efd;
161 struct epoll_event event;
162 struct epoll_event *events;
163 int ev_states[MAXEVENTS];
164 int j;
165 struct socks5_bridge* br;
166
167 for (j = 0; j < MAXEVENTS; j++)
168 ev_states[j] = SOCKS5_INIT;
169
170 if (argc != 2)
171 {
172 fprintf (stderr, "Usage: %s [port]\n", argv[0]);
173 exit (EXIT_FAILURE);
174 }
175
176 sfd = create_socket(argv[1]);
177 if (s == -1)
178 abort ();
179
180 s = setnonblocking (sfd);
181 if (s == -1)
182 abort ();
183
184 s = listen (sfd, SOMAXCONN);
185 if (s == -1)
186 {
187 perror ("listen");
188 abort ();
189 }
190
191 efd = epoll_create1 (0);
192 if (efd == -1)
193 {
194 perror ("epoll create");
195 abort ();
196 }
197
198 br = malloc(sizeof (struct socks5_bridge));
199 event.data.ptr = br;
200 br->fd = sfd;
201 br->remote_end = NULL;
202
203 event.events = EPOLLIN | EPOLLET;
204 s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event);
205 if (s == -1)
206 {
207 perror ("epoll ctl");
208 abort ();
209 }
210
211 events = calloc (MAXEVENTS, sizeof event);
212
213 while (1)
214 {
215 int n, i;
216
217 n = epoll_wait (efd, events, MAXEVENTS, -1);
218 for (i = 0; i < n; i++)
219 {
220 br = (struct socks5_bridge*)(events[i].data.ptr);
221
222 if ((events[i].events & EPOLLERR) ||
223 (events[i].events & EPOLLHUP) ||
224 (!(events[i].events & EPOLLIN)))
225 {
226 fprintf (stderr, "epoll error %d\n", events[i].events);
227 fprintf (stderr, "closing fd %d\n", br->fd);
228 close (br->fd);
229 continue;
230 }
231 else if (sfd == br->fd)
232 {
233 /* New connection(s) */
234 while (1)
235 {
236 struct sockaddr in_addr;
237 socklen_t in_len;
238 int infd;
239 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
240
241 in_len = sizeof (in_addr);
242 infd = accept (sfd, &in_addr, &in_len);
243 if (infd == -1)
244 {
245 if ((errno == EAGAIN) ||
246 (errno == EWOULDBLOCK))
247 {
248 break;
249 }
250 else
251 {
252 perror ("accept");
253 break;
254 }
255 }
256
257 s = getnameinfo (&in_addr, in_len,
258 hbuf, sizeof (hbuf),
259 sbuf, sizeof (sbuf),
260 NI_NUMERICHOST | NI_NUMERICSERV);
261 if (s == -1)
262 abort ();
263
264 s = setnonblocking (infd);
265 if (s == -1)
266 abort ();
267
268 event.events = EPOLLIN | EPOLLET;
269 br = malloc (sizeof (struct socks5_bridge));
270 br->fd = infd;
271 br->remote_end = NULL;
272 br->status = SOCKS5_INIT;
273 event.data.ptr = br;
274
275 s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event);
276 if (s == -1)
277 {
278 perror ("epoll ctl");
279 abort ();
280 }
281 }
282 continue;
283 }
284 else
285 {
286 /* Incoming data */
287 int done = 0;
288
289 while (1)
290 {
291 ssize_t count;
292 char buf[512];
293 struct socks5_server_hello hello;
294 struct socks5_server_response* resp;
295 struct socks5_client_request* req;
296 struct socks5_bridge* new_br;
297 char domain[256];
298 uint8_t msg[16];
299 uint8_t dom_len;
300 uint32_t srv_ip;
301 uint16_t srv_port;
302 struct sockaddr_in srv_addr;
303 int conn_fd;
304 struct hostent *phost;
305 struct in_addr *sin_addr;
306
307 count = read (br->fd, buf, sizeof (buf));
308
309 if (count == -1)
310 {
311 if (errno != EAGAIN)
312 {
313 perror ("read");
314 done = 1;
315 }
316 break;
317 }
318 else if (count == 0)
319 {
320 done = 1;
321 break;
322 }
323
324 if (br->status == SOCKS5_DATA_TRANSFER)
325 {
326 if (br->remote_end)
327 s = write (br->remote_end->fd, buf, count);
328 }
329
330 if (br->status == SOCKS5_INIT)
331 {
332 hello.version = 0x05;
333 hello.auth_method = 0;
334 write (br->fd, &hello, sizeof (hello));
335 br->status = SOCKS5_REQUEST;
336 }
337 if (br->status == SOCKS5_REQUEST)
338 {
339 req = (struct socks5_client_request*)buf;
340
341 memset(msg, 0, sizeof(msg));
342 resp = (struct socks5_server_response*)msg;
343
344 if (req->addr_type == 3)
345 {
346 dom_len = *((uint8_t*)(&(req->addr_type) + 1));
347 memset(domain, 0, sizeof(domain));
348 strncpy(domain, (char*)(&(req->addr_type) + 2), dom_len);
349
350 phost = (struct hostent*)gethostbyname (domain);
351 if (phost == NULL)
352 {
353 printf ("Resolve %s error!\n" , domain );
354 resp->version = 0x05;
355 resp->reply = 0x01;
356 write (br->fd, resp, sizeof (struct socks5_server_response));
357 break;
358 }
359
360 sin_addr = (struct in_addr*)(phost->h_addr);
361 srv_ip = sin_addr->s_addr;
362 srv_port = *((uint16_t*)(&(req->addr_type) + 2 + dom_len));
363 conn_fd = socket(AF_INET, SOCK_STREAM, 0);
364 memset(&srv_addr, 0, sizeof(srv_addr));
365 srv_addr.sin_family = AF_INET;
366 srv_addr.sin_addr.s_addr = srv_ip;
367 srv_addr.sin_port = srv_port;
368 //printf("target server: %s:%u\n", inet_ntoa(srv_addr.sin_addr),
369 //ntohs(srv_port));
370
371 if (connect (conn_fd, (struct sockaddr*)&srv_addr,
372 sizeof (struct sockaddr)) < 0)
373 {
374 printf("socket request error...\n");
375 resp->version = 0x05;
376 resp->reply = 0x01;
377 close(conn_fd);
378 write (br->fd, resp, 10);
379 }
380 else
381 {
382 setnonblocking(conn_fd);
383 resp->version = 0x05;
384 resp->reply = 0x00;
385 resp->reserved = 0x00;
386 resp->addr_type = 0x01;
387
388 new_br = malloc (sizeof (struct socks5_bridge));
389 br->remote_end = new_br;
390 br->status = SOCKS5_DATA_TRANSFER;
391 new_br->fd = conn_fd;
392 new_br->remote_end = br;
393 new_br->status = SOCKS5_DATA_TRANSFER;
394
395 event.data.ptr = new_br;
396 event.events = EPOLLIN | EPOLLET;
397 epoll_ctl (efd, EPOLL_CTL_ADD, conn_fd, &event);
398 write (br->fd, resp, 10);
399 }
400
401 }
402 else
403 {
404 printf("not implemented address type %02X\n", (int)req->addr_type);
405 }
406 }
407
408
409 if (s == -1)
410 {
411 perror ("write");
412 abort ();
413 }
414 }
415
416 if (done)
417 {
418 close (br->fd);
419
420 if (br->remote_end)
421 {
422 close (br->remote_end->fd);
423 free(br->remote_end);
424 }
425 free(br);
426 }
427 }
428 }
429 }
430
431 free (events);
432
433 close (sfd);
434
435 return EXIT_SUCCESS;
436}