ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn.C
Revision: 1.51
Committed: Sun Aug 10 14:48:57 2008 UTC (15 years, 9 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.50: +19 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 vpn.C -- handle the protocol, encryption, handshaking etc.
3 Copyright (C) 2003-2008 Marc Lehmann <gvpe@schmorp.de>
4
5 This file is part of GVPE.
6
7 GVPE is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, see <http://www.gnu.org/licenses/>.
19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this Program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a modified
24 version of that library), containing parts covered by the terms of the
25 OpenSSL or SSLeay licenses, the licensors of this Program grant you
26 additional permission to convey the resulting work. Corresponding
27 Source for a non-source form of such a combination shall include the
28 source code for the parts of OpenSSL used as well as that of the
29 covered work.
30 */
31
32 #include "config.h"
33
34 #include <list>
35
36 #include <cstdio>
37 #include <cstring>
38 #include <cstdlib>
39
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/wait.h>
43 #include <errno.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <sys/socket.h>
48
49 #include "netcompat.h"
50
51 #include "pidfile.h"
52
53 #include "connection.h"
54 #include "util.h"
55 #include "vpn.h"
56
57 vpn network; // THE vpn (bad design...)
58
59 /////////////////////////////////////////////////////////////////////////////
60
61 static void inline
62 set_tos (int fd, int &tos_prev, int tos)
63 {
64 #if defined(SOL_IP) && defined(IP_TOS)
65 if (tos_prev == tos)
66 return;
67
68 tos_prev = tos;
69 setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
70 #endif
71 }
72
73 void
74 vpn::script_init_env ()
75 {
76 // the tunnel device mtu should be the physical mtu - overhead
77 // the tricky part is rounding to the cipher key blocksize
78 int mtu = conf.mtu - ETH_OVERHEAD - VPE_OVERHEAD - MAX_OVERHEAD;
79 mtu += ETH_OVERHEAD - 6 - 6; // now we have the data portion
80 mtu -= mtu % EVP_CIPHER_block_size (CIPHER); // round
81 mtu -= ETH_OVERHEAD - 6 - 6; // and get interface mtu again
82
83 char *env;
84 asprintf (&env, "CONFBASE=%s", confbase); putenv (env);
85 asprintf (&env, "IFNAME=%s", tap->interface ()); putenv (env);
86 asprintf (&env, "IFTYPE=%s", IFTYPE); putenv (env);
87 asprintf (&env, "IFSUBTYPE=%s", IFSUBTYPE); putenv (env);
88 asprintf (&env, "MTU=%d", mtu); putenv (env);
89 asprintf (&env, "NODES=%d", conns.size ()); putenv (env);
90 asprintf (&env, "NODEID=%d", THISNODE->id); putenv (env);
91
92 conns [THISNODE->id - 1]->script_init_env ("");
93
94 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
95 {
96 char ext[16];
97 snprintf (ext, 16, "_%d", (*c)->conf->id);
98 (*c)->script_init_env (ext);
99 }
100 }
101
102 inline const char *
103 vpn::script_if_init ()
104 {
105 script_init_env ();
106
107 return tap->if_up ();
108 }
109
110 inline const char *
111 vpn::script_if_up ()
112 {
113 script_init_env ();
114
115 char *filename;
116 asprintf (&filename,
117 "%s/%s",
118 confbase,
119 ::conf.script_if_up ? ::conf.script_if_up : "if-up");
120
121 return filename;
122 }
123
124 int
125 vpn::setup ()
126 {
127 int success = 0;
128
129 ipv4_tos = -1;
130 ipv4_fd = -1;
131
132 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto)
133 {
134 ipv4_fd = socket (PF_INET, SOCK_RAW, ::conf.ip_proto);
135
136 if (ipv4_fd < 0)
137 return -1;
138
139 fcntl (ipv4_fd, F_SETFL, O_NONBLOCK);
140 fcntl (ipv4_fd, F_SETFD, FD_CLOEXEC);
141
142 #if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
143 // this I really consider a linux bug. I am neither connected
144 // nor do I fragment myself. Linux still sets DF and doesn't
145 // fragment for me sometimes.
146 {
147 int oval = IP_PMTUDISC_DONT;
148 setsockopt (ipv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
149 }
150 #endif
151
152 sockinfo si (THISNODE, PROT_IPv4);
153
154 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ()))
155 {
156 slog (L_ERR, _("can't bind ipv4 socket on %s: %s, exiting."), (const char *)si, strerror (errno));
157 exit (EXIT_FAILURE);
158 }
159
160 ipv4_ev_watcher.start (ipv4_fd, EV_READ);
161 ++success;
162 }
163 else
164 THISNODE->protocols &= ~PROT_IPv4;
165
166 udpv4_tos = -1;
167 udpv4_fd = -1;
168
169 if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port)
170 {
171 udpv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
172
173 if (udpv4_fd < 0)
174 return -1;
175
176 fcntl (udpv4_fd, F_SETFL, O_NONBLOCK);
177 fcntl (udpv4_fd, F_SETFD, FD_CLOEXEC);
178
179 // standard daemon practise...
180 {
181 int oval = 1;
182 setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
183 }
184
185 #if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
186 // this I really consider a linux bug. I am neither connected
187 // nor do I fragment myself. Linux still sets DF and doesn't
188 // fragment for me sometimes.
189 {
190 int oval = IP_PMTUDISC_DONT;
191 setsockopt (udpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
192 }
193 #endif
194
195 sockinfo si (THISNODE, PROT_UDPv4);
196
197 if (bind (udpv4_fd, si.sav4 (), si.salenv4 ()))
198 {
199 slog (L_ERR, _("can't bind udpv4 on %s: %s, exiting."), (const char *)si, strerror (errno));
200 exit (EXIT_FAILURE);
201 }
202
203 udpv4_ev_watcher.start (udpv4_fd, EV_READ);
204 ++success;
205 }
206 else
207 THISNODE->protocols &= ~PROT_UDPv4;
208
209 icmpv4_tos = -1;
210 icmpv4_fd = -1;
211
212 #if ENABLE_ICMP
213 if (THISNODE->protocols & PROT_ICMPv4)
214 {
215 icmpv4_fd = socket (PF_INET, SOCK_RAW, IPPROTO_ICMP);
216
217 if (icmpv4_fd < 0)
218 return -1;
219
220 fcntl (icmpv4_fd, F_SETFL, O_NONBLOCK);
221 fcntl (icmpv4_fd, F_SETFD, FD_CLOEXEC);
222
223 #ifdef ICMP_FILTER
224 {
225 icmp_filter oval;
226 oval.data = 0xffffffff;
227 if (::conf.icmp_type < 32)
228 oval.data &= ~(1 << ::conf.icmp_type);
229
230 setsockopt (icmpv4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval);
231 }
232 #endif
233
234 #if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
235 // this I really consider a linux bug. I am neither connected
236 // nor do I fragment myself. Linux still sets DF and doesn't
237 // fragment for me sometimes.
238 {
239 int oval = IP_PMTUDISC_DONT;
240 setsockopt (icmpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
241 }
242 #endif
243
244 sockinfo si (THISNODE, PROT_ICMPv4);
245
246 if (bind (icmpv4_fd, si.sav4 (), si.salenv4 ()))
247 {
248 slog (L_ERR, _("can't bind icmpv4 on %s: %s, exiting."), (const char *)si, strerror (errno));
249 exit (EXIT_FAILURE);
250 }
251
252 icmpv4_ev_watcher.start (icmpv4_fd, EV_READ);
253 ++success;
254 }
255 #endif
256
257 tcpv4_fd = -1;
258
259 #if ENABLE_TCP
260 if (THISNODE->protocols & PROT_TCPv4 && THISNODE->tcp_port)
261 {
262 tcpv4_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
263
264 if (tcpv4_fd < 0)
265 return -1;
266
267 fcntl (tcpv4_fd, F_SETFL, O_NONBLOCK);
268 fcntl (tcpv4_fd, F_SETFD, FD_CLOEXEC);
269
270 // standard daemon practise...
271 {
272 int oval = 1;
273 setsockopt (tcpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
274 }
275
276 sockinfo si (THISNODE, PROT_TCPv4);
277
278 if (bind (tcpv4_fd, si.sav4 (), si.salenv4 ()))
279 {
280 slog (L_ERR, _("can't bind tcpv4 on %s: %s, exiting."), (const char *)si, strerror (errno));
281 exit (EXIT_FAILURE);
282 }
283
284 if (listen (tcpv4_fd, 5))
285 {
286 slog (L_ERR, _("can't listen tcpv4 on %s: %s, exiting."), (const char *)si, strerror (errno));
287 exit (EXIT_FAILURE);
288 }
289
290 tcpv4_ev_watcher.start (tcpv4_fd, EV_READ);
291 ++success;
292 }
293 else
294 THISNODE->protocols &= ~PROT_TCPv4;
295 #endif
296
297 dnsv4_tos = -1;
298 dnsv4_fd = -1;
299
300 #if ENABLE_DNS
301 if (THISNODE->protocols & PROT_DNSv4)
302 {
303 dns_forwarder.set (::conf.dns_forw_host, ::conf.dns_forw_port, PROT_DNSv4);
304
305 dnsv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
306
307 if (dnsv4_fd < 0)
308 return -1;
309
310 fcntl (dnsv4_fd, F_SETFL, O_NONBLOCK);
311 fcntl (dnsv4_fd, F_SETFD, FD_CLOEXEC);
312
313 # if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
314 // this I really consider a linux bug. I am neither connected
315 // nor do I fragment myself. Linux still sets DF and doesn't
316 // fragment for me sometimes.
317 {
318 int oval = IP_PMTUDISC_DONT;
319 setsockopt (dnsv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
320 }
321 # endif
322
323 // standard daemon practise...
324 {
325 int oval = 1;
326 setsockopt (dnsv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
327 }
328
329 sockinfo si (THISNODE->dns_hostname,
330 THISNODE->dns_hostname ? THISNODE->dns_port : 0,
331 PROT_DNSv4);
332
333 if (bind (dnsv4_fd, si.sav4 (), si.salenv4 ()))
334 {
335 slog (L_ERR, _("can't bind dnsv4 on %s: %s, exiting."), (const char *)si, strerror (errno));
336 exit (EXIT_FAILURE);
337 }
338
339 dnsv4_ev_watcher.start (dnsv4_fd, EV_READ);
340 ++success;
341 }
342 #endif
343
344 /////////////////////////////////////////////////////////////////////////////
345
346 if (!success)
347 {
348 slog (L_ERR, _("no protocols enabled, exiting."));
349 exit (EXIT_FAILURE);
350 }
351
352 reconnect_all ();
353
354 /////////////////////////////////////////////////////////////////////////////
355
356 tap = new tap_device ();
357 if (!tap) //D this, of course, never catches
358 {
359 slog (L_ERR, _("cannot create network interface '%s', exiting."), conf.ifname);
360 exit (EXIT_FAILURE);
361 }
362
363 fcntl (tap->fd, F_SETFD, FD_CLOEXEC);
364
365 run_script_cb cb;
366 cb.set<vpn, &vpn::script_if_init> (this);
367
368 if (tap->if_up () &&
369 !run_script (cb, true))
370 {
371 slog (L_ERR, _("interface initialization command '%s' failed, exiting."),
372 tap->if_up ());
373 exit (EXIT_FAILURE);
374 }
375
376 cb.set<vpn, &vpn::script_if_up> (this);
377 if (!run_script (cb, true))
378 {
379 slog (L_ERR, _("if-up command execution failed, exiting."));
380 exit (EXIT_FAILURE);
381 }
382
383 tap_ev_watcher.start (tap->fd, EV_READ);
384
385 return 0;
386 }
387
388 bool
389 vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
390 {
391 set_tos (ipv4_fd, ipv4_tos, tos);
392 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
393
394 return true;
395 }
396
397 static u16
398 ipv4_checksum (u16 *data, unsigned int len)
399 {
400 // use 32 bit accumulator and fold back carry bits at the end
401 u32 sum = 0;
402
403 while (len > 1)
404 {
405 sum += *data++;
406 len -= 2;
407 }
408
409 // odd byte left?
410 if (len)
411 sum += *(u8 *)data;
412
413 // add back carry bits
414 sum = (sum >> 16) + (sum & 0xffff); // lo += hi
415 sum += (sum >> 16); // carry
416
417 return ~sum;
418 }
419
420 #if ENABLE_ICMP
421 bool
422 vpn::send_icmpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
423 {
424 pkt->unshift_hdr (4);
425
426 icmp_header *hdr = (icmp_header *)&((*pkt)[0]);
427 hdr->type = ::conf.icmp_type;
428 hdr->code = 255;
429 hdr->checksum = 0;
430 hdr->checksum = ipv4_checksum ((u16 *)hdr, pkt->len);
431
432 set_tos (icmpv4_fd, icmpv4_tos, tos);
433 sendto (icmpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
434
435 return true;
436 }
437 #endif
438
439 bool
440 vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
441 {
442 set_tos (udpv4_fd, udpv4_tos, tos);
443 sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
444
445 return true;
446 }
447
448 void
449 vpn::inject_data_packet (tap_packet *pkt, int dst)
450 {
451 if (dst)
452 {
453 // unicast
454 if (dst != THISNODE->id)
455 conns[dst - 1]->inject_data_packet (pkt);
456 }
457 else
458 {
459 // broadcast, this is ugly, but due to the security policy
460 // we have to connect to all hosts...
461 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
462 if ((*c)->conf != THISNODE)
463 (*c)->inject_data_packet (pkt);
464 }
465 }
466
467 void
468 vpn::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi)
469 {
470 unsigned int src = pkt->src ();
471 unsigned int dst = pkt->dst ();
472
473 slog (L_NOISE, _("<<?/%s received possible vpn packet type %d from %d to %d, length %d."),
474 (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst (), pkt->len);
475
476 if (src == 0 || src > conns.size ()
477 || dst > conns.size ()
478 || pkt->typ () >= vpn_packet::PT_MAX)
479 slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)."),
480 (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ());
481 else if (dst > conns.size ())
482 slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)."),
483 (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ());
484 else
485 {
486 connection *c = conns[src - 1];
487
488 if (dst == 0)
489 slog (L_WARN, _("%s(%s): received broadcast (protocol violation)."),
490 c->conf->nodename, (const char *)rsi);
491 else if (dst != THISNODE->id)
492 {
493 if (THISNODE->routerprio)
494 // the tos setting gets lost here. who cares.
495 conns[dst - 1]->inject_vpn_packet (pkt);
496 else
497 slog (L_WARN,
498 _("%s(%s): request to forward packet to %s, but we are no router (config mismatch?)."),
499 c->conf->nodename, (const char *)rsi,
500 conns[dst - 1]->conf->nodename);
501 }
502 else
503 c->recv_vpn_packet (pkt, rsi);
504 }
505 }
506
507 bool
508 vpn::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos)
509 {
510 switch (si.prot)
511 {
512 case PROT_IPv4:
513 return send_ipv4_packet (pkt, si, tos);
514
515 case PROT_UDPv4:
516 return send_udpv4_packet (pkt, si, tos);
517
518 #if ENABLE_TCP
519 case PROT_TCPv4:
520 return send_tcpv4_packet (pkt, si, tos);
521 #endif
522 #if ENABLE_ICMP
523 case PROT_ICMPv4:
524 return send_icmpv4_packet (pkt, si, tos);
525 #endif
526 #if ENABLE_DNS
527 case PROT_DNSv4:
528 return send_dnsv4_packet (pkt, si, tos);
529 #endif
530 default:
531 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol."), (const char *)si);
532 }
533
534 return false;
535 }
536
537 inline void
538 vpn::ipv4_ev (ev::io &w, int revents)
539 {
540 if (revents & EV_READ)
541 {
542 vpn_packet *pkt = new vpn_packet;
543 struct sockaddr_in sa;
544 socklen_t sa_len = sizeof (sa);
545 int len;
546
547 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
548
549 sockinfo si(sa, PROT_IPv4);
550
551 if (len > 0)
552 {
553 pkt->len = len;
554
555 // raw sockets deliver the ipv4 header, but don't expect it on sends
556 pkt->skip_hdr (IP_OVERHEAD);
557
558 recv_vpn_packet (pkt, si);
559 }
560 else
561 {
562 // probably ECONNRESET or somesuch
563 slog (L_DEBUG, _("%s: %s."), (const char *)si, strerror (errno));
564 }
565
566 delete pkt;
567 }
568 else
569 {
570 slog (L_ERR,
571 _("FATAL: unknown revents %08x in socket, exiting.\n"),
572 revents);
573 exit (EXIT_FAILURE);
574 }
575 }
576
577 #if ENABLE_ICMP
578 inline void
579 vpn::icmpv4_ev (ev::io &w, int revents)
580 {
581 if (revents & EV_READ)
582 {
583 vpn_packet *pkt = new vpn_packet;
584 struct sockaddr_in sa;
585 socklen_t sa_len = sizeof (sa);
586 int len;
587
588 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
589
590 sockinfo si(sa, PROT_ICMPv4);
591
592 if (len > 0)
593 {
594 pkt->len = len;
595
596 icmp_header *hdr = (icmp_header *)&((*pkt)[IP_OVERHEAD]);
597
598 if (hdr->type == ::conf.icmp_type
599 && hdr->code == 255)
600 {
601 // raw sockets deliver the ipv4, but don't expect it on sends
602 // this is slow, but...
603 pkt->skip_hdr (ICMP_OVERHEAD);
604
605 recv_vpn_packet (pkt, si);
606 }
607 }
608 else
609 {
610 // probably ECONNRESET or somesuch
611 slog (L_DEBUG, _("%s: %s."), (const char *)si, strerror (errno));
612 }
613
614 delete pkt;
615 }
616 else
617 {
618 slog (L_ERR,
619 _("FATAL: unknown revents %08x in socket, exiting.\n"),
620 revents);
621 exit (EXIT_FAILURE);
622 }
623 }
624 #endif
625
626 inline void
627 vpn::udpv4_ev (ev::io &w, int revents)
628 {
629 if (revents & EV_READ)
630 {
631 vpn_packet *pkt = new vpn_packet;
632 struct sockaddr_in sa;
633 socklen_t sa_len = sizeof (sa);
634 int len;
635
636 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
637
638 sockinfo si(sa, PROT_UDPv4);
639
640 if (len > 0)
641 {
642 pkt->len = len;
643
644 recv_vpn_packet (pkt, si);
645 }
646 else
647 {
648 // probably ECONNRESET or somesuch
649 slog (L_DEBUG, _("%s: fd %d, %s."), (const char *)si, w.fd, strerror (errno));
650 }
651
652 delete pkt;
653 }
654 else
655 {
656 slog (L_ERR,
657 _("FATAL: unknown revents %08x in socket, exiting.\n"),
658 revents);
659 exit (EXIT_FAILURE);
660 }
661 }
662
663 inline void
664 vpn::tap_ev (ev::io &w, int revents)
665 {
666 if (revents & EV_READ)
667 {
668 /* process data */
669 tap_packet *pkt;
670
671 pkt = tap->recv ();
672
673 if (!pkt)
674 return;
675
676 if (pkt->len > 14)
677 {
678 int dst = mac2id (pkt->dst);
679 int src = mac2id (pkt->src);
680
681 if (src != THISNODE->id)
682 {
683 slog (L_ERR, _("FATAL: tap packet not originating on current node received (if-up script not working properly?), exiting."));
684 exit (EXIT_FAILURE);
685 }
686
687 if (dst == THISNODE->id)
688 {
689 slog (L_ERR, _("FATAL: tap packet destined for current node received, exiting."));
690 exit (EXIT_FAILURE);
691 }
692
693 if (dst > conns.size ())
694 slog (L_ERR, _("tap packet for unknown node %d received, ignoring."), dst);
695 else
696 inject_data_packet (pkt, dst);
697 }
698
699 delete pkt;
700 }
701 else
702 abort ();
703 }
704
705 inline void
706 vpn::event_cb (ev::timer &w, int)
707 {
708 if (events)
709 {
710 if (events & EVENT_SHUTDOWN)
711 {
712 slog (L_INFO, _("preparing shutdown..."));
713
714 shutdown_all ();
715 remove_pid (conf.pidfilename);
716 slog (L_INFO, _("exiting."));
717 exit (EXIT_SUCCESS);
718 }
719
720 if (events & EVENT_RECONNECT)
721 {
722 slog (L_INFO, _("forced reconnect."));
723
724 reconnect_all ();
725 }
726
727 events = 0;
728 }
729 }
730
731 void
732 vpn::shutdown_all ()
733 {
734 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
735 (*c)->shutdown ();
736 }
737
738 void
739 vpn::reconnect_all ()
740 {
741 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
742 delete *c;
743
744 conns.clear ();
745
746 connection_init ();
747
748 for (configuration::node_vector::iterator i = conf.nodes.begin (); i != conf.nodes.end (); ++i)
749 conns.push_back (new connection (this, *i));
750
751 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
752 (*c)->establish_connection ();
753 }
754
755 bool vpn::can_direct (conf_node *src, conf_node *dst) const
756 {
757 return src != dst
758 && src->may_direct (dst)
759 && dst->may_direct (src)
760 && (((src->protocols & dst->protocols) && src->connectmode == conf_node::C_ALWAYS)
761 || (src->protocols & dst->connectable_protocols ()));
762 }
763
764 // only works for indirect and routed connections: find a router
765 // from THISNODE to dst
766 connection *vpn::find_router_for (const connection *dst)
767 {
768 connection *router = 0;
769
770 // first try to find a router with a direct connection
771 {
772 u32 prio = 1;
773
774 for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
775 {
776 connection *c = *i;
777
778 if (c->conf->routerprio > prio
779 && c->conf != THISNODE
780 && c != dst
781 && can_direct (c->conf, dst->conf))
782 {
783 if (c->ictx && c->octx)
784 {
785 prio = c->conf->routerprio;
786 router = c;
787 }
788 else
789 c->establish_connection ();
790 }
791 }
792 }
793
794 if (router)
795 return router;
796
797 // second try find the router with the highest priority higher than ours
798 {
799 u32 prio = 1;
800
801 for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
802 {
803 connection *c = *i;
804
805 if (c->conf->routerprio > prio
806 && c->conf->routerprio > THISNODE->routerprio
807 && c != dst
808 && c->conf != THISNODE)
809 {
810 if (c->ictx && c->octx)
811 {
812 prio = c->conf->routerprio;
813 router = c;
814 }
815 else
816 c->establish_connection ();
817 }
818 }
819 }
820 return router;
821 }
822
823 void vpn::connection_established (connection *c)
824 {
825 for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
826 {
827 connection *o = *i;
828
829 if (!o->is_direct
830 && o->si.valid ()
831 && c->si != o->si
832 && c == find_router_for (o))
833 {
834 slog (L_DEBUG, _("%s: can now route packets via %s, re-keying connection."),
835 o->conf->nodename, c->conf->nodename);
836 o->rekey ();
837 }
838 }
839 }
840
841 void vpn::send_connect_request (connection *c)
842 {
843 connection *r = find_router_for (c);
844
845 if (r)
846 {
847 slog (L_TRACE, _("%s: no way to connect, sending mediated connection request via %s."),
848 c->conf->nodename, r->conf->nodename);
849 r->send_connect_request (c->conf->id);
850 }
851 else
852 slog (L_DEBUG, _("%s: no way to connect and no router found: unable to connect."),
853 c->conf->nodename);
854 }
855
856 void
857 connection::dump_status ()
858 {
859 slog (L_NOTICE, _("node %s (id %d)"), conf->nodename, conf->id);
860 slog (L_NOTICE, _(" connectmode %d (%d) / sockaddr %s / minor %d"),
861 connectmode, conf->connectmode, (const char *)si, (int)prot_minor);
862 slog (L_NOTICE, _(" ictx/octx %08lx/%08lx / oseqno %d / retry_cnt %d"),
863 (long)ictx, (long)octx, (int)oseqno, (int)retry_cnt);
864 }
865
866 void
867 vpn::dump_status ()
868 {
869 slog (L_NOTICE, _("BEGIN status dump (%ld)"), (long)ev_now ());
870
871 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
872 (*c)->dump_status ();
873
874 slog (L_NOTICE, _("END status dump"));
875 }
876
877 vpn::vpn (void)
878 {
879 event .set<vpn, &vpn::event_cb > (this);
880 udpv4_ev_watcher .set<vpn, &vpn::udpv4_ev > (this);
881 ipv4_ev_watcher .set<vpn, &vpn::ipv4_ev > (this);
882 #if ENABLE_TCP
883 tcpv4_ev_watcher .set<vpn, &vpn::tcpv4_ev > (this);
884 #endif
885 #if ENABLE_ICMP
886 icmpv4_ev_watcher.set<vpn, &vpn::icmpv4_ev> (this);
887 #endif
888 #if ENABLE_DNS
889 dnsv4_ev_watcher .set<vpn, &vpn::dnsv4_ev > (this);
890 #endif
891 tap_ev_watcher .set<vpn, &vpn::tap_ev > (this);
892 }
893
894 vpn::~vpn ()
895 {
896 }
897