GNUnet 0.22.2
gnunet-helper-vpn.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2012 Christian Grothoff
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
35#include "platform.h"
36#ifdef IF_TUN_HDR
37#include IF_TUN_HDR
38#endif
39
43#include "gnunet_util_lib.h"
44#include "gnunet_common.h"
45
49#include "gnunet_protocols.h"
50
55#define DEBUG GNUNET_NO
56
60#define MAX_SIZE 65536
61
62#if ! defined(__ANDROID__)
63#ifndef _LINUX_IN6_H
67struct in6_ifreq
68{
69 struct in6_addr ifr6_addr;
70 uint32_t ifr6_prefixlen;
71 unsigned int ifr6_ifindex;
72};
73#endif
74#endif
75
76
84static int
85init_tun (char *dev)
86{
87 struct ifreq ifr;
88 int fd;
89
90 if (NULL == dev)
91 {
92 errno = EINVAL;
93 return -1;
94 }
95
96 if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
97 {
98 fprintf (stderr,
99 "Error opening `%s': %s\n",
100 "/dev/net/tun",
101 strerror (errno));
102 return -1;
103 }
104
105 if (fd >= FD_SETSIZE)
106 {
107 fprintf (stderr,
108 "File descriptor to large: %d",
109 fd);
110 (void) close (fd);
111 return -1;
112 }
113
114 memset (&ifr, 0, sizeof(ifr));
115 ifr.ifr_flags = IFF_TUN;
116
117 if ('\0' != *dev)
118 strncpy (ifr.ifr_name,
119 dev,
120 IFNAMSIZ);
121
122 if (-1 == ioctl (fd,
123 TUNSETIFF,
124 (void *) &ifr))
125 {
126 fprintf (stderr,
127 "Error with ioctl on `%s': %s\n",
128 "/dev/net/tun",
129 strerror (errno));
130 (void) close (fd);
131 return -1;
132 }
133 strcpy (dev, ifr.ifr_name);
134 return fd;
135}
136
137
145static void
146set_address6 (const char *dev,
147 const char *address,
148 unsigned long prefix_len)
149{
150 struct ifreq ifr;
151 struct in6_ifreq ifr6;
152 struct sockaddr_in6 sa6;
153 int fd;
154
155 /*
156 * parse the new address
157 */
158 memset (&sa6, 0, sizeof(struct sockaddr_in6));
159 sa6.sin6_family = AF_INET6;
160 if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
161 {
162 fprintf (stderr,
163 "Failed to parse IPv6 address `%s'\n",
164 address);
165 exit (1);
166 }
167
168 if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
169 {
170 fprintf (stderr,
171 "Error creating socket: %s\n",
172 strerror (errno));
173 exit (1);
174 }
175
176 memset (&ifr, 0, sizeof(struct ifreq));
177 /*
178 * Get the index of the if
179 */
180 strncpy (ifr.ifr_name,
181 dev,
182 IFNAMSIZ);
183 if (-1 == ioctl (fd,
184 SIOGIFINDEX,
185 &ifr))
186 {
187 fprintf (stderr,
188 "ioctl failed at %d: %s\n",
189 __LINE__,
190 strerror (errno));
191 (void) close (fd);
192 exit (1);
193 }
194
195 memset (&ifr6, 0, sizeof(struct in6_ifreq));
196 ifr6.ifr6_addr = sa6.sin6_addr;
197 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
198 ifr6.ifr6_prefixlen = prefix_len;
199
200 /*
201 * Set the address
202 */
203 if (-1 == ioctl (fd,
204 SIOCSIFADDR,
205 &ifr6))
206 {
207 fprintf (stderr,
208 "ioctl failed at line %d: %s\n",
209 __LINE__,
210 strerror (errno));
211 (void) close (fd);
212 exit (1);
213 }
214
215 /*
216 * Get the flags
217 */
218 if (-1 == ioctl (fd,
219 SIOCGIFFLAGS,
220 &ifr))
221 {
222 fprintf (stderr,
223 "ioctl failed at line %d: %s\n",
224 __LINE__,
225 strerror (errno));
226 (void) close (fd);
227 exit (1);
228 }
229
230 /*
231 * Add the UP and RUNNING flags
232 */
233 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
234 if (-1 == ioctl (fd,
235 SIOCSIFFLAGS,
236 &ifr))
237 {
238 fprintf (stderr,
239 "ioctl failed at line %d: %s\n",
240 __LINE__,
241 strerror (errno));
242 (void) close (fd);
243 exit (1);
244 }
245
246 if (0 != close (fd))
247 {
248 fprintf (stderr,
249 "close failed at line %d: %s\n",
250 __LINE__,
251 strerror (errno));
252 exit (1);
253 }
254}
255
256
264static void
265set_address4 (const char *dev,
266 const char *address,
267 const char *mask)
268{
269 int fd;
270 struct sockaddr_in *addr;
271 struct ifreq ifr;
272
273 memset (&ifr, 0, sizeof(struct ifreq));
274 addr = (struct sockaddr_in *) &(ifr.ifr_addr);
275 addr->sin_family = AF_INET;
276
277 /*
278 * Parse the address
279 */
280 if (1 != inet_pton (AF_INET,
281 address,
282 &addr->sin_addr.s_addr))
283 {
284 fprintf (stderr,
285 "Failed to parse IPv4 address `%s'\n",
286 address);
287 exit (1);
288 }
289
290 if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
291 {
292 fprintf (stderr,
293 "Error creating socket: %s\n",
294 strerror (errno));
295 exit (1);
296 }
297
298 strncpy (ifr.ifr_name, dev, IFNAMSIZ);
299
300 /*
301 * Set the address
302 */
303 if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
304 {
305 fprintf (stderr,
306 "ioctl failed at %d: %s\n",
307 __LINE__,
308 strerror (errno));
309 (void) close (fd);
310 exit (1);
311 }
312
313 /*
314 * Parse the netmask
315 */
316 addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
317 if (1 != inet_pton (AF_INET,
318 mask,
319 &addr->sin_addr.s_addr))
320 {
321 fprintf (stderr,
322 "Failed to parse IPv4 address mask `%s'\n",
323 mask);
324 (void) close (fd);
325 exit (1);
326 }
327
328 /*
329 * Set the netmask
330 */
331 if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
332 {
333 fprintf (stderr,
334 "ioctl failed at line %d: %s\n",
335 __LINE__,
336 strerror (errno));
337 (void) close (fd);
338 exit (1);
339 }
340
341 /*
342 * Get the flags
343 */
344 if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
345 {
346 fprintf (stderr,
347 "ioctl failed at line %d: %s\n",
348 __LINE__,
349 strerror (errno));
350 (void) close (fd);
351 exit (1);
352 }
353
354 /*
355 * Add the UP and RUNNING flags
356 */
357 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
358 if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
359 {
360 fprintf (stderr,
361 "ioctl failed at line %d: %s\n",
362 __LINE__,
363 strerror (errno));
364 (void) close (fd);
365 exit (1);
366 }
367
368 if (0 != close (fd))
369 {
370 fprintf (stderr,
371 "close failed at line %d: %s\n",
372 __LINE__,
373 strerror (errno));
374 exit (1);
375 }
376}
377
378
384static void
385run (int fd_tun)
386{
387 /*
388 * The buffer filled by reading from fd_tun
389 */
390 unsigned char buftun[MAX_SIZE];
391 ssize_t buftun_size = 0;
392 unsigned char *buftun_read = NULL;
393
394 /*
395 * The buffer filled by reading from stdin
396 */
397 unsigned char bufin[MAX_SIZE];
398 ssize_t bufin_size = 0;
399 size_t bufin_rpos = 0;
400 unsigned char *bufin_read = NULL;
401 int r;
402
403 fd_set fds_w;
404 fd_set fds_r;
405
406 /* read refers to reading from fd_tun, writing to stdout */
407 int read_open = 1;
408
409 /* write refers to reading from stdin, writing to fd_tun */
410 int write_open = 1;
411
412 while ((1 == read_open) && (1 == write_open))
413 {
414 FD_ZERO (&fds_w);
415 FD_ZERO (&fds_r);
416
417 /*
418 * We are supposed to read and the buffer is empty
419 * -> select on read from tun
420 */
421 if (read_open && (0 == buftun_size))
422 FD_SET (fd_tun, &fds_r);
423
424 /*
425 * We are supposed to read and the buffer is not empty
426 * -> select on write to stdout
427 */
428 if (read_open && (0 != buftun_size))
429 FD_SET (1, &fds_w);
430
431 /*
432 * We are supposed to write and the buffer is empty
433 * -> select on read from stdin
434 */
435 if (write_open && (NULL == bufin_read))
436 FD_SET (0, &fds_r);
437
438 /*
439 * We are supposed to write and the buffer is not empty
440 * -> select on write to tun
441 */
442 if (write_open && (NULL != bufin_read))
443 FD_SET (fd_tun, &fds_w);
444
445 r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
446
447 if (-1 == r)
448 {
449 if (EINTR == errno)
450 continue;
451 fprintf (stderr,
452 "select failed: %s\n",
453 strerror (errno));
454 exit (1);
455 }
456
457 if (r > 0)
458 {
459 if (FD_ISSET (fd_tun, &fds_r))
460 {
461 buftun_size =
462 read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
463 MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
464 if (-1 == buftun_size)
465 {
466 fprintf (stderr,
467 "read-error: %s\n",
468 strerror (errno));
469 shutdown (fd_tun, SHUT_RD);
470 shutdown (1, SHUT_WR);
471 read_open = 0;
472 buftun_size = 0;
473 }
474 else if (0 == buftun_size)
475 {
476 fprintf (stderr, "EOF on tun\n");
477 shutdown (fd_tun, SHUT_RD);
478 shutdown (1, SHUT_WR);
479 read_open = 0;
480 buftun_size = 0;
481 }
482 else
483 {
484 struct GNUNET_MessageHeader *hdr =
485 (struct GNUNET_MessageHeader *) buftun;
486 buftun_read = buftun;
487 buftun_size += sizeof(struct GNUNET_MessageHeader);
489 hdr->size = htons (buftun_size);
490 }
491 }
492 else if (FD_ISSET (1, &fds_w))
493 {
494 ssize_t written = write (1,
495 buftun_read,
496 buftun_size);
497
498 if (-1 == written)
499 {
500#if ! DEBUG
501 if (errno != EPIPE)
502#endif
503 fprintf (stderr,
504 "write-error to stdout: %s\n",
505 strerror (errno));
506 shutdown (fd_tun, SHUT_RD);
507 shutdown (1, SHUT_WR);
508 read_open = 0;
509 buftun_size = 0;
510 }
511 else if (0 == written)
512 {
513 fprintf (stderr,
514 "write returned 0!?\n");
515 exit (1);
516 }
517 else
518 {
519 buftun_size -= written;
520 buftun_read += written;
521 }
522 }
523
524 if (FD_ISSET (0, &fds_r))
525 {
526 bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
527 if (-1 == bufin_size)
528 {
529 fprintf (stderr,
530 "read-error: %s\n",
531 strerror (errno));
532 shutdown (0, SHUT_RD);
533 shutdown (fd_tun, SHUT_WR);
534 write_open = 0;
535 bufin_size = 0;
536 }
537 else if (0 == bufin_size)
538 {
539#if DEBUG
540 fprintf (stderr, "EOF on stdin\n");
541#endif
542 shutdown (0, SHUT_RD);
543 shutdown (fd_tun, SHUT_WR);
544 write_open = 0;
545 bufin_size = 0;
546 }
547 else
548 {
549 struct GNUNET_MessageHeader *hdr;
550
551PROCESS_BUFFER:
552 bufin_rpos += bufin_size;
553 if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
554 continue;
555 hdr = (struct GNUNET_MessageHeader *) bufin;
556 if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
557 {
558 fprintf (stderr,
559 "protocol violation!\n");
560 exit (1);
561 }
562 if (ntohs (hdr->size) > bufin_rpos)
563 continue;
564 bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
565 bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader);
566 bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
567 }
568 }
569 else if (FD_ISSET (fd_tun, &fds_w))
570 {
571 ssize_t written = write (fd_tun,
572 bufin_read,
573 bufin_size);
574
575 if (-1 == written)
576 {
577 fprintf (stderr,
578 "write-error to tun: %s\n",
579 strerror (errno));
580 shutdown (0, SHUT_RD);
581 shutdown (fd_tun, SHUT_WR);
582 write_open = 0;
583 bufin_size = 0;
584 }
585 else if (0 == written)
586 {
587 fprintf (stderr, "write returned 0!?\n");
588 exit (1);
589 }
590 else
591 {
592 bufin_size -= written;
593 bufin_read += written;
594 if (0 == bufin_size)
595 {
596 memmove (bufin, bufin_read, bufin_rpos);
597 bufin_read = NULL; /* start reading again */
598 bufin_size = 0;
599 goto PROCESS_BUFFER;
600 }
601 }
602 }
603 }
604 }
605}
606
607
619int
620main (int argc, char **argv)
621{
622 char dev[IFNAMSIZ];
623 int fd_tun;
624 int global_ret;
625
626 if (6 != argc)
627 {
628 fprintf (stderr, "Fatal: must supply 5 arguments!\n");
629 return 1;
630 }
631
632 strncpy (dev,
633 argv[1],
634 IFNAMSIZ);
635 dev[IFNAMSIZ - 1] = '\0';
636
637 if (-1 == (fd_tun = init_tun (dev)))
638 {
639 fprintf (stderr,
640 "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
641 dev,
642 argv[2],
643 argv[3],
644 argv[4],
645 argv[5]);
646 return 1;
647 }
648
649 if (0 != strcmp (argv[2], "-"))
650 {
651 const char *address = argv[2];
652 long prefix_len = atol (argv[3]);
653
654 if ((prefix_len < 1) || (prefix_len > 127))
655 {
656 fprintf (stderr,
657 "Fatal: prefix_len out of range\n");
658 (void) close (fd_tun);
659 return 1;
660 }
661
662 set_address6 (dev,
663 address,
664 prefix_len);
665 }
666
667 if (0 != strcmp (argv[4], "-"))
668 {
669 const char *address = argv[4];
670 const char *mask = argv[5];
671
672 set_address4 (dev, address, mask);
673 }
674
675#ifdef HAVE_SETRESUID
676 {
677 uid_t uid = getuid ();
678 if (0 != setresuid (uid, uid, uid))
679 {
680 fprintf (stderr,
681 "Failed to setresuid: %s\n",
682 strerror (errno));
683 global_ret = 2;
684 goto cleanup;
685 }
686 }
687#else
688 if (0 != (setuid (uid) | seteuid (uid)))
689 {
690 fprintf (stderr,
691 "Failed to setuid: %s\n",
692 strerror (errno));
693 global_ret = 2;
694 goto cleanup;
695 }
696#endif
697
698 if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
699 {
700 fprintf (stderr,
701 "Failed to protect against SIGPIPE: %s\n",
702 strerror (errno));
703 /* no exit, we might as well die with SIGPIPE should it ever happen */
704 }
705 run (fd_tun);
706 global_ret = 0;
707cleanup:
708 (void) close (fd_tun);
709 return global_ret;
710}
static char * address
GNS address for this phone.
static int global_ret
Global status value.
static void cleanup(void *cls)
Disconnect and shutdown.
Definition: gnunet-did.c:130
#define MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
static void run(int fd_tun)
Start forwarding to and from the tunnel.
int main(int argc, char **argv)
Open VPN tunnel interface.
static int init_tun(char *dev)
Creates a tun-interface called dev;.
static void set_address4(const char *dev, const char *address, const char *mask)
Sets the IPv4-Address given in address on the interface dev.
static void set_address6(const char *dev, const char *address, unsigned long prefix_len)
Sets the IPv6-Address given in address on the interface dev.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
Constants for network protocols.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
#define GNUNET_MESSAGE_TYPE_VPN_HELPER
Type of messages between the gnunet-vpn-helper and the daemon.
Header for all communications.
This is in linux/include/net/ipv6.h, but not always exported...
uint32_t ifr6_prefixlen
struct in6_addr ifr6_addr
unsigned int ifr6_ifindex