start the helper from the daemon, end it correctly
[oweals/gnunet.git] / src / vpn / gnunet-vpn-helper.c
1 #define _GNU_SOURCE
2 #include <arpa/inet.h>
3 #include <linux/if.h>
4
5 #include <fcntl.h>
6
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/ioctl.h>
10
11 #include <string.h>
12
13 #include <signal.h>
14
15 #include <stdio.h>
16 #include <unistd.h>
17
18 #include "gnunet-vpn-helper-p.h"
19 #include "tun.h"
20
21 #ifndef _LINUX_IN6_H
22 // This is in linux/include/net/ipv6.h.
23
24 struct in6_ifreq {
25     struct in6_addr ifr6_addr;
26     __u32 ifr6_prefixlen;
27     unsigned int ifr6_ifindex;
28 };
29
30 #endif
31
32 int running = 1;
33
34 void term(int sig) {
35         fprintf(stderr, "Got SIGTERM...\n");
36         if (sig == SIGTERM)
37                 running = 0;
38 }
39
40 static void set_address(char* dev, char* address, unsigned long prefix_len) { /* {{{ */
41         int fd = socket(AF_INET6, SOCK_DGRAM, 0);
42
43         struct ifreq ifr;
44         struct in6_ifreq ifr6;
45
46         struct sockaddr_in6 sa6;
47         memset(&sa6, 0, sizeof(struct sockaddr_in6));
48
49         sa6.sin6_family = AF_INET6;
50
51         /* FIXME */ inet_pton(AF_INET6, address, sa6.sin6_addr.s6_addr);
52
53         memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr, sizeof(struct in6_addr));
54
55         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
56
57         if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
58                 perror("SIOGIFINDEX");
59         }
60
61         ifr6.ifr6_ifindex = ifr.ifr_ifindex;
62         ifr6.ifr6_prefixlen = prefix_len;
63
64         if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
65                 perror("SIOCSIFADDR");
66         }
67
68         /* FIXME */ ioctl(fd, SIOCGIFFLAGS, &ifr);
69         ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
70         /* FIXME */ ioctl(fd, SIOCSIFFLAGS, &ifr);
71 } /* }}} */
72
73 void setnonblocking(int fd) {
74         int opts;
75
76         opts = fcntl(fd,F_GETFL);
77         if (opts < 0) {
78                         perror("fcntl(F_GETFL)");
79         }
80         opts = (opts | O_NONBLOCK);
81         if (fcntl(fd,F_SETFL,opts) < 0) {
82                         perror("fcntl(F_SETFL)");
83         }
84         return;
85 }
86
87 static int copy (int in, int out) {
88         unsigned char buf[65600]; // 64k + 64;
89         int r = read(in, buf, 65600);
90         int w = 0;
91         if (r < 0) return r;
92         while (w < r) {
93                 int t = write(out, buf + w, r - w);
94                 if (t > 0) w += t;
95                 if (t < 0) return t;
96         }
97         return 0;
98 }
99
100 int main(int argc, char** argv) {
101         char dev[IFNAMSIZ];
102         memset(dev, 0, IFNAMSIZ);
103
104         signal(SIGTERM, &term);
105
106         int fd_tun = init_tun(dev);
107         fprintf(stderr, "Initialized the interface %s as %d.\n", dev, fd_tun);
108
109         // TODO: get this out of argv
110         char address[] = "1234::1";
111         unsigned long prefix_len = 8;
112
113         set_address(dev, address, prefix_len);
114
115         uid_t uid = getuid ();
116         if (setresuid (uid, uid, uid) != 0 )
117                 fprintf (stderr, "Failed to setresuid: %m\n");
118
119         setnonblocking(0);
120         setnonblocking(1);
121         setnonblocking(fd_tun);
122
123         fd_set fds_w;
124         fd_set fds_r;
125
126         int r = 1;
127         int w = 1;
128         while(r != 0 && w != 0 && running == 1) {
129                 FD_ZERO(&fds_w);
130                 FD_ZERO(&fds_r);
131
132                 if (r) {
133                         FD_SET(fd_tun, &fds_r);
134                         FD_SET(1, &fds_w);
135                 }
136
137                 if (w) {
138                         FD_SET(0, &fds_r);
139                         FD_SET(fd_tun, &fds_w);
140                 }
141
142                 int r = select(fd_tun+1, &fds_r, &fds_w, (fd_set*)0, 0);
143
144                 if(r > 0) {
145                         if (FD_ISSET(0, &fds_r) && FD_ISSET(fd_tun, &fds_w)) {
146                                 if (copy(0, fd_tun) < 0) {
147                                         fprintf(stderr, "Closing Write\n");
148                                         shutdown(fd_tun, SHUT_WR);
149                                         w = 0;
150                                 }
151                         } else if (FD_ISSET(1, &fds_w) && FD_ISSET(fd_tun, &fds_r)) {
152                                 if (copy(fd_tun, 1) < 0) {
153                                         fprintf(stderr, "Closing Read\n");
154                                         shutdown(fd_tun, SHUT_RD);
155                                         r = 0;
156                                 }
157                         }
158                 }
159         }
160         fprintf(stderr, "Quitting!\n");
161
162         return 0;
163 }