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