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