ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn.C
Revision: 1.9
Committed: Tue Apr 8 02:00:54 2003 UTC (21 years, 1 month ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.8: +173 -27 lines
Log Message:
*** empty log message ***

File Contents

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