GNUnet  0.10.x
gnunet-helper-dns.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 
66 #include "platform.h"
67 
68 #include <linux/if_tun.h>
69 
73 #include "gnunet_crypto_lib.h"
74 #include "gnunet_common.h"
75 
79 #include "gnunet_protocols.h"
80 
84 #define MAX_SIZE 65536
85 
86 #if !HAVE_DECL_STRUCT_IN6_IFREQ
87 
90 struct in6_ifreq
91 {
92  struct in6_addr ifr6_addr;
93  uint32_t ifr6_prefixlen;
94  unsigned int ifr6_ifindex;
95 };
96 #endif
97 
101 static const char *sbin_iptables;
102 
106 static const char *sbin_ip6tables;
107 
111 static const char *sbin_sysctl;
112 
116 static const char *sbin_ip;
117 
121 #define DNS_PORT "53"
122 
129 #define DNS_MARK "136708149"
130 
138 #define DNS_TABLE "53"
139 
140 
145 static int cpipe[2];
146 
147 
154 static void
155 signal_handler (int signal)
156 {
157  /* ignore return value, as the signal handler could theoretically
158  be called many times before the shutdown can actually happen */
159  (void) write (cpipe[1], "K", 1);
160 }
161 
162 
170 static void
171 open_dev_null (int target_fd,
172  int flags)
173 {
174  int fd;
175 
176  fd = open ("/dev/null", flags);
177  if (-1 == fd)
178  abort ();
179  if (fd == target_fd)
180  return;
181  if (-1 == dup2 (fd, target_fd))
182  {
183  (void) close (fd);
184  abort ();
185  }
186  (void) close (fd);
187 }
188 
189 
197 static int
198 fork_and_exec (const char *file,
199  char *const cmd[])
200 {
201  int status;
202  pid_t pid;
203  pid_t ret;
204 
205  pid = fork ();
206  if (-1 == pid)
207  {
208  fprintf (stderr,
209  "fork failed: %s\n",
210  strerror (errno));
211  return 1;
212  }
213  if (0 == pid)
214  {
215  /* we are the child process */
216  /* close stdin/stdout to not cause interference
217  with the helper's main protocol! */
218  (void) close (0);
219  open_dev_null (0, O_RDONLY);
220  (void) close (1);
221  open_dev_null (1, O_WRONLY);
222  (void) execv (file, cmd);
223  /* can only get here on error */
224  fprintf (stderr,
225  "exec `%s' failed: %s\n",
226  file,
227  strerror (errno));
228  _exit (1);
229  }
230  /* keep running waitpid as long as the only error we get is 'EINTR' */
231  while ( (-1 == (ret = waitpid (pid, &status, 0))) &&
232  (errno == EINTR) );
233  if (-1 == ret)
234  {
235  fprintf (stderr,
236  "waitpid failed: %s\n",
237  strerror (errno));
238  return 1;
239  }
240  if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
241  return 1;
242  /* child process completed and returned success, we're happy */
243  return 0;
244 }
245 
246 
254 static int
255 init_tun (char *dev)
256 {
257  struct ifreq ifr;
258  int fd;
259 
260  if (NULL == dev)
261  {
262  errno = EINVAL;
263  return -1;
264  }
265 
266  if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
267  {
268  fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun",
269  strerror (errno));
270  return -1;
271  }
272 
273  if (fd >= FD_SETSIZE)
274  {
275  fprintf (stderr, "File descriptor to large: %d", fd);
276  (void) close (fd);
277  return -1;
278  }
279 
280  memset (&ifr, 0, sizeof (ifr));
281  ifr.ifr_flags = IFF_TUN;
282 
283  if ('\0' != *dev)
284  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
285 
286  if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr))
287  {
288  fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun",
289  strerror (errno));
290  (void) close (fd);
291  return -1;
292  }
293  strcpy (dev, ifr.ifr_name);
294  return fd;
295 }
296 
297 
305 static void
306 set_address6 (const char *dev, const char *address, unsigned long prefix_len)
307 {
308  struct ifreq ifr;
309  struct in6_ifreq ifr6;
310  struct sockaddr_in6 sa6;
311  int fd;
312 
313  /*
314  * parse the new address
315  */
316  memset (&sa6, 0, sizeof (struct sockaddr_in6));
317  sa6.sin6_family = AF_INET6;
318  if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
319  {
320  fprintf (stderr,
321  "Failed to parse IPv6 address `%s': %s\n",
322  address,
323  strerror (errno));
324  exit (1);
325  }
326 
327  if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
328  {
329  fprintf (stderr,
330  "Error creating IPv6 socket: %s (ignored)\n",
331  strerror (errno));
332  /* ignore error, maybe only IPv4 works on this system! */
333  return;
334  }
335 
336  memset (&ifr, 0, sizeof (struct ifreq));
337  /*
338  * Get the index of the if
339  */
340  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
341  if (-1 == ioctl (fd, SIOGIFINDEX, &ifr))
342  {
343  fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno));
344  (void) close (fd);
345  exit (1);
346  }
347 
348  memset (&ifr6, 0, sizeof (struct in6_ifreq));
349  ifr6.ifr6_addr = sa6.sin6_addr;
350  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
351  ifr6.ifr6_prefixlen = prefix_len;
352 
353  /*
354  * Set the address
355  */
356  if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6))
357  {
358  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
359  strerror (errno));
360  (void) close (fd);
361  exit (1);
362  }
363 
364  /*
365  * Get the flags
366  */
367  if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
368  {
369  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
370  strerror (errno));
371  (void) close (fd);
372  exit (1);
373  }
374 
375  /*
376  * Add the UP and RUNNING flags
377  */
378  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
379  if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
380  {
381  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
382  strerror (errno));
383  (void) close (fd);
384  exit (1);
385  }
386 
387  if (0 != close (fd))
388  {
389  fprintf (stderr, "close failed: %s\n", strerror (errno));
390  exit (1);
391  }
392 }
393 
394 
402 static void
403 set_address4 (const char *dev, const char *address, const char *mask)
404 {
405  int fd;
406  struct sockaddr_in *addr;
407  struct ifreq ifr;
408 
409  memset (&ifr, 0, sizeof (struct ifreq));
410  addr = (struct sockaddr_in *) &(ifr.ifr_addr);
411  addr->sin_family = AF_INET;
412 
413  /*
414  * Parse the address
415  */
416  if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr))
417  {
418  fprintf (stderr,
419  "Failed to parse IPv4 address `%s': %s\n",
420  address,
421  strerror (errno));
422  exit (1);
423  }
424 
425  if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
426  {
427  fprintf (stderr,
428  "Error creating IPv4 socket: %s\n",
429  strerror (errno));
430  exit (1);
431  }
432 
433  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
434 
435  /*
436  * Set the address
437  */
438  if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
439  {
440  fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno));
441  (void) close (fd);
442  exit (1);
443  }
444 
445  /*
446  * Parse the netmask
447  */
448  addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
449  if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr))
450  {
451  fprintf (stderr, "Failed to parse address `%s': %s\n", mask,
452  strerror (errno));
453  (void) close (fd);
454  exit (1);
455  }
456 
457  /*
458  * Set the netmask
459  */
460  if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
461  {
462  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
463  strerror (errno));
464  (void) close (fd);
465  exit (1);
466  }
467 
468  /*
469  * Get the flags
470  */
471  if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
472  {
473  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
474  strerror (errno));
475  (void) close (fd);
476  exit (1);
477  }
478 
479  /*
480  * Add the UP and RUNNING flags
481  */
482  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
483  if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
484  {
485  fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
486  strerror (errno));
487  (void) close (fd);
488  exit (1);
489  }
490 
491  if (0 != close (fd))
492  {
493  fprintf (stderr, "close failed: %s\n", strerror (errno));
494  (void) close (fd);
495  exit (1);
496  }
497 }
498 
499 
507 static void
508 run (int fd_tun)
509 {
510  /*
511  * The buffer filled by reading from fd_tun
512  */
513  unsigned char buftun[MAX_SIZE];
514  ssize_t buftun_size = 0;
515  unsigned char *buftun_read = NULL;
516 
517  /*
518  * The buffer filled by reading from stdin
519  */
520  unsigned char bufin[MAX_SIZE];
521  ssize_t bufin_size = 0;
522  size_t bufin_rpos = 0;
523  unsigned char *bufin_read = NULL;
524  fd_set fds_w;
525  fd_set fds_r;
526  int max;
527 
528  while (1)
529  {
530  FD_ZERO (&fds_w);
531  FD_ZERO (&fds_r);
532 
533  /*
534  * We are supposed to read and the buffer is empty
535  * -> select on read from tun
536  */
537  if (0 == buftun_size)
538  FD_SET (fd_tun, &fds_r);
539 
540  /*
541  * We are supposed to read and the buffer is not empty
542  * -> select on write to stdout
543  */
544  if (0 < buftun_size)
545  FD_SET (1, &fds_w);
546 
547  /*
548  * We are supposed to write and the buffer is empty
549  * -> select on read from stdin
550  */
551  if (NULL == bufin_read)
552  FD_SET (0, &fds_r);
553 
554  /*
555  * We are supposed to write and the buffer is not empty
556  * -> select on write to tun
557  */
558  if (NULL != bufin_read)
559  FD_SET (fd_tun, &fds_w);
560 
561  FD_SET (cpipe[0], &fds_r);
562  max = (fd_tun > cpipe[0]) ? fd_tun : cpipe[0];
563 
564  int r = select (max + 1, &fds_r, &fds_w, NULL, NULL);
565 
566  if (-1 == r)
567  {
568  if (EINTR == errno)
569  continue;
570  fprintf (stderr, "select failed: %s\n", strerror (errno));
571  return;
572  }
573 
574  if (r > 0)
575  {
576  if (FD_ISSET (cpipe[0], &fds_r))
577  return; /* aborted by signal */
578 
579  if (FD_ISSET (fd_tun, &fds_r))
580  {
581  buftun_size =
582  read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader),
583  MAX_SIZE - sizeof (struct GNUNET_MessageHeader));
584  if (-1 == buftun_size)
585  {
586  if ( (errno == EINTR) ||
587  (errno == EAGAIN) )
588  {
589  buftun_size = 0;
590  continue;
591  }
592  fprintf (stderr, "read-error: %s\n", strerror (errno));
593  return;
594  }
595  if (0 == buftun_size)
596  {
597  fprintf (stderr, "EOF on tun\n");
598  return;
599  }
600  buftun_read = buftun;
601  {
602  struct GNUNET_MessageHeader *hdr =
603  (struct GNUNET_MessageHeader *) buftun;
604  buftun_size += sizeof (struct GNUNET_MessageHeader);
605  hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
606  hdr->size = htons (buftun_size);
607  }
608  }
609  else if (FD_ISSET (1, &fds_w))
610  {
611  ssize_t written = write (1, buftun_read, buftun_size);
612 
613  if (-1 == written)
614  {
615  if ( (errno == EINTR) ||
616  (errno == EAGAIN) )
617  continue;
618  fprintf (stderr, "write-error to stdout: %s\n", strerror (errno));
619  return;
620  }
621  if (0 == written)
622  {
623  fprintf (stderr, "write returned 0\n");
624  return;
625  }
626  buftun_size -= written;
627  buftun_read += written;
628  }
629 
630  if (FD_ISSET (0, &fds_r))
631  {
632  bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
633  if (-1 == bufin_size)
634  {
635  bufin_read = NULL;
636  if ( (errno == EINTR) ||
637  (errno == EAGAIN) )
638  continue;
639  fprintf (stderr, "read-error: %s\n", strerror (errno));
640  return;
641  }
642  if (0 == bufin_size)
643  {
644  bufin_read = NULL;
645  fprintf (stderr, "EOF on stdin\n");
646  return;
647  }
648  {
649  struct GNUNET_MessageHeader *hdr;
650 
651 PROCESS_BUFFER:
652  bufin_rpos += bufin_size;
653  if (bufin_rpos < sizeof (struct GNUNET_MessageHeader))
654  continue;
655  hdr = (struct GNUNET_MessageHeader *) bufin;
656  if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_DNS_HELPER)
657  {
658  fprintf (stderr, "protocol violation!\n");
659  return;
660  }
661  if (ntohs (hdr->size) > bufin_rpos)
662  continue;
663  bufin_read = bufin + sizeof (struct GNUNET_MessageHeader);
664  bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader);
665  bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader);
666  }
667  }
668  else if (FD_ISSET (fd_tun, &fds_w))
669  {
670  ssize_t written = write (fd_tun, bufin_read, bufin_size);
671 
672  if (-1 == written)
673  {
674  if ( (errno == EINTR) ||
675  (errno == EAGAIN) )
676  continue;
677  fprintf (stderr, "write-error to tun: %s\n", strerror (errno));
678  return;
679  }
680  if (0 == written)
681  {
682  fprintf (stderr, "write returned 0\n");
683  return;
684  }
685  {
686  bufin_size -= written;
687  bufin_read += written;
688  if (0 == bufin_size)
689  {
690  memmove (bufin, bufin_read, bufin_rpos);
691  bufin_read = NULL; /* start reading again */
692  bufin_size = 0;
693  goto PROCESS_BUFFER;
694  }
695  }
696  }
697  }
698  }
699 }
700 
701 
734 int
735 main (int argc, char *const*argv)
736 {
737  int r;
738  char dev[IFNAMSIZ];
739  char mygid[32];
740  int fd_tun;
741  uid_t uid;
742  int nortsetup = 0;
743 
744  if (7 != argc)
745  {
746  fprintf (stderr, "Fatal: must supply 6 arguments!\n");
747  return 1;
748  }
749 
750  /* assert privs so we can modify the firewall rules! */
751  uid = getuid ();
752 #ifdef HAVE_SETRESUID
753  if (0 != setresuid (uid, 0, 0))
754  {
755  fprintf (stderr, "Failed to setresuid to root: %s\n", strerror (errno));
756  return 254;
757  }
758 #else
759  if (0 != seteuid (0))
760  {
761  fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno));
762  return 254;
763  }
764 #endif
765  if (0 == strncmp (argv[6], "1", 2))
766  nortsetup = 1;
767 
768  if (0 == nortsetup)
769  {
770  /* verify that the binaries we care about are executable */
771 #ifdef IPTABLES
772  if (0 == access (IPTABLES, X_OK))
773  sbin_iptables = IPTABLES;
774  else
775 #endif
776  if (0 == access ("/sbin/iptables", X_OK))
777  sbin_iptables = "/sbin/iptables";
778  else if (0 == access ("/usr/sbin/iptables", X_OK))
779  sbin_iptables = "/usr/sbin/iptables";
780  else
781  {
782  fprintf (stderr,
783  "Fatal: executable iptables not found in approved directories: %s\n",
784  strerror (errno));
785  return 3;
786  }
787 #ifdef IP6TABLES
788  if (0 == access (IP6TABLES, X_OK))
789  sbin_ip6tables = IP6TABLES;
790  else
791 #endif
792  if (0 == access ("/sbin/ip6tables", X_OK))
793  sbin_ip6tables = "/sbin/ip6tables";
794  else if (0 == access ("/usr/sbin/ip6tables", X_OK))
795  sbin_ip6tables = "/usr/sbin/ip6tables";
796  else
797  {
798  fprintf (stderr,
799  "Fatal: executable ip6tables not found in approved directories: %s\n",
800  strerror (errno));
801  return 3;
802  }
803 #ifdef PATH_TO_IP
804  if (0 == access (PATH_TO_IP, X_OK))
805  sbin_ip = PATH_TO_IP;
806  else
807 #endif
808  if (0 == access ("/sbin/ip", X_OK))
809  sbin_ip = "/sbin/ip";
810  else if (0 == access ("/usr/sbin/ip", X_OK))
811  sbin_ip = "/usr/sbin/ip";
812  else if (0 == access ("/bin/ip", X_OK)) /* gentoo has it there */
813  sbin_ip = "/bin/ip";
814  else
815  {
816  fprintf (stderr,
817  "Fatal: executable ip not found in approved directories: %s\n",
818  strerror (errno));
819  return 4;
820  }
821 #ifdef SYSCTL
822  if (0 == access (SYSCTL, X_OK))
823  sbin_sysctl = SYSCTL;
824  else
825 #endif
826  if (0 == access ("/sbin/sysctl", X_OK))
827  sbin_sysctl = "/sbin/sysctl";
828  else if (0 == access ("/usr/sbin/sysctl", X_OK))
829  sbin_sysctl = "/usr/sbin/sysctl";
830  else
831  {
832  fprintf (stderr,
833  "Fatal: executable sysctl not found in approved directories: %s\n",
834  strerror (errno));
835  return 5;
836  }
837  }
838 
839  /* setup 'mygid' string */
840  snprintf (mygid, sizeof (mygid), "%d", (int) getegid());
841 
842  /* do not die on SIGPIPE */
843  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
844  {
845  fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
846  strerror (errno));
847  return 7;
848  }
849 
850  /* setup pipe to shutdown nicely on SIGINT */
851  if (0 != pipe (cpipe))
852  {
853  fprintf (stderr,
854  "Fatal: could not setup control pipe: %s\n",
855  strerror (errno));
856  return 6;
857  }
858  if (cpipe[0] >= FD_SETSIZE)
859  {
860  fprintf (stderr, "Pipe file descriptor to large: %d", cpipe[0]);
861  (void) close (cpipe[0]);
862  (void) close (cpipe[1]);
863  return 6;
864  }
865  {
866  /* make pipe non-blocking, as we theoretically could otherwise block
867  in the signal handler */
868  int flags = fcntl (cpipe[1], F_GETFL);
869  if (-1 == flags)
870  {
871  fprintf (stderr, "Failed to read flags for pipe: %s", strerror (errno));
872  (void) close (cpipe[0]);
873  (void) close (cpipe[1]);
874  return 6;
875  }
876  flags |= O_NONBLOCK;
877  if (0 != fcntl (cpipe[1], F_SETFL, flags))
878  {
879  fprintf (stderr, "Failed to make pipe non-blocking: %s", strerror (errno));
880  (void) close (cpipe[0]);
881  (void) close (cpipe[1]);
882  return 6;
883  }
884  }
885  if ( (SIG_ERR == signal (SIGTERM, &signal_handler)) ||
886 #if (SIGTERM != GNUNET_TERM_SIG)
887  (SIG_ERR == signal (GNUNET_TERM_SIG, &signal_handler)) ||
888 #endif
889  (SIG_ERR == signal (SIGINT, &signal_handler)) ||
890  (SIG_ERR == signal (SIGHUP, &signal_handler)) )
891  {
892  fprintf (stderr,
893  "Fatal: could not initialize signal handler: %s\n",
894  strerror (errno));
895  (void) close (cpipe[0]);
896  (void) close (cpipe[1]);
897  return 7;
898  }
899 
900 
901  /* get interface name */
902  strncpy (dev, argv[1], IFNAMSIZ);
903  dev[IFNAMSIZ - 1] = '\0';
904 
905  /* Disable rp filtering */
906  if (0 == nortsetup)
907  {
908  char *const sysctl_args[] = {"sysctl", "-w",
909  "net.ipv4.conf.all.rp_filter=0", NULL};
910  char *const sysctl_args2[] = {"sysctl", "-w",
911  "net.ipv4.conf.default.rp_filter=0", NULL};
912  if ((0 != fork_and_exec (sbin_sysctl, sysctl_args)) ||
913  (0 != fork_and_exec (sbin_sysctl, sysctl_args2)))
914  {
915  fprintf (stderr,
916  "Failed to disable rp filtering.\n");
917  return 5;
918  }
919  }
920 
921 
922  /* now open virtual interface (first part that requires root) */
923  if (-1 == (fd_tun = init_tun (dev)))
924  {
925  fprintf (stderr, "Fatal: could not initialize tun-interface\n");
926  (void) signal (SIGTERM, SIG_IGN);
927 #if (SIGTERM != GNUNET_TERM_SIG)
928  (void) signal (GNUNET_TERM_SIG, SIG_IGN);
929 #endif
930  (void) signal (SIGINT, SIG_IGN);
931  (void) signal (SIGHUP, SIG_IGN);
932  (void) close (cpipe[0]);
933  (void) close (cpipe[1]);
934  return 5;
935  }
936 
937  /* now set interface addresses */
938  {
939  const char *address = argv[2];
940  long prefix_len = atol (argv[3]);
941 
942  if ((prefix_len < 1) || (prefix_len > 127))
943  {
944  fprintf (stderr, "Fatal: prefix_len out of range\n");
945  (void) signal (SIGTERM, SIG_IGN);
946 #if (SIGTERM != GNUNET_TERM_SIG)
947  (void) signal (GNUNET_TERM_SIG, SIG_IGN);
948 #endif
949  (void) signal (SIGINT, SIG_IGN);
950  (void) signal (SIGHUP, SIG_IGN);
951  (void) close (cpipe[0]);
952  (void) close (cpipe[1]);
953  return 2;
954  }
955  set_address6 (dev, address, prefix_len);
956  }
957 
958  {
959  const char *address = argv[4];
960  const char *mask = argv[5];
961 
962  set_address4 (dev, address, mask);
963  }
964 
965 
966  /* update routing tables -- next part why we need SUID! */
967  /* Forward everything from our EGID (which should only be held
968  by the 'gnunet-service-dns') and with destination
969  to port 53 on UDP, without hijacking */
970  if (0 == nortsetup)
971  {
972  r = 8; /* failed to fully setup routing table */
973  {
974  char *const mangle_args[] =
975  {
976  "iptables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p",
977  "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j",
978  "ACCEPT", NULL
979  };
980  if (0 != fork_and_exec (sbin_iptables, mangle_args))
981  goto cleanup_rest;
982  }
983  {
984  char *const mangle_args[] =
985  {
986  "ip6tables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p",
987  "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j",
988  "ACCEPT", NULL
989  };
990  if (0 != fork_and_exec (sbin_ip6tables, mangle_args))
991  goto cleanup_mangle_1b;
992  }
993  /* Mark all of the other DNS traffic using our mark DNS_MARK,
994  unless it is on a link-local IPv6 address, which we cannot support. */
995  {
996  char *const mark_args[] =
997  {
998  "iptables", "-t", "mangle", "-I", "OUTPUT", "2", "-p",
999  "udp", "--dport", DNS_PORT,
1000  "-j", "MARK", "--set-mark", DNS_MARK,
1001  NULL
1002  };
1003  if (0 != fork_and_exec (sbin_iptables, mark_args))
1004  goto cleanup_mangle_1;
1005  }
1006  {
1007  char *const mark_args[] =
1008  {
1009  "ip6tables", "-t", "mangle", "-I", "OUTPUT", "2", "-p",
1010  "udp", "--dport", DNS_PORT,
1011  "!", "-s", "fe80::/10", /* this line excludes link-local traffic */
1012  "-j", "MARK", "--set-mark", DNS_MARK,
1013  NULL
1014  };
1015  if (0 != fork_and_exec (sbin_ip6tables, mark_args))
1016  goto cleanup_mark_2b;
1017  }
1018  /* Forward all marked DNS traffic to our DNS_TABLE */
1019  {
1020  char *const forward_args[] =
1021  {
1022  "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
1023  };
1024  if (0 != fork_and_exec (sbin_ip, forward_args))
1025  goto cleanup_mark_2;
1026  }
1027  {
1028  char *const forward_args[] =
1029  {
1030  "ip", "-6", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
1031  };
1032  if (0 != fork_and_exec (sbin_ip, forward_args))
1033  goto cleanup_forward_3b;
1034  }
1035  /* Finally, add rule in our forwarding table to pass to our virtual interface */
1036  {
1037  char *const route_args[] =
1038  {
1039  "ip", "route", "add", "default", "dev", dev,
1040  "table", DNS_TABLE, NULL
1041  };
1042  if (0 != fork_and_exec (sbin_ip, route_args))
1043  goto cleanup_forward_3;
1044  }
1045  {
1046  char *const route_args[] =
1047  {
1048  "ip", "-6", "route", "add", "default", "dev", dev,
1049  "table", DNS_TABLE, NULL
1050  };
1051  if (0 != fork_and_exec (sbin_ip, route_args))
1052  goto cleanup_route_4b;
1053  }
1054  }
1055 
1056  /* drop privs *except* for the saved UID; this is not perfect, but better
1057  than doing nothing */
1058 #ifdef HAVE_SETRESUID
1059  if (0 != setresuid (uid, uid, 0))
1060  {
1061  fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
1062  r = 24;
1063  goto cleanup_route_4;
1064  }
1065 #else
1066  /* Note: no 'setuid' here as we must keep our saved UID as root */
1067  if (0 != seteuid (uid))
1068  {
1069  fprintf (stderr, "Failed to seteuid: %s\n", strerror (errno));
1070  r = 24;
1071  goto cleanup_route_4;
1072  }
1073 #endif
1074 
1075  r = 0; /* did fully setup routing table (if nothing else happens, we were successful!) */
1076 
1077  /* now forward until we hit a problem */
1078  run (fd_tun);
1079 
1080  /* now need to regain privs so we can remove the firewall rules we added! */
1081 #ifdef HAVE_SETRESUID
1082  if (0 != setresuid (uid, 0, 0))
1083  {
1084  fprintf (stderr, "Failed to setresuid back to root: %s\n", strerror (errno));
1085  r = 40;
1086  goto cleanup_route_4;
1087  }
1088 #else
1089  if (0 != seteuid (0))
1090  {
1091  fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno));
1092  r = 40;
1093  goto cleanup_route_4;
1094  }
1095 #endif
1096 
1097  /* update routing tables again -- this is why we could not fully drop privs */
1098  /* now undo updating of routing tables; normal exit or clean-up-on-error case */
1099  cleanup_route_4:
1100  if (0 == nortsetup)
1101  {
1102  char *const route_clean_args[] =
1103  {
1104  "ip", "-6", "route", "del", "default", "dev", dev,
1105  "table", DNS_TABLE, NULL
1106  };
1107  if (0 != fork_and_exec (sbin_ip, route_clean_args))
1108  r += 1;
1109  }
1110  cleanup_route_4b:
1111  if (0 == nortsetup)
1112  {
1113  char *const route_clean_args[] =
1114  {
1115  "ip", "route", "del", "default", "dev", dev,
1116  "table", DNS_TABLE, NULL
1117  };
1118  if (0 != fork_and_exec (sbin_ip, route_clean_args))
1119  r += 1;
1120  }
1121  cleanup_forward_3:
1122  if (0 == nortsetup)
1123  {
1124  char *const forward_clean_args[] =
1125  {
1126  "ip", "-6", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
1127  };
1128  if (0 != fork_and_exec (sbin_ip, forward_clean_args))
1129  r += 2;
1130  }
1131  cleanup_forward_3b:
1132  if (0 == nortsetup)
1133  {
1134  char *const forward_clean_args[] =
1135  {
1136  "ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
1137  };
1138  if (0 != fork_and_exec (sbin_ip, forward_clean_args))
1139  r += 2;
1140  }
1141  cleanup_mark_2:
1142  if (0 == nortsetup)
1143  {
1144  char *const mark_clean_args[] =
1145  {
1146  "ip6tables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
1147  "--dport", DNS_PORT,
1148  "!", "-s", "fe80::/10", /* this line excludes link-local traffic */
1149  "-j", "MARK", "--set-mark", DNS_MARK, NULL
1150  };
1151  if (0 != fork_and_exec (sbin_ip6tables, mark_clean_args))
1152  r += 4;
1153  }
1154  cleanup_mark_2b:
1155  if (0 == nortsetup)
1156  {
1157  char *const mark_clean_args[] =
1158  {
1159  "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
1160  "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL
1161  };
1162  if (0 != fork_and_exec (sbin_iptables, mark_clean_args))
1163  r += 4;
1164  }
1165  cleanup_mangle_1:
1166  if (0 == nortsetup)
1167  {
1168  char *const mangle_clean_args[] =
1169  {
1170  "ip6tables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
1171  "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT",
1172  NULL
1173  };
1174  if (0 != fork_and_exec (sbin_ip6tables, mangle_clean_args))
1175  r += 8;
1176  }
1177  cleanup_mangle_1b:
1178  if (0 == nortsetup)
1179  {
1180  char *const mangle_clean_args[] =
1181  {
1182  "iptables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
1183  "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT",
1184  NULL
1185  };
1186  if (0 != fork_and_exec (sbin_iptables, mangle_clean_args))
1187  r += 8;
1188  }
1189 
1190  cleanup_rest:
1191  /* close virtual interface */
1192  (void) close (fd_tun);
1193  /* remove signal handler so we can close the pipes */
1194  (void) signal (SIGTERM, SIG_IGN);
1195 #if (SIGTERM != GNUNET_TERM_SIG)
1196  (void) signal (GNUNET_TERM_SIG, SIG_IGN);
1197 #endif
1198  (void) signal (SIGINT, SIG_IGN);
1199  (void) signal (SIGHUP, SIG_IGN);
1200  (void) close (cpipe[0]);
1201  (void) close (cpipe[1]);
1202  return r;
1203 }
1204 
1205 /* end of gnunet-helper-dns.c */
uint32_t ifr6_prefixlen
int main(int argc, char *const *argv)
Main function of "gnunet-helper-dns", which opens a VPN tunnel interface, redirects all outgoing DNS ...
static const char * sbin_ip
Name and full path of IPTABLES binary.
#define MAX_SIZE
Need &#39;struct GNUNET_MessageHeader&#39;.
static int fork_and_exec(const char *file, char *const cmd[])
Run the given command and wait for it to complete.
struct in6_addr ifr6_addr
static const char * sbin_sysctl
Name and full path of sysctl binary.
static int init_tun(char *dev)
Creates a tun-interface called dev;.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
static int ret
Final status code.
Definition: gnunet-arm.c:89
static void open_dev_null(int target_fd, int flags)
Open &#39;/dev/null&#39; and make the result the given file descriptor.
#define FD_SETSIZE
Definition: winproc.h:39
cryptographic primitives for GNUnet
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
static const char * sbin_iptables
Name and full path of IPTABLES binary.
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.
static void set_address4(const char *dev, const char *address, const char *mask)
Sets the IPv4-Address given in address on the interface dev.
#define DNS_MARK
Marker we set for our hijacked DNS traffic.
uint16_t status
See PRISM_STATUS_*-constants.
static void signal_handler(int signal)
Signal handler called to initiate "nice" shutdown.
static int cpipe[2]
Control pipe for shutdown via signal.
static void run(int fd_tun)
Start forwarding to and from the tunnel.
#define GNUNET_MESSAGE_TYPE_DNS_HELPER
Type of messages between the gnunet-helper-dns and the service.
This is in linux/include/net/ipv6.h, but not always exported...
static const char * sbin_ip6tables
Name and full path of IPTABLES binary.
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
#define DNS_TABLE
Table we use for our DNS rules.
Header for all communications.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
unsigned int ifr6_ifindex
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:282
static char * address
GNS address for this phone.
#define DNS_PORT
Port for DNS traffic.