ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn.C
Revision: 1.6
Committed: Sun Apr 6 04:17:36 2003 UTC (21 years, 1 month ago) by pcg
Content type: text/plain
Branch: MAIN
Changes since 1.5: +13 -6 lines
Log Message:
*** empty log message ***

File Contents

# Content
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 const char *vpn::script_if_up ()
46 {
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 // standard daemon practise...
86 {
87 int oval = 1;
88 setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
89 }
90
91 sockinfo si (THISNODE, PROT_UDPv4);
92
93 if (bind (udpv4_fd, si.sav4 (), si.salenv4 ()))
94 {
95 slog (L_ERR, _("can't bind udpv4 on %s: %s"), (const char *)si, strerror (errno));
96 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 sockinfo si (THISNODE, PROT_IPv4);
121
122 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ()))
123 {
124 slog (L_ERR, _("can't bind ipv4 socket on %s: %s"), (const char *)si, strerror (errno));
125 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 #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 // standard daemon practise...
150 {
151 int oval = 1;
152 setsockopt (tcpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
153 }
154
155 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 tcpv4_ev_watcher.start (tcpv4_fd, POLLIN);
170 }
171 #endif
172
173 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 // send a vpn packet out to other hosts
190 void
191 vpn::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos)
192 {
193 switch (si.prot)
194 {
195 case PROT_IPv4:
196 send_ipv4_packet (pkt, si, tos);
197 break;
198
199 case PROT_UDPv4:
200 send_udpv4_packet (pkt, si, tos);
201 break;
202
203 #if ENABLE_TCP
204 case PROT_TCPv4:
205 send_tcpv4_packet (pkt, si, tos);
206 break;
207 #endif
208
209 default:
210 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol"), (const char *)si);
211 abort ();
212 }
213 }
214
215 void
216 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 }
221
222 void
223 vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
224 {
225 setsockopt (udpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
226 sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
227 }
228
229 void
230 vpn::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi)
231 {
232 unsigned int src = pkt->src ();
233 unsigned int dst = pkt->dst ();
234
235 slog (L_NOISE, _("<<?/%s received possible vpn packet type %d from %d to %d, length %d"),
236 (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst (), pkt->len);
237
238 if (src == 0 || src > conns.size ()
239 || dst > conns.size ()
240 || pkt->typ () >= vpn_packet::PT_MAX)
241 slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)"),
242 (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ());
243 else if (dst > conns.size ())
244 slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)"),
245 (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ());
246 else
247 {
248 connection *c = conns[src - 1];
249
250 if (dst == 0 && !THISNODE->routerprio)
251 slog (L_WARN, _("%s(%s): received broadcast, but we are no router"),
252 c->conf->nodename, (const char *)rsi);
253 else if (dst != 0 && dst != THISNODE->id)
254 {
255 if (THISNODE->routerprio)
256 // the tos setting gets lost here. who cares.
257 conns[dst - 1]->inject_vpn_packet (pkt);
258 else
259 slog (L_WARN,
260 _("%s(%s): forwarding request (=> %s), but we are no router"),
261 c->conf->nodename, (const char *)rsi,
262 conns[dst - 1]->conf->nodename);
263 }
264 else
265 c->recv_vpn_packet (pkt, rsi);
266 }
267 }
268
269 void
270 vpn::udpv4_ev (io_watcher &w, short revents)
271 {
272 if (revents & (POLLIN | POLLERR))
273 {
274 vpn_packet *pkt = new vpn_packet;
275 struct sockaddr_in sa;
276 socklen_t sa_len = sizeof (sa);
277 int len;
278
279 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
280
281 sockinfo si(sa, PROT_UDPv4);
282
283 if (len > 0)
284 {
285 pkt->len = len;
286
287 recv_vpn_packet (pkt, si);
288 }
289 else
290 {
291 // probably ECONNRESET or somesuch
292 slog (L_DEBUG, _("%s: fd %d, %s"), (const char *)si, w.fd, strerror (errno));
293 }
294
295 delete pkt;
296 }
297 else if (revents & POLLHUP)
298 {
299 // this cannot ;) happen on udp sockets
300 slog (L_ERR, _("FATAL: POLLHUP on udp v4 fd, terminating."));
301 exit (1);
302 }
303 else
304 {
305 slog (L_ERR,
306 _("FATAL: unknown revents %08x in socket, terminating\n"),
307 revents);
308 exit (1);
309 }
310 }
311
312 void
313 vpn::ipv4_ev (io_watcher &w, short revents)
314 {
315 if (revents & (POLLIN | POLLERR))
316 {
317 vpn_packet *pkt = new vpn_packet;
318 struct sockaddr_in sa;
319 socklen_t sa_len = sizeof (sa);
320 int len;
321
322 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
323
324 sockinfo si(sa, PROT_IPv4);
325
326 if (len > 0)
327 {
328 pkt->len = len;
329
330 // raw sockets deliver the ipv4, but don't expect it on sends
331 // this is slow, but...
332 pkt->skip_hdr (IP_OVERHEAD);
333
334 recv_vpn_packet (pkt, si);
335 }
336 else
337 {
338 // probably ECONNRESET or somesuch
339 slog (L_DEBUG, _("%s: %s"), (const char *)si, strerror (errno));
340 }
341
342 delete pkt;
343 }
344 else if (revents & POLLHUP)
345 {
346 // this cannot ;) happen on udp sockets
347 slog (L_ERR, _("FATAL: POLLHUP on ipv4 fd, terminating."));
348 exit (1);
349 }
350 else
351 {
352 slog (L_ERR,
353 _("FATAL: unknown revents %08x in socket, terminating\n"),
354 revents);
355 exit (1);
356 }
357 }
358
359 void
360 vpn::tap_ev (io_watcher &w, short revents)
361 {
362 if (revents & POLLIN)
363 {
364 /* process data */
365 tap_packet *pkt;
366
367 pkt = tap->recv ();
368
369 int dst = mac2id (pkt->dst);
370 int src = mac2id (pkt->src);
371
372 if (src != THISNODE->id)
373 {
374 slog (L_ERR, _("FATAL: tap packet not originating on current node received, terminating."));
375 exit (1);
376 }
377
378 if (dst == THISNODE->id)
379 {
380 slog (L_ERR, _("FATAL: tap packet destined for current node received, terminating."));
381 exit (1);
382 }
383
384 if (dst > conns.size ())
385 slog (L_ERR, _("tap packet for unknown node %d received, ignoring."), dst);
386 else
387 {
388 if (dst)
389 {
390 // unicast
391 if (dst != THISNODE->id)
392 conns[dst - 1]->inject_data_packet (pkt);
393 }
394 else
395 {
396 // broadcast, first check router, then self, then english
397 connection *router = find_router ();
398
399 if (router)
400 router->inject_data_packet (pkt, true);
401 else
402 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
403 if ((*c)->conf != THISNODE)
404 (*c)->inject_data_packet (pkt);
405 }
406 }
407
408 delete pkt;
409 }
410 else if (revents & (POLLHUP | POLLERR))
411 {
412 slog (L_ERR, _("FATAL: POLLHUP or POLLERR on network device fd, terminating."));
413 exit (1);
414 }
415 else
416 abort ();
417 }
418
419 void
420 vpn::event_cb (time_watcher &w)
421 {
422 if (events)
423 {
424 if (events & EVENT_SHUTDOWN)
425 {
426 slog (L_INFO, _("preparing shutdown..."));
427
428 shutdown_all ();
429
430 remove_pid (pidfilename);
431
432 slog (L_INFO, _("terminating"));
433
434 exit (0);
435 }
436
437 if (events & EVENT_RECONNECT)
438 {
439 slog (L_INFO, _("forced reconnect"));
440
441 reconnect_all ();
442 }
443
444 events = 0;
445 }
446
447 w.at = TSTAMP_CANCEL;
448 }
449
450 void
451 vpn::shutdown_all ()
452 {
453 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
454 (*c)->shutdown ();
455 }
456
457 void
458 vpn::reconnect_all ()
459 {
460 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
461 delete *c;
462
463 conns.clear ();
464
465 connection_init ();
466
467 for (configuration::node_vector::iterator i = conf.nodes.begin ();
468 i != conf.nodes.end (); ++i)
469 {
470 connection *conn = new connection (this);
471
472 conn->conf = *i;
473 conns.push_back (conn);
474
475 conn->establish_connection ();
476 }
477 }
478
479 connection *vpn::find_router ()
480 {
481 u32 prio = 0;
482 connection *router = 0;
483
484 for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
485 {
486 connection *c = *i;
487
488 if (c->conf->routerprio > prio
489 && c->connectmode == conf_node::C_ALWAYS
490 && c->conf != THISNODE
491 && c->ictx && c->octx)
492 {
493 prio = c->conf->routerprio;
494 router = c;
495 }
496 }
497
498 return router;
499 }
500
501 void vpn::connect_request (int id)
502 {
503 connection *c = find_router ();
504
505 if (c)
506 c->connect_request (id);
507 //else // does not work, because all others must connect to the same router
508 // // no router found, aggressively connect to all routers
509 // for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
510 // if ((*i)->conf->routerprio)
511 // (*i)->establish_connection ();
512 }
513
514 void
515 connection::dump_status ()
516 {
517 slog (L_NOTICE, _("node %s (id %d)"), conf->nodename, conf->id);
518 slog (L_NOTICE, _(" connectmode %d (%d) / sockaddr %s / minor %d"),
519 connectmode, conf->connectmode, (const char *)si, (int)prot_minor);
520 slog (L_NOTICE, _(" ictx/octx %08lx/%08lx / oseqno %d / retry_cnt %d"),
521 (long)ictx, (long)octx, (int)oseqno, (int)retry_cnt);
522 slog (L_NOTICE, _(" establish_conn %ld / rekey %ld / keepalive %ld"),
523 (long)(establish_connection.at), (long)(rekey.at), (long)(keepalive.at));
524 }
525
526 void
527 vpn::dump_status ()
528 {
529 slog (L_NOTICE, _("BEGIN status dump (%ld)"), (long)NOW);
530
531 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
532 (*c)->dump_status ();
533
534 slog (L_NOTICE, _("END status dump"));
535 }
536
537 vpn::vpn (void)
538 : event(this, &vpn::event_cb)
539 , udpv4_ev_watcher(this, &vpn::udpv4_ev)
540 , ipv4_ev_watcher (this, &vpn::ipv4_ev)
541 , tap_ev_watcher (this, &vpn::tap_ev)
542 #if ENABLE_TCP
543 , tcpv4_ev_watcher(this, &vpn::tcpv4_ev)
544 #endif
545 {
546 }
547
548 vpn::~vpn ()
549 {
550 }
551