GNUnet 0.21.1
gnunet-helper-vpn.c File Reference

the helper for the VPN service. More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_common.h"
#include "gnunet_protocols.h"
Include dependency graph for gnunet-helper-vpn.c:

Go to the source code of this file.

Data Structures

struct  in6_ifreq
 This is in linux/include/net/ipv6.h, but not always exported... More...
 

Macros

#define DEBUG   GNUNET_NO
 Need 'struct GNUNET_MessageHeader'. More...
 
#define MAX_SIZE   65536
 Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE) More...
 

Functions

static int init_tun (char *dev)
 Creates a tun-interface called dev;. More...
 
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. More...
 
static void set_address4 (const char *dev, const char *address, const char *mask)
 Sets the IPv4-Address given in address on the interface dev. More...
 
static void run (int fd_tun)
 Start forwarding to and from the tunnel. More...
 
int main (int argc, char **argv)
 Open VPN tunnel interface. More...
 

Detailed Description

the helper for the VPN service.

Opens a virtual network-interface, sends data received on the if to stdout, sends data received on stdin to the interface

Author
Philipp Tölke
Christian Grothoff

The following list of people have reviewed this code and considered it safe since the last modification (if you reviewed it, please have your name added to the list):

  • Philipp Tölke

Definition in file gnunet-helper-vpn.c.

Macro Definition Documentation

◆ DEBUG

#define DEBUG   GNUNET_NO

Need 'struct GNUNET_MessageHeader'.

Need VPN message types. Should we print (interesting|debug) messages that can happen during normal operation?

Definition at line 55 of file gnunet-helper-vpn.c.

◆ MAX_SIZE

#define MAX_SIZE   65536

Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)

Definition at line 60 of file gnunet-helper-vpn.c.

Function Documentation

◆ init_tun()

static int init_tun ( char *  dev)
static

Creates a tun-interface called dev;.

Parameters
devis assumed to point to a char[IFNAMSIZ] if *dev == '\0', uses the name supplied by the kernel;
Returns
the fd to the tun or -1 on error

Definition at line 85 of file gnunet-helper-vpn.c.

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}

Referenced by main().

Here is the caller graph for this function:

◆ set_address6()

static void set_address6 ( const char *  dev,
const char *  address,
unsigned long  prefix_len 
)
static

Sets the IPv6-Address given in address on the interface dev.

Parameters
devthe interface to configure
addressthe IPv6-Address
prefix_lenthe length of the network-prefix

Definition at line 146 of file gnunet-helper-vpn.c.

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}
static char * address
GNS address for this phone.
This is in linux/include/net/ipv6.h, but not always exported...

References address, in6_ifreq::ifr6_addr, in6_ifreq::ifr6_ifindex, and in6_ifreq::ifr6_prefixlen.

Referenced by main().

Here is the caller graph for this function:

◆ set_address4()

static void set_address4 ( const char *  dev,
const char *  address,
const char *  mask 
)
static

Sets the IPv4-Address given in address on the interface dev.

Parameters
devthe interface to configure
addressthe IPv4-Address
maskthe netmask

Definition at line 265 of file gnunet-helper-vpn.c.

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}

References address.

Referenced by main().

Here is the caller graph for this function:

◆ run()

static void run ( int  fd_tun)
static

Start forwarding to and from the tunnel.

Parameters
fd_tuntunnel FD

Definition at line 385 of file gnunet-helper-vpn.c.

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
402 fd_set fds_w;
403 fd_set fds_r;
404
405 /* read refers to reading from fd_tun, writing to stdout */
406 int read_open = 1;
407
408 /* write refers to reading from stdin, writing to fd_tun */
409 int write_open = 1;
410
411 while ((1 == read_open) && (1 == write_open))
412 {
413 FD_ZERO (&fds_w);
414 FD_ZERO (&fds_r);
415
416 /*
417 * We are supposed to read and the buffer is empty
418 * -> select on read from tun
419 */
420 if (read_open && (0 == buftun_size))
421 FD_SET (fd_tun, &fds_r);
422
423 /*
424 * We are supposed to read and the buffer is not empty
425 * -> select on write to stdout
426 */
427 if (read_open && (0 != buftun_size))
428 FD_SET (1, &fds_w);
429
430 /*
431 * We are supposed to write and the buffer is empty
432 * -> select on read from stdin
433 */
434 if (write_open && (NULL == bufin_read))
435 FD_SET (0, &fds_r);
436
437 /*
438 * We are supposed to write and the buffer is not empty
439 * -> select on write to tun
440 */
441 if (write_open && (NULL != bufin_read))
442 FD_SET (fd_tun, &fds_w);
443
444 int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
445
446 if (-1 == r)
447 {
448 if (EINTR == errno)
449 continue;
450 fprintf (stderr,
451 "select failed: %s\n",
452 strerror (errno));
453 exit (1);
454 }
455
456 if (r > 0)
457 {
458 if (FD_ISSET (fd_tun, &fds_r))
459 {
460 buftun_size =
461 read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
462 MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
463 if (-1 == buftun_size)
464 {
465 fprintf (stderr,
466 "read-error: %s\n",
467 strerror (errno));
468 shutdown (fd_tun, SHUT_RD);
469 shutdown (1, SHUT_WR);
470 read_open = 0;
471 buftun_size = 0;
472 }
473 else if (0 == buftun_size)
474 {
475 fprintf (stderr, "EOF on tun\n");
476 shutdown (fd_tun, SHUT_RD);
477 shutdown (1, SHUT_WR);
478 read_open = 0;
479 buftun_size = 0;
480 }
481 else
482 {
483 buftun_read = buftun;
484 struct GNUNET_MessageHeader *hdr =
485 (struct GNUNET_MessageHeader *) buftun;
486 buftun_size += sizeof(struct GNUNET_MessageHeader);
488 hdr->size = htons (buftun_size);
489 }
490 }
491 else if (FD_ISSET (1, &fds_w))
492 {
493 ssize_t written = write (1,
494 buftun_read,
495 buftun_size);
496
497 if (-1 == written)
498 {
499#if ! DEBUG
500 if (errno != EPIPE)
501#endif
502 fprintf (stderr,
503 "write-error to stdout: %s\n",
504 strerror (errno));
505 shutdown (fd_tun, SHUT_RD);
506 shutdown (1, SHUT_WR);
507 read_open = 0;
508 buftun_size = 0;
509 }
510 else if (0 == written)
511 {
512 fprintf (stderr,
513 "write returned 0!?\n");
514 exit (1);
515 }
516 else
517 {
518 buftun_size -= written;
519 buftun_read += written;
520 }
521 }
522
523 if (FD_ISSET (0, &fds_r))
524 {
525 bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
526 if (-1 == bufin_size)
527 {
528 fprintf (stderr,
529 "read-error: %s\n",
530 strerror (errno));
531 shutdown (0, SHUT_RD);
532 shutdown (fd_tun, SHUT_WR);
533 write_open = 0;
534 bufin_size = 0;
535 }
536 else if (0 == bufin_size)
537 {
538#if DEBUG
539 fprintf (stderr, "EOF on stdin\n");
540#endif
541 shutdown (0, SHUT_RD);
542 shutdown (fd_tun, SHUT_WR);
543 write_open = 0;
544 bufin_size = 0;
545 }
546 else
547 {
548 struct GNUNET_MessageHeader *hdr;
549
550PROCESS_BUFFER:
551 bufin_rpos += bufin_size;
552 if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
553 continue;
554 hdr = (struct GNUNET_MessageHeader *) bufin;
555 if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
556 {
557 fprintf (stderr,
558 "protocol violation!\n");
559 exit (1);
560 }
561 if (ntohs (hdr->size) > bufin_rpos)
562 continue;
563 bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
564 bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader);
565 bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
566 }
567 }
568 else if (FD_ISSET (fd_tun, &fds_w))
569 {
570 ssize_t written = write (fd_tun,
571 bufin_read,
572 bufin_size);
573
574 if (-1 == written)
575 {
576 fprintf (stderr,
577 "write-error to tun: %s\n",
578 strerror (errno));
579 shutdown (0, SHUT_RD);
580 shutdown (fd_tun, SHUT_WR);
581 write_open = 0;
582 bufin_size = 0;
583 }
584 else if (0 == written)
585 {
586 fprintf (stderr, "write returned 0!?\n");
587 exit (1);
588 }
589 else
590 {
591 bufin_size -= written;
592 bufin_read += written;
593 if (0 == bufin_size)
594 {
595 memmove (bufin, bufin_read, bufin_rpos);
596 bufin_read = NULL; /* start reading again */
597 bufin_size = 0;
598 goto PROCESS_BUFFER;
599 }
600 }
601 }
602 }
603 }
604}
#define MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
#define GNUNET_MESSAGE_TYPE_VPN_HELPER
Type of messages between the gnunet-vpn-helper and the daemon.
Header for all communications.
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.

References GNUNET_MESSAGE_TYPE_VPN_HELPER, MAX_SIZE, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by main().

Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Open VPN tunnel interface.

Parameters
argcmust be 6
argv0: binary name (gnunet-helper-vpn) 1: tunnel interface name (gnunet-vpn) 2: IPv6 address (::1), "-" to disable 3: IPv6 netmask length in bits (64), ignored if #2 is "-" 4: IPv4 address (1.2.3.4), "-" to disable 5: IPv4 netmask (255.255.0.0), ignored if #4 is "-"

Definition at line 619 of file gnunet-helper-vpn.c.

620{
621 char dev[IFNAMSIZ];
622 int fd_tun;
623 int global_ret;
624
625 if (6 != argc)
626 {
627 fprintf (stderr, "Fatal: must supply 5 arguments!\n");
628 return 1;
629 }
630
631 strncpy (dev,
632 argv[1],
633 IFNAMSIZ);
634 dev[IFNAMSIZ - 1] = '\0';
635
636 if (-1 == (fd_tun = init_tun (dev)))
637 {
638 fprintf (stderr,
639 "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
640 dev,
641 argv[2],
642 argv[3],
643 argv[4],
644 argv[5]);
645 return 1;
646 }
647
648 if (0 != strcmp (argv[2], "-"))
649 {
650 const char *address = argv[2];
651 long prefix_len = atol (argv[3]);
652
653 if ((prefix_len < 1) || (prefix_len > 127))
654 {
655 fprintf (stderr,
656 "Fatal: prefix_len out of range\n");
657 (void) close (fd_tun);
658 return 1;
659 }
660
661 set_address6 (dev,
662 address,
663 prefix_len);
664 }
665
666 if (0 != strcmp (argv[4], "-"))
667 {
668 const char *address = argv[4];
669 const char *mask = argv[5];
670
671 set_address4 (dev, address, mask);
672 }
673
674 uid_t uid = getuid ();
675#ifdef HAVE_SETRESUID
676 if (0 != setresuid (uid, uid, uid))
677 {
678 fprintf (stderr,
679 "Failed to setresuid: %s\n",
680 strerror (errno));
681 global_ret = 2;
682 goto cleanup;
683 }
684#else
685 if (0 != (setuid (uid) | seteuid (uid)))
686 {
687 fprintf (stderr,
688 "Failed to setuid: %s\n",
689 strerror (errno));
690 global_ret = 2;
691 goto cleanup;
692 }
693#endif
694
695 if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
696 {
697 fprintf (stderr,
698 "Failed to protect against SIGPIPE: %s\n",
699 strerror (errno));
700 /* no exit, we might as well die with SIGPIPE should it ever happen */
701 }
702 run (fd_tun);
703 global_ret = 0;
704cleanup:
705 (void) close (fd_tun);
706 return global_ret;
707}
static int global_ret
Global status value.
static void cleanup(void *cls)
Disconnect and shutdown.
Definition: gnunet-did.c:131
static void run(int fd_tun)
Start forwarding to and from the tunnel.
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.

References address, cleanup(), global_ret, init_tun(), run(), set_address4(), and set_address6().

Here is the call graph for this function: