diff options
Diffstat (limited to 'src/dns/gnunet-helper-dns.c')
-rw-r--r-- | src/dns/gnunet-helper-dns.c | 1195 |
1 files changed, 0 insertions, 1195 deletions
diff --git a/src/dns/gnunet-helper-dns.c b/src/dns/gnunet-helper-dns.c deleted file mode 100644 index f0e39464d..000000000 --- a/src/dns/gnunet-helper-dns.c +++ /dev/null | |||
@@ -1,1195 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2011, 2012 Christian Grothoff | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file dns/gnunet-helper-dns.c | ||
23 | * @brief helper to install firewall rules to hijack all DNS traffic | ||
24 | * and send it to our virtual interface (except for DNS traffic | ||
25 | * that originates on the specified port). We then | ||
26 | * allow interacting with our virtual interface via stdin/stdout. | ||
27 | * @author Philipp Tölke | ||
28 | * @author Christian Grothoff | ||
29 | * | ||
30 | * This program alters the Linux firewall rules so that DNS traffic | ||
31 | * that ordinarily exits the system can be intercepted and managed by | ||
32 | * a virtual interface. In order to achieve this, DNS traffic is | ||
33 | * marked with the DNS_MARK given in below and re-routed to a custom | ||
34 | * table with the DNS_TABLE ID given below. Systems and | ||
35 | * administrators must take care to not cause conflicts with these | ||
36 | * values (it was deemed safest to hardcode them as passing these | ||
37 | * values as arguments might permit messing with arbitrary firewall | ||
38 | * rules, which would be dangerous). Traffic coming from the same | ||
39 | * group ID as the effective group ID that this process is running | ||
40 | * as is not intercepted. | ||
41 | * | ||
42 | * The code first sets up the virtual interface, then begins to | ||
43 | * redirect the DNS traffic to it, and then on errors or SIGTERM shuts | ||
44 | * down the virtual interface and removes the rules for the traffic | ||
45 | * redirection. | ||
46 | * | ||
47 | * | ||
48 | * Note that having this binary SUID is only partially safe: it will | ||
49 | * allow redirecting (and intercepting / mangling) of all DNS traffic | ||
50 | * originating from this system by any user who is able to run it. | ||
51 | * Furthermore, this code will make it trivial to DoS all DNS traffic | ||
52 | * originating from the current system, simply by sending it to | ||
53 | * nowhere (redirect stdout to /dev/null). | ||
54 | * | ||
55 | * Naturally, neither of these problems can be helped as this is the | ||
56 | * fundamental purpose of the binary. Certifying that this code is | ||
57 | * "safe" thus only means that it doesn't allow anything else (such | ||
58 | * as local priv. escalation, etc.). | ||
59 | * | ||
60 | * The following list of people have reviewed this code and considered | ||
61 | * it safe (within specifications) since the last modification (if you | ||
62 | * reviewed it, please have your name added to the list): | ||
63 | * | ||
64 | * - Christian Grothoff | ||
65 | */ | ||
66 | #include "platform.h" | ||
67 | |||
68 | #ifdef IF_TUN_HDR | ||
69 | #include IF_TUN_HDR | ||
70 | #endif | ||
71 | |||
72 | /** | ||
73 | * Need 'struct GNUNET_MessageHeader'. | ||
74 | */ | ||
75 | #include "gnunet_crypto_lib.h" | ||
76 | #include "gnunet_common.h" | ||
77 | |||
78 | /** | ||
79 | * Need DNS message types. | ||
80 | */ | ||
81 | #include "gnunet_protocols.h" | ||
82 | |||
83 | /** | ||
84 | * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE) | ||
85 | */ | ||
86 | #define MAX_SIZE 65536 | ||
87 | |||
88 | #if ! HAVE_DECL_STRUCT_IN6_IFREQ | ||
89 | /** | ||
90 | * This is in linux/include/net/ipv6.h, but not always exported... | ||
91 | */ | ||
92 | struct in6_ifreq | ||
93 | { | ||
94 | struct in6_addr ifr6_addr; | ||
95 | uint32_t ifr6_prefixlen; | ||
96 | unsigned int ifr6_ifindex; | ||
97 | }; | ||
98 | #endif | ||
99 | |||
100 | /** | ||
101 | * Name and full path of IPTABLES binary. | ||
102 | */ | ||
103 | static const char *sbin_iptables; | ||
104 | |||
105 | /** | ||
106 | * Name and full path of IPTABLES binary. | ||
107 | */ | ||
108 | static const char *sbin_ip6tables; | ||
109 | |||
110 | /** | ||
111 | * Name and full path of sysctl binary | ||
112 | */ | ||
113 | static const char *sbin_sysctl; | ||
114 | |||
115 | /** | ||
116 | * Name and full path of IPTABLES binary. | ||
117 | */ | ||
118 | static const char *sbin_ip; | ||
119 | |||
120 | /** | ||
121 | * Port for DNS traffic. | ||
122 | */ | ||
123 | #define DNS_PORT "53" | ||
124 | |||
125 | /** | ||
126 | * Marker we set for our hijacked DNS traffic. We use GNUnet's | ||
127 | * port (2086) plus the DNS port (53) in HEX to make a 32-bit mark | ||
128 | * (which is hopefully long enough to not collide); so | ||
129 | * 0x08260035 = 136708149 (hopefully unique enough...). | ||
130 | */ | ||
131 | #define DNS_MARK "136708149" | ||
132 | |||
133 | /** | ||
134 | * Table we use for our DNS rules. 0-255 is the range and | ||
135 | * 0, 253, 254 and 255 are already reserved. As this is about | ||
136 | * DNS and as "53" is likely (fingers crossed!) high enough to | ||
137 | * not usually conflict with a normal user's setup, we use 53 | ||
138 | * to give a hint that this has something to do with DNS. | ||
139 | */ | ||
140 | #define DNS_TABLE "53" | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Control pipe for shutdown via signal. [0] is the read end, | ||
145 | * [1] is the write end. | ||
146 | */ | ||
147 | static int cpipe[2]; | ||
148 | |||
149 | |||
150 | /** | ||
151 | * Signal handler called to initiate "nice" shutdown. Signals select | ||
152 | * loop via non-bocking pipe 'cpipe'. | ||
153 | * | ||
154 | * @param signal signal number of the signal (not used) | ||
155 | */ | ||
156 | static void | ||
157 | signal_handler (int signal) | ||
158 | { | ||
159 | /* ignore return value, as the signal handler could theoretically | ||
160 | be called many times before the shutdown can actually happen */ | ||
161 | (void) write (cpipe[1], "K", 1); | ||
162 | } | ||
163 | |||
164 | |||
165 | /** | ||
166 | * Open '/dev/null' and make the result the given | ||
167 | * file descriptor. | ||
168 | * | ||
169 | * @param target_fd desired FD to point to /dev/null | ||
170 | * @param flags open flags (O_RDONLY, O_WRONLY) | ||
171 | */ | ||
172 | static void | ||
173 | open_dev_null (int target_fd, | ||
174 | int flags) | ||
175 | { | ||
176 | int fd; | ||
177 | |||
178 | fd = open ("/dev/null", flags); | ||
179 | if (-1 == fd) | ||
180 | abort (); | ||
181 | if (fd == target_fd) | ||
182 | return; | ||
183 | if (-1 == dup2 (fd, target_fd)) | ||
184 | { | ||
185 | (void) close (fd); | ||
186 | abort (); | ||
187 | } | ||
188 | (void) close (fd); | ||
189 | } | ||
190 | |||
191 | |||
192 | /** | ||
193 | * Run the given command and wait for it to complete. | ||
194 | * | ||
195 | * @param file name of the binary to run | ||
196 | * @param cmd command line arguments (as given to 'execv') | ||
197 | * @return 0 on success, 1 on any error | ||
198 | */ | ||
199 | static int | ||
200 | fork_and_exec (const char *file, | ||
201 | char *const cmd[]) | ||
202 | { | ||
203 | int status; | ||
204 | pid_t pid; | ||
205 | pid_t ret; | ||
206 | |||
207 | pid = fork (); | ||
208 | if (-1 == pid) | ||
209 | { | ||
210 | fprintf (stderr, | ||
211 | "fork failed: %s\n", | ||
212 | strerror (errno)); | ||
213 | return 1; | ||
214 | } | ||
215 | if (0 == pid) | ||
216 | { | ||
217 | /* we are the child process */ | ||
218 | /* close stdin/stdout to not cause interference | ||
219 | with the helper's main protocol! */ | ||
220 | (void) close (0); | ||
221 | open_dev_null (0, O_RDONLY); | ||
222 | (void) close (1); | ||
223 | open_dev_null (1, O_WRONLY); | ||
224 | (void) execv (file, cmd); | ||
225 | /* can only get here on error */ | ||
226 | fprintf (stderr, | ||
227 | "exec `%s' failed: %s\n", | ||
228 | file, | ||
229 | strerror (errno)); | ||
230 | _exit (1); | ||
231 | } | ||
232 | /* keep running waitpid as long as the only error we get is 'EINTR' */ | ||
233 | while ((-1 == (ret = waitpid (pid, &status, 0))) && | ||
234 | (errno == EINTR)) | ||
235 | ; | ||
236 | if (-1 == ret) | ||
237 | { | ||
238 | fprintf (stderr, | ||
239 | "waitpid failed: %s\n", | ||
240 | strerror (errno)); | ||
241 | return 1; | ||
242 | } | ||
243 | if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status)))) | ||
244 | return 1; | ||
245 | /* child process completed and returned success, we're happy */ | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Creates a tun-interface called @a dev; | ||
252 | * | ||
253 | * @param dev is assumed to point to a char[IFNAMSIZ] | ||
254 | * if *dev == '\\0', uses the name supplied by the kernel; | ||
255 | * @return the fd to the tun or -1 on error | ||
256 | */ | ||
257 | static int | ||
258 | init_tun (char *dev) | ||
259 | { | ||
260 | struct ifreq ifr; | ||
261 | int fd; | ||
262 | |||
263 | if (NULL == dev) | ||
264 | { | ||
265 | errno = EINVAL; | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | if (-1 == (fd = open ("/dev/net/tun", O_RDWR))) | ||
270 | { | ||
271 | fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun", | ||
272 | strerror (errno)); | ||
273 | return -1; | ||
274 | } | ||
275 | |||
276 | if (fd >= FD_SETSIZE) | ||
277 | { | ||
278 | fprintf (stderr, "File descriptor to large: %d", fd); | ||
279 | (void) close (fd); | ||
280 | return -1; | ||
281 | } | ||
282 | |||
283 | memset (&ifr, 0, sizeof(ifr)); | ||
284 | ifr.ifr_flags = IFF_TUN; | ||
285 | |||
286 | if ('\0' != *dev) | ||
287 | strncpy (ifr.ifr_name, dev, IFNAMSIZ); | ||
288 | |||
289 | if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr)) | ||
290 | { | ||
291 | fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun", | ||
292 | strerror (errno)); | ||
293 | (void) close (fd); | ||
294 | return -1; | ||
295 | } | ||
296 | strcpy (dev, ifr.ifr_name); | ||
297 | return fd; | ||
298 | } | ||
299 | |||
300 | |||
301 | /** | ||
302 | * @brief Sets the IPv6-Address given in @a address on the interface @a dev | ||
303 | * | ||
304 | * @param dev the interface to configure | ||
305 | * @param address the IPv6-Address | ||
306 | * @param prefix_len the length of the network-prefix | ||
307 | */ | ||
308 | static void | ||
309 | set_address6 (const char *dev, const char *address, unsigned long prefix_len) | ||
310 | { | ||
311 | struct ifreq ifr; | ||
312 | struct in6_ifreq ifr6; | ||
313 | struct sockaddr_in6 sa6; | ||
314 | int fd; | ||
315 | |||
316 | /* | ||
317 | * parse the new address | ||
318 | */ | ||
319 | memset (&sa6, 0, sizeof(struct sockaddr_in6)); | ||
320 | sa6.sin6_family = AF_INET6; | ||
321 | if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr)) | ||
322 | { | ||
323 | fprintf (stderr, | ||
324 | "Failed to parse IPv6 address `%s': %s\n", | ||
325 | address, | ||
326 | strerror (errno)); | ||
327 | exit (1); | ||
328 | } | ||
329 | |||
330 | if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0))) | ||
331 | { | ||
332 | fprintf (stderr, | ||
333 | "Error creating IPv6 socket: %s (ignored)\n", | ||
334 | strerror (errno)); | ||
335 | /* ignore error, maybe only IPv4 works on this system! */ | ||
336 | return; | ||
337 | } | ||
338 | |||
339 | memset (&ifr, 0, sizeof(struct ifreq)); | ||
340 | /* | ||
341 | * Get the index of the if | ||
342 | */ | ||
343 | strncpy (ifr.ifr_name, dev, IFNAMSIZ); | ||
344 | if (-1 == ioctl (fd, SIOGIFINDEX, &ifr)) | ||
345 | { | ||
346 | fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); | ||
347 | (void) close (fd); | ||
348 | exit (1); | ||
349 | } | ||
350 | |||
351 | memset (&ifr6, 0, sizeof(struct in6_ifreq)); | ||
352 | ifr6.ifr6_addr = sa6.sin6_addr; | ||
353 | ifr6.ifr6_ifindex = ifr.ifr_ifindex; | ||
354 | ifr6.ifr6_prefixlen = prefix_len; | ||
355 | |||
356 | /* | ||
357 | * Set the address | ||
358 | */ | ||
359 | if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6)) | ||
360 | { | ||
361 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
362 | strerror (errno)); | ||
363 | (void) close (fd); | ||
364 | exit (1); | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * Get the flags | ||
369 | */ | ||
370 | if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) | ||
371 | { | ||
372 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
373 | strerror (errno)); | ||
374 | (void) close (fd); | ||
375 | exit (1); | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * Add the UP and RUNNING flags | ||
380 | */ | ||
381 | ifr.ifr_flags |= IFF_UP | IFF_RUNNING; | ||
382 | if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) | ||
383 | { | ||
384 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
385 | strerror (errno)); | ||
386 | (void) close (fd); | ||
387 | exit (1); | ||
388 | } | ||
389 | |||
390 | if (0 != close (fd)) | ||
391 | { | ||
392 | fprintf (stderr, "close failed: %s\n", strerror (errno)); | ||
393 | exit (1); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | |||
398 | /** | ||
399 | * @brief Sets the IPv4-Address given in @a address on the interface @a dev | ||
400 | * | ||
401 | * @param dev the interface to configure | ||
402 | * @param address the IPv4-Address | ||
403 | * @param mask the netmask | ||
404 | */ | ||
405 | static void | ||
406 | set_address4 (const char *dev, const char *address, const char *mask) | ||
407 | { | ||
408 | int fd; | ||
409 | struct sockaddr_in *addr; | ||
410 | struct ifreq ifr; | ||
411 | |||
412 | memset (&ifr, 0, sizeof(struct ifreq)); | ||
413 | addr = (struct sockaddr_in *) &(ifr.ifr_addr); | ||
414 | addr->sin_family = AF_INET; | ||
415 | |||
416 | /* | ||
417 | * Parse the address | ||
418 | */ | ||
419 | if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr)) | ||
420 | { | ||
421 | fprintf (stderr, | ||
422 | "Failed to parse IPv4 address `%s': %s\n", | ||
423 | address, | ||
424 | strerror (errno)); | ||
425 | exit (1); | ||
426 | } | ||
427 | |||
428 | if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0))) | ||
429 | { | ||
430 | fprintf (stderr, | ||
431 | "Error creating IPv4 socket: %s\n", | ||
432 | strerror (errno)); | ||
433 | exit (1); | ||
434 | } | ||
435 | |||
436 | strncpy (ifr.ifr_name, dev, IFNAMSIZ); | ||
437 | |||
438 | /* | ||
439 | * Set the address | ||
440 | */ | ||
441 | if (-1 == ioctl (fd, SIOCSIFADDR, &ifr)) | ||
442 | { | ||
443 | fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); | ||
444 | (void) close (fd); | ||
445 | exit (1); | ||
446 | } | ||
447 | |||
448 | /* | ||
449 | * Parse the netmask | ||
450 | */ | ||
451 | addr = (struct sockaddr_in *) &(ifr.ifr_netmask); | ||
452 | if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr)) | ||
453 | { | ||
454 | fprintf (stderr, "Failed to parse address `%s': %s\n", mask, | ||
455 | strerror (errno)); | ||
456 | (void) close (fd); | ||
457 | exit (1); | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * Set the netmask | ||
462 | */ | ||
463 | if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr)) | ||
464 | { | ||
465 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
466 | strerror (errno)); | ||
467 | (void) close (fd); | ||
468 | exit (1); | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * Get the flags | ||
473 | */ | ||
474 | if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) | ||
475 | { | ||
476 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
477 | strerror (errno)); | ||
478 | (void) close (fd); | ||
479 | exit (1); | ||
480 | } | ||
481 | |||
482 | /* | ||
483 | * Add the UP and RUNNING flags | ||
484 | */ | ||
485 | ifr.ifr_flags |= IFF_UP | IFF_RUNNING; | ||
486 | if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) | ||
487 | { | ||
488 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
489 | strerror (errno)); | ||
490 | (void) close (fd); | ||
491 | exit (1); | ||
492 | } | ||
493 | |||
494 | if (0 != close (fd)) | ||
495 | { | ||
496 | fprintf (stderr, "close failed: %s\n", strerror (errno)); | ||
497 | (void) close (fd); | ||
498 | exit (1); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | |||
503 | /** | ||
504 | * Start forwarding to and from the tunnel. This function runs with | ||
505 | * "reduced" privileges (saved UID is still 0, but effective UID is | ||
506 | * the real user ID). | ||
507 | * | ||
508 | * @param fd_tun tunnel FD | ||
509 | */ | ||
510 | static void | ||
511 | run (int fd_tun) | ||
512 | { | ||
513 | /* | ||
514 | * The buffer filled by reading from fd_tun | ||
515 | */ | ||
516 | unsigned char buftun[MAX_SIZE]; | ||
517 | ssize_t buftun_size = 0; | ||
518 | unsigned char *buftun_read = NULL; | ||
519 | |||
520 | /* | ||
521 | * The buffer filled by reading from stdin | ||
522 | */ | ||
523 | unsigned char bufin[MAX_SIZE]; | ||
524 | ssize_t bufin_size = 0; | ||
525 | size_t bufin_rpos = 0; | ||
526 | unsigned char *bufin_read = NULL; | ||
527 | fd_set fds_w; | ||
528 | fd_set fds_r; | ||
529 | int max; | ||
530 | |||
531 | while (1) | ||
532 | { | ||
533 | FD_ZERO (&fds_w); | ||
534 | FD_ZERO (&fds_r); | ||
535 | |||
536 | /* | ||
537 | * We are supposed to read and the buffer is empty | ||
538 | * -> select on read from tun | ||
539 | */ | ||
540 | if (0 == buftun_size) | ||
541 | FD_SET (fd_tun, &fds_r); | ||
542 | |||
543 | /* | ||
544 | * We are supposed to read and the buffer is not empty | ||
545 | * -> select on write to stdout | ||
546 | */ | ||
547 | if (0 < buftun_size) | ||
548 | FD_SET (1, &fds_w); | ||
549 | |||
550 | /* | ||
551 | * We are supposed to write and the buffer is empty | ||
552 | * -> select on read from stdin | ||
553 | */ | ||
554 | if (NULL == bufin_read) | ||
555 | FD_SET (0, &fds_r); | ||
556 | |||
557 | /* | ||
558 | * We are supposed to write and the buffer is not empty | ||
559 | * -> select on write to tun | ||
560 | */ | ||
561 | if (NULL != bufin_read) | ||
562 | FD_SET (fd_tun, &fds_w); | ||
563 | |||
564 | FD_SET (cpipe[0], &fds_r); | ||
565 | max = (fd_tun > cpipe[0]) ? fd_tun : cpipe[0]; | ||
566 | |||
567 | int r = select (max + 1, &fds_r, &fds_w, NULL, NULL); | ||
568 | |||
569 | if (-1 == r) | ||
570 | { | ||
571 | if (EINTR == errno) | ||
572 | continue; | ||
573 | fprintf (stderr, "select failed: %s\n", strerror (errno)); | ||
574 | return; | ||
575 | } | ||
576 | |||
577 | if (r > 0) | ||
578 | { | ||
579 | if (FD_ISSET (cpipe[0], &fds_r)) | ||
580 | return; /* aborted by signal */ | ||
581 | |||
582 | if (FD_ISSET (fd_tun, &fds_r)) | ||
583 | { | ||
584 | buftun_size = | ||
585 | read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader), | ||
586 | MAX_SIZE - sizeof(struct GNUNET_MessageHeader)); | ||
587 | if (-1 == buftun_size) | ||
588 | { | ||
589 | if ((errno == EINTR) || | ||
590 | (errno == EAGAIN)) | ||
591 | { | ||
592 | buftun_size = 0; | ||
593 | continue; | ||
594 | } | ||
595 | fprintf (stderr, "read-error: %s\n", strerror (errno)); | ||
596 | return; | ||
597 | } | ||
598 | if (0 == buftun_size) | ||
599 | { | ||
600 | fprintf (stderr, "EOF on tun\n"); | ||
601 | return; | ||
602 | } | ||
603 | buftun_read = buftun; | ||
604 | { | ||
605 | struct GNUNET_MessageHeader *hdr = | ||
606 | (struct GNUNET_MessageHeader *) buftun; | ||
607 | buftun_size += sizeof(struct GNUNET_MessageHeader); | ||
608 | hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER); | ||
609 | hdr->size = htons (buftun_size); | ||
610 | } | ||
611 | } | ||
612 | else if (FD_ISSET (1, &fds_w)) | ||
613 | { | ||
614 | ssize_t written = write (1, buftun_read, buftun_size); | ||
615 | |||
616 | if (-1 == written) | ||
617 | { | ||
618 | if ((errno == EINTR) || | ||
619 | (errno == EAGAIN)) | ||
620 | continue; | ||
621 | fprintf (stderr, "write-error to stdout: %s\n", strerror (errno)); | ||
622 | return; | ||
623 | } | ||
624 | if (0 == written) | ||
625 | { | ||
626 | fprintf (stderr, "write returned 0\n"); | ||
627 | return; | ||
628 | } | ||
629 | buftun_size -= written; | ||
630 | buftun_read += written; | ||
631 | } | ||
632 | |||
633 | if (FD_ISSET (0, &fds_r)) | ||
634 | { | ||
635 | bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); | ||
636 | if (-1 == bufin_size) | ||
637 | { | ||
638 | bufin_read = NULL; | ||
639 | if ((errno == EINTR) || | ||
640 | (errno == EAGAIN)) | ||
641 | continue; | ||
642 | fprintf (stderr, "read-error: %s\n", strerror (errno)); | ||
643 | return; | ||
644 | } | ||
645 | if (0 == bufin_size) | ||
646 | { | ||
647 | bufin_read = NULL; | ||
648 | fprintf (stderr, "EOF on stdin\n"); | ||
649 | return; | ||
650 | } | ||
651 | { | ||
652 | struct GNUNET_MessageHeader *hdr; | ||
653 | |||
654 | PROCESS_BUFFER: | ||
655 | bufin_rpos += bufin_size; | ||
656 | if (bufin_rpos < sizeof(struct GNUNET_MessageHeader)) | ||
657 | continue; | ||
658 | hdr = (struct GNUNET_MessageHeader *) bufin; | ||
659 | if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_DNS_HELPER) | ||
660 | { | ||
661 | fprintf (stderr, "protocol violation!\n"); | ||
662 | return; | ||
663 | } | ||
664 | if (ntohs (hdr->size) > bufin_rpos) | ||
665 | continue; | ||
666 | bufin_read = bufin + sizeof(struct GNUNET_MessageHeader); | ||
667 | bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader); | ||
668 | bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader); | ||
669 | } | ||
670 | } | ||
671 | else if (FD_ISSET (fd_tun, &fds_w)) | ||
672 | { | ||
673 | ssize_t written = write (fd_tun, bufin_read, bufin_size); | ||
674 | |||
675 | if (-1 == written) | ||
676 | { | ||
677 | if ((errno == EINTR) || | ||
678 | (errno == EAGAIN)) | ||
679 | continue; | ||
680 | fprintf (stderr, "write-error to tun: %s\n", strerror (errno)); | ||
681 | return; | ||
682 | } | ||
683 | if (0 == written) | ||
684 | { | ||
685 | fprintf (stderr, "write returned 0\n"); | ||
686 | return; | ||
687 | } | ||
688 | { | ||
689 | bufin_size -= written; | ||
690 | bufin_read += written; | ||
691 | if (0 == bufin_size) | ||
692 | { | ||
693 | memmove (bufin, bufin_read, bufin_rpos); | ||
694 | bufin_read = NULL; /* start reading again */ | ||
695 | bufin_size = 0; | ||
696 | goto PROCESS_BUFFER; | ||
697 | } | ||
698 | } | ||
699 | } | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | |||
704 | |||
705 | /** | ||
706 | * Main function of "gnunet-helper-dns", which opens a VPN tunnel interface, | ||
707 | * redirects all outgoing DNS traffic (except from the specified port) to that | ||
708 | * interface and then passes traffic from and to the interface via stdin/stdout. | ||
709 | * | ||
710 | * Once stdin/stdout close or have other errors, the tunnel is closed and the | ||
711 | * DNS traffic redirection is stopped. | ||
712 | * | ||
713 | * @param argc number of arguments | ||
714 | * @param argv 0: binary name (should be "gnunet-helper-vpn") | ||
715 | * 1: tunnel interface name (typically "gnunet-dns") | ||
716 | * 2: IPv6 address for the tunnel ("FE80::1") | ||
717 | * 3: IPv6 netmask length in bits ("64") | ||
718 | * 4: IPv4 address for the tunnel ("1.2.3.4") | ||
719 | * 5: IPv4 netmask ("255.255.0.0") | ||
720 | * 6: skip sysctl, routing and iptables setup ("0") | ||
721 | * @return 0 on success, otherwise code indicating type of error: | ||
722 | * 1 wrong number of arguments | ||
723 | * 2 invalid arguments (i.e. port number / prefix length wrong) | ||
724 | * 3 iptables not executable | ||
725 | * 4 ip not executable | ||
726 | * 5 failed to initialize tunnel interface | ||
727 | * 6 failed to initialize control pipe | ||
728 | * 8 failed to change routing table, cleanup successful | ||
729 | * 9-23 failed to change routing table and failed to undo some changes to routing table | ||
730 | * 24 failed to drop privs | ||
731 | * 25-39 failed to drop privs and then failed to undo some changes to routing table | ||
732 | * 40 failed to regain privs | ||
733 | * 41-55 failed to regain prisv and then failed to undo some changes to routing table | ||
734 | * 254 insufficient privileges | ||
735 | * 255 failed to handle kill signal properly | ||
736 | */ | ||
737 | int | ||
738 | main (int argc, char *const*argv) | ||
739 | { | ||
740 | int r; | ||
741 | char dev[IFNAMSIZ]; | ||
742 | char mygid[32]; | ||
743 | int fd_tun; | ||
744 | uid_t uid; | ||
745 | int nortsetup = 0; | ||
746 | |||
747 | if (7 != argc) | ||
748 | { | ||
749 | fprintf (stderr, "Fatal: must supply 6 arguments!\n"); | ||
750 | return 1; | ||
751 | } | ||
752 | |||
753 | /* assert privs so we can modify the firewall rules! */ | ||
754 | uid = getuid (); | ||
755 | #ifdef HAVE_SETRESUID | ||
756 | if (0 != setresuid (uid, 0, 0)) | ||
757 | { | ||
758 | fprintf (stderr, "Failed to setresuid to root: %s\n", strerror (errno)); | ||
759 | return 254; | ||
760 | } | ||
761 | #else | ||
762 | if (0 != seteuid (0)) | ||
763 | { | ||
764 | fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno)); | ||
765 | return 254; | ||
766 | } | ||
767 | #endif | ||
768 | if (0 == strncmp (argv[6], "1", 2)) | ||
769 | nortsetup = 1; | ||
770 | |||
771 | if (0 == nortsetup) | ||
772 | { | ||
773 | /* verify that the binaries we care about are executable */ | ||
774 | #ifdef IPTABLES | ||
775 | if (0 == access (IPTABLES, X_OK)) | ||
776 | sbin_iptables = IPTABLES; | ||
777 | else | ||
778 | #endif | ||
779 | if (0 == access ("/sbin/iptables", X_OK)) | ||
780 | sbin_iptables = "/sbin/iptables"; | ||
781 | else if (0 == access ("/usr/sbin/iptables", X_OK)) | ||
782 | sbin_iptables = "/usr/sbin/iptables"; | ||
783 | else | ||
784 | { | ||
785 | fprintf (stderr, | ||
786 | "Fatal: executable iptables not found in approved directories: %s\n", | ||
787 | strerror (errno)); | ||
788 | return 3; | ||
789 | } | ||
790 | #ifdef IP6TABLES | ||
791 | if (0 == access (IP6TABLES, X_OK)) | ||
792 | sbin_ip6tables = IP6TABLES; | ||
793 | else | ||
794 | #endif | ||
795 | if (0 == access ("/sbin/ip6tables", X_OK)) | ||
796 | sbin_ip6tables = "/sbin/ip6tables"; | ||
797 | else if (0 == access ("/usr/sbin/ip6tables", X_OK)) | ||
798 | sbin_ip6tables = "/usr/sbin/ip6tables"; | ||
799 | else | ||
800 | { | ||
801 | fprintf (stderr, | ||
802 | "Fatal: executable ip6tables not found in approved directories: %s\n", | ||
803 | strerror (errno)); | ||
804 | return 3; | ||
805 | } | ||
806 | #ifdef PATH_TO_IP | ||
807 | if (0 == access (PATH_TO_IP, X_OK)) | ||
808 | sbin_ip = PATH_TO_IP; | ||
809 | else | ||
810 | #endif | ||
811 | if (0 == access ("/sbin/ip", X_OK)) | ||
812 | sbin_ip = "/sbin/ip"; | ||
813 | else if (0 == access ("/usr/sbin/ip", X_OK)) | ||
814 | sbin_ip = "/usr/sbin/ip"; | ||
815 | else if (0 == access ("/bin/ip", X_OK)) /* gentoo has it there */ | ||
816 | sbin_ip = "/bin/ip"; | ||
817 | else | ||
818 | { | ||
819 | fprintf (stderr, | ||
820 | "Fatal: executable ip not found in approved directories: %s\n", | ||
821 | strerror (errno)); | ||
822 | return 4; | ||
823 | } | ||
824 | #ifdef SYSCTL | ||
825 | if (0 == access (SYSCTL, X_OK)) | ||
826 | sbin_sysctl = SYSCTL; | ||
827 | else | ||
828 | #endif | ||
829 | if (0 == access ("/sbin/sysctl", X_OK)) | ||
830 | sbin_sysctl = "/sbin/sysctl"; | ||
831 | else if (0 == access ("/usr/sbin/sysctl", X_OK)) | ||
832 | sbin_sysctl = "/usr/sbin/sysctl"; | ||
833 | else | ||
834 | { | ||
835 | fprintf (stderr, | ||
836 | "Fatal: executable sysctl not found in approved directories: %s\n", | ||
837 | strerror (errno)); | ||
838 | return 5; | ||
839 | } | ||
840 | } | ||
841 | |||
842 | /* setup 'mygid' string */ | ||
843 | snprintf (mygid, sizeof(mygid), "%d", (int) getegid ()); | ||
844 | |||
845 | /* do not die on SIGPIPE */ | ||
846 | if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) | ||
847 | { | ||
848 | fprintf (stderr, "Failed to protect against SIGPIPE: %s\n", | ||
849 | strerror (errno)); | ||
850 | return 7; | ||
851 | } | ||
852 | |||
853 | /* setup pipe to shutdown nicely on SIGINT */ | ||
854 | if (0 != pipe (cpipe)) | ||
855 | { | ||
856 | fprintf (stderr, | ||
857 | "Fatal: could not setup control pipe: %s\n", | ||
858 | strerror (errno)); | ||
859 | return 6; | ||
860 | } | ||
861 | if (cpipe[0] >= FD_SETSIZE) | ||
862 | { | ||
863 | fprintf (stderr, "Pipe file descriptor to large: %d", cpipe[0]); | ||
864 | (void) close (cpipe[0]); | ||
865 | (void) close (cpipe[1]); | ||
866 | return 6; | ||
867 | } | ||
868 | { | ||
869 | /* make pipe non-blocking, as we theoretically could otherwise block | ||
870 | in the signal handler */ | ||
871 | int flags = fcntl (cpipe[1], F_GETFL); | ||
872 | if (-1 == flags) | ||
873 | { | ||
874 | fprintf (stderr, "Failed to read flags for pipe: %s", strerror (errno)); | ||
875 | (void) close (cpipe[0]); | ||
876 | (void) close (cpipe[1]); | ||
877 | return 6; | ||
878 | } | ||
879 | flags |= O_NONBLOCK; | ||
880 | if (0 != fcntl (cpipe[1], F_SETFL, flags)) | ||
881 | { | ||
882 | fprintf (stderr, "Failed to make pipe non-blocking: %s", strerror ( | ||
883 | errno)); | ||
884 | (void) close (cpipe[0]); | ||
885 | (void) close (cpipe[1]); | ||
886 | return 6; | ||
887 | } | ||
888 | } | ||
889 | if ((SIG_ERR == signal (SIGTERM, &signal_handler)) || | ||
890 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
891 | (SIG_ERR == signal (GNUNET_TERM_SIG, &signal_handler)) || | ||
892 | #endif | ||
893 | (SIG_ERR == signal (SIGINT, &signal_handler)) || | ||
894 | (SIG_ERR == signal (SIGHUP, &signal_handler))) | ||
895 | { | ||
896 | fprintf (stderr, | ||
897 | "Fatal: could not initialize signal handler: %s\n", | ||
898 | strerror (errno)); | ||
899 | (void) close (cpipe[0]); | ||
900 | (void) close (cpipe[1]); | ||
901 | return 7; | ||
902 | } | ||
903 | |||
904 | |||
905 | /* get interface name */ | ||
906 | strncpy (dev, argv[1], IFNAMSIZ); | ||
907 | dev[IFNAMSIZ - 1] = '\0'; | ||
908 | |||
909 | /* Disable rp filtering */ | ||
910 | if (0 == nortsetup) | ||
911 | { | ||
912 | char *const sysctl_args[] = { "sysctl", "-w", | ||
913 | "net.ipv4.conf.all.rp_filter=0", NULL }; | ||
914 | char *const sysctl_args2[] = { "sysctl", "-w", | ||
915 | "net.ipv4.conf.default.rp_filter=0", NULL }; | ||
916 | if ((0 != fork_and_exec (sbin_sysctl, sysctl_args)) || | ||
917 | (0 != fork_and_exec (sbin_sysctl, sysctl_args2))) | ||
918 | { | ||
919 | fprintf (stderr, | ||
920 | "Failed to disable rp filtering.\n"); | ||
921 | return 5; | ||
922 | } | ||
923 | } | ||
924 | |||
925 | |||
926 | /* now open virtual interface (first part that requires root) */ | ||
927 | if (-1 == (fd_tun = init_tun (dev))) | ||
928 | { | ||
929 | fprintf (stderr, "Fatal: could not initialize tun-interface\n"); | ||
930 | (void) signal (SIGTERM, SIG_IGN); | ||
931 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
932 | (void) signal (GNUNET_TERM_SIG, SIG_IGN); | ||
933 | #endif | ||
934 | (void) signal (SIGINT, SIG_IGN); | ||
935 | (void) signal (SIGHUP, SIG_IGN); | ||
936 | (void) close (cpipe[0]); | ||
937 | (void) close (cpipe[1]); | ||
938 | return 5; | ||
939 | } | ||
940 | |||
941 | /* now set interface addresses */ | ||
942 | { | ||
943 | const char *address = argv[2]; | ||
944 | long prefix_len = atol (argv[3]); | ||
945 | |||
946 | if ((prefix_len < 1) || (prefix_len > 127)) | ||
947 | { | ||
948 | fprintf (stderr, "Fatal: prefix_len out of range\n"); | ||
949 | (void) signal (SIGTERM, SIG_IGN); | ||
950 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
951 | (void) signal (GNUNET_TERM_SIG, SIG_IGN); | ||
952 | #endif | ||
953 | (void) signal (SIGINT, SIG_IGN); | ||
954 | (void) signal (SIGHUP, SIG_IGN); | ||
955 | (void) close (cpipe[0]); | ||
956 | (void) close (cpipe[1]); | ||
957 | return 2; | ||
958 | } | ||
959 | set_address6 (dev, address, prefix_len); | ||
960 | } | ||
961 | |||
962 | { | ||
963 | const char *address = argv[4]; | ||
964 | const char *mask = argv[5]; | ||
965 | |||
966 | set_address4 (dev, address, mask); | ||
967 | } | ||
968 | |||
969 | |||
970 | /* update routing tables -- next part why we need SUID! */ | ||
971 | /* Forward everything from our EGID (which should only be held | ||
972 | by the 'gnunet-service-dns') and with destination | ||
973 | to port 53 on UDP, without hijacking */ | ||
974 | if (0 == nortsetup) | ||
975 | { | ||
976 | r = 8; /* failed to fully setup routing table */ | ||
977 | { | ||
978 | char *const mangle_args[] = { | ||
979 | "iptables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p", | ||
980 | "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j", | ||
981 | "ACCEPT", NULL | ||
982 | }; | ||
983 | if (0 != fork_and_exec (sbin_iptables, mangle_args)) | ||
984 | goto cleanup_rest; | ||
985 | } | ||
986 | { | ||
987 | char *const mangle_args[] = { | ||
988 | "ip6tables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p", | ||
989 | "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j", | ||
990 | "ACCEPT", NULL | ||
991 | }; | ||
992 | if (0 != fork_and_exec (sbin_ip6tables, mangle_args)) | ||
993 | goto cleanup_mangle_1b; | ||
994 | } | ||
995 | /* Mark all of the other DNS traffic using our mark DNS_MARK, | ||
996 | unless it is on a link-local IPv6 address, which we cannot support. */ | ||
997 | { | ||
998 | char *const mark_args[] = { | ||
999 | "iptables", "-t", "mangle", "-I", "OUTPUT", "2", "-p", | ||
1000 | "udp", "--dport", DNS_PORT, | ||
1001 | "-j", "MARK", "--set-mark", DNS_MARK, | ||
1002 | NULL | ||
1003 | }; | ||
1004 | if (0 != fork_and_exec (sbin_iptables, mark_args)) | ||
1005 | goto cleanup_mangle_1; | ||
1006 | } | ||
1007 | { | ||
1008 | char *const mark_args[] = { | ||
1009 | "ip6tables", "-t", "mangle", "-I", "OUTPUT", "2", "-p", | ||
1010 | "udp", "--dport", DNS_PORT, | ||
1011 | "!", "-s", "fe80::/10", /* this line excludes link-local traffic */ | ||
1012 | "-j", "MARK", "--set-mark", DNS_MARK, | ||
1013 | NULL | ||
1014 | }; | ||
1015 | if (0 != fork_and_exec (sbin_ip6tables, mark_args)) | ||
1016 | goto cleanup_mark_2b; | ||
1017 | } | ||
1018 | /* Forward all marked DNS traffic to our DNS_TABLE */ | ||
1019 | { | ||
1020 | char *const forward_args[] = { | ||
1021 | "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL | ||
1022 | }; | ||
1023 | if (0 != fork_and_exec (sbin_ip, forward_args)) | ||
1024 | goto cleanup_mark_2; | ||
1025 | } | ||
1026 | { | ||
1027 | char *const forward_args[] = { | ||
1028 | "ip", "-6", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL | ||
1029 | }; | ||
1030 | if (0 != fork_and_exec (sbin_ip, forward_args)) | ||
1031 | goto cleanup_forward_3b; | ||
1032 | } | ||
1033 | /* Finally, add rule in our forwarding table to pass to our virtual interface */ | ||
1034 | { | ||
1035 | char *const route_args[] = { | ||
1036 | "ip", "route", "add", "default", "dev", dev, | ||
1037 | "table", DNS_TABLE, NULL | ||
1038 | }; | ||
1039 | if (0 != fork_and_exec (sbin_ip, route_args)) | ||
1040 | goto cleanup_forward_3; | ||
1041 | } | ||
1042 | { | ||
1043 | char *const route_args[] = { | ||
1044 | "ip", "-6", "route", "add", "default", "dev", dev, | ||
1045 | "table", DNS_TABLE, NULL | ||
1046 | }; | ||
1047 | if (0 != fork_and_exec (sbin_ip, route_args)) | ||
1048 | goto cleanup_route_4b; | ||
1049 | } | ||
1050 | } | ||
1051 | |||
1052 | /* drop privs *except* for the saved UID; this is not perfect, but better | ||
1053 | than doing nothing */ | ||
1054 | #ifdef HAVE_SETRESUID | ||
1055 | if (0 != setresuid (uid, uid, 0)) | ||
1056 | { | ||
1057 | fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); | ||
1058 | r = 24; | ||
1059 | goto cleanup_route_4; | ||
1060 | } | ||
1061 | #else | ||
1062 | /* Note: no 'setuid' here as we must keep our saved UID as root */ | ||
1063 | if (0 != seteuid (uid)) | ||
1064 | { | ||
1065 | fprintf (stderr, "Failed to seteuid: %s\n", strerror (errno)); | ||
1066 | r = 24; | ||
1067 | goto cleanup_route_4; | ||
1068 | } | ||
1069 | #endif | ||
1070 | |||
1071 | r = 0; /* did fully setup routing table (if nothing else happens, we were successful!) */ | ||
1072 | |||
1073 | /* now forward until we hit a problem */ | ||
1074 | run (fd_tun); | ||
1075 | |||
1076 | /* now need to regain privs so we can remove the firewall rules we added! */ | ||
1077 | #ifdef HAVE_SETRESUID | ||
1078 | if (0 != setresuid (uid, 0, 0)) | ||
1079 | { | ||
1080 | fprintf (stderr, "Failed to setresuid back to root: %s\n", strerror ( | ||
1081 | errno)); | ||
1082 | r = 40; | ||
1083 | goto cleanup_route_4; | ||
1084 | } | ||
1085 | #else | ||
1086 | if (0 != seteuid (0)) | ||
1087 | { | ||
1088 | fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno)); | ||
1089 | r = 40; | ||
1090 | goto cleanup_route_4; | ||
1091 | } | ||
1092 | #endif | ||
1093 | |||
1094 | /* update routing tables again -- this is why we could not fully drop privs */ | ||
1095 | /* now undo updating of routing tables; normal exit or clean-up-on-error case */ | ||
1096 | cleanup_route_4: | ||
1097 | if (0 == nortsetup) | ||
1098 | { | ||
1099 | char *const route_clean_args[] = { | ||
1100 | "ip", "-6", "route", "del", "default", "dev", dev, | ||
1101 | "table", DNS_TABLE, NULL | ||
1102 | }; | ||
1103 | if (0 != fork_and_exec (sbin_ip, route_clean_args)) | ||
1104 | r += 1; | ||
1105 | } | ||
1106 | cleanup_route_4b: | ||
1107 | if (0 == nortsetup) | ||
1108 | { | ||
1109 | char *const route_clean_args[] = { | ||
1110 | "ip", "route", "del", "default", "dev", dev, | ||
1111 | "table", DNS_TABLE, NULL | ||
1112 | }; | ||
1113 | if (0 != fork_and_exec (sbin_ip, route_clean_args)) | ||
1114 | r += 1; | ||
1115 | } | ||
1116 | cleanup_forward_3: | ||
1117 | if (0 == nortsetup) | ||
1118 | { | ||
1119 | char *const forward_clean_args[] = { | ||
1120 | "ip", "-6", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL | ||
1121 | }; | ||
1122 | if (0 != fork_and_exec (sbin_ip, forward_clean_args)) | ||
1123 | r += 2; | ||
1124 | } | ||
1125 | cleanup_forward_3b: | ||
1126 | if (0 == nortsetup) | ||
1127 | { | ||
1128 | char *const forward_clean_args[] = { | ||
1129 | "ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL | ||
1130 | }; | ||
1131 | if (0 != fork_and_exec (sbin_ip, forward_clean_args)) | ||
1132 | r += 2; | ||
1133 | } | ||
1134 | cleanup_mark_2: | ||
1135 | if (0 == nortsetup) | ||
1136 | { | ||
1137 | char *const mark_clean_args[] = { | ||
1138 | "ip6tables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", | ||
1139 | "--dport", DNS_PORT, | ||
1140 | "!", "-s", "fe80::/10", /* this line excludes link-local traffic */ | ||
1141 | "-j", "MARK", "--set-mark", DNS_MARK, NULL | ||
1142 | }; | ||
1143 | if (0 != fork_and_exec (sbin_ip6tables, mark_clean_args)) | ||
1144 | r += 4; | ||
1145 | } | ||
1146 | cleanup_mark_2b: | ||
1147 | if (0 == nortsetup) | ||
1148 | { | ||
1149 | char *const mark_clean_args[] = { | ||
1150 | "iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", | ||
1151 | "--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL | ||
1152 | }; | ||
1153 | if (0 != fork_and_exec (sbin_iptables, mark_clean_args)) | ||
1154 | r += 4; | ||
1155 | } | ||
1156 | cleanup_mangle_1: | ||
1157 | if (0 == nortsetup) | ||
1158 | { | ||
1159 | char *const mangle_clean_args[] = { | ||
1160 | "ip6tables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", | ||
1161 | "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT", | ||
1162 | NULL | ||
1163 | }; | ||
1164 | if (0 != fork_and_exec (sbin_ip6tables, mangle_clean_args)) | ||
1165 | r += 8; | ||
1166 | } | ||
1167 | cleanup_mangle_1b: | ||
1168 | if (0 == nortsetup) | ||
1169 | { | ||
1170 | char *const mangle_clean_args[] = { | ||
1171 | "iptables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp", | ||
1172 | "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT", | ||
1173 | NULL | ||
1174 | }; | ||
1175 | if (0 != fork_and_exec (sbin_iptables, mangle_clean_args)) | ||
1176 | r += 8; | ||
1177 | } | ||
1178 | |||
1179 | cleanup_rest: | ||
1180 | /* close virtual interface */ | ||
1181 | (void) close (fd_tun); | ||
1182 | /* remove signal handler so we can close the pipes */ | ||
1183 | (void) signal (SIGTERM, SIG_IGN); | ||
1184 | #if (SIGTERM != GNUNET_TERM_SIG) | ||
1185 | (void) signal (GNUNET_TERM_SIG, SIG_IGN); | ||
1186 | #endif | ||
1187 | (void) signal (SIGINT, SIG_IGN); | ||
1188 | (void) signal (SIGHUP, SIG_IGN); | ||
1189 | (void) close (cpipe[0]); | ||
1190 | (void) close (cpipe[1]); | ||
1191 | return r; | ||
1192 | } | ||
1193 | |||
1194 | |||
1195 | /* end of gnunet-helper-dns.c */ | ||