GNUnet 0.22.2
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 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}
#define MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
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.

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 620 of file gnunet-helper-vpn.c.

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 int global_ret
Global status value.
static void cleanup(void *cls)
Disconnect and shutdown.
Definition: gnunet-did.c:130
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: