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  struct in6_addr ifr6_addr;
92  uint32_t ifr6_prefixlen;
93  unsigned int ifr6_ifindex;
94 };
95 #endif
96 
100 static const char *sbin_iptables;
101 
105 static const char *sbin_ip6tables;
106 
110 static const char *sbin_sysctl;
111 
115 static const char *sbin_ip;
116 
120 #define DNS_PORT "53"
121 
128 #define DNS_MARK "136708149"
129 
137 #define DNS_TABLE "53"
138 
139 
144 static int cpipe[2];
145 
146 
153 static void
154 signal_handler(int signal)
155 {
156  /* ignore return value, as the signal handler could theoretically
157  be called many times before the shutdown can actually happen */
158  (void)write(cpipe[1], "K", 1);
159 }
160 
161 
169 static void
170 open_dev_null(int target_fd,
171  int flags)
172 {
173  int fd;
174 
175  fd = open("/dev/null", flags);
176  if (-1 == fd)
177  abort();
178  if (fd == target_fd)
179  return;
180  if (-1 == dup2(fd, target_fd))
181  {
182  (void)close(fd);
183  abort();
184  }
185  (void)close(fd);
186 }
187 
188 
196 static int
197 fork_and_exec(const char *file,
198  char *const cmd[])
199 {
200  int status;
201  pid_t pid;
202  pid_t ret;
203 
204  pid = fork();
205  if (-1 == pid)
206  {
207  fprintf(stderr,
208  "fork failed: %s\n",
209  strerror(errno));
210  return 1;
211  }
212  if (0 == pid)
213  {
214  /* we are the child process */
215  /* close stdin/stdout to not cause interference
216  with the helper's main protocol! */
217  (void)close(0);
218  open_dev_null(0, O_RDONLY);
219  (void)close(1);
220  open_dev_null(1, O_WRONLY);
221  (void)execv(file, cmd);
222  /* can only get here on error */
223  fprintf(stderr,
224  "exec `%s' failed: %s\n",
225  file,
226  strerror(errno));
227  _exit(1);
228  }
229  /* keep running waitpid as long as the only error we get is 'EINTR' */
230  while ((-1 == (ret = waitpid(pid, &status, 0))) &&
231  (errno == EINTR))
232  ;
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.
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.
#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:242
static char * address
GNS address for this phone.
#define DNS_PORT
Port for DNS traffic.