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.34 by pcg, Sat Mar 26 03:16:24 2005 UTC vs.
Revision 1.44 by pcg, Tue Dec 4 17:17:20 2007 UTC

1/* 1/*
2 vpn.C -- handle the protocol, encryption, handshaking etc. 2 vpn.C -- handle the protocol, encryption, handshaking etc.
3 Copyright (C) 2003-2005 Marc Lehmann <gvpe@schmorp.de> 3 Copyright (C) 2003-2007 Marc Lehmann <gvpe@schmorp.de>
4 4
5 This file is part of GVPE. 5 This file is part of GVPE.
6 6
7 GVPE is free software; you can redistribute it and/or modify 7 GVPE is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by 8 it under the terms of the GNU General Public License as published by
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details. 15 GNU General Public License for more details.
16 16
17 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
18 along with gvpe; if not, write to the Free Software 18 along with gvpe; if not, write to the Free Software
19 Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20*/ 20*/
21 21
22#include "config.h" 22#include "config.h"
23 23
24#include <list> 24#include <list>
46 46
47vpn network; // THE vpn (bad design...) 47vpn network; // THE vpn (bad design...)
48 48
49///////////////////////////////////////////////////////////////////////////// 49/////////////////////////////////////////////////////////////////////////////
50 50
51static void inline
52set_tos (int fd, int &tos_prev, int tos)
53{
54#if defined(SOL_IP) && defined(IP_TOS)
55 if (tos_prev == tos)
56 return;
57
58 tos_prev = tos;
59 setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos);
60#endif
61}
62
51void 63void
52vpn::script_init_env () 64vpn::script_init_env ()
53{ 65{
54 // the tunnel device mtu should be the physical mtu - overhead 66 // the tunnel device mtu should be the physical mtu - overhead
55 // the tricky part is rounding to the cipher key blocksize 67 // the tricky part is rounding to the cipher key blocksize
98} 110}
99 111
100int 112int
101vpn::setup () 113vpn::setup ()
102{ 114{
115 ipv4_tos = -1;
103 ipv4_fd = -1; 116 ipv4_fd = -1;
104 117
105 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto) 118 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto)
106 { 119 {
107 ipv4_fd = socket (PF_INET, SOCK_RAW, ::conf.ip_proto); 120 ipv4_fd = socket (PF_INET, SOCK_RAW, ::conf.ip_proto);
108 121
109 if (ipv4_fd < 0) 122 if (ipv4_fd < 0)
110 return -1; 123 return -1;
111 124
112 fcntl (ipv4_fd, F_SETFL, O_NONBLOCK); 125 fcntl (ipv4_fd, F_SETFL, O_NONBLOCK);
126 fcntl (ipv4_fd, F_SETFD, FD_CLOEXEC);
113 127
114#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) 128#if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
115 // this I really consider a linux bug. I am neither connected 129 // this I really consider a linux bug. I am neither connected
116 // nor do I fragment myself. Linux still sets DF and doesn't 130 // nor do I fragment myself. Linux still sets DF and doesn't
117 // fragment for me sometimes. 131 // fragment for me sometimes.
127 { 141 {
128 slog (L_ERR, _("can't bind ipv4 socket on %s: %s"), (const char *)si, strerror (errno)); 142 slog (L_ERR, _("can't bind ipv4 socket on %s: %s"), (const char *)si, strerror (errno));
129 exit (EXIT_FAILURE); 143 exit (EXIT_FAILURE);
130 } 144 }
131 145
132 ipv4_ev_watcher.start (ipv4_fd, EVENT_READ); 146 ipv4_ev_watcher.start (ipv4_fd, EV_READ);
133 } 147 }
134 148
149 udpv4_tos = -1;
135 udpv4_fd = -1; 150 udpv4_fd = -1;
136 151
137 if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port) 152 if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port)
138 { 153 {
139 udpv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); 154 udpv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
140 155
141 if (udpv4_fd < 0) 156 if (udpv4_fd < 0)
142 return -1; 157 return -1;
143 158
144 fcntl (udpv4_fd, F_SETFL, O_NONBLOCK); 159 fcntl (udpv4_fd, F_SETFL, O_NONBLOCK);
160 fcntl (udpv4_fd, F_SETFD, FD_CLOEXEC);
145 161
146 // standard daemon practise... 162 // standard daemon practise...
147 { 163 {
148 int oval = 1; 164 int oval = 1;
149 setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval); 165 setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
165 { 181 {
166 slog (L_ERR, _("can't bind udpv4 on %s: %s"), (const char *)si, strerror (errno)); 182 slog (L_ERR, _("can't bind udpv4 on %s: %s"), (const char *)si, strerror (errno));
167 exit (EXIT_FAILURE); 183 exit (EXIT_FAILURE);
168 } 184 }
169 185
170 udpv4_ev_watcher.start (udpv4_fd, EVENT_READ); 186 udpv4_ev_watcher.start (udpv4_fd, EV_READ);
171 } 187 }
172 188
189 icmpv4_tos = -1;
173 icmpv4_fd = -1; 190 icmpv4_fd = -1;
174 191
175#if ENABLE_ICMP 192#if ENABLE_ICMP
176 if (THISNODE->protocols & PROT_ICMPv4) 193 if (THISNODE->protocols & PROT_ICMPv4)
177 { 194 {
178 icmpv4_fd = socket (PF_INET, SOCK_RAW, IPPROTO_ICMP); 195 icmpv4_fd = socket (PF_INET, SOCK_RAW, IPPROTO_ICMP);
179 196
180 if (icmpv4_fd < 0) 197 if (icmpv4_fd < 0)
181 return -1; 198 return -1;
182 199
183 fcntl (icmpv4_fd, F_SETFL, O_NONBLOCK); 200 fcntl (icmpv4_fd, F_SETFL, O_NONBLOCK);
201 fcntl (icmpv4_fd, F_SETFD, FD_CLOEXEC);
184 202
185#ifdef ICMP_FILTER 203#ifdef ICMP_FILTER
186 { 204 {
187 icmp_filter oval; 205 icmp_filter oval;
188 oval.data = 0xffffffff; 206 oval.data = 0xffffffff;
197 // this I really consider a linux bug. I am neither connected 215 // this I really consider a linux bug. I am neither connected
198 // nor do I fragment myself. Linux still sets DF and doesn't 216 // nor do I fragment myself. Linux still sets DF and doesn't
199 // fragment for me sometimes. 217 // fragment for me sometimes.
200 { 218 {
201 int oval = IP_PMTUDISC_DONT; 219 int oval = IP_PMTUDISC_DONT;
202 setsockopt (udpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval); 220 setsockopt (icmpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
203 } 221 }
204#endif 222#endif
205 223
206 sockinfo si (THISNODE, PROT_ICMPv4); 224 sockinfo si (THISNODE, PROT_ICMPv4);
207 225
209 { 227 {
210 slog (L_ERR, _("can't bind icmpv4 on %s: %s"), (const char *)si, strerror (errno)); 228 slog (L_ERR, _("can't bind icmpv4 on %s: %s"), (const char *)si, strerror (errno));
211 exit (EXIT_FAILURE); 229 exit (EXIT_FAILURE);
212 } 230 }
213 231
214 icmpv4_ev_watcher.start (icmpv4_fd, EVENT_READ); 232 icmpv4_ev_watcher.start (icmpv4_fd, EV_READ);
215 } 233 }
216#endif 234#endif
217 235
218 tcpv4_fd = -1; 236 tcpv4_fd = -1;
219 237
224 242
225 if (tcpv4_fd < 0) 243 if (tcpv4_fd < 0)
226 return -1; 244 return -1;
227 245
228 fcntl (tcpv4_fd, F_SETFL, O_NONBLOCK); 246 fcntl (tcpv4_fd, F_SETFL, O_NONBLOCK);
247 fcntl (tcpv4_fd, F_SETFD, FD_CLOEXEC);
229 248
230 // standard daemon practise... 249 // standard daemon practise...
231 { 250 {
232 int oval = 1; 251 int oval = 1;
233 setsockopt (tcpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval); 252 setsockopt (tcpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
245 { 264 {
246 slog (L_ERR, _("can't listen tcpv4 on %s: %s"), (const char *)si, strerror (errno)); 265 slog (L_ERR, _("can't listen tcpv4 on %s: %s"), (const char *)si, strerror (errno));
247 exit (EXIT_FAILURE); 266 exit (EXIT_FAILURE);
248 } 267 }
249 268
250 tcpv4_ev_watcher.start (tcpv4_fd, EVENT_READ); 269 tcpv4_ev_watcher.start (tcpv4_fd, EV_READ);
251 } 270 }
252#endif 271#endif
272
273 dnsv4_tos = -1;
274 dnsv4_fd = -1;
253 275
254#if ENABLE_DNS 276#if ENABLE_DNS
255 if (THISNODE->protocols & PROT_DNSv4) 277 if (THISNODE->protocols & PROT_DNSv4)
256 { 278 {
257 dns_forwarder.set (::conf.dns_forw_host, ::conf.dns_forw_port, PROT_DNSv4); 279 dns_forwarder.set (::conf.dns_forw_host, ::conf.dns_forw_port, PROT_DNSv4);
259 dnsv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); 281 dnsv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
260 282
261 if (dnsv4_fd < 0) 283 if (dnsv4_fd < 0)
262 return -1; 284 return -1;
263 285
286 fcntl (dnsv4_fd, F_SETFL, O_NONBLOCK);
287 fcntl (dnsv4_fd, F_SETFD, FD_CLOEXEC);
288
264#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) 289# if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
265 // this I really consider a linux bug. I am neither connected 290 // this I really consider a linux bug. I am neither connected
266 // nor do I fragment myself. Linux still sets DF and doesn't 291 // nor do I fragment myself. Linux still sets DF and doesn't
267 // fragment for me sometimes. 292 // fragment for me sometimes.
268 { 293 {
269 int oval = IP_PMTUDISC_DONT; 294 int oval = IP_PMTUDISC_DONT;
270 setsockopt (udpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval); 295 setsockopt (dnsv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
271 } 296 }
272#endif 297# endif
273 298
274 // standard daemon practise... 299 // standard daemon practise...
275 { 300 {
276 int oval = 1; 301 int oval = 1;
277 setsockopt (dnsv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval); 302 setsockopt (dnsv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
285 { 310 {
286 slog (L_ERR, _("can't bind dnsv4 on %s: %s"), (const char *)si, strerror (errno)); 311 slog (L_ERR, _("can't bind dnsv4 on %s: %s"), (const char *)si, strerror (errno));
287 exit (EXIT_FAILURE); 312 exit (EXIT_FAILURE);
288 } 313 }
289 314
290 dnsv4_ev_watcher.start (dnsv4_fd, EVENT_READ); 315 dnsv4_ev_watcher.start (dnsv4_fd, EV_READ);
291 } 316 }
292#endif 317#endif
293 318
294 ///////////////////////////////////////////////////////////////////////////// 319 /////////////////////////////////////////////////////////////////////////////
295 320
302 { 327 {
303 slog (L_ERR, _("cannot create network interface '%s'"), conf.ifname); 328 slog (L_ERR, _("cannot create network interface '%s'"), conf.ifname);
304 exit (EXIT_FAILURE); 329 exit (EXIT_FAILURE);
305 } 330 }
306 331
332 fcntl (tap->fd, F_SETFD, FD_CLOEXEC);
333
334 run_script_cb cb;
335 cb.set<vpn, &vpn::script_if_init> (this);
336
307 if (tap->if_up () && 337 if (tap->if_up () &&
308 !run_script (run_script_cb (this, &vpn::script_if_init), true)) 338 !run_script (cb, true))
309 { 339 {
310 slog (L_ERR, _("interface initialization command '%s' failed, exiting."), 340 slog (L_ERR, _("interface initialization command '%s' failed, exiting."),
311 tap->if_up ()); 341 tap->if_up ());
312 exit (EXIT_FAILURE); 342 exit (EXIT_FAILURE);
313 } 343 }
314 344
315 if (!run_script (run_script_cb (this, &vpn::script_if_up), true)) 345 cb.set<vpn, &vpn::script_if_up> (this);
346 if (!run_script (cb, true))
316 { 347 {
317 slog (L_ERR, _("if-up command execution failed, exiting.")); 348 slog (L_ERR, _("if-up command execution failed, exiting."));
318 exit (EXIT_FAILURE); 349 exit (EXIT_FAILURE);
319 } 350 }
320 351
321 tap_ev_watcher.start (tap->fd, EVENT_READ); 352 tap_ev_watcher.start (tap->fd, EV_READ);
322 353
323 return 0; 354 return 0;
324} 355}
325 356
326bool 357bool
327vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) 358vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
328{ 359{
329#if defined(SOL_IP) && defined(IP_TOS) 360 set_tos (ipv4_fd, ipv4_tos, tos);
330 setsockopt (ipv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
331#endif
332 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); 361 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
333 362
334 return true; 363 return true;
335} 364}
336 365
359 388
360#if ENABLE_ICMP 389#if ENABLE_ICMP
361bool 390bool
362vpn::send_icmpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) 391vpn::send_icmpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
363{ 392{
364#if defined(SOL_IP) && defined(IP_TOS)
365 setsockopt (icmpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
366#endif
367
368 pkt->unshift_hdr (4); 393 pkt->unshift_hdr (4);
369 394
370 icmp_header *hdr = (icmp_header *)&((*pkt)[0]); 395 icmp_header *hdr = (icmp_header *)&((*pkt)[0]);
371 hdr->type = ::conf.icmp_type; 396 hdr->type = ::conf.icmp_type;
372 hdr->code = 255; 397 hdr->code = 255;
373 hdr->checksum = 0; 398 hdr->checksum = 0;
374 hdr->checksum = ipv4_checksum ((u16 *)hdr, pkt->len); 399 hdr->checksum = ipv4_checksum ((u16 *)hdr, pkt->len);
375 400
401 set_tos (icmpv4_fd, icmpv4_tos, tos);
376 sendto (icmpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); 402 sendto (icmpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
377 403
378 return true; 404 return true;
379} 405}
380#endif 406#endif
381 407
382bool 408bool
383vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) 409vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
384{ 410{
385#if defined(SOL_IP) && defined(IP_TOS) 411 set_tos (udpv4_fd, udpv4_tos, tos);
386 setsockopt (udpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos);
387#endif
388 sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); 412 sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
389 413
390 return true; 414 return true;
391} 415}
392 416
454{ 478{
455 switch (si.prot) 479 switch (si.prot)
456 { 480 {
457 case PROT_IPv4: 481 case PROT_IPv4:
458 return send_ipv4_packet (pkt, si, tos); 482 return send_ipv4_packet (pkt, si, tos);
483
459 case PROT_UDPv4: 484 case PROT_UDPv4:
460 return send_udpv4_packet (pkt, si, tos); 485 return send_udpv4_packet (pkt, si, tos);
486
461#if ENABLE_TCP 487#if ENABLE_TCP
462 case PROT_TCPv4: 488 case PROT_TCPv4:
463 return send_tcpv4_packet (pkt, si, tos); 489 return send_tcpv4_packet (pkt, si, tos);
464#endif 490#endif
465#if ENABLE_ICMP 491#if ENABLE_ICMP
468#endif 494#endif
469#if ENABLE_DNS 495#if ENABLE_DNS
470 case PROT_DNSv4: 496 case PROT_DNSv4:
471 return send_dnsv4_packet (pkt, si, tos); 497 return send_dnsv4_packet (pkt, si, tos);
472#endif 498#endif
473
474 default: 499 default:
475 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol"), (const char *)si); 500 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol"), (const char *)si);
476 } 501 }
477 502
478 return false; 503 return false;
479} 504}
480 505
481void 506void
482vpn::ipv4_ev (io_watcher &w, short revents) 507vpn::ipv4_ev (ev::io &w, int revents)
483{ 508{
484 if (revents & EVENT_READ) 509 if (revents & EV_READ)
485 { 510 {
486 vpn_packet *pkt = new vpn_packet; 511 vpn_packet *pkt = new vpn_packet;
487 struct sockaddr_in sa; 512 struct sockaddr_in sa;
488 socklen_t sa_len = sizeof (sa); 513 socklen_t sa_len = sizeof (sa);
489 int len; 514 int len;
518 } 543 }
519} 544}
520 545
521#if ENABLE_ICMP 546#if ENABLE_ICMP
522void 547void
523vpn::icmpv4_ev (io_watcher &w, short revents) 548vpn::icmpv4_ev (ev::io &w, int revents)
524{ 549{
525 if (revents & EVENT_READ) 550 if (revents & EV_READ)
526 { 551 {
527 vpn_packet *pkt = new vpn_packet; 552 vpn_packet *pkt = new vpn_packet;
528 struct sockaddr_in sa; 553 struct sockaddr_in sa;
529 socklen_t sa_len = sizeof (sa); 554 socklen_t sa_len = sizeof (sa);
530 int len; 555 int len;
566 } 591 }
567} 592}
568#endif 593#endif
569 594
570void 595void
571vpn::udpv4_ev (io_watcher &w, short revents) 596vpn::udpv4_ev (ev::io &w, int revents)
572{ 597{
573 if (revents & EVENT_READ) 598 if (revents & EV_READ)
574 { 599 {
575 vpn_packet *pkt = new vpn_packet; 600 vpn_packet *pkt = new vpn_packet;
576 struct sockaddr_in sa; 601 struct sockaddr_in sa;
577 socklen_t sa_len = sizeof (sa); 602 socklen_t sa_len = sizeof (sa);
578 int len; 603 int len;
603 exit (EXIT_FAILURE); 628 exit (EXIT_FAILURE);
604 } 629 }
605} 630}
606 631
607void 632void
608vpn::tap_ev (io_watcher &w, short revents) 633vpn::tap_ev (ev::io &w, int revents)
609{ 634{
610 if (revents & EVENT_READ) 635 if (revents & EV_READ)
611 { 636 {
612 /* process data */ 637 /* process data */
613 tap_packet *pkt; 638 tap_packet *pkt;
614 639
615 pkt = tap->recv (); 640 pkt = tap->recv ();
645 else 670 else
646 abort (); 671 abort ();
647} 672}
648 673
649void 674void
650vpn::event_cb (time_watcher &w) 675vpn::event_cb (ev::timer &w, int)
651{ 676{
652 if (events) 677 if (events)
653 { 678 {
654 if (events & EVENT_SHUTDOWN) 679 if (events & EVENT_SHUTDOWN)
655 { 680 {
746} 771}
747 772
748void 773void
749vpn::dump_status () 774vpn::dump_status ()
750{ 775{
751 slog (L_NOTICE, _("BEGIN status dump (%ld)"), (long)NOW); 776 slog (L_NOTICE, _("BEGIN status dump (%ld)"), (long)ev_now ());
752 777
753 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c) 778 for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c)
754 (*c)->dump_status (); 779 (*c)->dump_status ();
755 780
756 slog (L_NOTICE, _("END status dump")); 781 slog (L_NOTICE, _("END status dump"));
757} 782}
758 783
759vpn::vpn (void) 784vpn::vpn (void)
785{
760: event (this, &vpn::event_cb) 786 event .set<vpn, &vpn::event_cb > (this);
761, udpv4_ev_watcher (this, &vpn::udpv4_ev) 787 udpv4_ev_watcher .set<vpn, &vpn::udpv4_ev > (this);
762, ipv4_ev_watcher (this, &vpn::ipv4_ev) 788 ipv4_ev_watcher .set<vpn, &vpn::ipv4_ev > (this);
763#if ENABLE_TCP 789#if ENABLE_TCP
764, tcpv4_ev_watcher (this, &vpn::tcpv4_ev) 790 tcpv4_ev_watcher .set<vpn, &vpn::tcpv4_ev > (this);
765#endif 791#endif
766#if ENABLE_ICMP 792#if ENABLE_ICMP
767, icmpv4_ev_watcher(this, &vpn::icmpv4_ev) 793 icmpv4_ev_watcher.set<vpn, &vpn::icmpv4_ev> (this);
768#endif 794#endif
769#if ENABLE_DNS 795#if ENABLE_DNS
770, dnsv4_ev_watcher (this, &vpn::dnsv4_ev) 796 dnsv4_ev_watcher .set<vpn, &vpn::dnsv4_ev > (this);
771#endif 797#endif
772, tap_ev_watcher (this, &vpn::tap_ev) 798 tap_ev_watcher .set<vpn, &vpn::tap_ev > (this);
773{
774} 799}
775 800
776vpn::~vpn () 801vpn::~vpn ()
777{ 802{
778} 803}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines