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.62 by root, Sat Dec 17 22:05:34 2011 UTC vs.
Revision 1.67 by root, Fri Oct 11 04:07:24 2013 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-2008,2010,2011 Marc Lehmann <gvpe@schmorp.de> 3 Copyright (C) 2003-2008,2010,2011,2013 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 it 7 GVPE is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the 8 under the terms of the GNU General Public License as published by the
38#include <cstdlib> 38#include <cstdlib>
39 39
40#include <sys/types.h> 40#include <sys/types.h>
41#include <sys/socket.h> 41#include <sys/socket.h>
42#include <sys/wait.h> 42#include <sys/wait.h>
43#include <sys/stat.h>
43#include <errno.h> 44#include <errno.h>
44#include <time.h> 45#include <time.h>
45#include <unistd.h> 46#include <unistd.h>
46#include <fcntl.h> 47#include <fcntl.h>
47#include <sys/socket.h> 48#include <sys/socket.h>
52 53
53#include "connection.h" 54#include "connection.h"
54#include "util.h" 55#include "util.h"
55#include "vpn.h" 56#include "vpn.h"
56 57
58using namespace std;
59
57vpn network; // THE vpn (bad design...) 60vpn network; // THE vpn (bad design...)
58 61
59///////////////////////////////////////////////////////////////////////////// 62/////////////////////////////////////////////////////////////////////////////
60 63
61static void inline 64static void inline
75{ 78{
76 // the tunnel device mtu should be the physical mtu - overhead 79 // the tunnel device mtu should be the physical mtu - overhead
77 // the tricky part is rounding to the cipher key blocksize 80 // the tricky part is rounding to the cipher key blocksize
78 int mtu = conf.mtu - ETH_OVERHEAD - VPE_OVERHEAD - MAX_OVERHEAD; 81 int mtu = conf.mtu - ETH_OVERHEAD - VPE_OVERHEAD - MAX_OVERHEAD;
79 mtu += ETH_OVERHEAD - 6 - 6; // now we have the data portion 82 mtu += ETH_OVERHEAD - 6 - 6; // now we have the data portion
80 mtu -= mtu % EVP_CIPHER_block_size (CIPHER); // round 83 mtu -= mtu % BLOCK_SIZE (CIPHER); // round
81 mtu -= ETH_OVERHEAD - 6 - 6; // and get interface mtu again 84 mtu -= ETH_OVERHEAD - 6 - 6; // and get interface mtu again
82 85
83 char *env; 86 char *env;
84 asprintf (&env, "CONFBASE=%s", confbase); putenv (env); 87 asprintf (&env, "CONFBASE=%s", confbase); putenv (env);
85 asprintf (&env, "IFNAME=%s", tap->interface ()); putenv (env); 88 asprintf (&env, "IFNAME=%s", tap->interface ()); putenv (env);
110inline const char * 113inline const char *
111vpn::script_if_up () 114vpn::script_if_up ()
112{ 115{
113 script_init_env (); 116 script_init_env ();
114 117
115 char *filename; 118 return conf.config_filename (::conf.script_if_up, "if-up");
116 asprintf (&filename,
117 "%s/%s",
118 confbase,
119 ::conf.script_if_up ? ::conf.script_if_up : "if-up");
120
121 return filename;
122} 119}
123 120
124int 121int
125vpn::setup_socket (u8 prot, int family, int type, int proto) 122vpn::setup_socket (u8 prot, int family, int type, int proto)
126{ 123{
147int 144int
148vpn::setup () 145vpn::setup ()
149{ 146{
150 int success = 0; 147 int success = 0;
151 148
152#if 1//D2
153 ipv42_tos = -1; 149 ipv4_tos = -1;
154 ipv42_fd = -1; 150 ipv4_fd = -1;
155 151
156 if (THISNODE->protocols & PROT_IPv42 && ::conf.ip_proto) 152 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto)
157 { 153 {
158 ipv42_fd = setup_socket (PROT_IPv42, PF_INET, SOCK_RAW, ::conf.ip2_proto); 154 ipv4_fd = setup_socket (PROT_IPv4, PF_INET, SOCK_RAW, ::conf.ip_proto);
159 155
160 if (ipv42_fd < 0) 156 if (ipv4_fd < 0)
161 return -1; 157 return -1;
162 158
163#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) 159#if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
164 // this I really consider a linux bug. I am neither connected 160 // this I really consider a linux bug. I am neither connected
165 // nor do I fragment myself. Linux still sets DF and doesn't 161 // nor do I fragment myself. Linux still sets DF and doesn't
166 // fragment for me sometimes. 162 // fragment for me sometimes.
167 { 163 {
168 int oval = IP_PMTUDISC_DONT; 164 int oval = IP_PMTUDISC_DONT;
169 setsockopt (ipv42_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval); 165 setsockopt (ipv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
170 } 166 }
171#endif 167#endif
172 168
173 sockinfo si (THISNODE, PROT_IPv42); 169 sockinfo si (THISNODE, PROT_IPv4);
174 170
175 if (bind (ipv42_fd, si.sav4 (), si.salenv4 ())) 171 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ()))
176 { 172 {
177 slog (L_ERR, _("can't bind ipv42 socket on %s: %s, exiting."), (const char *)si, strerror (errno)); 173 slog (L_ERR, _("can't bind ipv4 socket on %s: %s, exiting."), (const char *)si, strerror (errno));
178 return -1; 174 return -1;
179 } 175 }
180 176
181 ipv42_ev_watcher.start (ipv42_fd, EV_READ); 177 ipv4_ev_watcher.start (ipv4_fd, EV_READ);
182 ++success; 178 ++success;
183 } 179 }
184 else 180 else
185 THISNODE->protocols &= ~PROT_IPv42; 181 THISNODE->protocols &= ~PROT_IPv4;
186#endif
187 182
188 ipv4_tos = -1; 183 udpv4_tos = -1;
189 ipv4_fd = -1; 184 udpv4_fd = -1;
190 185
191 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto) 186 if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port)
192 { 187 {
193 ipv4_fd = setup_socket (PROT_IPv4, PF_INET, SOCK_RAW, ::conf.ip_proto); 188 udpv4_fd = setup_socket (PROT_UDPv4, PF_INET, SOCK_DGRAM, IPPROTO_UDP);
194 189
195 if (ipv4_fd < 0) 190 if (udpv4_fd < 0)
196 return -1; 191 return -1;
192
193 // standard daemon practise...
194 {
195 int oval = 1;
196 setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
197 }
197 198
198#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) 199#if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
199 // this I really consider a linux bug. I am neither connected 200 // this I really consider a linux bug. I am neither connected
200 // nor do I fragment myself. Linux still sets DF and doesn't 201 // nor do I fragment myself. Linux still sets DF and doesn't
201 // fragment for me sometimes. 202 // fragment for me sometimes.
202 { 203 {
203 int oval = IP_PMTUDISC_DONT; 204 int oval = IP_PMTUDISC_DONT;
204 setsockopt (ipv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval); 205 setsockopt (udpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
205 } 206 }
206#endif 207#endif
207 208
208 sockinfo si (THISNODE, PROT_IPv4); 209 sockinfo si (THISNODE, PROT_UDPv4);
209 210
210 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ())) 211 if (bind (udpv4_fd, si.sav4 (), si.salenv4 ()))
211 { 212 {
212 slog (L_ERR, _("can't bind ipv4 socket on %s: %s, exiting."), (const char *)si, strerror (errno)); 213 slog (L_ERR, _("can't bind udpv4 on %s: %s, exiting."), (const char *)si, strerror (errno));
213 return -1; 214 return -1;
214 } 215 }
215 216
216 ipv4_ev_watcher.start (ipv4_fd, EV_READ); 217 udpv4_ev_watcher.start (udpv4_fd, EV_READ);
217 ++success; 218 ++success;
218 } 219 }
219 else 220 else
220 THISNODE->protocols &= ~PROT_IPv4; 221 THISNODE->protocols &= ~PROT_UDPv4;
221 222
222 udpv4_tos = -1; 223 icmpv4_tos = -1;
223 udpv4_fd = -1; 224 icmpv4_fd = -1;
224 225
225 if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port) 226#if ENABLE_ICMP
227 if (THISNODE->protocols & PROT_ICMPv4)
226 { 228 {
227 udpv4_fd = setup_socket (PROT_UDPv4, PF_INET, SOCK_DGRAM, IPPROTO_UDP); 229 icmpv4_fd = setup_socket (PROT_ICMPv4, PF_INET, SOCK_RAW, IPPROTO_ICMP);
228 230
229 if (udpv4_fd < 0) 231 if (icmpv4_fd < 0)
230 return -1; 232 return -1;
231 233
232 // standard daemon practise... 234#ifdef ICMP_FILTER
233 {
234 int oval = 1;
235 setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
236 } 235 {
236 icmp_filter oval;
237 oval.data = 0xffffffff;
238 if (::conf.icmp_type < 32)
239 oval.data &= ~(1 << ::conf.icmp_type);
240
241 setsockopt (icmpv4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval);
242 }
243#endif
237 244
238#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) 245#if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
239 // this I really consider a linux bug. I am neither connected 246 // this I really consider a linux bug. I am neither connected
240 // nor do I fragment myself. Linux still sets DF and doesn't 247 // nor do I fragment myself. Linux still sets DF and doesn't
241 // fragment for me sometimes. 248 // fragment for me sometimes.
242 { 249 {
243 int oval = IP_PMTUDISC_DONT; 250 int oval = IP_PMTUDISC_DONT;
244 setsockopt (udpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
245 }
246#endif
247
248 sockinfo si (THISNODE, PROT_UDPv4);
249
250 if (bind (udpv4_fd, si.sav4 (), si.salenv4 ()))
251 {
252 slog (L_ERR, _("can't bind udpv4 on %s: %s, exiting."), (const char *)si, strerror (errno));
253 return -1;
254 }
255
256 udpv4_ev_watcher.start (udpv4_fd, EV_READ);
257 ++success;
258 }
259 else
260 THISNODE->protocols &= ~PROT_UDPv4;
261
262 icmpv4_tos = -1;
263 icmpv4_fd = -1;
264
265#if ENABLE_ICMP
266 if (THISNODE->protocols & PROT_ICMPv4)
267 {
268 icmpv4_fd = setup_socket (PROT_ICMPv4, PF_INET, SOCK_RAW, IPPROTO_ICMP);
269
270 if (icmpv4_fd < 0)
271 return -1;
272
273#ifdef ICMP_FILTER
274 {
275 icmp_filter oval;
276 oval.data = 0xffffffff;
277 if (::conf.icmp_type < 32)
278 oval.data &= ~(1 << ::conf.icmp_type);
279
280 setsockopt (icmpv4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval);
281 }
282#endif
283
284#if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
285 // this I really consider a linux bug. I am neither connected
286 // nor do I fragment myself. Linux still sets DF and doesn't
287 // fragment for me sometimes.
288 {
289 int oval = IP_PMTUDISC_DONT;
290 setsockopt (icmpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval); 251 setsockopt (icmpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
291 } 252 }
292#endif 253#endif
293 254
294 sockinfo si (THISNODE, PROT_ICMPv4); 255 sockinfo si (THISNODE, PROT_ICMPv4);
428 389
429 return 0; 390 return 0;
430} 391}
431 392
432bool 393bool
394vpn::drop_privileges ()
395{
396 if (::conf.change_root)
397 {
398 if (!strcmp (::conf.change_root, "/"))
399 {
400 char dir [L_tmpnam];
401 if (!tmpnam (dir))
402 {
403 slog (L_CRIT, _("unable to create anonymous root path."));
404 return false;
405 }
406
407 if (mkdir (dir, 0700))
408 {
409 slog (L_CRIT, _("unable to crate anonymous root directory."));
410 return false;
411 }
412
413 if (chdir (dir))
414 {
415 slog (L_CRIT, _("unable to change to anonymous root directory."));
416 return false;
417 }
418
419 if (rmdir (dir))
420 slog (L_ERR, _("unable to remove anonymous root directory, continuing."));
421 }
422 else
423 {
424 if (chdir (::conf.change_root))
425 {
426 slog (L_CRIT, _("%s: unable to change to specified root directory."), ::conf.change_root);
427 return false;
428 }
429 }
430
431 if (chroot ("."))
432 {
433 slog (L_CRIT, _("unable to set new root directory."));
434 return false;
435 }
436
437 if (chdir ("/"))
438 {
439 slog (L_CRIT, _("unable to set cwd to new root directory."));
440 return false;
441 }
442 }
443
444 if (::conf.change_gid)
445 if (setgid (::conf.change_gid))
446 {
447 slog (L_CRIT, _("unable to change group id to %d."), ::conf.change_gid);
448 return false;
449 }
450
451 if (::conf.change_uid)
452 if (setuid (::conf.change_uid))
453 {
454 slog (L_CRIT, _("unable to change user id to %d."), ::conf.change_uid);
455 return false;
456 }
457
458 return true;
459}
460
461bool
433vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) 462vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
434{ 463{
435 set_tos (ipv4_fd, ipv4_tos, tos); 464 set_tos (ipv4_fd, ipv4_tos, tos);
436 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); 465 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
437 466
438 return true; 467 return true;
439} 468}
440
441#if 1 //D
442bool
443vpn::send_ipv42_packet (vpn_packet *pkt, const sockinfo &si, int tos)
444{
445 set_tos (ipv42_fd, ipv42_tos, tos);
446 sendto (ipv42_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
447
448 return true;
449}
450#endif
451 469
452static u16 470static u16
453ipv4_checksum (u16 *data, unsigned int len) 471ipv4_checksum (u16 *data, unsigned int len)
454{ 472{
455 // use 32 bit accumulator and fold back carry bits at the end 473 // use 32 bit accumulator and fold back carry bits at the end
559bool 577bool
560vpn::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos) 578vpn::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos)
561{ 579{
562 switch (si.prot) 580 switch (si.prot)
563 { 581 {
564#if 1//D2
565 case PROT_IPv42:
566 return send_ipv42_packet (pkt, si, tos);
567#endif
568
569 case PROT_IPv4: 582 case PROT_IPv4:
570 return send_ipv4_packet (pkt, si, tos); 583 return send_ipv4_packet (pkt, si, tos);
571 584
572 case PROT_UDPv4: 585 case PROT_UDPv4:
573 return send_udpv4_packet (pkt, si, tos); 586 return send_udpv4_packet (pkt, si, tos);
574 587
575#if ENABLE_TCP 588#if ENABLE_TCP
576 case PROT_TCPv4: 589 case PROT_TCPv4:
577 return send_tcpv4_packet (pkt, si, tos); 590 return send_tcpv4_packet (pkt, si, tos);
578#endif 591#endif
579#if ENABLE_ICMP 592#if ENABLE_ICMP
580 case PROT_ICMPv4: 593 case PROT_ICMPv4:
581 return send_icmpv4_packet (pkt, si, tos); 594 return send_icmpv4_packet (pkt, si, tos);
582#endif 595#endif
583#if ENABLE_DNS 596#if ENABLE_DNS
584 case PROT_DNSv4: 597 case PROT_DNSv4:
585 return send_dnsv4_packet (pkt, si, tos); 598 return send_dnsv4_packet (pkt, si, tos);
586#endif 599#endif
587 default: 600 default:
588 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol."), (const char *)si); 601 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol."), (const char *)si);
589 } 602 }
590 603
591 return false; 604 return false;
592} 605}
593
594#if 1//D2
595inline void
596vpn::ipv42_ev (ev::io &w, int revents)
597{
598 if (revents & EV_READ)
599 {
600 vpn_packet *pkt = new vpn_packet;
601 struct sockaddr_in sa;
602 socklen_t sa_len = sizeof (sa);
603 int len;
604
605 len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len);
606
607 sockinfo si(sa, PROT_IPv42);
608
609 if (len > 0)
610 {
611 pkt->len = len;
612
613 // raw sockets deliver the ipv4 header, but don't expect it on sends
614 pkt->skip_hdr (pkt->ipv4_hdr_len ());
615
616 recv_vpn_packet (pkt, si);
617 }
618 else
619 {
620 // probably ECONNRESET or somesuch
621 slog (L_DEBUG, _("%s: %s."), (const char *)si, strerror (errno));
622 }
623
624 delete pkt;
625 }
626 else
627 {
628 slog (L_ERR,
629 _("FATAL: unknown revents %08x in socket, exiting.\n"),
630 revents);
631 exit (EXIT_FAILURE);
632 }
633}
634#endif
635 606
636inline void 607inline void
637vpn::ipv4_ev (ev::io &w, int revents) 608vpn::ipv4_ev (ev::io &w, int revents)
638{ 609{
639 if (revents & EV_READ) 610 if (revents & EV_READ)
918{ 889{
919 for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i) 890 for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i)
920 { 891 {
921 connection *o = *i; 892 connection *o = *i;
922 893
923 if (!o->is_direct
924 && o->si.valid () 894 if (o->si.valid ()
925 && c->si != o->si 895 && c->si != o->si
926 && c == find_router_for (o)) 896 && c == find_router_for (o)
897 && !can_direct (THISNODE, o->conf))
927 { 898 {
928 slog (L_DEBUG, _("%s: can now route packets via %s, re-keying connection."), 899 slog (L_DEBUG, _("%s: can now route packets via %s, re-keying connection."),
929 o->conf->nodename, c->conf->nodename); 900 o->conf->nodename, c->conf->nodename);
930 o->rekey (); 901 o->rekey ();
931 } 902 }
972vpn::vpn (void) 943vpn::vpn (void)
973{ 944{
974 event .set<vpn, &vpn::event_cb > (this); 945 event .set<vpn, &vpn::event_cb > (this);
975 udpv4_ev_watcher .set<vpn, &vpn::udpv4_ev > (this); 946 udpv4_ev_watcher .set<vpn, &vpn::udpv4_ev > (this);
976 ipv4_ev_watcher .set<vpn, &vpn::ipv4_ev > (this); 947 ipv4_ev_watcher .set<vpn, &vpn::ipv4_ev > (this);
977#if 1//D2
978 ipv42_ev_watcher .set<vpn, &vpn::ipv42_ev > (this);
979#endif
980#if ENABLE_TCP 948#if ENABLE_TCP
981 tcpv4_ev_watcher .set<vpn, &vpn::tcpv4_ev > (this); 949 tcpv4_ev_watcher .set<vpn, &vpn::tcpv4_ev > (this);
982#endif 950#endif
983#if ENABLE_ICMP 951#if ENABLE_ICMP
984 icmpv4_ev_watcher.set<vpn, &vpn::icmpv4_ev> (this); 952 icmpv4_ev_watcher.set<vpn, &vpn::icmpv4_ev> (this);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines