mysql hacking
[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_address(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 void setnonblocking(int fd) {/*{{{*/
104         int opts;
105
106         opts = fcntl(fd,F_GETFL);
107         if (opts < 0) {
108                         perror("fcntl(F_GETFL)");
109         }
110         opts = (opts | O_NONBLOCK);
111         if (fcntl(fd,F_SETFL,opts) < 0) {
112                         perror("fcntl(F_SETFL)");
113         }
114         return;
115 }/*}}}*/
116
117 int main(int argc, char** argv) {
118         unsigned char buf[MAX_SIZE];
119
120         char dev[IFNAMSIZ];
121         memset(dev, 0, IFNAMSIZ);
122
123         signal(SIGTERM, &term);
124
125         int fd_tun = init_tun(dev);
126
127         if (fd_tun < 0) {
128                 fprintf(stderr, "Could not initialize tun-interface: %m\n");
129                 exit(1);
130         }
131
132         fprintf(stderr, "Initialized the interface %s as %d.\n", dev, fd_tun);
133
134         // TODO: get this out of argv
135         char address[] = "1234::1";
136         unsigned long prefix_len = 16;
137
138         set_address(dev, address, prefix_len);
139
140         uid_t uid = getuid ();
141         if (setresuid (uid, uid, uid) != 0 )
142                 fprintf (stderr, "Failed to setresuid: %m\n");
143
144         setnonblocking(0);
145         setnonblocking(1);
146         setnonblocking(fd_tun);
147
148         fd_set fds_w;
149         fd_set fds_r;
150
151         int rea = 1;
152         int wri = 1;
153
154         int write_fd_possible = 0;
155         int write_stdout_possible = 0;
156 outer:
157         while((rea == 1 || wri == 1) && running == 1) {
158                 FD_ZERO(&fds_w);
159                 FD_ZERO(&fds_r);
160
161                 if (rea) {
162                         FD_SET(fd_tun, &fds_r);
163                         if (!write_stdout_possible)
164                                 FD_SET(1, &fds_w);
165                 }
166
167                 if (wri) {
168                         FD_SET(0, &fds_r);
169                         if (!write_fd_possible)
170                                 FD_SET(fd_tun, &fds_w);
171                 }
172
173                 int r = select(fd_tun+1, &fds_r, &fds_w, (fd_set*)0, 0);
174
175                 if(r > 0) {
176                         if (FD_ISSET(fd_tun, &fds_w)) write_fd_possible = 1;
177                         if (FD_ISSET(1, &fds_w)) write_stdout_possible = 1;
178
179                         if (FD_ISSET(0, &fds_r) && write_fd_possible) {
180                                 write_fd_possible = 0;
181                                 struct suid_packet *pkt = (struct suid_packet*) buf;
182                                 r = read(0, buf, sizeof(struct GNUNET_MessageHeader));
183                                 if (r <= 0) {
184                                         fprintf(stderr, "read-error: %m\n");
185                                         shutdown(fd_tun, SHUT_WR);
186                                         shutdown(0, SHUT_RD);
187                                         wri=0;
188                                         goto outer;
189                                 }
190                                 while (r < ntohs(pkt->hdr.size)) {
191                                         int t = read(0, buf + r, ntohs(pkt->hdr.size) - r);
192                                         if (r < 0) {
193                                                 fprintf(stderr, "read-error: %m\n");
194                                                 shutdown(fd_tun, SHUT_WR);
195                                                 shutdown(0, SHUT_RD);
196                                                 wri=0;
197                                                 goto outer;
198                                         }
199                                         r += t;
200                                 }
201                                 r = 0;
202                                 while (r < ntohs(pkt->hdr.size) - sizeof(struct GNUNET_MessageHeader)) {
203                                         int t = write(fd_tun, pkt->data, ntohs(pkt->hdr.size) - sizeof(struct GNUNET_MessageHeader) - r);
204                                         if (t < 0) {
205                                                 fprintf(stderr, "write-error 3: %m\n");
206                                                 shutdown(fd_tun, SHUT_WR);
207                                                 shutdown(0, SHUT_RD);
208                                                 wri = 0;
209                                                 goto outer;
210                                         }
211                                         r += t;
212                                 }
213                         } else if (write_stdout_possible && FD_ISSET(fd_tun, &fds_r)) {
214                                 write_stdout_possible = 0;
215                                 r = read(fd_tun, buf, MAX_SIZE);
216                                 if (r <= 0) {
217                                         fprintf(stderr, "read-error: %m\n");
218                                         shutdown(fd_tun, SHUT_RD);
219                                         shutdown(1, SHUT_WR);
220                                         rea = 0;
221                                         goto outer;
222                                 }
223                                 struct GNUNET_MessageHeader hdr = { .size = htons(r + sizeof(struct GNUNET_MessageHeader)), .type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER) };
224                                 r = 0;
225                                 while(r < sizeof(struct GNUNET_MessageHeader)) {
226                                         int t = write(1, &hdr, sizeof(struct GNUNET_MessageHeader) - r);
227                                         if (t < 0) {
228                                                 fprintf(stderr, "write-error 2: %m\n");
229                                                 shutdown(fd_tun, SHUT_RD);
230                                                 shutdown(1, SHUT_WR);
231                                                 rea = 0;
232                                                 goto outer;
233                                         }
234                                         r += t;
235                                 }
236                                 while(r < ntohs(hdr.size)) {
237                                         int t = write(1, buf, ntohs(hdr.size) - r);
238                                         if (t < 0) {
239                                                 fprintf(stderr, "write-error 1: %m, written %d/%d\n", r, ntohs(hdr.size));
240                                                 shutdown(fd_tun, SHUT_RD);
241                                                 shutdown(1, SHUT_WR);
242                                                 rea = 0;
243                                                 goto outer;
244                                         }
245                                         r += t;
246                                 }
247                         }
248                 }
249         }
250         fprintf(stderr, "Quitting!\n");
251
252         return 0;
253 }