diff options
author | Martin Schanzenbach <mschanzenbach@posteo.de> | 2012-05-15 21:12:04 +0000 |
---|---|---|
committer | Martin Schanzenbach <mschanzenbach@posteo.de> | 2012-05-15 21:12:04 +0000 |
commit | 7a1e0e0da32a6fb1028e361edd64a456fdc43ab8 (patch) | |
tree | 5186c38bfa735f51b67ad42d3a9d117a277576d5 | |
parent | c014977a343ad2c8008b4eae5c1bf2a074fad34e (diff) | |
download | gnunet-7a1e0e0da32a6fb1028e361edd64a456fdc43ab8.tar.gz gnunet-7a1e0e0da32a6fb1028e361edd64a456fdc43ab8.zip |
-new proxy
-rw-r--r-- | src/gns/gnocksy/gnocksy.c | 436 |
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 */ | ||
21 | enum | ||
22 | { | ||
23 | SOCKS5_INIT, | ||
24 | SOCKS5_REQUEST, | ||
25 | SOCKS5_DATA_TRANSFER | ||
26 | }; | ||
27 | |||
28 | /* Client hello */ | ||
29 | struct socks5_client_hello | ||
30 | { | ||
31 | uint8_t version; | ||
32 | uint8_t num_auth_methods; | ||
33 | char* auth_methods; | ||
34 | }; | ||
35 | |||
36 | /* Client socks request */ | ||
37 | struct 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 */ | ||
50 | struct socks5_server_hello | ||
51 | { | ||
52 | uint8_t version; | ||
53 | uint8_t auth_method; | ||
54 | }; | ||
55 | |||
56 | /* Struct used to store connection | ||
57 | * information | ||
58 | */ | ||
59 | struct socks5_bridge | ||
60 | { | ||
61 | int fd; | ||
62 | struct socks5_bridge* remote_end; | ||
63 | int status; | ||
64 | }; | ||
65 | |||
66 | /* Server response to client requests */ | ||
67 | struct 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 | */ | ||
83 | static int | ||
84 | create_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 | */ | ||
134 | static int | ||
135 | setnonblocking (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 | |||
157 | int 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 | } | ||