--- gvpe/src/connection.C 2003/04/02 03:06:22 1.1 +++ gvpe/src/connection.C 2003/04/02 05:15:00 1.3 @@ -24,12 +24,17 @@ #include +#include +#include +#include +#include + #include "gettext.h" #include "conf.h" #include "slog.h" #include "device.h" -#include "protocol.h" +#include "vpn.h" #include "connection.h" #if !HAVE_RAND_PSEUDO_BYTES @@ -580,20 +585,29 @@ protocol = best_protocol (THISNODE->protocols & conf->protocols); - rsachallenge chg; + // mask out protocols we cannot establish + if (!conf->udp_port) protocol &= ~PROT_UDPv4; + if (!conf->tcp_port) protocol &= ~PROT_TCPv4; - rsa_cache.gen (pkt->id, chg); + if (protocol) + { + rsachallenge chg; - if (0 > RSA_public_encrypt (sizeof chg, - (unsigned char *)&chg, (unsigned char *)&pkt->encr, - conf->rsa_key, RSA_PKCS1_OAEP_PADDING)) - fatal ("RSA_public_encrypt error"); + rsa_cache.gen (pkt->id, chg); - slog (L_TRACE, ">>%d PT_AUTH_REQ [%s]", conf->id, (const char *)si); + if (0 > RSA_public_encrypt (sizeof chg, + (unsigned char *)&chg, (unsigned char *)&pkt->encr, + conf->rsa_key, RSA_PKCS1_OAEP_PADDING)) + fatal ("RSA_public_encrypt error"); - send_vpn_packet (pkt, si, IPTOS_RELIABILITY); // rsa is very very costly + slog (L_TRACE, ">>%d PT_AUTH_REQ [%s]", conf->id, (const char *)si); - delete pkt; + send_vpn_packet (pkt, si, IPTOS_RELIABILITY); // rsa is very very costly + + delete pkt; + } + else + ; // silently fail } void @@ -747,261 +761,260 @@ switch (pkt->typ ()) { - case vpn_packet::PT_PING: - // we send pings instead of auth packets after some retries, - // so reset the retry counter and establish a connection - // when we receive a ping. - if (!ictx) + case vpn_packet::PT_PING: + // we send pings instead of auth packets after some retries, + // so reset the retry counter and establish a connection + // when we receive a ping. + if (!ictx) + { + if (auth_rate_limiter.can (rsi)) + send_auth_request (rsi, true); + } + else + send_ping (rsi, 1); // pong + + break; + + case vpn_packet::PT_PONG: + break; + + case vpn_packet::PT_RESET: { - if (auth_rate_limiter.can (rsi)) - send_auth_request (rsi, true); + reset_connection (); + + config_packet *p = (config_packet *) pkt; + + if (!p->chk_config ()) + { + slog (L_WARN, _("%s(%s): protocol mismatch, disabling node"), + conf->nodename, (const char *)rsi); + connectmode = conf_node::C_DISABLED; + } + else if (connectmode == conf_node::C_ALWAYS) + establish_connection (); } - else - send_ping (rsi, 1); // pong + break; - break; + case vpn_packet::PT_AUTH_REQ: + if (auth_rate_limiter.can (rsi)) + { + auth_req_packet *p = (auth_req_packet *) pkt; - case vpn_packet::PT_PONG: - break; + slog (L_TRACE, "<<%d PT_AUTH_REQ(%d)", conf->id, p->initiate); - case vpn_packet::PT_RESET: - { - reset_connection (); + if (p->chk_config () && !strncmp (p->magic, MAGIC, 8)) + { + if (p->prot_minor != PROTOCOL_MINOR) + slog (L_INFO, _("%s(%s): protocol minor version mismatch: ours is %d, %s's is %d."), + conf->nodename, (const char *)rsi, + PROTOCOL_MINOR, conf->nodename, p->prot_minor); + + if (p->initiate) + send_auth_request (rsi, false); + + rsachallenge k; + + if (0 > RSA_private_decrypt (sizeof (p->encr), + (unsigned char *)&p->encr, (unsigned char *)&k, + ::conf.rsa_key, RSA_PKCS1_OAEP_PADDING)) + slog (L_ERR, _("%s(%s): challenge illegal or corrupted"), + conf->nodename, (const char *)rsi); + else + { + retry_cnt = 0; + establish_connection.set (NOW + 8); //? ;) + keepalive.reset (); + rekey.reset (); - config_packet *p = (config_packet *) pkt; + delete ictx; + ictx = 0; - if (!p->chk_config ()) - { - slog (L_WARN, _("%s(%s): protocol mismatch, disabling node"), - conf->nodename, (const char *)rsi); - connectmode = conf_node::C_DISABLED; + delete octx; + + octx = new crypto_ctx (k, 1); + oseqno = ntohl (*(u32 *)&k[CHG_SEQNO]) & 0x7fffffff; + + conf->protocols = p->protocols; + send_auth_response (rsi, p->id, k); + + break; + } + } + + send_reset (rsi); } - else if (connectmode == conf_node::C_ALWAYS) - establish_connection (); - } - break; - case vpn_packet::PT_AUTH_REQ: - if (auth_rate_limiter.can (rsi)) + break; + + case vpn_packet::PT_AUTH_RES: { - auth_req_packet *p = (auth_req_packet *) pkt; + auth_res_packet *p = (auth_res_packet *) pkt; - slog (L_TRACE, "<<%d PT_AUTH_REQ(%d)", conf->id, p->initiate); + slog (L_TRACE, "<<%d PT_AUTH_RES", conf->id); - if (p->chk_config () && !strncmp (p->magic, MAGIC, 8)) + if (p->chk_config ()) { if (p->prot_minor != PROTOCOL_MINOR) slog (L_INFO, _("%s(%s): protocol minor version mismatch: ours is %d, %s's is %d."), conf->nodename, (const char *)rsi, PROTOCOL_MINOR, conf->nodename, p->prot_minor); - if (p->initiate) - send_auth_request (rsi, false); + rsachallenge chg; - rsachallenge k; - - if (0 > RSA_private_decrypt (sizeof (p->encr), - (unsigned char *)&p->encr, (unsigned char *)&k, - ::conf.rsa_key, RSA_PKCS1_OAEP_PADDING)) - slog (L_ERR, _("%s(%s): challenge illegal or corrupted"), + if (!rsa_cache.find (p->id, chg)) + slog (L_ERR, _("%s(%s): unrequested auth response"), conf->nodename, (const char *)rsi); else { - retry_cnt = 0; - establish_connection.set (NOW + 8); //? ;) - keepalive.reset (); - rekey.reset (); + crypto_ctx *cctx = new crypto_ctx (chg, 0); + + if (!p->hmac_chk (cctx)) + slog (L_ERR, _("%s(%s): hmac authentication error on auth response, received invalid packet\n" + "could be an attack, or just corruption or an synchronization error"), + conf->nodename, (const char *)rsi); + else + { + rsaresponse h; + + rsa_hash (p->id, chg, h); + + if (!memcmp ((u8 *)&h, (u8 *)p->response, sizeof h)) + { + prot_minor = p->prot_minor; - delete ictx; - ictx = 0; + delete ictx; ictx = cctx; - delete octx; + iseqno.reset (ntohl (*(u32 *)&chg[CHG_SEQNO]) & 0x7fffffff); // at least 2**31 sequence numbers are valid - octx = new crypto_ctx (k, 1); - oseqno = ntohl (*(u32 *)&k[CHG_SEQNO]) & 0x7fffffff; + si = rsi; - conf->protocols = p->protocols; - send_auth_response (rsi, p->id, k); + rekey.set (NOW + ::conf.rekey); + keepalive.set (NOW + ::conf.keepalive); - break; + // send queued packets + while (tap_packet *p = queue.get ()) + { + send_data_packet (p); + delete p; + } + + connectmode = conf->connectmode; + + slog (L_INFO, _("%s(%s): %s connection established, protocol version %d.%d"), + conf->nodename, (const char *)rsi, + strprotocol (protocol), + p->prot_major, p->prot_minor); + + if (::conf.script_node_up) + run_script (run_script_cb (this, &connection::script_node_up), false); + + break; + } + else + slog (L_ERR, _("%s(%s): sent and received challenge do not match"), + conf->nodename, (const char *)rsi); + } + + delete cctx; } } - - send_reset (rsi); } - break; + send_reset (rsi); + break; - case vpn_packet::PT_AUTH_RES: - { - auth_res_packet *p = (auth_res_packet *) pkt; + case vpn_packet::PT_DATA_COMPRESSED: +#if !ENABLE_COMPRESSION + send_reset (rsi); + break; +#endif - slog (L_TRACE, "<<%d PT_AUTH_RES", conf->id); + case vpn_packet::PT_DATA_UNCOMPRESSED: - if (p->chk_config ()) + if (ictx && octx) { - if (p->prot_minor != PROTOCOL_MINOR) - slog (L_INFO, _("%s(%s): protocol minor version mismatch: ours is %d, %s's is %d."), - conf->nodename, (const char *)rsi, - PROTOCOL_MINOR, conf->nodename, p->prot_minor); + vpndata_packet *p = (vpndata_packet *)pkt; - rsachallenge chg; - - if (!rsa_cache.find (p->id, chg)) - slog (L_ERR, _("%s(%s): unrequested auth response"), - conf->nodename, (const char *)rsi); - else + if (rsi == si) { - crypto_ctx *cctx = new crypto_ctx (chg, 0); - - if (!p->hmac_chk (cctx)) - slog (L_ERR, _("%s(%s): hmac authentication error on auth response, received invalid packet\n" + if (!p->hmac_chk (ictx)) + slog (L_ERR, _("%s(%s): hmac authentication error, received invalid packet\n" "could be an attack, or just corruption or an synchronization error"), conf->nodename, (const char *)rsi); else { - rsaresponse h; - - rsa_hash (p->id, chg, h); + u32 seqno; + tap_packet *d = p->unpack (this, seqno); - if (!memcmp ((u8 *)&h, (u8 *)p->response, sizeof h)) + if (iseqno.recv_ok (seqno)) { - prot_minor = p->prot_minor; - - delete ictx; ictx = cctx; - - iseqno.reset (ntohl (*(u32 *)&chg[CHG_SEQNO]) & 0x7fffffff); // at least 2**31 sequence numbers are valid - - si = rsi; - - rekey.set (NOW + ::conf.rekey); - keepalive.set (NOW + ::conf.keepalive); - - // send queued packets - while (tap_packet *p = queue.get ()) - { - send_data_packet (p); - delete p; - } + vpn->tap->send (d); - connectmode = conf->connectmode; + if (p->dst () == 0) // re-broadcast + for (vpn::conns_vector::iterator i = vpn->conns.begin (); i != vpn->conns.end (); ++i) + { + connection *c = *i; + + if (c->conf != THISNODE && c->conf != conf) + c->inject_data_packet (d); + } - slog (L_INFO, _("%s(%s): %s connection established, protocol version %d.%d"), - conf->nodename, (const char *)rsi, - strprotocol (protocol), - p->prot_major, p->prot_minor); - - if (::conf.script_node_up) - run_script (run_script_cb (this, &connection::script_node_up), false); + delete d; break; } - else - slog (L_ERR, _("%s(%s): sent and received challenge do not match"), - conf->nodename, (const char *)rsi); } - - delete cctx; } + else + slog (L_ERR, _("received data packet from unknown source %s"), (const char *)rsi); } - } - - send_reset (rsi); - break; - - case vpn_packet::PT_DATA_COMPRESSED: -#if !ENABLE_COMPRESSION - send_reset (rsi); - break; -#endif - - case vpn_packet::PT_DATA_UNCOMPRESSED: - - if (ictx && octx) - { - vpndata_packet *p = (vpndata_packet *)pkt; - - if (rsi == si) - { - if (!p->hmac_chk (ictx)) - slog (L_ERR, _("%s(%s): hmac authentication error, received invalid packet\n" - "could be an attack, or just corruption or an synchronization error"), - conf->nodename, (const char *)rsi); - else - { - u32 seqno; - tap_packet *d = p->unpack (this, seqno); - - if (iseqno.recv_ok (seqno)) - { - vpn->tap->send (d); - - if (p->dst () == 0) // re-broadcast - for (vpn::conns_vector::iterator i = vpn->conns.begin (); i != vpn->conns.end (); ++i) - { - connection *c = *i; - if (c->conf != THISNODE && c->conf != conf) - c->inject_data_packet (d); - } + send_reset (rsi); + break; - delete d; - - break; - } - } - } - else - slog (L_ERR, _("received data packet from unknown source %s"), (const char *)rsi); - } - - send_reset (rsi); - break; - - case vpn_packet::PT_CONNECT_REQ: - if (ictx && octx && rsi == si && pkt->hmac_chk (ictx)) - { - connect_req_packet *p = (connect_req_packet *) pkt; - - assert (p->id > 0 && p->id <= vpn->conns.size ()); // hmac-auth does not mean we accept anything - conf->protocols = p->protocols; - connection *c = vpn->conns[p->id - 1]; + case vpn_packet::PT_CONNECT_REQ: + if (ictx && octx && rsi == si && pkt->hmac_chk (ictx)) + { + connect_req_packet *p = (connect_req_packet *) pkt; - slog (L_TRACE, "<<%d PT_CONNECT_REQ(%d) [%d]\n", - conf->id, p->id, c->ictx && c->octx); + assert (p->id > 0 && p->id <= vpn->conns.size ()); // hmac-auth does not mean we accept anything + conf->protocols = p->protocols; + connection *c = vpn->conns[p->id - 1]; - if (c->ictx && c->octx) - { - // send connect_info packets to both sides, in case one is - // behind a nat firewall (or both ;) - c->send_connect_info (conf->id, si, conf->protocols); - send_connect_info (c->conf->id, c->si, c->conf->protocols); - } - } + slog (L_TRACE, "<<%d PT_CONNECT_REQ(%d) [%d]\n", + conf->id, p->id, c->ictx && c->octx); - break; + if (c->ictx && c->octx) + { + // send connect_info packets to both sides, in case one is + // behind a nat firewall (or both ;) + c->send_connect_info (conf->id, si, conf->protocols); + send_connect_info (c->conf->id, c->si, c->conf->protocols); + } + } - case vpn_packet::PT_CONNECT_INFO: - if (ictx && octx && rsi == si && pkt->hmac_chk (ictx)) - { - connect_info_packet *p = (connect_info_packet *) pkt; + break; - assert (p->id > 0 && p->id <= vpn->conns.size ()); // hmac-auth does not mean we accept anything - conf->protocols = p->protocols; - connection *c = vpn->conns[p->id - 1]; + case vpn_packet::PT_CONNECT_INFO: + if (ictx && octx && rsi == si && pkt->hmac_chk (ictx)) + { + connect_info_packet *p = (connect_info_packet *) pkt; - slog (L_TRACE, "<<%d PT_CONNECT_INFO(%d,%s) (%d)", - conf->id, p->id, (const char *)p->si, !c->ictx && !c->octx); + assert (p->id > 0 && p->id <= vpn->conns.size ()); // hmac-auth does not mean we accept anything + conf->protocols = p->protocols; + connection *c = vpn->conns[p->id - 1]; - c->send_auth_request (p->si, true); - } + slog (L_TRACE, "<<%d PT_CONNECT_INFO(%d,%s) (%d)", + conf->id, p->id, (const char *)p->si, !c->ictx && !c->octx); - break; + c->send_auth_request (p->si, true); + } - default: - send_reset (rsi); - break; + break; + default: + send_reset (rsi); + break; } } @@ -1037,7 +1050,7 @@ void connection::script_node () { - vpn->script_if_up (0); + vpn->script_if_up (); char *env; asprintf (&env, "DESTID=%d", conf->id); putenv (env); @@ -1046,7 +1059,7 @@ asprintf (&env, "DESTPORT=%d", ntohs (si.port)); putenv (env); } -const char *connection::script_node_up (int) +const char *connection::script_node_up () { script_node (); @@ -1055,7 +1068,7 @@ return ::conf.script_node_up ? ::conf.script_node_up : "node-up"; } -const char *connection::script_node_down (int) +const char *connection::script_node_down () { script_node (); @@ -1068,10 +1081,20 @@ void connection::send_vpn_packet (vpn_packet *pkt, const sockinfo &si, int tos) { - if (protocol & PROT_IPv4) - vpn->send_ipv4_packet (pkt, si, tos); - else - vpn->send_udpv4_packet (pkt, si, tos); + switch (protocol) + { + case PROT_IPv4: + vpn->send_ipv4_packet (pkt, si, tos); + break; + + case PROT_UDPv4: + vpn->send_udpv4_packet (pkt, si, tos); + break; + + case PROT_TCPv4: + vpn->send_tcpv4_packet (pkt, si, tos); + break; + } } connection::connection(struct vpn *vpn_)