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.67 by pcg, Thu Aug 7 16:34:21 2008 UTC vs.
Revision 1.76 by pcg, Sun Aug 10 15:16:55 2008 UTC

1/* 1/*
2 connection.C -- manage a single connection 2 connection.C -- manage a single connection
3 Copyright (C) 2003-2005 Marc Lehmann <gvpe@schmorp.de> 3 Copyright (C) 2003-2008 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 it
8 it under the terms of the GNU General Public License as published by 8 under the terms of the GNU General Public License as published by the
9 the Free Software Foundation; either version 2 of the License, or 9 Free Software Foundation; either version 3 of the License, or (at your
10 (at your option) any later version. 10 option) any later version.
11 11
12 This program is distributed in the hope that it will be useful, 12 This program is distributed in the hope that it will be useful, but
13 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 GNU General Public License for more details. 15 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 along
18 along with gvpe; if not, write to the Free Software 18 with this program; if not, see <http://www.gnu.org/licenses/>.
19 Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this Program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a modified
24 version of that library), containing parts covered by the terms of the
25 OpenSSL or SSLeay licenses, the licensors of this Program grant you
26 additional permission to convey the resulting work. Corresponding
27 Source for a non-source form of such a combination shall include the
28 source code for the parts of OpenSSL used as well as that of the
29 covered work.
20*/ 30*/
21 31
22#include "config.h" 32#include "config.h"
23 33
24#include <list> 34#include <list>
35#include <queue>
36#include <utility>
25 37
26#include <openssl/rand.h> 38#include <openssl/rand.h>
27#include <openssl/evp.h> 39#include <openssl/evp.h>
28#include <openssl/rsa.h> 40#include <openssl/rsa.h>
29#include <openssl/err.h> 41#include <openssl/err.h>
45#define ULTRA_FAST 1 57#define ULTRA_FAST 1
46#define HLOG 15 58#define HLOG 15
47#include "lzf/lzf.h" 59#include "lzf/lzf.h"
48#include "lzf/lzf_c.c" 60#include "lzf/lzf_c.c"
49#include "lzf/lzf_d.c" 61#include "lzf/lzf_d.c"
62
63//////////////////////////////////////////////////////////////////////////////
64
65static std::queue< std::pair<run_script_cb *, const char *> > rs_queue;
66static ev::child rs_child_ev;
67
68void // c++ requires external linkage here, apparently :(
69rs_child_cb (ev::child &w, int revents)
70{
71 w.stop ();
72
73 if (rs_queue.empty ())
74 return;
75
76 pid_t pid = run_script (*rs_queue.front ().first, false);
77 if (pid)
78 {
79 w.set (pid);
80 w.start ();
81 }
82 else
83 slog (L_WARN, rs_queue.front ().second);
84
85 delete rs_queue.front ().first;
86 rs_queue.pop ();
87}
88
89// despite the fancy name, this is quite a hack
90static void
91run_script_queued (run_script_cb *cb, const char *warnmsg)
92{
93 rs_queue.push (std::make_pair (cb, warnmsg));
94
95 if (!rs_child_ev.is_active ())
96 {
97 rs_child_ev.set<rs_child_cb> ();
98 rs_child_ev ();
99 }
100}
101
102//////////////////////////////////////////////////////////////////////////////
50 103
51struct crypto_ctx 104struct crypto_ctx
52{ 105{
53 EVP_CIPHER_CTX cctx; 106 EVP_CIPHER_CTX cctx;
54 HMAC_CTX hctx; 107 HMAC_CTX hctx;
643 { 696 {
644 if (p->len) send_vpn_packet (p, si, IPTOS_RELIABILITY); 697 if (p->len) send_vpn_packet (p, si, IPTOS_RELIABILITY);
645 delete p; 698 delete p;
646 } 699 }
647 } 700 }
701
702 vpn->connection_established (this);
648 } 703 }
649 else 704 else
650 { 705 {
651 retry_cnt = 0; 706 retry_cnt = 0;
652 establish_connection.start (5); 707 establish_connection.start (5);
656} 711}
657 712
658void 713void
659connection::reset_si () 714connection::reset_si ()
660{ 715{
716 if (vpn->can_direct (THISNODE, conf))
661 protocol = best_protocol (THISNODE->protocols & conf->protocols); 717 protocol = best_protocol (THISNODE->protocols & conf->connectable_protocols ());
662 718 else
663 // mask out protocols we cannot establish
664 if (!conf->udp_port) protocol &= ~PROT_UDPv4;
665 if (!conf->tcp_port) protocol &= ~PROT_TCPv4;
666 if (!conf->dns_port) protocol &= ~PROT_DNSv4;
667
668 if (protocol
669 && (!conf->can_direct (THISNODE)
670 || !THISNODE->can_direct (conf)))
671 { 719 {
672 slog (L_DEBUG, _("%s: direct connection denied"), conf->nodename); 720 slog (L_TRACE, _("%s: direct connection denied by config."), conf->nodename);
673 protocol = 0; 721 protocol = 0;
674 } 722 }
675 723
676 si.set (conf, protocol); 724 si.set (conf, protocol);
725
726 is_direct = si.valid ();
677} 727}
678 728
679// ensure sockinfo is valid, forward if necessary 729// ensure sockinfo is valid, forward if necessary
680const sockinfo & 730const sockinfo &
681connection::forward_si (const sockinfo &si) const 731connection::forward_si (const sockinfo &si) const
682{ 732{
683 if (!si.valid ()) 733 if (!si.valid ())
684 { 734 {
685 connection *r = vpn->find_router (); 735 connection *r = vpn->find_router_for (this);
686 736
687 if (r) 737 if (r)
688 { 738 {
689 slog (L_DEBUG, _("%s: no common protocol, trying indirectly through %s (%s)"), 739 slog (L_DEBUG, _("%s: no common protocol, trying to route through %s."),
690 conf->nodename, r->conf->nodename, (const char *)r->si); 740 conf->nodename, r->conf->nodename);
691 return r->si; 741 return r->si;
692 } 742 }
693 else 743 else
694 slog (L_DEBUG, _("%s: node unreachable, no common protocol"), 744 slog (L_DEBUG, _("%s: node unreachable, no common protocol or no router available."),
695 conf->nodename); 745 conf->nodename);
696 } 746 }
697 747
698 return si; 748 return si;
699} 749}
709connection::send_ping (const sockinfo &si, u8 pong) 759connection::send_ping (const sockinfo &si, u8 pong)
710{ 760{
711 ping_packet *pkt = new ping_packet; 761 ping_packet *pkt = new ping_packet;
712 762
713 pkt->setup (conf->id, pong ? ping_packet::PT_PONG : ping_packet::PT_PING); 763 pkt->setup (conf->id, pong ? ping_packet::PT_PONG : ping_packet::PT_PING);
764
765 slog (L_TRACE, ">>%d %s [%s]", conf->id, pong ? "PT_PONG" : "PT_PING", (const char *)si);
766
714 send_vpn_packet (pkt, si, IPTOS_LOWDELAY); 767 send_vpn_packet (pkt, si, IPTOS_LOWDELAY);
715 768
716 delete pkt; 769 delete pkt;
717} 770}
718 771
793 { 846 {
794 reset_connection (); 847 reset_connection ();
795 return; 848 return;
796 } 849 }
797 850
851 last_establish_attempt = ev_now ();
852
798 ev::tstamp retry_int = ev::tstamp (retry_cnt & 3 853 ev::tstamp retry_int = ev::tstamp (retry_cnt & 3
799 ? (retry_cnt & 3) + 1 854 ? (retry_cnt & 3) + 1
800 : 1 << (retry_cnt >> 2)); 855 : 1 << (retry_cnt >> 2));
801 856
802 reset_si (); 857 reset_si ();
803 858
804 bool slow = si.prot & PROT_SLOW; 859 bool slow = si.prot & PROT_SLOW;
805 860
806 if (si.prot && !si.host) 861 if (si.prot && !si.host && vpn->can_direct (THISNODE, conf))
807 { 862 {
808 slog (L_TRACE, _("%s: connection request (indirect)"), conf->nodename);
809 /*TODO*/ /* start the timer so we don't recurse endlessly */ 863 /*TODO*/ /* start the timer so we don't recurse endlessly */
810 w.start (1); 864 w.start (1);
811 vpn->send_connect_request (conf->id); 865 vpn->send_connect_request (this);
812 } 866 }
813 else 867 else
814 { 868 {
815 slog (L_TRACE, _("%s: connection request (direct)"), conf->nodename, !!ictx, !!octx); 869 if (si.valid ())
870 slog (L_DEBUG, _("%s: sending direct connection request to %s."),
871 conf->nodename, (const char *)si);
816 872
817 const sockinfo &dsi = forward_si (si); 873 const sockinfo &dsi = forward_si (si);
818 874
819 slow = slow || (dsi.prot & PROT_SLOW); 875 slow = slow || (dsi.prot & PROT_SLOW);
820 876
825 else 881 else
826 send_ping (dsi, 0); 882 send_ping (dsi, 0);
827 } 883 }
828 } 884 }
829 885
830 retry_int *= slow ? 8. : 0.7; 886 retry_int *= slow ? 8. : 0.9;
831 887
832 if (retry_int < conf->max_retry) 888 if (retry_int < conf->max_retry)
833 retry_cnt++; 889 retry_cnt++;
834 else 890 else
835 retry_int = conf->max_retry; 891 retry_int = conf->max_retry;
846 slog (L_INFO, _("%s(%s): connection lost"), 902 slog (L_INFO, _("%s(%s): connection lost"),
847 conf->nodename, (const char *)si); 903 conf->nodename, (const char *)si);
848 904
849 if (::conf.script_node_down) 905 if (::conf.script_node_down)
850 { 906 {
851 run_script_cb cb; 907 run_script_cb *cb = new run_script_cb;
852 cb.set<connection, &connection::script_node_down> (this); 908 cb->set<connection, &connection::script_node_down> (this);
853 if (!run_script (cb, false))
854 slog (L_WARN, _("node-down command execution failed, continuing.")); 909 run_script_queued (cb, _("node-down command execution failed, continuing."));
855 } 910 }
856 } 911 }
857 912
858 delete ictx; ictx = 0; 913 delete ictx; ictx = 0;
859 delete octx; octx = 0; 914 delete octx; octx = 0;
861 dnsv4_reset_connection (); 916 dnsv4_reset_connection ();
862#endif 917#endif
863 918
864 si.host = 0; 919 si.host = 0;
865 920
866 last_activity = 0; 921 last_activity = 0.;
922 //last_si_change = 0.;
867 retry_cnt = 0; 923 retry_cnt = 0;
868 924
869 rekey.stop (); 925 rekey.stop ();
870 keepalive.stop (); 926 keepalive.stop ();
871 establish_connection.stop (); 927 establish_connection.stop ();
878 send_reset (si); 934 send_reset (si);
879 935
880 reset_connection (); 936 reset_connection ();
881} 937}
882 938
939// poor-man's rekeying
883inline void 940inline void
884connection::rekey_cb (ev::timer &w, int revents) 941connection::rekey_cb (ev::timer &w, int revents)
885{ 942{
886 reset_connection (); 943 reset_connection ();
887 establish_connection (); 944 establish_connection ();
905 if (oseqno > MAX_SEQNO) 962 if (oseqno > MAX_SEQNO)
906 rekey (); 963 rekey ();
907} 964}
908 965
909void 966void
967connection::post_inject_queue ()
968{
969 // force a connection every now and when when packets are sent (max 1/s)
970 if (ev_now () - last_establish_attempt >= 0.95) // arbitrary
971 establish_connection.stop ();
972
973 establish_connection ();
974}
975
976void
910connection::inject_data_packet (tap_packet *pkt, bool broadcast/*TODO DDD*/) 977connection::inject_data_packet (tap_packet *pkt)
911{ 978{
912 if (ictx && octx) 979 if (ictx && octx)
913 send_data_packet (pkt); 980 send_data_packet (pkt);
914 else 981 else
915 { 982 {
916 if (!broadcast)
917 data_queue.put (new tap_packet (*pkt)); 983 data_queue.put (new tap_packet (*pkt));
918 984 post_inject_queue ();
919 establish_connection ();
920 } 985 }
921} 986}
922 987
923void connection::inject_vpn_packet (vpn_packet *pkt, int tos) 988void connection::inject_vpn_packet (vpn_packet *pkt, int tos)
924{ 989{
925 if (ictx && octx) 990 if (ictx && octx)
926 send_vpn_packet (pkt, si, tos); 991 send_vpn_packet (pkt, si, tos);
927 else 992 else
928 { 993 {
929 vpn_queue.put ((vpn_packet *)new data_packet (*(data_packet *)pkt)); 994 vpn_queue.put ((vpn_packet *)new data_packet (*(data_packet *)pkt));
930 995 post_inject_queue ();
931 establish_connection ();
932 } 996 }
933} 997}
934 998
935void 999void
936connection::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi) 1000connection::recv_vpn_packet (vpn_packet *pkt, const sockinfo &rsi)
937{ 1001{
938 last_activity = ev_now (); 1002 last_activity = ev_now ();
939 1003
940 slog (L_NOISE, "<<%d received packet type %d from %d to %d", 1004 slog (L_NOISE, "<<%d received packet type %d from %d to %d.",
941 conf->id, pkt->typ (), pkt->src (), pkt->dst ()); 1005 conf->id, pkt->typ (), pkt->src (), pkt->dst ());
942 1006
943 if (connectmode == conf_node::C_DISABLED) 1007 if (connectmode == conf_node::C_DISABLED)
944 return; 1008 return;
945 1009
953 { 1017 {
954 if (auth_rate_limiter.can (rsi)) 1018 if (auth_rate_limiter.can (rsi))
955 send_auth_request (rsi, true); 1019 send_auth_request (rsi, true);
956 } 1020 }
957 else 1021 else
1022 // we would love to change thre socket address here, but ping's aren't
1023 // authenticated, so we best ignore it.
958 send_ping (rsi, 1); // pong 1024 send_ping (rsi, 1); // pong
959 1025
960 break; 1026 break;
961 1027
962 case vpn_packet::PT_PONG: 1028 case vpn_packet::PT_PONG:
968 1034
969 config_packet *p = (config_packet *) pkt; 1035 config_packet *p = (config_packet *) pkt;
970 1036
971 if (!p->chk_config ()) 1037 if (!p->chk_config ())
972 { 1038 {
973 slog (L_WARN, _("%s(%s): protocol mismatch, disabling node"), 1039 slog (L_WARN, _("%s(%s): protocol mismatch, disabling node."),
974 conf->nodename, (const char *)rsi); 1040 conf->nodename, (const char *)rsi);
975 connectmode = conf_node::C_DISABLED; 1041 connectmode = conf_node::C_DISABLED;
976 } 1042 }
977 else if (connectmode == conf_node::C_ALWAYS) 1043 else if (connectmode == conf_node::C_ALWAYS)
978 establish_connection (); 1044 establish_connection ();
1020 1086
1021 break; 1087 break;
1022 } 1088 }
1023 } 1089 }
1024 else 1090 else
1025 slog (L_WARN, _("%s(%s): protocol mismatch"), 1091 slog (L_WARN, _("%s(%s): protocol mismatch."),
1026 conf->nodename, (const char *)rsi); 1092 conf->nodename, (const char *)rsi);
1027 1093
1028 send_reset (rsi); 1094 send_reset (rsi);
1029 } 1095 }
1030 1096
1045 1111
1046 rsachallenge chg; 1112 rsachallenge chg;
1047 1113
1048 if (!rsa_cache.find (p->id, chg)) 1114 if (!rsa_cache.find (p->id, chg))
1049 { 1115 {
1050 slog (L_ERR, _("%s(%s): unrequested auth response ignored"), 1116 slog (L_ERR, _("%s(%s): unrequested auth response, ignoring."),
1051 conf->nodename, (const char *)rsi); 1117 conf->nodename, (const char *)rsi);
1052 break; 1118 break;
1053 } 1119 }
1054 else 1120 else
1055 { 1121 {
1056 crypto_ctx *cctx = new crypto_ctx (chg, 0); 1122 crypto_ctx *cctx = new crypto_ctx (chg, 0);
1057 1123
1058 if (!p->hmac_chk (cctx)) 1124 if (!p->hmac_chk (cctx))
1059 { 1125 {
1060 slog (L_ERR, _("%s(%s): hmac authentication error on auth response, received invalid packet\n" 1126 slog (L_ERR, _("%s(%s): hmac authentication error on auth response, received invalid packet\n"
1061 "could be an attack, or just corruption or a synchronization error"), 1127 "could be an attack, or just corruption or a synchronization error."),
1062 conf->nodename, (const char *)rsi); 1128 conf->nodename, (const char *)rsi);
1063 break; 1129 break;
1064 } 1130 }
1065 else 1131 else
1066 { 1132 {
1077 iseqno.reset (ntohl (*(u32 *)&chg[CHG_SEQNO]) & 0x7fffffff); // at least 2**31 sequence numbers are valid 1143 iseqno.reset (ntohl (*(u32 *)&chg[CHG_SEQNO]) & 0x7fffffff); // at least 2**31 sequence numbers are valid
1078 1144
1079 si = rsi; 1145 si = rsi;
1080 protocol = rsi.prot; 1146 protocol = rsi.prot;
1081 1147
1148 slog (L_INFO, _("%s(%s): connection established (%s), protocol version %d.%d."),
1149 conf->nodename, (const char *)rsi,
1150 is_direct ? "direct" : "routed",
1151 p->prot_major, p->prot_minor);
1152
1082 connection_established (); 1153 connection_established ();
1083
1084 slog (L_INFO, _("%s(%s): connection established, protocol version %d.%d"),
1085 conf->nodename, (const char *)rsi,
1086 p->prot_major, p->prot_minor);
1087 1154
1088 if (::conf.script_node_up) 1155 if (::conf.script_node_up)
1089 { 1156 {
1090 run_script_cb cb; 1157 run_script_cb *cb = new run_script_cb;
1091 cb.set<connection, &connection::script_node_up> (this); 1158 cb->set<connection, &connection::script_node_up> (this);
1092 if (!run_script (cb, false))
1093 slog (L_WARN, _("node-up command execution failed, continuing.")); 1159 run_script_queued (cb, _("node-up command execution failed, continuing."));
1094 } 1160 }
1095 1161
1096 break; 1162 break;
1097 } 1163 }
1098 else 1164 else
1099 slog (L_ERR, _("%s(%s): sent and received challenge do not match"), 1165 slog (L_ERR, _("%s(%s): sent and received challenge do not match."),
1100 conf->nodename, (const char *)rsi); 1166 conf->nodename, (const char *)rsi);
1101 } 1167 }
1102 1168
1103 delete cctx; 1169 delete cctx;
1104 } 1170 }
1120 { 1186 {
1121 vpndata_packet *p = (vpndata_packet *)pkt; 1187 vpndata_packet *p = (vpndata_packet *)pkt;
1122 1188
1123 if (!p->hmac_chk (ictx)) 1189 if (!p->hmac_chk (ictx))
1124 slog (L_ERR, _("%s(%s): hmac authentication error, received invalid packet\n" 1190 slog (L_ERR, _("%s(%s): hmac authentication error, received invalid packet\n"
1125 "could be an attack, or just corruption or a synchronization error"), 1191 "could be an attack, or just corruption or a synchronization error."),
1126 conf->nodename, (const char *)rsi); 1192 conf->nodename, (const char *)rsi);
1127 else 1193 else
1128 { 1194 {
1129 u32 seqno; 1195 u32 seqno;
1130 tap_packet *d = p->unpack (this, seqno); 1196 tap_packet *d = p->unpack (this, seqno);
1197 int seqclass = iseqno.seqno_classify (seqno);
1131 1198
1132 if (iseqno.recv_ok (seqno)) 1199 if (seqclass == 0) // ok
1133 { 1200 {
1134 vpn->tap->send (d); 1201 vpn->tap->send (d);
1135 1202
1136 if (si != rsi) 1203 if (si != rsi)
1137 { 1204 {
1138 // fast re-sync on source address changes, useful especially for tcp/ip 1205 // fast re-sync on source address changes, useful especially for tcp/ip
1206 //if (last_si_change < ev_now () + 5.)
1207 // {
1139 si = rsi; 1208 si = rsi;
1140 1209
1141 slog (L_INFO, _("%s(%s): socket address changed to %s"), 1210 slog (L_INFO, _("%s(%s): socket address changed to %s."),
1142 conf->nodename, (const char *)si, (const char *)rsi); 1211 conf->nodename, (const char *)si, (const char *)rsi);
1212 // }
1213 //else
1214 // slog (L_INFO, _("%s(%s): accepted packet from %s, not (yet) redirecting traffic."),
1215 // conf->nodename, (const char *)si, (const char *)rsi);
1143 } 1216 }
1217 }
1218 else if (seqclass == 1) // far history
1219 slog (L_ERR, _("received very old packet (received %08lx, expected %08lx). "
1220 "possible replay attack, or just packet duplication/delay, ignoring."), seqno, iseqno.seq + 1);
1221 else if (seqclass == 2) // in-window duplicate, happens often on wireless
1222 slog (L_DEBUG, _("received recent duplicated packet (received %08lx, expected %08lx). "
1223 "possible replay attack, or just packet duplication, ignoring."), seqno, iseqno.seq + 1);
1224 else if (seqclass == 3) // reset
1225 {
1226 slog (L_ERR, _("received out-of-sync (far future) packet (received %08lx, expected %08lx). "
1227 "probably just massive packet loss, sending reset."), seqno, iseqno.seq + 1);
1228 send_reset (rsi);
1144 } 1229 }
1145 1230
1146 delete d; 1231 delete d;
1147 break; 1232 break;
1148 } 1233 }
1308connection::connection (struct vpn *vpn, conf_node *conf) 1393connection::connection (struct vpn *vpn, conf_node *conf)
1309: vpn(vpn), conf(conf), 1394: vpn(vpn), conf(conf),
1310#if ENABLE_DNS 1395#if ENABLE_DNS
1311 dns (0), 1396 dns (0),
1312#endif 1397#endif
1313 data_queue(conf->max_ttl, conf->max_queue), 1398 data_queue(conf->max_ttl, conf->max_queue + 1),
1314 vpn_queue(conf->max_ttl, conf->max_queue) 1399 vpn_queue(conf->max_ttl, conf->max_queue + 1)
1315{ 1400{
1316 rekey .set<connection, &connection::rekey_cb > (this); 1401 rekey .set<connection, &connection::rekey_cb > (this);
1317 keepalive .set<connection, &connection::keepalive_cb > (this); 1402 keepalive .set<connection, &connection::keepalive_cb > (this);
1318 establish_connection.set<connection, &connection::establish_connection_cb> (this); 1403 establish_connection.set<connection, &connection::establish_connection_cb> (this);
1319 1404
1405 last_establish_attempt = 0.;
1320 octx = ictx = 0; 1406 octx = ictx = 0;
1321 retry_cnt = 0;
1322 1407
1323 if (!conf->protocols) // make sure some protocol is enabled 1408 if (!conf->protocols) // make sure some protocol is enabled
1324 conf->protocols = PROT_UDPv4; 1409 conf->protocols = PROT_UDPv4;
1325 1410
1326 connectmode = conf->connectmode; 1411 connectmode = conf->connectmode;
1327 1412
1328 // queue a dummy packet to force an initial connection attempt 1413 // queue a dummy packet to force an initial connection attempt
1329 if (connectmode != conf_node::C_ALWAYS && connectmode != conf_node::C_DISABLED) 1414 if (connectmode != conf_node::C_ALWAYS && connectmode != conf_node::C_DISABLED)
1330 { 1415 vpn_queue.put (new net_packet);
1331 net_packet *p = new net_packet;
1332 p->len = 0;
1333 vpn_queue.put (p);
1334 }
1335 1416
1336 reset_connection (); 1417 reset_connection ();
1337} 1418}
1338 1419
1339connection::~connection () 1420connection::~connection ()

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines