read the output of the helper
[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 int main(int argc, char** argv) {
88         unsigned char buf[65600]; // 64k + 64;
89
90         char dev[IFNAMSIZ];
91         memset(dev, 0, IFNAMSIZ);
92
93         signal(SIGTERM, &term);
94
95         int fd_tun = init_tun(dev);
96         fprintf(stderr, "Initialized the interface %s as %d.\n", dev, fd_tun);
97
98         // TODO: get this out of argv
99         char address[] = "1234::1";
100         unsigned long prefix_len = 8;
101
102         set_address(dev, address, prefix_len);
103
104         uid_t uid = getuid ();
105         if (setresuid (uid, uid, uid) != 0 )
106                 fprintf (stderr, "Failed to setresuid: %m\n");
107
108         setnonblocking(0);
109         setnonblocking(1);
110         setnonblocking(fd_tun);
111
112         fd_set fds_w;
113         fd_set fds_r;
114
115         int rea = 1;
116         int wri = 1;
117 outer:
118         while(rea != 0 && wri != 0 && running == 1) {
119                 FD_ZERO(&fds_w);
120                 FD_ZERO(&fds_r);
121
122                 if (rea) {
123                         FD_SET(fd_tun, &fds_r);
124                         FD_SET(1, &fds_w);
125                 }
126
127                 if (wri) {
128                         FD_SET(0, &fds_r);
129                         FD_SET(fd_tun, &fds_w);
130                 }
131
132                 int r = select(fd_tun+1, &fds_r, &fds_w, (fd_set*)0, 0);
133
134                 if(r > 0) {
135                         if (FD_ISSET(0, &fds_r) && FD_ISSET(fd_tun, &fds_w)) {
136                                 struct suid_packet *pkt = (struct suid_packet*) buf;
137                                 r = read(0, buf, sizeof(struct suid_packet_header));
138                                 if (r < 0) {
139                                         fprintf(stderr, "read-error: %m\n");
140                                         shutdown(fd_tun, SHUT_WR);
141                                         shutdown(0, SHUT_RD);
142                                         wri=0;
143                                         goto outer;
144                                 }
145                                 r = 0;
146                                 while (r < ntohl(pkt->hdr.size)) {
147                                         int t = read(0, buf + r, ntohl(pkt->hdr.size) - r);
148                                         if (r < 0) {
149                                                 fprintf(stderr, "read-error: %m\n");
150                                                 shutdown(fd_tun, SHUT_WR);
151                                                 shutdown(0, SHUT_RD);
152                                                 wri=0;
153                                                 goto outer;
154                                         }
155                                         r += t;
156                                 }
157                                 r = 0;
158                                 while (r < ntohl(pkt->hdr.size) - sizeof(struct suid_packet_header)) {
159                                         int t = write(fd_tun, pkt->data, ntohl(pkt->hdr.size) - sizeof(struct suid_packet_header) - r);
160                                         if (t < 0) {
161                                                 fprintf(stderr, "write-error 3: %m\n");
162                                                 shutdown(fd_tun, SHUT_WR);
163                                                 shutdown(0, SHUT_RD);
164                                                 wri = 0;
165                                                 goto outer;
166                                         }
167                                         r += t;
168                                 }
169                         } else if (FD_ISSET(1, &fds_w) && FD_ISSET(fd_tun, &fds_r)) {
170                                 r = read(fd_tun, buf, 65600);
171                                 if (r < 0) {
172                                         fprintf(stderr, "read-error: %m\n");
173                                         shutdown(fd_tun, SHUT_RD);
174                                         shutdown(1, SHUT_WR);
175                                         rea = 0;
176                                         goto outer;
177                                 }
178                                 struct suid_packet_header hdr = { .size = htonl(r + sizeof(struct suid_packet_header))};
179                                 r = 0;
180                                 while(r < sizeof(struct suid_packet_header)) {
181                                         int t = write(1, &hdr, sizeof(struct suid_packet_header) - r);
182                                         if (t < 0) {
183                                                 fprintf(stderr, "write-error 2: %m\n");
184                                                 shutdown(fd_tun, SHUT_RD);
185                                                 shutdown(1, SHUT_WR);
186                                                 rea = 0;
187                                                 goto outer;
188                                         }
189                                         r += t;
190                                 }
191                                 while(r < ntohl(hdr.size)) {
192                                         int t = write(1, buf, ntohl(hdr.size) - r);
193                                         if (t < 0) {
194                                                 fprintf(stderr, "write-error 1: %m, written %d/%d\n", r, ntohl(hdr.size));
195                                                 shutdown(fd_tun, SHUT_RD);
196                                                 shutdown(1, SHUT_WR);
197                                                 rea = 0;
198                                                 goto outer;
199                                         }
200                                         r += t;
201                                 }
202                         }
203                 }
204         }
205         fprintf(stderr, "Quitting!\n");
206
207         return 0;
208 }