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