Give the tun-interface an IPv4-Address
[oweals/gnunet.git] / src / vpn / gnunet-helper-vpn.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-daemon-vpn.c
23  * @brief
24  * @author Philipp Tölke
25  */
26 #define _GNU_SOURCE
27 #include <arpa/inet.h>
28 #include <linux/if.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36
37 #include <string.h>
38
39 #include <signal.h>
40
41 #include <stdio.h>
42 #include <unistd.h>
43
44 #include "gnunet-vpn-tun.h"
45 #include "gnunet_common.h"
46 #include "gnunet_protocols.h"
47 #include "gnunet-vpn-helper-p.h"
48
49 #ifndef _LINUX_IN6_H
50 // This is in linux/include/net/ipv6.h.
51
52 #define MAX_SIZE (65535 - sizeof(struct GNUNET_MessageHeader))
53
54 struct in6_ifreq {
55     struct in6_addr ifr6_addr;
56     __u32 ifr6_prefixlen;
57     unsigned int ifr6_ifindex;
58 };
59
60 #endif
61
62 int running = 1;
63
64 void term(int sig) {
65         fprintf(stderr, "Got SIGTERM...\n");
66         if (sig == SIGTERM)
67                 running = 0;
68 }
69
70 static void set_address6(char* dev, char* address, unsigned long prefix_len) { /* {{{ */
71         int fd = socket(AF_INET6, SOCK_DGRAM, 0);
72
73         struct ifreq ifr;
74         struct in6_ifreq ifr6;
75
76         struct sockaddr_in6 sa6;
77         memset(&sa6, 0, sizeof(struct sockaddr_in6));
78
79         sa6.sin6_family = AF_INET6;
80
81         /* FIXME */ inet_pton(AF_INET6, address, sa6.sin6_addr.s6_addr);
82
83         memcpy((char *) &ifr6.ifr6_addr, (char *) &sa6.sin6_addr, sizeof(struct in6_addr));
84
85         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
86
87         if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
88                 perror("SIOGIFINDEX");
89         }
90
91         ifr6.ifr6_ifindex = ifr.ifr_ifindex;
92         ifr6.ifr6_prefixlen = prefix_len;
93
94         if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
95                 perror("SIOCSIFADDR");
96         }
97
98         /* FIXME */ ioctl(fd, SIOCGIFFLAGS, &ifr);
99         ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
100         /* FIXME */ ioctl(fd, SIOCSIFFLAGS, &ifr);
101 } /* }}} */
102
103 static void set_address4(char* dev, char* address, char* mask) { /* {{{ */
104         int fd=0;
105         struct sockaddr_in* addr;
106         struct ifreq ifr;
107
108         memset(&ifr, 0, sizeof(struct ifreq));
109         addr = (struct sockaddr_in *)&(ifr.ifr_addr);
110         memset(addr, 0, sizeof(struct sockaddr_in));
111         addr->sin_family = AF_INET;
112         addr->sin_addr.s_addr = inet_addr(address);
113
114         /* FIXME */ inet_pton(AF_INET, address, &addr->sin_addr.s_addr);
115
116         fd = socket(PF_INET, SOCK_DGRAM, 0);
117         if(fd < 0) {
118                 perror("socket()");
119                 return;
120         }
121
122         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
123
124         if(ioctl(fd, SIOCSIFADDR, &ifr) != 0 ) {
125                 perror("SIOCSIFADDR");
126                 close(fd);
127                 return;
128         }
129
130         addr = (struct sockaddr_in*)&(ifr.ifr_netmask);
131         /* FIXME */ inet_pton(AF_INET, mask, &addr->sin_addr.s_addr);
132
133         if(ioctl(fd, SIOCSIFNETMASK, &ifr) != 0 ) {
134                 perror("SIOCSIFNETMASK");
135                 close(fd);
136                 return;
137         }
138
139         /* FIXME */ ioctl(fd, SIOCGIFFLAGS, &ifr);
140         ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
141         /* FIXME */ ioctl(fd, SIOCSIFFLAGS, &ifr);
142 } /* }}} */
143
144 void setnonblocking(int fd) {/*{{{*/
145         int opts;
146
147         opts = fcntl(fd,F_GETFL);
148         if (opts < 0) {
149                         perror("fcntl(F_GETFL)");
150         }
151         opts = (opts | O_NONBLOCK);
152         if (fcntl(fd,F_SETFL,opts) < 0) {
153                         perror("fcntl(F_SETFL)");
154         }
155         return;
156 }/*}}}*/
157
158 int main(int argc, char** argv) {
159         unsigned char buf[MAX_SIZE];
160
161         char dev[IFNAMSIZ];
162         memset(dev, 0, IFNAMSIZ);
163
164         signal(SIGTERM, &term);
165
166         int fd_tun = init_tun(dev);
167
168         if (fd_tun < 0) {
169                 fprintf(stderr, "Could not initialize tun-interface: %m\n");
170                 exit(1);
171         }
172
173         fprintf(stderr, "Initialized the interface %s as %d.\n", dev, fd_tun);
174
175         {
176         // TODO: get this out of argv
177         char address[] = "1234::1";
178         unsigned long prefix_len = 16;
179
180         set_address6(dev, address, prefix_len);
181         }
182
183         {
184         char address[] = "10.10.10.1";
185         char mask[] = "255.255.255.252";
186
187         set_address4(dev, address, mask);
188         }
189
190         uid_t uid = getuid ();
191         if (setresuid (uid, uid, uid) != 0 )
192                 fprintf (stderr, "Failed to setresuid: %m\n");
193
194         setnonblocking(0);
195         setnonblocking(1);
196         setnonblocking(fd_tun);
197
198         fd_set fds_w;
199         fd_set fds_r;
200
201         int rea = 1;
202         int wri = 1;
203
204         int write_fd_possible = 0;
205         int write_stdout_possible = 0;
206 outer:
207         while((rea == 1 || wri == 1) && running == 1) {
208                 FD_ZERO(&fds_w);
209                 FD_ZERO(&fds_r);
210
211                 if (rea) {
212                         FD_SET(fd_tun, &fds_r);
213                         if (!write_stdout_possible)
214                                 FD_SET(1, &fds_w);
215                 }
216
217                 if (wri) {
218                         FD_SET(0, &fds_r);
219                         if (!write_fd_possible)
220                                 FD_SET(fd_tun, &fds_w);
221                 }
222
223                 int r = select(fd_tun+1, &fds_r, &fds_w, (fd_set*)0, 0);
224
225                 if(r > 0) {
226                         if (FD_ISSET(fd_tun, &fds_w)) write_fd_possible = 1;
227                         if (FD_ISSET(1, &fds_w)) write_stdout_possible = 1;
228
229                         if (FD_ISSET(0, &fds_r) && write_fd_possible) {
230                                 write_fd_possible = 0;
231                                 struct suid_packet *pkt = (struct suid_packet*) buf;
232                                 r = read(0, buf, sizeof(struct GNUNET_MessageHeader));
233                                 if (r <= 0) {
234                                         fprintf(stderr, "read-error: %m\n");
235                                         shutdown(fd_tun, SHUT_WR);
236                                         shutdown(0, SHUT_RD);
237                                         wri=0;
238                                         goto outer;
239                                 }
240                                 while (r < ntohs(pkt->hdr.size)) {
241                                         int t = read(0, buf + r, ntohs(pkt->hdr.size) - r);
242                                         if (r < 0) {
243                                                 fprintf(stderr, "read-error: %m\n");
244                                                 shutdown(fd_tun, SHUT_WR);
245                                                 shutdown(0, SHUT_RD);
246                                                 wri=0;
247                                                 goto outer;
248                                         }
249                                         r += t;
250                                 }
251                                 r = 0;
252                                 while (r < ntohs(pkt->hdr.size) - sizeof(struct GNUNET_MessageHeader)) {
253                                         int t = write(fd_tun, pkt->data, ntohs(pkt->hdr.size) - sizeof(struct GNUNET_MessageHeader) - r);
254                                         if (t < 0) {
255                                                 fprintf(stderr, "write-error 3: %m\n");
256                                                 shutdown(fd_tun, SHUT_WR);
257                                                 shutdown(0, SHUT_RD);
258                                                 wri = 0;
259                                                 goto outer;
260                                         }
261                                         r += t;
262                                 }
263                         } else if (write_stdout_possible && FD_ISSET(fd_tun, &fds_r)) {
264                                 write_stdout_possible = 0;
265                                 r = read(fd_tun, buf, MAX_SIZE);
266                                 if (r <= 0) {
267                                         fprintf(stderr, "read-error: %m\n");
268                                         shutdown(fd_tun, SHUT_RD);
269                                         shutdown(1, SHUT_WR);
270                                         rea = 0;
271                                         goto outer;
272                                 }
273                                 struct GNUNET_MessageHeader hdr = { .size = htons(r + sizeof(struct GNUNET_MessageHeader)), .type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER) };
274                                 r = 0;
275                                 while(r < sizeof(struct GNUNET_MessageHeader)) {
276                                         int t = write(1, &hdr, sizeof(struct GNUNET_MessageHeader) - r);
277                                         if (t < 0) {
278                                                 fprintf(stderr, "write-error 2: %m\n");
279                                                 shutdown(fd_tun, SHUT_RD);
280                                                 shutdown(1, SHUT_WR);
281                                                 rea = 0;
282                                                 goto outer;
283                                         }
284                                         r += t;
285                                 }
286                                 while(r < ntohs(hdr.size)) {
287                                         int t = write(1, buf, ntohs(hdr.size) - r);
288                                         if (t < 0) {
289                                                 fprintf(stderr, "write-error 1: %m, written %d/%d\n", r, ntohs(hdr.size));
290                                                 shutdown(fd_tun, SHUT_RD);
291                                                 shutdown(1, SHUT_WR);
292                                                 rea = 0;
293                                                 goto outer;
294                                         }
295                                         r += t;
296                                 }
297                         }
298                 }
299         }
300         fprintf(stderr, "Quitting!\n");
301
302         return 0;
303 }