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.64 by root, Tue Dec 4 10:29:43 2012 UTC

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>
51#include "pidfile.h" 52#include "pidfile.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"
57
58using namespace std;
56 59
57vpn network; // THE vpn (bad design...) 60vpn network; // THE vpn (bad design...)
58 61
59///////////////////////////////////////////////////////////////////////////// 62/////////////////////////////////////////////////////////////////////////////
60 63
147int 150int
148vpn::setup () 151vpn::setup ()
149{ 152{
150 int success = 0; 153 int success = 0;
151 154
152#if 1//D2
153 ipv42_tos = -1; 155 ipv4_tos = -1;
154 ipv42_fd = -1; 156 ipv4_fd = -1;
155 157
156 if (THISNODE->protocols & PROT_IPv42 && ::conf.ip_proto) 158 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto)
157 { 159 {
158 ipv42_fd = setup_socket (PROT_IPv42, PF_INET, SOCK_RAW, ::conf.ip2_proto); 160 ipv4_fd = setup_socket (PROT_IPv4, PF_INET, SOCK_RAW, ::conf.ip_proto);
159 161
160 if (ipv42_fd < 0) 162 if (ipv4_fd < 0)
161 return -1; 163 return -1;
162 164
163#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) 165#if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
164 // this I really consider a linux bug. I am neither connected 166 // this I really consider a linux bug. I am neither connected
165 // nor do I fragment myself. Linux still sets DF and doesn't 167 // nor do I fragment myself. Linux still sets DF and doesn't
166 // fragment for me sometimes. 168 // fragment for me sometimes.
167 { 169 {
168 int oval = IP_PMTUDISC_DONT; 170 int oval = IP_PMTUDISC_DONT;
169 setsockopt (ipv42_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval); 171 setsockopt (ipv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
170 } 172 }
171#endif 173#endif
172 174
173 sockinfo si (THISNODE, PROT_IPv42); 175 sockinfo si (THISNODE, PROT_IPv4);
174 176
175 if (bind (ipv42_fd, si.sav4 (), si.salenv4 ())) 177 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ()))
176 { 178 {
177 slog (L_ERR, _("can't bind ipv42 socket on %s: %s, exiting."), (const char *)si, strerror (errno)); 179 slog (L_ERR, _("can't bind ipv4 socket on %s: %s, exiting."), (const char *)si, strerror (errno));
178 return -1; 180 return -1;
179 } 181 }
180 182
181 ipv42_ev_watcher.start (ipv42_fd, EV_READ); 183 ipv4_ev_watcher.start (ipv4_fd, EV_READ);
182 ++success; 184 ++success;
183 } 185 }
184 else 186 else
185 THISNODE->protocols &= ~PROT_IPv42; 187 THISNODE->protocols &= ~PROT_IPv4;
186#endif
187 188
188 ipv4_tos = -1; 189 udpv4_tos = -1;
189 ipv4_fd = -1; 190 udpv4_fd = -1;
190 191
191 if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto) 192 if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port)
192 { 193 {
193 ipv4_fd = setup_socket (PROT_IPv4, PF_INET, SOCK_RAW, ::conf.ip_proto); 194 udpv4_fd = setup_socket (PROT_UDPv4, PF_INET, SOCK_DGRAM, IPPROTO_UDP);
194 195
195 if (ipv4_fd < 0) 196 if (udpv4_fd < 0)
196 return -1; 197 return -1;
198
199 // standard daemon practise...
200 {
201 int oval = 1;
202 setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
203 }
197 204
198#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) 205#if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
199 // this I really consider a linux bug. I am neither connected 206 // this I really consider a linux bug. I am neither connected
200 // nor do I fragment myself. Linux still sets DF and doesn't 207 // nor do I fragment myself. Linux still sets DF and doesn't
201 // fragment for me sometimes. 208 // fragment for me sometimes.
202 { 209 {
203 int oval = IP_PMTUDISC_DONT; 210 int oval = IP_PMTUDISC_DONT;
204 setsockopt (ipv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval); 211 setsockopt (udpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
205 } 212 }
206#endif 213#endif
207 214
208 sockinfo si (THISNODE, PROT_IPv4); 215 sockinfo si (THISNODE, PROT_UDPv4);
209 216
210 if (bind (ipv4_fd, si.sav4 (), si.salenv4 ())) 217 if (bind (udpv4_fd, si.sav4 (), si.salenv4 ()))
211 { 218 {
212 slog (L_ERR, _("can't bind ipv4 socket on %s: %s, exiting."), (const char *)si, strerror (errno)); 219 slog (L_ERR, _("can't bind udpv4 on %s: %s, exiting."), (const char *)si, strerror (errno));
213 return -1; 220 return -1;
214 } 221 }
215 222
216 ipv4_ev_watcher.start (ipv4_fd, EV_READ); 223 udpv4_ev_watcher.start (udpv4_fd, EV_READ);
217 ++success; 224 ++success;
218 } 225 }
219 else 226 else
220 THISNODE->protocols &= ~PROT_IPv4; 227 THISNODE->protocols &= ~PROT_UDPv4;
221 228
222 udpv4_tos = -1; 229 icmpv4_tos = -1;
223 udpv4_fd = -1; 230 icmpv4_fd = -1;
224 231
225 if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port) 232#if ENABLE_ICMP
233 if (THISNODE->protocols & PROT_ICMPv4)
226 { 234 {
227 udpv4_fd = setup_socket (PROT_UDPv4, PF_INET, SOCK_DGRAM, IPPROTO_UDP); 235 icmpv4_fd = setup_socket (PROT_ICMPv4, PF_INET, SOCK_RAW, IPPROTO_ICMP);
228 236
229 if (udpv4_fd < 0) 237 if (icmpv4_fd < 0)
230 return -1; 238 return -1;
231 239
232 // standard daemon practise... 240#ifdef ICMP_FILTER
233 {
234 int oval = 1;
235 setsockopt (udpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval);
236 } 241 {
242 icmp_filter oval;
243 oval.data = 0xffffffff;
244 if (::conf.icmp_type < 32)
245 oval.data &= ~(1 << ::conf.icmp_type);
246
247 setsockopt (icmpv4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval);
248 }
249#endif
237 250
238#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) 251#if defined(SOL_IP) && defined(IP_MTU_DISCOVER)
239 // this I really consider a linux bug. I am neither connected 252 // this I really consider a linux bug. I am neither connected
240 // nor do I fragment myself. Linux still sets DF and doesn't 253 // nor do I fragment myself. Linux still sets DF and doesn't
241 // fragment for me sometimes. 254 // fragment for me sometimes.
242 { 255 {
243 int oval = IP_PMTUDISC_DONT; 256 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); 257 setsockopt (icmpv4_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval);
291 } 258 }
292#endif 259#endif
293 260
294 sockinfo si (THISNODE, PROT_ICMPv4); 261 sockinfo si (THISNODE, PROT_ICMPv4);
428 395
429 return 0; 396 return 0;
430} 397}
431 398
432bool 399bool
400vpn::drop_privileges ()
401{
402 if (::conf.change_root)
403 {
404 if (!strcmp (::conf.change_root, "/"))
405 {
406 char dir [L_tmpnam];
407 if (!tmpnam (dir))
408 {
409 slog (L_CRIT, _("unable to create anonymous root path."));
410 return false;
411 }
412
413 if (mkdir (dir, 0700))
414 {
415 slog (L_CRIT, _("unable to crate anonymous root directory."));
416 return false;
417 }
418
419 if (chdir (dir))
420 {
421 slog (L_CRIT, _("unable to change to anonymous root directory."));
422 return false;
423 }
424
425 if (rmdir (dir))
426 slog (L_ERR, _("unable to remove anonymous root directory, continuing."));
427 }
428 else
429 {
430 if (chdir (::conf.change_root))
431 {
432 slog (L_CRIT, _("%s: unable to change to specified root directory."), ::conf.change_root);
433 return false;
434 }
435 }
436
437 if (chroot ("."))
438 {
439 slog (L_CRIT, _("unable to set new root directory."));
440 return false;
441 }
442
443 if (chdir ("/"))
444 {
445 slog (L_CRIT, _("unable to set cwd to new root directory."));
446 return false;
447 }
448 }
449
450 if (::conf.change_gid)
451 if (setgid (::conf.change_gid))
452 {
453 slog (L_CRIT, _("unable to change group id to %d."), ::conf.change_gid);
454 return false;
455 }
456
457 if (::conf.change_uid)
458 if (setuid (::conf.change_uid))
459 {
460 slog (L_CRIT, _("unable to change user id to %d."), ::conf.change_uid);
461 return false;
462 }
463
464 return true;
465}
466
467bool
433vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) 468vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos)
434{ 469{
435 set_tos (ipv4_fd, ipv4_tos, tos); 470 set_tos (ipv4_fd, ipv4_tos, tos);
436 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); 471 sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ());
437 472
438 return true; 473 return true;
439} 474}
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 475
452static u16 476static u16
453ipv4_checksum (u16 *data, unsigned int len) 477ipv4_checksum (u16 *data, unsigned int len)
454{ 478{
455 // use 32 bit accumulator and fold back carry bits at the end 479 // use 32 bit accumulator and fold back carry bits at the end
559bool 583bool
560vpn::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos) 584vpn::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos)
561{ 585{
562 switch (si.prot) 586 switch (si.prot)
563 { 587 {
564#if 1//D2
565 case PROT_IPv42:
566 return send_ipv42_packet (pkt, si, tos);
567#endif
568
569 case PROT_IPv4: 588 case PROT_IPv4:
570 return send_ipv4_packet (pkt, si, tos); 589 return send_ipv4_packet (pkt, si, tos);
571 590
572 case PROT_UDPv4: 591 case PROT_UDPv4:
573 return send_udpv4_packet (pkt, si, tos); 592 return send_udpv4_packet (pkt, si, tos);
574 593
575#if ENABLE_TCP 594#if ENABLE_TCP
576 case PROT_TCPv4: 595 case PROT_TCPv4:
577 return send_tcpv4_packet (pkt, si, tos); 596 return send_tcpv4_packet (pkt, si, tos);
578#endif 597#endif
579#if ENABLE_ICMP 598#if ENABLE_ICMP
580 case PROT_ICMPv4: 599 case PROT_ICMPv4:
581 return send_icmpv4_packet (pkt, si, tos); 600 return send_icmpv4_packet (pkt, si, tos);
582#endif 601#endif
583#if ENABLE_DNS 602#if ENABLE_DNS
584 case PROT_DNSv4: 603 case PROT_DNSv4:
585 return send_dnsv4_packet (pkt, si, tos); 604 return send_dnsv4_packet (pkt, si, tos);
586#endif 605#endif
587 default: 606 default:
588 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol."), (const char *)si); 607 slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol."), (const char *)si);
589 } 608 }
590 609
591 return false; 610 return false;
592} 611}
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 612
636inline void 613inline void
637vpn::ipv4_ev (ev::io &w, int revents) 614vpn::ipv4_ev (ev::io &w, int revents)
638{ 615{
639 if (revents & EV_READ) 616 if (revents & EV_READ)
972vpn::vpn (void) 949vpn::vpn (void)
973{ 950{
974 event .set<vpn, &vpn::event_cb > (this); 951 event .set<vpn, &vpn::event_cb > (this);
975 udpv4_ev_watcher .set<vpn, &vpn::udpv4_ev > (this); 952 udpv4_ev_watcher .set<vpn, &vpn::udpv4_ev > (this);
976 ipv4_ev_watcher .set<vpn, &vpn::ipv4_ev > (this); 953 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 954#if ENABLE_TCP
981 tcpv4_ev_watcher .set<vpn, &vpn::tcpv4_ev > (this); 955 tcpv4_ev_watcher .set<vpn, &vpn::tcpv4_ev > (this);
982#endif 956#endif
983#if ENABLE_ICMP 957#if ENABLE_ICMP
984 icmpv4_ev_watcher.set<vpn, &vpn::icmpv4_ev> (this); 958 icmpv4_ev_watcher.set<vpn, &vpn::icmpv4_ev> (this);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines