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

Comparing gvpe/src/connection.C (file contents):
Revision 1.14 by pcg, Fri Aug 8 09:29:22 2003 UTC vs.
Revision 1.25 by pcg, Sat Jan 17 01:18:36 2004 UTC

1/* 1/*
2 connection.C -- manage a single connection 2 connection.C -- manage a single connection
3 Copyright (C) 2003-2004 Marc Lehmann <pcg@goof.com>
3 4
4 This program is free software; you can redistribute it and/or modify 5 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 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 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version. 8 (at your option) any later version.
20 21
21extern "C" { 22extern "C" {
22# include "lzf/lzf.h" 23# include "lzf/lzf.h"
23} 24}
24 25
26#include <cassert>
27
25#include <list> 28#include <list>
26 29
27#include <openssl/rand.h> 30#include <openssl/rand.h>
28#include <openssl/evp.h> 31#include <openssl/evp.h>
29#include <openssl/rsa.h> 32#include <openssl/rsa.h>
34#include "conf.h" 37#include "conf.h"
35#include "slog.h" 38#include "slog.h"
36#include "device.h" 39#include "device.h"
37#include "vpn.h" 40#include "vpn.h"
38#include "connection.h" 41#include "connection.h"
42
43#include "netcompat.h"
39 44
40#if !HAVE_RAND_PSEUDO_BYTES 45#if !HAVE_RAND_PSEUDO_BYTES
41# define RAND_pseudo_bytes RAND_bytes 46# define RAND_pseudo_bytes RAND_bytes
42#endif 47#endif
43 48
131 136
132} rsa_cache; 137} rsa_cache;
133 138
134void rsa_cache::cleaner_cb (time_watcher &w) 139void rsa_cache::cleaner_cb (time_watcher &w)
135{ 140{
136 if (empty ()) 141 if (!empty ())
137 w.at = TSTAMP_CANCEL;
138 else
139 { 142 {
140 w.at = NOW + RSA_TTL; 143 w.start (NOW + RSA_TTL);
141 144
142 for (iterator i = begin (); i != end (); ) 145 for (iterator i = begin (); i != end (); )
143 if (i->expire <= NOW) 146 if (i->expire <= NOW)
144 i = erase (i); 147 i = erase (i);
145 else 148 else
197// only do action once every x seconds per host whole allowing bursts. 200// only do action once every x seconds per host whole allowing bursts.
198// this implementation ("splay list" ;) is inefficient, 201// this implementation ("splay list" ;) is inefficient,
199// but low on resources. 202// but low on resources.
200struct net_rate_limiter : list<net_rateinfo> 203struct net_rate_limiter : list<net_rateinfo>
201{ 204{
202 static const double ALPHA = 1. - 1. / 180.; // allow bursts 205 static const double ALPHA = 1. - 1. / 600.; // allow bursts
203 static const double CUTOFF = 10.; // one event every CUTOFF seconds 206 static const double CUTOFF = 10.; // one event every CUTOFF seconds
204 static const double EXPIRE = CUTOFF * 30.; // expire entries after this time 207 static const double EXPIRE = CUTOFF * 30.; // expire entries after this time
205 static const double MAXDIF = CUTOFF * (1. / (1. - ALPHA)); // maximum diff /count value 208 static const double MAXDIF = CUTOFF * (1. / (1. - ALPHA)); // maximum diff /count value
206 209
207 bool can (const sockinfo &si) { return can((u32)si.host); } 210 bool can (const sockinfo &si) { return can((u32)si.host); }
208 bool can (u32 host); 211 bool can (u32 host);
209}; 212};
210 213
211net_rate_limiter auth_rate_limiter, reset_rate_limiter; 214net_rate_limiter auth_rate_limiter, reset_rate_limiter;
212 215
475 set_hdr (type, dst); 478 set_hdr (type, dst);
476} 479}
477 480
478bool config_packet::chk_config () const 481bool config_packet::chk_config () const
479{ 482{
480 return prot_major == PROTOCOL_MAJOR 483 if (prot_major != PROTOCOL_MAJOR)
481 && randsize == RAND_SIZE 484 slog (L_WARN, _("major version mismatch (remote %d <=> local %d)"), prot_major, PROTOCOL_MAJOR);
482 && hmaclen == HMACLENGTH 485 else if (randsize != RAND_SIZE)
483 && flags == curflags () 486 slog (L_WARN, _("rand size mismatch (remote %d <=> local %d)"), randsize, RAND_SIZE);
487 else if (hmaclen != HMACLENGTH)
488 slog (L_WARN, _("hmac length mismatch (remote %d <=> local %d)"), hmaclen, HMACLENGTH);
489 else if (flags != curflags ())
490 slog (L_WARN, _("flag mismatch (remote %x <=> local %x)"), flags, curflags ());
484 && challengelen == sizeof (rsachallenge) 491 else if (challengelen != sizeof (rsachallenge))
492 slog (L_WARN, _("challenge length mismatch (remote %d <=> local %d)"), challengelen, sizeof (rsachallenge));
485 && cipher_nid == htonl (EVP_CIPHER_nid (CIPHER)) 493 else if (cipher_nid != htonl (EVP_CIPHER_nid (CIPHER)))
494 slog (L_WARN, _("cipher mismatch (remote %x <=> local %x)"), ntohl (cipher_nid), EVP_CIPHER_nid (CIPHER));
486 && digest_nid == htonl (EVP_MD_type (RSA_HASH)) 495 else if (digest_nid != htonl (EVP_MD_type (RSA_HASH)))
496 slog (L_WARN, _("digest mismatch (remote %x <=> local %x)"), ntohl (digest_nid), EVP_MD_type (RSA_HASH));
487 && hmac_nid == htonl (EVP_MD_type (DIGEST)); 497 else if (hmac_nid != htonl (EVP_MD_type (DIGEST)))
498 slog (L_WARN, _("hmac mismatch (remote %x <=> local %x)"), ntohl (hmac_nid), EVP_MD_type (DIGEST));
499 else
500 return true;
501
502 return false;
488} 503}
489 504
490struct auth_req_packet : config_packet 505struct auth_req_packet : config_packet
491{ 506{
492 char magic[8]; 507 char magic[8];
583 } 598 }
584 else 599 else
585 { 600 {
586 retry_cnt = 0; 601 retry_cnt = 0;
587 establish_connection.start (NOW + 5); 602 establish_connection.start (NOW + 5);
588 keepalive.reset (); 603 keepalive.stop ();
589 rekey.reset (); 604 rekey.stop ();
590 } 605 }
591} 606}
592 607
593void 608void
594connection::reset_si () 609connection::reset_si ()
660connection::send_auth_request (const sockinfo &si, bool initiate) 675connection::send_auth_request (const sockinfo &si, bool initiate)
661{ 676{
662 auth_req_packet *pkt = new auth_req_packet (conf->id, initiate, THISNODE->protocols); 677 auth_req_packet *pkt = new auth_req_packet (conf->id, initiate, THISNODE->protocols);
663 678
664 rsachallenge chg; 679 rsachallenge chg;
665
666 rsa_cache.gen (pkt->id, chg); 680 rsa_cache.gen (pkt->id, chg);
667 681 rsa_encrypt (conf->rsa_key, chg, pkt->encr);
668 if (0 > RSA_public_encrypt (sizeof chg,
669 (unsigned char *)&chg, (unsigned char *)&pkt->encr,
670 conf->rsa_key, RSA_PKCS1_OAEP_PADDING))
671 fatal ("RSA_public_encrypt error");
672 682
673 slog (L_TRACE, ">>%d PT_AUTH_REQ [%s]", conf->id, (const char *)si); 683 slog (L_TRACE, ">>%d PT_AUTH_REQ [%s]", conf->id, (const char *)si);
674 684
675 send_vpn_packet (pkt, si, IPTOS_RELIABILITY | IPTOS_LOWDELAY); // rsa is very very costly 685 send_vpn_packet (pkt, si, IPTOS_RELIABILITY | IPTOS_LOWDELAY); // rsa is very very costly
676 686
710} 720}
711 721
712void 722void
713connection::establish_connection_cb (time_watcher &w) 723connection::establish_connection_cb (time_watcher &w)
714{ 724{
715 if (ictx || conf == THISNODE 725 if (!ictx
726 && conf != THISNODE
716 || connectmode == conf_node::C_NEVER 727 && connectmode != conf_node::C_NEVER
717 || connectmode == conf_node::C_DISABLED) 728 && connectmode != conf_node::C_DISABLED
718 w.at = TSTAMP_CANCEL; 729 && w.at <= NOW)
719 else if (w.at <= NOW)
720 { 730 {
721 double retry_int = double (retry_cnt & 3 ? (retry_cnt & 3) : 1 << (retry_cnt >> 2)) * 0.6; 731 double retry_int = double (retry_cnt & 3 ? (retry_cnt & 3) : 1 << (retry_cnt >> 2)) * 0.6;
722 732
723 if (retry_int < 3600 * 8) 733 if (retry_int < 3600 * 8)
724 retry_cnt++; 734 retry_cnt++;
725 735
726 w.at = NOW + retry_int; 736 w.start (NOW + retry_int);
727 737
728 reset_si (); 738 reset_si ();
729 739
730 if (si.prot && !si.host) 740 if (si.prot && !si.host)
731 vpn->send_connect_request (conf->id); 741 vpn->send_connect_request (conf->id);
762 si.host= 0; 772 si.host= 0;
763 773
764 last_activity = 0; 774 last_activity = 0;
765 retry_cnt = 0; 775 retry_cnt = 0;
766 776
767 rekey.reset (); 777 rekey.stop ();
768 keepalive.reset (); 778 keepalive.stop ();
769 establish_connection.reset (); 779 establish_connection.stop ();
770} 780}
771 781
772void 782void
773connection::shutdown () 783connection::shutdown ()
774{ 784{
779} 789}
780 790
781void 791void
782connection::rekey_cb (time_watcher &w) 792connection::rekey_cb (time_watcher &w)
783{ 793{
784 w.at = TSTAMP_CANCEL;
785
786 reset_connection (); 794 reset_connection ();
787 establish_connection (); 795 establish_connection ();
788} 796}
789 797
790void 798void
791connection::send_data_packet (tap_packet *pkt, bool broadcast) 799connection::send_data_packet (tap_packet *pkt)
792{ 800{
793 vpndata_packet *p = new vpndata_packet; 801 vpndata_packet *p = new vpndata_packet;
794 int tos = 0; 802 int tos = 0;
795 803
796 // I am not hilarious about peeking into packets, but so be it. 804 // I am not hilarious about peeking into packets, but so be it.
797 if (conf->inherit_tos 805 if (conf->inherit_tos && pkt->is_ipv4 ())
798 && (*pkt)[12] == 0x08 && (*pkt)[13] == 0x00 // IP
799 && ((*pkt)[14] & 0xf0) == 0x40) // IPv4
800 tos = (*pkt)[15] & IPTOS_TOS_MASK; 806 tos = (*pkt)[15] & IPTOS_TOS_MASK;
801 807
802 p->setup (this, broadcast ? 0 : conf->id, &((*pkt)[6 + 6]), pkt->len - 6 - 6, ++oseqno); // skip 2 macs 808 p->setup (this, conf->id, &((*pkt)[6 + 6]), pkt->len - 6 - 6, ++oseqno); // skip 2 macs
803 send_vpn_packet (p, si, tos); 809 send_vpn_packet (p, si, tos);
804 810
805 delete p; 811 delete p;
806 812
807 if (oseqno > MAX_SEQNO) 813 if (oseqno > MAX_SEQNO)
808 rekey (); 814 rekey ();
809} 815}
810 816
811void 817void
812connection::inject_data_packet (tap_packet *pkt, bool broadcast) 818connection::inject_data_packet (tap_packet *pkt, bool broadcast/*TODO DDD*/)
813{ 819{
814 if (ictx && octx) 820 if (ictx && octx)
815 send_data_packet (pkt, broadcast); 821 send_data_packet (pkt);
816 else 822 else
817 { 823 {
818 if (!broadcast)//DDDD 824 if (!broadcast)//DDDD
819 data_queue.put (new tap_packet (*pkt)); 825 data_queue.put (new tap_packet (*pkt));
820 826
895 if (p->initiate) 901 if (p->initiate)
896 send_auth_request (rsi, false); 902 send_auth_request (rsi, false);
897 903
898 rsachallenge k; 904 rsachallenge k;
899 905
900 if (0 > RSA_private_decrypt (sizeof (p->encr), 906 if (!rsa_decrypt (::conf.rsa_key, p->encr, k))
901 (unsigned char *)&p->encr, (unsigned char *)&k, 907 {
902 ::conf.rsa_key, RSA_PKCS1_OAEP_PADDING))
903 slog (L_ERR, _("%s(%s): challenge illegal or corrupted"), 908 slog (L_ERR, _("%s(%s): challenge illegal or corrupted (%s). mismatched key or config file?"),
904 conf->nodename, (const char *)rsi); 909 conf->nodename, (const char *)rsi, ERR_error_string (ERR_get_error (), 0));
910 break;
911 }
905 else 912 else
906 { 913 {
907 delete octx; 914 delete octx;
908 915
909 octx = new crypto_ctx (k, 1); 916 octx = new crypto_ctx (k, 1);
916 connection_established (); 923 connection_established ();
917 924
918 break; 925 break;
919 } 926 }
920 } 927 }
928 else
929 slog (L_WARN, _("%s(%s): protocol mismatch"),
930 conf->nodename, (const char *)rsi);
921 931
922 send_reset (rsi); 932 send_reset (rsi);
923 } 933 }
924 934
925 break; 935 break;
939 949
940 rsachallenge chg; 950 rsachallenge chg;
941 951
942 if (!rsa_cache.find (p->id, chg)) 952 if (!rsa_cache.find (p->id, chg))
943 { 953 {
944 slog (L_ERR, _("%s(%s): unrequested auth response"), 954 slog (L_ERR, _("%s(%s): unrequested auth response ignored"),
945 conf->nodename, (const char *)rsi); 955 conf->nodename, (const char *)rsi);
946 break; 956 break;
947 } 957 }
948 else 958 else
949 { 959 {
950 crypto_ctx *cctx = new crypto_ctx (chg, 0); 960 crypto_ctx *cctx = new crypto_ctx (chg, 0);
951 961
952 if (!p->hmac_chk (cctx)) 962 if (!p->hmac_chk (cctx))
963 {
953 slog (L_ERR, _("%s(%s): hmac authentication error on auth response, received invalid packet\n" 964 slog (L_ERR, _("%s(%s): hmac authentication error on auth response, received invalid packet\n"
954 "could be an attack, or just corruption or an synchronization error"), 965 "could be an attack, or just corruption or an synchronization error"),
955 conf->nodename, (const char *)rsi); 966 conf->nodename, (const char *)rsi);
967 break;
968 }
956 else 969 else
957 { 970 {
958 rsaresponse h; 971 rsaresponse h;
959 972
960 rsa_hash (p->id, chg, h); 973 rsa_hash (p->id, chg, h);
1016 tap_packet *d = p->unpack (this, seqno); 1029 tap_packet *d = p->unpack (this, seqno);
1017 1030
1018 if (iseqno.recv_ok (seqno)) 1031 if (iseqno.recv_ok (seqno))
1019 { 1032 {
1020 vpn->tap->send (d); 1033 vpn->tap->send (d);
1021
1022 if (p->dst () == 0) // re-broadcast
1023 for (vpn::conns_vector::iterator i = vpn->conns.begin (); i != vpn->conns.end (); ++i)
1024 {
1025 connection *c = *i;
1026
1027 if (c->conf != THISNODE && c->conf != conf)
1028 c->inject_data_packet (d);
1029 }
1030 1034
1031 if (si != rsi) 1035 if (si != rsi)
1032 { 1036 {
1033 // fast re-sync on connection changes, useful especially for tcp/ip 1037 // fast re-sync on connection changes, useful especially for tcp/ip
1034 si = rsi; 1038 si = rsi;
1108 { 1112 {
1109 reset_connection (); 1113 reset_connection ();
1110 establish_connection (); 1114 establish_connection ();
1111 } 1115 }
1112 else if (NOW < last_activity + ::conf.keepalive) 1116 else if (NOW < last_activity + ::conf.keepalive)
1113 w.at = last_activity + ::conf.keepalive; 1117 w.start (last_activity + ::conf.keepalive);
1114 else if (conf->connectmode != conf_node::C_ONDEMAND 1118 else if (conf->connectmode != conf_node::C_ONDEMAND
1115 || THISNODE->connectmode != conf_node::C_ONDEMAND) 1119 || THISNODE->connectmode != conf_node::C_ONDEMAND)
1116 { 1120 {
1117 send_ping (si); 1121 send_ping (si);
1118 w.at = NOW + 5; 1122 w.start (NOW + 5);
1119 } 1123 }
1120 else if (NOW < last_activity + ::conf.keepalive + 10) 1124 else if (NOW < last_activity + ::conf.keepalive + 10)
1121 // hold ondemand connections implicitly a few seconds longer 1125 // hold ondemand connections implicitly a few seconds longer
1122 // should delete octx, though, or something like that ;) 1126 // should delete octx, though, or something like that ;)
1123 w.at = last_activity + ::conf.keepalive + 10; 1127 w.start (last_activity + ::conf.keepalive + 10);
1124 else 1128 else
1125 reset_connection (); 1129 reset_connection ();
1126} 1130}
1127 1131
1128void connection::send_connect_request (int id) 1132void connection::send_connect_request (int id)

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines