GNUnet  0.20.0
gnunet-helper-exit.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010, 2011, 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 
44 #include "platform.h"
45 
46 #ifdef IF_TUN_HDR
47 #include IF_TUN_HDR
48 #endif
49 
50 #if defined(BSD) || defined(SOLARIS)
51 #define ifr_netmask ifr_ifru.ifru_addr
52 #define SIOGIFINDEX SIOCGIFINDEX
53 #endif
54 
58 #include "gnunet_util_lib.h"
59 #include "gnunet_common.h"
60 
64 #include "gnunet_protocols.h"
65 
70 #define DEBUG GNUNET_NO
71 
75 #define MAX_SIZE 65536
76 
80 static const char *sbin_sysctl;
81 
85 static const char *sbin_iptables;
86 
87 
88 #if ! defined(__ANDROID__)
89 #if ! defined(_LINUX_IN6_H) && defined(__linux__)
93 struct in6_ifreq
94 {
95  struct in6_addr ifr6_addr;
96  uint32_t ifr6_prefixlen; /* __u32 in the original */
97  int ifr6_ifindex;
98 };
99 #endif
100 #endif
101 
102 
110 static void
111 open_dev_null (int target_fd,
112  int flags)
113 {
114  int fd;
115 
116  fd = open ("/dev/null", flags);
117  if (-1 == fd)
118  abort ();
119  if (fd == target_fd)
120  return;
121  if (-1 == dup2 (fd, target_fd))
122  {
123  (void) close (fd);
124  abort ();
125  }
126  (void) close (fd);
127 }
128 
129 
137 static int
138 fork_and_exec (const char *file,
139  char *const cmd[])
140 {
141  int status;
142  pid_t pid;
143  pid_t ret;
144 
145  pid = fork ();
146  if (-1 == pid)
147  {
148  fprintf (stderr,
149  "fork failed: %s\n",
150  strerror (errno));
151  return 1;
152  }
153  if (0 == pid)
154  {
155  /* we are the child process */
156  /* close stdin/stdout to not cause interference
157  with the helper's main protocol! */
158  (void) close (0);
159  open_dev_null (0, O_RDONLY);
160  (void) close (1);
161  open_dev_null (1, O_WRONLY);
162  (void) execv (file, cmd);
163  /* can only get here on error */
164  fprintf (stderr,
165  "exec `%s' failed: %s\n",
166  file,
167  strerror (errno));
168  _exit (1);
169  }
170  /* keep running waitpid as long as the only error we get is 'EINTR' */
171  while ((-1 == (ret = waitpid (pid, &status, 0))) &&
172  (errno == EINTR))
173  ;
174  if (-1 == ret)
175  {
176  fprintf (stderr,
177  "waitpid failed: %s\n",
178  strerror (errno));
179  return 1;
180  }
181  if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
182  return 1;
183  /* child process completed and returned success, we're happy */
184  return 0;
185 }
186 
187 
195 #ifdef IFF_TUN /* LINUX */
196 static int
197 init_tun (char *dev)
198 {
199  struct ifreq ifr;
200  int fd;
201 
202  if (NULL == dev)
203  {
204  errno = EINVAL;
205  return -1;
206  }
207 
208  if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
209  {
210  fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun",
211  strerror (errno));
212  return -1;
213  }
214 
215  if (fd >= FD_SETSIZE)
216  {
217  fprintf (stderr, "File descriptor to large: %d", fd);
218  (void) close (fd);
219  return -1;
220  }
221 
222  memset (&ifr, 0, sizeof(ifr));
223  ifr.ifr_flags = IFF_TUN;
224 
225  if ('\0' != *dev)
226  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
227 
228  if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr))
229  {
230  fprintf (stderr,
231  "Error with ioctl on `%s': %s\n", "/dev/net/tun",
232  strerror (errno));
233  (void) close (fd);
234  return -1;
235  }
236  strcpy (dev, ifr.ifr_name);
237  return fd;
238 }
239 
240 
241 #else /* BSD et al, including DARWIN */
242 
243 #ifdef SIOCIFCREATE
244 static int
245 init_tun (char *dev)
246 {
247  int fd;
248  int s;
249  struct ifreq ifr;
250 
251  fd = open (dev, O_RDWR);
252  if (fd == -1)
253  {
254  s = socket (AF_INET, SOCK_DGRAM, 0);
255  if (s < 0)
256  return -1;
257  memset (&ifr, 0, sizeof(ifr));
258  strncpy (ifr.ifr_name, dev + 5, sizeof(ifr.ifr_name) - 1);
259  if (! ioctl (s, SIOCIFCREATE, &ifr))
260  fd = open (dev, O_RDWR);
261  close (s);
262  }
263  return fd;
264 }
265 
266 
267 #else
268 #define init_tun(dev) open (dev, O_RDWR)
269 #endif
270 #endif /* !IFF_TUN (BSD) */
271 
279 static void
280 set_address6 (const char *dev, const char *address, unsigned long prefix_len)
281 {
282  struct ifreq ifr;
283  struct sockaddr_in6 sa6;
284  int fd;
285  struct in6_ifreq ifr6;
286 
287  /*
288  * parse the new address
289  */
290  memset (&sa6, 0, sizeof(struct sockaddr_in6));
291  sa6.sin6_family = AF_INET6;
292  if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr))
293  {
294  fprintf (stderr, "Failed to parse address `%s': %s\n", address,
295  strerror (errno));
296  exit (1);
297  }
298 
299  if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
300  {
301  fprintf (stderr, "Error creating socket: %s\n", strerror (errno));
302  exit (1);
303  }
304 
305  memset (&ifr, 0, sizeof(struct ifreq));
306  /*
307  * Get the index of the if
308  */
309  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
310  if (-1 == ioctl (fd, SIOGIFINDEX, &ifr))
311  {
312  fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno));
313  (void) close (fd);
314  exit (1);
315  }
316 
317  memset (&ifr6, 0, sizeof(struct in6_ifreq));
318  ifr6.ifr6_addr = sa6.sin6_addr;
319  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
320  ifr6.ifr6_prefixlen = prefix_len;
321 
322  /*
323  * Set the address
324  */
325  if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6))
326  {
327  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
328  strerror (errno));
329  (void) close (fd);
330  exit (1);
331  }
332 
333  /*
334  * Get the flags
335  */
336  if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
337  {
338  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
339  strerror (errno));
340  (void) close (fd);
341  exit (1);
342  }
343 
344  /*
345  * Add the UP and RUNNING flags
346  */
347  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
348  if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
349  {
350  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
351  strerror (errno));
352  (void) close (fd);
353  exit (1);
354  }
355 
356  if (0 != close (fd))
357  {
358  fprintf (stderr, "close failed: %s\n", strerror (errno));
359  exit (1);
360  }
361 }
362 
363 
371 static void
372 set_address4 (const char *dev, const char *address, const char *mask)
373 {
374  int fd;
375  struct sockaddr_in *addr;
376  struct ifreq ifr;
377 
378  memset (&ifr, 0, sizeof(struct ifreq));
379  addr = (struct sockaddr_in *) &(ifr.ifr_addr);
380  addr->sin_family = AF_INET;
381 
382  /*
383  * Parse the address
384  */
385  if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr))
386  {
387  fprintf (stderr, "Failed to parse address `%s': %s\n", address,
388  strerror (errno));
389  exit (1);
390  }
391 
392  if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
393  {
394  fprintf (stderr, "Error creating socket: %s\n", strerror (errno));
395  exit (1);
396  }
397 
398  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
399 
400  /*
401  * Set the address
402  */
403  if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
404  {
405  fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno));
406  (void) close (fd);
407  exit (1);
408  }
409 
410  /*
411  * Parse the netmask
412  */
413  addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
414  if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr))
415  {
416  fprintf (stderr, "Failed to parse address `%s': %s\n", mask,
417  strerror (errno));
418  (void) close (fd);
419  exit (1);
420  }
421 
422  /*
423  * Set the netmask
424  */
425  if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
426  {
427  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
428  strerror (errno));
429  (void) close (fd);
430  exit (1);
431  }
432 
433  /*
434  * Get the flags
435  */
436  if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
437  {
438  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
439  strerror (errno));
440  (void) close (fd);
441  exit (1);
442  }
443 
444  /*
445  * Add the UP and RUNNING flags
446  */
447  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
448  if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
449  {
450  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
451  strerror (errno));
452  (void) close (fd);
453  exit (1);
454  }
455 
456  if (0 != close (fd))
457  {
458  fprintf (stderr, "close failed: %s\n", strerror (errno));
459  (void) close (fd);
460  exit (1);
461  }
462 }
463 
464 
470 static void
471 run (int fd_tun)
472 {
473  /*
474  * The buffer filled by reading from fd_tun
475  */
476  unsigned char buftun[MAX_SIZE];
477  ssize_t buftun_size = 0;
478  unsigned char *buftun_read = NULL;
479 
480  /*
481  * The buffer filled by reading from stdin
482  */
483  unsigned char bufin[MAX_SIZE];
484  ssize_t bufin_size = 0;
485  size_t bufin_rpos = 0;
486  unsigned char *bufin_read = NULL;
487 
488  fd_set fds_w;
489  fd_set fds_r;
490 
491  /* read refers to reading from fd_tun, writing to stdout */
492  int read_open = 1;
493 
494  /* write refers to reading from stdin, writing to fd_tun */
495  int write_open = 1;
496 
497  while ((1 == read_open) && (1 == write_open))
498  {
499  FD_ZERO (&fds_w);
500  FD_ZERO (&fds_r);
501 
502  /*
503  * We are supposed to read and the buffer is empty
504  * -> select on read from tun
505  */
506  if (read_open && (0 == buftun_size))
507  FD_SET (fd_tun, &fds_r);
508 
509  /*
510  * We are supposed to read and the buffer is not empty
511  * -> select on write to stdout
512  */
513  if (read_open && (0 != buftun_size))
514  FD_SET (1, &fds_w);
515 
516  /*
517  * We are supposed to write and the buffer is empty
518  * -> select on read from stdin
519  */
520  if (write_open && (NULL == bufin_read))
521  FD_SET (0, &fds_r);
522 
523  /*
524  * We are supposed to write and the buffer is not empty
525  * -> select on write to tun
526  */
527  if (write_open && (NULL != bufin_read))
528  FD_SET (fd_tun, &fds_w);
529 
530  int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
531 
532  if (-1 == r)
533  {
534  if (EINTR == errno)
535  continue;
536  fprintf (stderr, "select failed: %s\n", strerror (errno));
537  exit (1);
538  }
539 
540  if (r > 0)
541  {
542  if (FD_ISSET (fd_tun, &fds_r))
543  {
544  buftun_size =
545  read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
546  MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
547  if (-1 == buftun_size)
548  {
549  fprintf (stderr,
550  "read-error: %s\n",
551  strerror (errno));
552  shutdown (fd_tun, SHUT_RD);
553  shutdown (1, SHUT_WR);
554  read_open = 0;
555  buftun_size = 0;
556  }
557  else if (0 == buftun_size)
558  {
559 #if DEBUG
560  fprintf (stderr, "EOF on tun\n");
561 #endif
562  shutdown (fd_tun, SHUT_RD);
563  shutdown (1, SHUT_WR);
564  read_open = 0;
565  buftun_size = 0;
566  }
567  else
568  {
569  buftun_read = buftun;
570  struct GNUNET_MessageHeader *hdr =
571  (struct GNUNET_MessageHeader *) buftun;
572  buftun_size += sizeof(struct GNUNET_MessageHeader);
573  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
574  hdr->size = htons (buftun_size);
575  }
576  }
577  else if (FD_ISSET (1, &fds_w))
578  {
579  ssize_t written = write (1, buftun_read, buftun_size);
580 
581  if (-1 == written)
582  {
583 #if ! DEBUG
584  if (errno != EPIPE)
585 #endif
586  fprintf (stderr,
587  "write-error to stdout: %s\n",
588  strerror (errno));
589  shutdown (fd_tun, SHUT_RD);
590  shutdown (1, SHUT_WR);
591  read_open = 0;
592  buftun_size = 0;
593  }
594  else if (0 == written)
595  {
596  fprintf (stderr, "write returned 0!?\n");
597  exit (1);
598  }
599  else
600  {
601  buftun_size -= written;
602  buftun_read += written;
603  }
604  }
605 
606  if (FD_ISSET (0, &fds_r))
607  {
608  bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
609  if (-1 == bufin_size)
610  {
611  fprintf (stderr, "read-error: %s\n", strerror (errno));
612  shutdown (0, SHUT_RD);
613  shutdown (fd_tun, SHUT_WR);
614  write_open = 0;
615  bufin_size = 0;
616  }
617  else if (0 == bufin_size)
618  {
619 #if DEBUG
620  fprintf (stderr, "EOF on stdin\n");
621 #endif
622  shutdown (0, SHUT_RD);
623  shutdown (fd_tun, SHUT_WR);
624  write_open = 0;
625  bufin_size = 0;
626  }
627  else
628  {
629  struct GNUNET_MessageHeader *hdr;
630 
631 PROCESS_BUFFER:
632  bufin_rpos += bufin_size;
633  if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
634  continue;
635  hdr = (struct GNUNET_MessageHeader *) bufin;
636  if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
637  {
638  fprintf (stderr, "protocol violation!\n");
639  exit (1);
640  }
641  if (ntohs (hdr->size) > bufin_rpos)
642  continue;
643  bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
644  bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader);
645  bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
646  }
647  }
648  else if (FD_ISSET (fd_tun, &fds_w))
649  {
650  ssize_t written = write (fd_tun, bufin_read, bufin_size);
651 
652  if (-1 == written)
653  {
654  fprintf (stderr, "write-error to tun: %s\n", strerror (errno));
655  shutdown (0, SHUT_RD);
656  shutdown (fd_tun, SHUT_WR);
657  write_open = 0;
658  bufin_size = 0;
659  }
660  else if (0 == written)
661  {
662  fprintf (stderr, "write returned 0!?\n");
663  exit (1);
664  }
665  else
666  {
667  bufin_size -= written;
668  bufin_read += written;
669  if (0 == bufin_size)
670  {
671  memmove (bufin, bufin_read, bufin_rpos);
672  bufin_read = NULL; /* start reading again */
673  bufin_size = 0;
674  goto PROCESS_BUFFER;
675  }
676  }
677  }
678  }
679  }
680 }
681 
682 
696 int
697 main (int argc, char **argv)
698 {
699  char dev[IFNAMSIZ];
700  int fd_tun;
701  int global_ret;
702 
703  if (7 != argc)
704  {
705  fprintf (stderr, "Fatal: must supply 6 arguments!\n");
706  return 1;
707  }
708  if ((0 == strcmp (argv[3], "-")) &&
709  (0 == strcmp (argv[5], "-")))
710  {
711  fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n");
712  return 1;
713  }
714  if (0 != strcmp (argv[2], "-"))
715  {
716 #ifdef IPTABLES
717  if (0 == access (IPTABLES, X_OK))
718  sbin_iptables = IPTABLES;
719  else
720 #endif
721  if (0 == access ("/sbin/iptables", X_OK))
722  sbin_iptables = "/sbin/iptables";
723  else if (0 == access ("/usr/sbin/iptables", X_OK))
724  sbin_iptables = "/usr/sbin/iptables";
725  else
726  {
727  fprintf (stderr,
728  "Fatal: executable iptables not found in approved directories: %s\n",
729  strerror (errno));
730  return 1;
731  }
732 #ifdef SYSCTL
733  if (0 == access (SYSCTL, X_OK))
734  sbin_sysctl = SYSCTL;
735  else
736 #endif
737  if (0 == access ("/sbin/sysctl", X_OK))
738  sbin_sysctl = "/sbin/sysctl";
739  else if (0 == access ("/usr/sbin/sysctl", X_OK))
740  sbin_sysctl = "/usr/sbin/sysctl";
741  else
742  {
743  fprintf (stderr,
744  "Fatal: executable sysctl not found in approved directories: %s\n",
745  strerror (errno));
746  return 1;
747  }
748  }
749 
750  strncpy (dev, argv[1], IFNAMSIZ);
751  dev[IFNAMSIZ - 1] = '\0';
752 
753  if (-1 == (fd_tun = init_tun (dev)))
754  {
755  fprintf (stderr,
756  "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
757  dev,
758  argv[3],
759  argv[4],
760  argv[5],
761  argv[6]);
762  return 1;
763  }
764 
765  if (0 != strcmp (argv[3], "-"))
766  {
767  {
768  const char *address = argv[3];
769  long prefix_len = atol (argv[4]);
770 
771  if ((prefix_len < 1) || (prefix_len > 127))
772  {
773  fprintf (stderr, "Fatal: prefix_len out of range\n");
774  return 1;
775  }
776  set_address6 (dev, address, prefix_len);
777  }
778  if (0 != strcmp (argv[2], "-"))
779  {
780  char *const sysctl_args[] = {
781  "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL
782  };
783  if (0 != fork_and_exec (sbin_sysctl,
784  sysctl_args))
785  {
786  fprintf (stderr,
787  "Failed to enable IPv6 forwarding. Will continue anyway.\n");
788  }
789  }
790  }
791 
792  if (0 != strcmp (argv[5], "-"))
793  {
794  {
795  const char *address = argv[5];
796  const char *mask = argv[6];
797 
798  set_address4 (dev, address, mask);
799  }
800  if (0 != strcmp (argv[2], "-"))
801  {
802  {
803  char *const sysctl_args[] = {
804  "sysctl", "-w", "net.ipv4.ip_forward=1", NULL
805  };
806  if (0 != fork_and_exec (sbin_sysctl,
807  sysctl_args))
808  {
809  fprintf (stderr,
810  "Failed to enable IPv4 forwarding. Will continue anyway.\n");
811  }
812  }
813  {
814  char *const iptables_args[] = {
815  "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j",
816  "MASQUERADE", NULL
817  };
818  if (0 != fork_and_exec (sbin_iptables,
819  iptables_args))
820  {
821  fprintf (stderr,
822  "Failed to enable IPv4 masquerading (NAT). Will continue anyway.\n");
823  }
824  }
825  }
826  }
827 
828  uid_t uid = getuid ();
829 #ifdef HAVE_SETRESUID
830  if (0 != setresuid (uid, uid, uid))
831  {
832  fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
833  global_ret = 2;
834  goto cleanup;
835  }
836 #else
837  if (0 != (setuid (uid) | seteuid (uid)))
838  {
839  fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
840  global_ret = 2;
841  goto cleanup;
842  }
843 #endif
844 
845  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
846  {
847  fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
848  strerror (errno));
849  /* no exit, we might as well die with SIGPIPE should it ever happen */
850  }
851  run (fd_tun);
852  global_ret = 0;
853 cleanup:
854  (void) close (fd_tun);
855  return global_ret;
856 }
857 
858 
859 /* end of gnunet-helper-exit.c */
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static char * address
GNS address for this phone.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
#define MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
static const char * sbin_sysctl
Path to 'sysctl' binary.
static void run(int fd_tun)
Start forwarding to and from the tunnel.
static int fork_and_exec(const char *file, char *const cmd[])
Run the given command and wait for it to complete.
int main(int argc, char **argv)
Open VPN tunnel interface.
static const char * sbin_iptables
Path to 'iptables' binary.
static void open_dev_null(int target_fd, int flags)
Open '/dev/null' and make the result the given file descriptor.
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.
#define init_tun(dev)
Creates a tun-interface called dev;.
uint16_t status
See PRISM_STATUS_*-constants.
static int global_ret
Return value from main.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
Constants for network protocols.
#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.
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