ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn.C
Revision: 1.46
Committed: Thu Aug 7 17:30:28 2008 UTC (15 years, 9 months ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.45: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

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