ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn.C
Revision: 1.8
Committed: Mon Apr 7 01:28:56 2003 UTC (21 years, 1 month ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.7: +28 -25 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 <netinet/in.h>
32     #include <arpa/inet.h>
33     #include <errno.h>
34     #include <time.h>
35     #include <unistd.h>
36    
37     #include "pidfile.h"
38    
39     #include "connection.h"
40     #include "util.h"
41     #include "vpn.h"
42    
43     /////////////////////////////////////////////////////////////////////////////
44    
45 pcg 1.2 const char *vpn::script_if_up ()
46 pcg 1.1 {
47     // the tunnel device mtu should be the physical mtu - overhead
48     // the tricky part is rounding to the cipher key blocksize
49     int mtu = conf.mtu - ETH_OVERHEAD - VPE_OVERHEAD - MAX_OVERHEAD;
50     mtu += ETH_OVERHEAD - 6 - 6; // now we have the data portion
51     mtu -= mtu % EVP_CIPHER_block_size (CIPHER); // round
52     mtu -= ETH_OVERHEAD - 6 - 6; // and get interface mtu again
53    
54     char *env;
55     asprintf (&env, "CONFBASE=%s", confbase);
56     putenv (env);
57     asprintf (&env, "NODENAME=%s", THISNODE->nodename);
58     putenv (env);
59     asprintf (&env, "NODEID=%d", THISNODE->id);
60     putenv (env);
61     asprintf (&env, "IFNAME=%s", tap->interface ());
62     putenv (env);
63     asprintf (&env, "MTU=%d", mtu);
64     putenv (env);
65     asprintf (&env, "MAC=%02x:%02x:%02x:%02x:%02x:%02x",
66     0xfe, 0xfd, 0x80, 0x00, THISNODE->id >> 8,
67     THISNODE->id & 0xff);
68     putenv (env);
69    
70     return ::conf.script_if_up ? ::conf.script_if_up : "if-up";
71     }
72    
73     int
74     vpn::setup ()
75     {
76 pcg 1.8 ipv4_fd = -1;
77 pcg 1.1
78 pcg 1.8 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto)
79 pcg 1.1 {
80 pcg 1.8 ipv4_fd = socket (PF_INET, SOCK_RAW, ::conf.ip_proto);
81 pcg 1.1
82 pcg 1.8 if (ipv4_fd < 0)
83 pcg 1.1 return -1;
84    
85 pcg 1.8 sockinfo si (THISNODE, PROT_IPv4);
86 pcg 1.3
87 pcg 1.8 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ()))
88 pcg 1.1 {
89 pcg 1.8 slog (L_ERR, _("can't bind ipv4 socket on %s: %s"), (const char *)si, strerror (errno));
90 pcg 1.1 exit (1);
91     }
92    
93     #ifdef IP_MTU_DISCOVER
94     // this I really consider a linux bug. I am neither connected
95     // nor do I fragment myself. Linux still sets DF and doesn't
96     // fragment for me sometimes.
97     {
98     int oval = IP_PMTUDISC_DONT;
99 pcg 1.8 setsockopt (ipv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
100 pcg 1.1 }
101     #endif
102    
103 pcg 1.8 ipv4_ev_watcher.start (ipv4_fd, POLLIN);
104 pcg 1.1 }
105    
106 pcg 1.8 udpv4_fd = -1;
107    
108     if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port)
109 pcg 1.1 {
110 pcg 1.8 udpv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
111 pcg 1.1
112 pcg 1.8 if (udpv4_fd < 0)
113 pcg 1.1 return -1;
114    
115 pcg 1.8 // standard daemon practise...
116     {
117     int oval = 1;
118     setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
119     }
120    
121     sockinfo si (THISNODE, PROT_UDPv4);
122 pcg 1.2
123 pcg 1.8 if (bind (udpv4_fd, si.sav4 (), si.salenv4 ()))
124 pcg 1.1 {
125 pcg 1.8 slog (L_ERR, _("can't bind udpv4 on %s: %s"), (const char *)si, strerror (errno));
126 pcg 1.1 exit (1);
127     }
128    
129     #ifdef IP_MTU_DISCOVER
130     // this I really consider a linux bug. I am neither connected
131     // nor do I fragment myself. Linux still sets DF and doesn't
132     // fragment for me sometimes.
133     {
134     int oval = IP_PMTUDISC_DONT;
135 pcg 1.8 setsockopt (udpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
136 pcg 1.1 }
137     #endif
138    
139 pcg 1.8 udpv4_ev_watcher.start (udpv4_fd, POLLIN);
140 pcg 1.1 }
141    
142 pcg 1.8 tcpv4_fd = -1;
143    
144 pcg 1.2 #if ENABLE_TCP
145 pcg 1.8 if (THISNODE->protocols & PROT_TCPv4 && THISNODE->tcp_port)
146 pcg 1.2 {
147     tcpv4_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
148    
149     if (tcpv4_fd < 0)
150     return -1;
151    
152 pcg 1.3 // standard daemon practise...
153     {
154     int oval = 1;
155     setsockopt (tcpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
156     }
157    
158 pcg 1.2 sockinfo si (THISNODE, PROT_TCPv4);
159    
160     if (bind (tcpv4_fd, si.sav4 (), si.salenv4 ()))
161     {
162     slog (L_ERR, _("can't bind tcpv4 on %s: %s"), (const char *)si, strerror (errno));
163     exit (1);
164     }
165    
166     if (listen (tcpv4_fd, 5))
167     {
168     slog (L_ERR, _("can't listen tcpv4 on %s: %s"), (const char *)si, strerror (errno));
169     exit (1);
170     }
171    
172 pcg 1.3 tcpv4_ev_watcher.start (tcpv4_fd, POLLIN);
173 pcg 1.2 }
174     #endif
175    
176 pcg 1.1 tap = new tap_device ();
177     if (!tap) //D this, of course, never catches
178     {
179     slog (L_ERR, _("cannot create network interface '%s'"), conf.ifname);
180     exit (1);
181     }
182    
183     run_script (run_script_cb (this, &vpn::script_if_up), true);
184    
185     tap_ev_watcher.start (tap->fd, POLLIN);
186    
187     reconnect_all ();
188    
189     return 0;
190     }
191    
192 pcg 1.5 // send a vpn packet out to other hosts
193 pcg 1.7 bool
194 pcg 1.5 vpn::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos)
195     {
196     switch (si.prot)
197     {
198     case PROT_IPv4:
199 pcg 1.7 return send_ipv4_packet (pkt, si, tos);
200 pcg 1.5
201     case PROT_UDPv4:
202 pcg 1.7 return send_udpv4_packet (pkt, si, tos);
203 pcg 1.5
204     #if ENABLE_TCP
205     case PROT_TCPv4:
206 pcg 1.7 return send_tcpv4_packet (pkt, si, tos);
207 pcg 1.5 #endif
208    
209     default:
210     slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol"), (const char *)si);
211 pcg 1.7 return false;
212 pcg 1.5 }
213     }
214    
215 pcg 1.7 bool
216 pcg 1.1 vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
217     {
218     setsockopt (ipv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
219     sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
220 pcg 1.7
221     return true;
222 pcg 1.1 }
223    
224 pcg 1.7 bool
225 pcg 1.1 vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
226     {
227     setsockopt (udpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
228     sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
229 pcg 1.7
230     return true;
231 pcg 1.1 }
232    
233     void
234     vpn::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi)
235     {
236     unsigned int src = pkt->src ();
237     unsigned int dst = pkt->dst ();
238    
239     slog (L_NOISE, _("<<?/%s received possible vpn packet type %d from %d to %d, length %d"),
240     (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst (), pkt->len);
241    
242     if (src == 0 || src > conns.size ()
243     || dst > conns.size ()
244     || pkt->typ () >= vpn_packet::PT_MAX)
245     slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)"),
246     (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ());
247 pcg 1.6 else if (dst > conns.size ())
248     slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)"),
249     (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ());
250 pcg 1.1 else
251     {
252     connection *c = conns[src - 1];
253    
254     if (dst == 0 && !THISNODE->routerprio)
255     slog (L_WARN, _("%s(%s): received broadcast, but we are no router"),
256     c->conf->nodename, (const char *)rsi);
257     else if (dst != 0 && dst != THISNODE->id)
258 pcg 1.6 {
259     if (THISNODE->routerprio)
260     // the tos setting gets lost here. who cares.
261     conns[dst - 1]->inject_vpn_packet (pkt);
262     else
263     slog (L_WARN,
264     _("%s(%s): forwarding request (=> %s), but we are no router"),
265     c->conf->nodename, (const char *)rsi,
266     conns[dst - 1]->conf->nodename);
267     }
268 pcg 1.1 else
269     c->recv_vpn_packet (pkt, rsi);
270     }
271     }
272    
273     void
274 pcg 1.3 vpn::udpv4_ev (io_watcher &w, short revents)
275 pcg 1.1 {
276     if (revents & (POLLIN | POLLERR))
277     {
278     vpn_packet *pkt = new vpn_packet;
279     struct sockaddr_in sa;
280     socklen_t sa_len = sizeof (sa);
281     int len;
282    
283 pcg 1.5 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
284 pcg 1.1
285 pcg 1.5 sockinfo si(sa, PROT_UDPv4);
286 pcg 1.1
287     if (len > 0)
288     {
289     pkt->len = len;
290    
291     recv_vpn_packet (pkt, si);
292     }
293     else
294     {
295     // probably ECONNRESET or somesuch
296 pcg 1.5 slog (L_DEBUG, _("%s: fd %d, %s"), (const char *)si, w.fd, strerror (errno));
297 pcg 1.1 }
298    
299     delete pkt;
300     }
301     else if (revents & POLLHUP)
302     {
303     // this cannot ;) happen on udp sockets
304     slog (L_ERR, _("FATAL: POLLHUP on udp v4 fd, terminating."));
305     exit (1);
306     }
307     else
308     {
309     slog (L_ERR,
310     _("FATAL: unknown revents %08x in socket, terminating\n"),
311     revents);
312     exit (1);
313     }
314     }
315    
316     void
317 pcg 1.3 vpn::ipv4_ev (io_watcher &w, short revents)
318 pcg 1.1 {
319     if (revents & (POLLIN | POLLERR))
320     {
321     vpn_packet *pkt = new vpn_packet;
322     struct sockaddr_in sa;
323     socklen_t sa_len = sizeof (sa);
324     int len;
325    
326 pcg 1.5 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
327 pcg 1.1
328     sockinfo si(sa, PROT_IPv4);
329    
330     if (len > 0)
331     {
332     pkt->len = len;
333    
334     // raw sockets deliver the ipv4, but don't expect it on sends
335     // this is slow, but...
336     pkt->skip_hdr (IP_OVERHEAD);
337    
338     recv_vpn_packet (pkt, si);
339     }
340     else
341     {
342     // probably ECONNRESET or somesuch
343     slog (L_DEBUG, _("%s: %s"), (const char *)si, strerror (errno));
344     }
345    
346     delete pkt;
347     }
348     else if (revents & POLLHUP)
349     {
350     // this cannot ;) happen on udp sockets
351     slog (L_ERR, _("FATAL: POLLHUP on ipv4 fd, terminating."));
352     exit (1);
353     }
354     else
355     {
356     slog (L_ERR,
357     _("FATAL: unknown revents %08x in socket, terminating\n"),
358     revents);
359     exit (1);
360     }
361     }
362 pcg 1.2
363     void
364 pcg 1.3 vpn::tap_ev (io_watcher &w, short revents)
365 pcg 1.1 {
366     if (revents & POLLIN)
367     {
368     /* process data */
369     tap_packet *pkt;
370    
371     pkt = tap->recv ();
372    
373     int dst = mac2id (pkt->dst);
374     int src = mac2id (pkt->src);
375    
376     if (src != THISNODE->id)
377     {
378     slog (L_ERR, _("FATAL: tap packet not originating on current node received, terminating."));
379     exit (1);
380     }
381    
382     if (dst == THISNODE->id)
383     {
384     slog (L_ERR, _("FATAL: tap packet destined for current node received, terminating."));
385     exit (1);
386     }
387    
388     if (dst > conns.size ())
389     slog (L_ERR, _("tap packet for unknown node %d received, ignoring."), dst);
390     else
391     {
392     if (dst)
393     {
394     // unicast
395     if (dst != THISNODE->id)
396     conns[dst - 1]->inject_data_packet (pkt);
397     }
398     else
399     {
400     // broadcast, first check router, then self, then english
401     connection *router = find_router ();
402    
403     if (router)
404     router->inject_data_packet (pkt, true);
405     else
406     for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
407     if ((*c)->conf != THISNODE)
408     (*c)->inject_data_packet (pkt);
409     }
410     }
411    
412     delete pkt;
413     }
414     else if (revents & (POLLHUP | POLLERR))
415     {
416     slog (L_ERR, _("FATAL: POLLHUP or POLLERR on network device fd, terminating."));
417     exit (1);
418     }
419     else
420     abort ();
421     }
422    
423     void
424 pcg 1.3 vpn::event_cb (time_watcher &w)
425 pcg 1.1 {
426     if (events)
427     {
428     if (events & EVENT_SHUTDOWN)
429     {
430     slog (L_INFO, _("preparing shutdown..."));
431    
432     shutdown_all ();
433    
434     remove_pid (pidfilename);
435    
436     slog (L_INFO, _("terminating"));
437    
438     exit (0);
439     }
440    
441     if (events & EVENT_RECONNECT)
442     {
443     slog (L_INFO, _("forced reconnect"));
444    
445     reconnect_all ();
446     }
447    
448     events = 0;
449     }
450    
451 pcg 1.3 w.at = TSTAMP_CANCEL;
452 pcg 1.1 }
453    
454     void
455     vpn::shutdown_all ()
456     {
457     for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
458     (*c)->shutdown ();
459     }
460    
461     void
462     vpn::reconnect_all ()
463     {
464     for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
465     delete *c;
466    
467     conns.clear ();
468    
469     connection_init ();
470    
471     for (configuration::node_vector::iterator i = conf.nodes.begin ();
472     i != conf.nodes.end (); ++i)
473     {
474     connection *conn = new connection (this);
475    
476     conn->conf = *i;
477     conns.push_back (conn);
478    
479     conn->establish_connection ();
480     }
481     }
482    
483     connection *vpn::find_router ()
484     {
485     u32 prio = 0;
486     connection *router = 0;
487    
488     for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
489     {
490     connection *c = *i;
491    
492     if (c->conf->routerprio > prio
493     && c->connectmode == conf_node::C_ALWAYS
494     && c->conf != THISNODE
495     && c->ictx && c->octx)
496     {
497     prio = c->conf->routerprio;
498     router = c;
499     }
500     }
501    
502     return router;
503     }
504    
505 pcg 1.7 void vpn::send_connect_request (int id)
506 pcg 1.1 {
507     connection *c = find_router ();
508    
509     if (c)
510 pcg 1.7 c->send_connect_request (id);
511     else
512     // no router found, aggressively connect to all routers
513     for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
514     if ((*i)->conf->routerprio)
515     (*i)->establish_connection ();
516 pcg 1.1 }
517    
518     void
519     connection::dump_status ()
520     {
521     slog (L_NOTICE, _("node %s (id %d)"), conf->nodename, conf->id);
522     slog (L_NOTICE, _(" connectmode %d (%d) / sockaddr %s / minor %d"),
523     connectmode, conf->connectmode, (const char *)si, (int)prot_minor);
524     slog (L_NOTICE, _(" ictx/octx %08lx/%08lx / oseqno %d / retry_cnt %d"),
525     (long)ictx, (long)octx, (int)oseqno, (int)retry_cnt);
526     slog (L_NOTICE, _(" establish_conn %ld / rekey %ld / keepalive %ld"),
527     (long)(establish_connection.at), (long)(rekey.at), (long)(keepalive.at));
528     }
529    
530     void
531     vpn::dump_status ()
532     {
533     slog (L_NOTICE, _("BEGIN status dump (%ld)"), (long)NOW);
534    
535     for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
536     (*c)->dump_status ();
537    
538     slog (L_NOTICE, _("END status dump"));
539     }
540    
541     vpn::vpn (void)
542 pcg 1.2 : event(this, &vpn::event_cb)
543     , udpv4_ev_watcher(this, &vpn::udpv4_ev)
544     , ipv4_ev_watcher (this, &vpn::ipv4_ev)
545     , tap_ev_watcher (this, &vpn::tap_ev)
546     #if ENABLE_TCP
547 pcg 1.3 , tcpv4_ev_watcher(this, &vpn::tcpv4_ev)
548 pcg 1.2 #endif
549 pcg 1.1 {
550     }
551    
552     vpn::~vpn ()
553     {
554     }
555