ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/vpn.C
(Generate patch)

Comparing gvpe/src/vpn.C (file contents):
Revision 1.3 by pcg, Wed Apr 2 21:02:25 2003 UTC vs.
Revision 1.8 by pcg, Mon Apr 7 01:28:56 2003 UTC

38 38
39#include "connection.h" 39#include "connection.h"
40#include "util.h" 40#include "util.h"
41#include "vpn.h" 41#include "vpn.h"
42 42
43#if ENABLE_TCP
44# include <map>
45# include <unistd.h>
46# include <fcntl.h>
47# include <sys/poll.h>
48#endif
49
50///////////////////////////////////////////////////////////////////////////// 43/////////////////////////////////////////////////////////////////////////////
51 44
52const char *vpn::script_if_up () 45const char *vpn::script_if_up ()
53{ 46{
54 // the tunnel device mtu should be the physical mtu - overhead 47 // the tunnel device mtu should be the physical mtu - overhead
78} 71}
79 72
80int 73int
81vpn::setup () 74vpn::setup ()
82{ 75{
76 ipv4_fd = -1;
77
78 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto)
79 {
80 ipv4_fd = socket (PF_INET, SOCK_RAW, ::conf.ip_proto);
81
82 if (ipv4_fd < 0)
83 return -1;
84
85 sockinfo si (THISNODE, PROT_IPv4);
86
87 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ()))
88 {
89 slog (L_ERR, _("can't bind ipv4 socket on %s: %s"), (const char *)si, strerror (errno));
90 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 setsockopt (ipv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
100 }
101#endif
102
103 ipv4_ev_watcher.start (ipv4_fd, POLLIN);
104 }
105
83 udpv4_fd = -1; 106 udpv4_fd = -1;
84 107
85 if (THISNODE->protocols & PROT_UDPv4) 108 if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port)
86 { 109 {
87 udpv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); 110 udpv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
88 111
89 if (udpv4_fd < 0) 112 if (udpv4_fd < 0)
90 return -1; 113 return -1;
114#endif 137#endif
115 138
116 udpv4_ev_watcher.start (udpv4_fd, POLLIN); 139 udpv4_ev_watcher.start (udpv4_fd, POLLIN);
117 } 140 }
118 141
119 ipv4_fd = -1; 142 tcpv4_fd = -1;
120 if (THISNODE->protocols & PROT_IPv4)
121 {
122 ipv4_fd = socket (PF_INET, SOCK_RAW, ::conf.ip_proto);
123
124 if (ipv4_fd < 0)
125 return -1;
126
127 sockinfo si (THISNODE, PROT_IPv4);
128
129 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ()))
130 {
131 slog (L_ERR, _("can't bind ipv4 socket on %s: %s"), (const char *)si, strerror (errno));
132 exit (1);
133 }
134
135#ifdef IP_MTU_DISCOVER
136 // this I really consider a linux bug. I am neither connected
137 // nor do I fragment myself. Linux still sets DF and doesn't
138 // fragment for me sometimes.
139 {
140 int oval = IP_PMTUDISC_DONT;
141 setsockopt (ipv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
142 }
143#endif
144
145 ipv4_ev_watcher.start (ipv4_fd, POLLIN);
146 }
147 143
148#if ENABLE_TCP 144#if ENABLE_TCP
149 if (THISNODE->protocols & PROT_TCPv4) 145 if (THISNODE->protocols & PROT_TCPv4 && THISNODE->tcp_port)
150 { 146 {
151 tcpv4_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); 147 tcpv4_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
152 148
153 if (tcpv4_fd < 0) 149 if (tcpv4_fd < 0)
154 return -1; 150 return -1;
191 reconnect_all (); 187 reconnect_all ();
192 188
193 return 0; 189 return 0;
194} 190}
195 191
196void 192// send a vpn packet out to other hosts
193bool
194vpn::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos)
195{
196 switch (si.prot)
197 {
198 case PROT_IPv4:
199 return send_ipv4_packet (pkt, si, tos);
200
201 case PROT_UDPv4:
202 return send_udpv4_packet (pkt, si, tos);
203
204#if ENABLE_TCP
205 case PROT_TCPv4:
206 return send_tcpv4_packet (pkt, si, tos);
207#endif
208
209 default:
210 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol"), (const char *)si);
211 return false;
212 }
213}
214
215bool
197vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) 216vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
198{ 217{
199 setsockopt (ipv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos); 218 setsockopt (ipv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
200 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); 219 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
201}
202 220
203void 221 return true;
222}
223
224bool
204vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) 225vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
205{ 226{
206 setsockopt (udpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos); 227 setsockopt (udpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
207 sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); 228 sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
229
230 return true;
208} 231}
209 232
210void 233void
211vpn::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi) 234vpn::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi)
212{ 235{
219 if (src == 0 || src > conns.size () 242 if (src == 0 || src > conns.size ()
220 || dst > conns.size () 243 || dst > conns.size ()
221 || pkt->typ () >= vpn_packet::PT_MAX) 244 || pkt->typ () >= vpn_packet::PT_MAX)
222 slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)"), 245 slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)"),
223 (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ()); 246 (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ());
247 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 ());
224 else 250 else
225 { 251 {
226 connection *c = conns[src - 1]; 252 connection *c = conns[src - 1];
227 253
228 if (dst == 0 && !THISNODE->routerprio) 254 if (dst == 0 && !THISNODE->routerprio)
229 slog (L_WARN, _("%s(%s): received broadcast, but we are no router"), 255 slog (L_WARN, _("%s(%s): received broadcast, but we are no router"),
230 c->conf->nodename, (const char *)rsi); 256 c->conf->nodename, (const char *)rsi);
231 else if (dst != 0 && dst != THISNODE->id) 257 else if (dst != 0 && dst != THISNODE->id)
232 // FORWARDING NEEDED ;) 258 {
259 if (THISNODE->routerprio)
260 // the tos setting gets lost here. who cares.
261 conns[dst - 1]->inject_vpn_packet (pkt);
262 else
233 slog (L_WARN, 263 slog (L_WARN,
234 _("received frame for node %d ('%s') from %s, but this is node %d ('%s')"), 264 _("%s(%s): forwarding request (=> %s), but we are no router"),
265 c->conf->nodename, (const char *)rsi,
235 dst, conns[dst - 1]->conf->nodename, 266 conns[dst - 1]->conf->nodename);
236 (const char *)rsi, 267 }
237 THISNODE->id, THISNODE->nodename);
238 else 268 else
239 c->recv_vpn_packet (pkt, rsi); 269 c->recv_vpn_packet (pkt, rsi);
240 } 270 }
241} 271}
242 272
250 socklen_t sa_len = sizeof (sa); 280 socklen_t sa_len = sizeof (sa);
251 int len; 281 int len;
252 282
253 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len); 283 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
254 284
255 sockinfo si(sa); 285 sockinfo si(sa, PROT_UDPv4);
256 286
257 if (len > 0) 287 if (len > 0)
258 { 288 {
259 pkt->len = len; 289 pkt->len = len;
260 290
261 recv_vpn_packet (pkt, si); 291 recv_vpn_packet (pkt, si);
262 } 292 }
263 else 293 else
264 { 294 {
265 // probably ECONNRESET or somesuch 295 // probably ECONNRESET or somesuch
266 slog (L_DEBUG, _("%s: %s"), (const char *)si, strerror (errno)); 296 slog (L_DEBUG, _("%s: fd %d, %s"), (const char *)si, w.fd, strerror (errno));
267 } 297 }
268 298
269 delete pkt; 299 delete pkt;
270 } 300 }
271 else if (revents & POLLHUP) 301 else if (revents & POLLHUP)
327 _("FATAL: unknown revents %08x in socket, terminating\n"), 357 _("FATAL: unknown revents %08x in socket, terminating\n"),
328 revents); 358 revents);
329 exit (1); 359 exit (1);
330 } 360 }
331} 361}
332
333#if ENABLE_TCP
334
335struct tcp_connection;
336
337struct lt_sockinfo
338{
339 bool operator()(const sockinfo *a, const sockinfo *b) const
340 {
341 return *a < *b;
342 }
343};
344
345struct tcp_si_map : public map<const sockinfo *, tcp_connection *, lt_sockinfo> {
346 void cleaner_cb (time_watcher &w); time_watcher cleaner;
347
348 tcp_si_map ()
349 : cleaner(this, &tcp_si_map::cleaner_cb)
350 {
351 cleaner.start (0);
352 }
353} tcp_si;
354
355struct tcp_connection : io_watcher {
356 tstamp last_activity;
357 const sockinfo si;
358 vpn &v;
359 bool ok;
360
361 void tcpv4_ev (io_watcher &w, short revents);
362
363 operator tcp_si_map::value_type()
364 {
365 return tcp_si_map::value_type (&si, this);
366 }
367
368 tcp_connection (int fd_, const sockinfo &si_, vpn &v_)
369 : v(v_), si(si_), io_watcher(this, &tcp_connection::tcpv4_ev), ok(false)
370 {
371 last_activity = NOW;
372 start (fd_, POLLOUT);
373 }
374
375 ~tcp_connection () { close (fd); }
376};
377
378void tcp_si_map::cleaner_cb (time_watcher &w)
379{
380 w.at = NOW + 600;
381 tstamp to = NOW - ::conf.keepalive - 30;
382
383 for (iterator i = begin (); i != end(); )
384 if (i->second->last_activity >= to)
385 ++i;
386 else
387 {
388 erase (i);
389 i = begin ();
390 }
391}
392
393void
394vpn::send_tcpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
395{
396 tcp_si_map::iterator info = tcp_si.find (&si);
397
398 if (info == tcp_si.end ())
399 {
400 // woaw, the first lost packet ;)
401 int fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
402
403 if (fd >= 0)
404 {
405 fcntl (fd, F_SETFL, O_NONBLOCK);
406
407 if (connect (fd, si.sav4 (), si.salenv4 ()) >= 0
408 || errno == EINPROGRESS)
409 {
410 tcp_connection *i = new tcp_connection (fd, si, *this);
411
412 tcp_si.insert (*i);
413 }
414 else
415 close (fd);
416 }
417 }
418 else
419 {
420 tcp_connection *i = info->second;
421
422 i->last_activity = NOW;
423
424 if (i->ok)
425 {
426 setsockopt (i->fd, SOL_IP, IP_TOS, &tos, sizeof tos);
427
428 // we use none of the advantages of tcp
429 write (i->fd, (void *)pkt, pkt->len + sizeof (u32)) != pkt->len + sizeof (u32);
430 }
431 }
432
433#if 0
434 setsockopt (udpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
435 sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
436#endif
437}
438
439void
440tcp_connection::tcpv4_ev (io_watcher &w, short revents)
441{
442 last_activity = NOW;
443
444 if (!ok) // just established?
445 {
446 ok = true;
447 fcntl (fd, F_SETFL, 0);
448 stop ();
449 start (fd, POLLIN);
450 }
451
452 if (revents & (POLLIN | POLLERR))
453 {
454 u32 len;
455
456 if (sizeof (len) == read (fd, &len, sizeof (len)))
457 {
458 vpn_packet *pkt = new vpn_packet;
459
460 if (len == read (fd, &((*pkt)[0]), len))
461 {
462 pkt->len = len;
463
464 v.recv_vpn_packet (pkt, si);
465 return;
466 }
467
468 delete pkt;
469 }
470
471 tcp_si.erase (&si);
472 stop ();
473 }
474}
475
476void
477vpn::tcpv4_ev (io_watcher &w, short revents)
478{
479 if (revents & (POLLIN | POLLERR))
480 {
481 struct sockaddr_in sa;
482 socklen_t sa_len = sizeof (sa);
483 int len;
484
485 int fd = accept (w.fd, (sockaddr *)&sa, &sa_len);
486
487 if (fd >= 0)
488 {
489 fcntl (fd, F_SETFL, O_NONBLOCK);
490
491 sockinfo si(sa, PROT_TCPv4);
492 tcp_connection *i = new tcp_connection (fd, si, *this);
493
494 slog (L_ERR, "accepted %d\n", fd);//D
495
496 tcp_si.insert (*i);
497 }
498 }
499}
500
501#endif
502 362
503void 363void
504vpn::tap_ev (io_watcher &w, short revents) 364vpn::tap_ev (io_watcher &w, short revents)
505{ 365{
506 if (revents & POLLIN) 366 if (revents & POLLIN)
640 } 500 }
641 501
642 return router; 502 return router;
643} 503}
644 504
645void vpn::connect_request (int id) 505void vpn::send_connect_request (int id)
646{ 506{
647 connection *c = find_router (); 507 connection *c = find_router ();
648 508
649 if (c) 509 if (c)
650 c->connect_request (id); 510 c->send_connect_request (id);
651 //else // does not work, because all others must connect to the same router 511 else
652 // // no router found, aggressively connect to all routers 512 // no router found, aggressively connect to all routers
653 // for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i) 513 for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
654 // if ((*i)->conf->routerprio) 514 if ((*i)->conf->routerprio)
655 // (*i)->establish_connection (); 515 (*i)->establish_connection ();
656} 516}
657 517
658void 518void
659connection::dump_status () 519connection::dump_status ()
660{ 520{

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines