ee7ae18738d88e2208edfc670fabe413bb8f63db
[oweals/gnunet.git] / src / vpn / gnunet-helper-hijack-dns.c
1 /*
2    This file is part of GNUnet.
3    (C) 2010 Christian Grothoff
4
5    GNUnet is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published
7    by the Free Software Foundation; either version 3, or (at your
8    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    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with GNUnet; see the file COPYING.  If not, write to the
17    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.
19    */
20
21 /**
22  * @file vpn/gnunet-helper-hijack-dns.c
23  * @brief
24  * @author Philipp Tölke
25  */
26 #include <platform.h>
27
28 #include "gnunet_common.h"
29
30 int fork_and_exec(char* file, char* cmd[]) {
31         pid_t pid = fork();
32         if (pid < 0) {
33                 fprintf(stderr, "could not fork: %s\n", strerror(errno));
34                 return GNUNET_SYSERR;
35         }
36
37         int st = 0;
38
39         if (pid == 0) {
40                 execv(file, cmd);
41         } else {
42                 waitpid(pid, &st, 0);
43         }
44         return WIFEXITED(st) && (WEXITSTATUS(st) == 0);
45 }
46
47 int main(int argc, char** argv) {
48         int delete = 0;
49         int port = 0;
50         char* virt_dns;
51         if (argc < 3) return GNUNET_SYSERR;
52
53         if (strncmp(argv[1], "-d", 2) == 0) {
54                 if (argc < 3) return GNUNET_SYSERR;
55                 delete = 1;
56                 port = atoi(argv[2]);
57                 virt_dns = argv[3];
58         } else {
59                 port = atoi(argv[1]);
60                 virt_dns = argv[2];
61         }
62
63         if (port == 0) return GNUNET_SYSERR;
64
65         struct stat s;
66         if (stat("/sbin/iptables", &s) < 0) {
67                 fprintf(stderr, "stat on /sbin/iptables failed: %s\n", strerror(errno));
68                 return GNUNET_SYSERR;
69         }
70         if (stat("/sbin/ip", &s) < 0) {
71                 fprintf(stderr, "stat on /sbin/ip failed: %s\n", strerror(errno));
72                 return GNUNET_SYSERR;
73         }
74
75         char localport[7];
76         snprintf(localport, 7, "%d", port);
77
78         int r;
79         if (delete) {
80 e4:
81                 r = fork_and_exec("/sbin/ip", (char*[]){"ip", "route", "del", "default", "via", virt_dns,"table","2", NULL});
82 e3:
83                 r = fork_and_exec("/sbin/ip", (char*[]){"ip", "rule", "del", "fwmark", "3", "table","2", NULL});
84 e2:
85                 r = fork_and_exec("/sbin/iptables", (char*[]){"iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", "--dport", "53", "-j", "MARK", "--set-mark", "3", NULL});
86 e1:
87                 r = fork_and_exec("/sbin/iptables", (char*[]){"iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", "--sport", localport, "--dport", "53", "-j", "ACCEPT", NULL});
88                 if (!delete) r = 0;
89         } else {
90                 r = fork_and_exec("/sbin/iptables", (char*[]){"iptables", "-t", "mangle", "-I", "OUTPUT", "1", "-p", "udp", "--sport", localport, "--dport", "53", "-j", "ACCEPT", NULL});
91                 if (!r) goto e1;
92                 r = fork_and_exec("/sbin/iptables", (char*[]){"iptables", "-t", "mangle", "-I", "OUTPUT", "2", "-p", "udp", "--dport", "53", "-j", "MARK", "--set-mark", "3", NULL});
93                 if (!r) goto e2;
94                 r = fork_and_exec("/sbin/ip", (char*[]){"ip", "rule", "add", "fwmark", "3", "table","2", NULL});
95                 if (!r) goto e3;
96                 r = fork_and_exec("/sbin/ip", (char*[]){"ip", "route", "add", "default", "via", virt_dns, "table","2", NULL});
97                 if (!r) goto e4;
98         }
99         if (r) return GNUNET_YES;
100         return GNUNET_SYSERR;
101 }