along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id: net.c,v 1.35.4.152 2002/02/10 21:57:54 guus Exp $
+ $Id: net.c,v 1.35.4.154 2002/02/11 15:59:18 guus Exp $
*/
#include "config.h"
#define RAND_pseudo_bytes RAND_bytes
#endif
+#include <zlib.h>
+
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
{
- vpn_packet_t outpkt;
+ vpn_packet_t pkt1, pkt2;
+ vpn_packet_t *pkt[] = {&pkt1, &pkt2, &pkt1, &pkt2};
+ int nextpkt = 0;
+ vpn_packet_t *outpkt = pkt[0];
int outlen, outpad;
+ long int complen = MTU + 12;
EVP_CIPHER_CTX ctx;
char hmac[EVP_MAX_MD_SIZE];
cp
+ /* Check the message authentication code */
if(myself->digest && myself->maclength)
{
if(myself->cipher)
{
+ outpkt = pkt[nextpkt++];
+
EVP_DecryptInit(&ctx, myself->cipher, myself->key, myself->key + myself->cipher->key_len);
- EVP_DecryptUpdate(&ctx, (char *)&outpkt.seqno, &outlen, (char *)&inpkt->seqno, inpkt->len);
- EVP_DecryptFinal(&ctx, (char *)&outpkt.seqno + outlen, &outpad);
- outlen += outpad;
- outpkt.len = outlen - sizeof(outpkt.seqno);
- }
- else
- {
- memcpy((char *)&outpkt.seqno, (char *)&inpkt->seqno, inpkt->len);
- outpkt.len = inpkt->len - sizeof(outpkt.seqno);
+ EVP_DecryptUpdate(&ctx, (char *)&outpkt->seqno, &outlen, (char *)&inpkt->seqno, inpkt->len);
+ EVP_DecryptFinal(&ctx, (char *)&outpkt->seqno + outlen, &outpad);
+
+ outpkt->len = outlen + outpad;
+ inpkt = outpkt;
}
- if (ntohl(outpkt.seqno) <= n->received_seqno)
+ /* Check the sequence number */
+
+ inpkt->len -= sizeof(inpkt->seqno);
+ inpkt->seqno = ntohl(inpkt->seqno);
+
+ if(inpkt->seqno <= n->received_seqno)
{
- syslog(LOG_DEBUG, _("Got late or replayed packet from %s (%s), seqno %d"), n->name, n->hostname, ntohl(*(unsigned int *)&outpkt.seqno));
+ syslog(LOG_DEBUG, _("Got late or replayed packet from %s (%s), seqno %d"), n->name, n->hostname, inpkt->seqno);
return;
}
- n->received_seqno = ntohl(outpkt.seqno);
+ n->received_seqno = inpkt->seqno;
if(n->received_seqno > MAX_SEQNO)
keyexpires = 0;
- receive_packet(n, &outpkt);
+ /* Decompress the packet */
+
+ if(myself->compression)
+ {
+ outpkt = pkt[nextpkt++];
+
+ if(uncompress(outpkt->data, &complen, inpkt->data, inpkt->len) != Z_OK)
+ {
+ syslog(LOG_ERR, _("Error while uncompressing packet from %s (%s)"), n->name, n->hostname);
+ return;
+ }
+
+ outpkt->len = complen;
+ inpkt = outpkt;
+ }
+
+ receive_packet(n, inpkt);
cp
}
void send_udppacket(node_t *n, vpn_packet_t *inpkt)
{
- vpn_packet_t outpkt;
+ vpn_packet_t pkt1, pkt2;
+ vpn_packet_t *pkt[] = {&pkt1, &pkt2, &pkt1, &pkt2};
+ int nextpkt = 0;
+ vpn_packet_t *outpkt;
int outlen, outpad;
+ long int complen = MTU + 12;
EVP_CIPHER_CTX ctx;
struct sockaddr_in to;
socklen_t tolen = sizeof(to);
if(!n->status.waitingforkey)
send_req_key(n->nexthop->connection, myself, n);
+
+ return;
+ }
+
+ /* Compress the packet */
+
+ if(n->compression)
+ {
+ outpkt = pkt[nextpkt++];
+
+ if(compress2(outpkt->data, &complen, inpkt->data, inpkt->len, n->compression) != Z_OK)
+ {
+ syslog(LOG_ERR, _("Error while compressing packet to %s (%s)"), n->name, n->hostname);
return;
}
+
+ outpkt->len = complen;
+ inpkt = outpkt;
+ }
- /* Encrypt the packet. */
+ /* Add sequence number */
inpkt->seqno = htonl(++(n->sent_seqno));
+ inpkt->len += sizeof(inpkt->seqno);
+
+ /* Encrypt the packet */
if(n->cipher)
{
+ outpkt = pkt[nextpkt++];
+
EVP_EncryptInit(&ctx, n->cipher, n->key, n->key + n->cipher->key_len);
- EVP_EncryptUpdate(&ctx, (char *)&outpkt.seqno, &outlen, (char *)&inpkt->seqno, inpkt->len + sizeof(inpkt->seqno));
- EVP_EncryptFinal(&ctx, (char *)&outpkt.seqno + outlen, &outpad);
- outlen += outpad;
- }
- else
- {
- memcpy((char *)&outpkt.seqno, (char *)&inpkt->seqno, inpkt->len + sizeof(inpkt->seqno));
- outlen = inpkt->len + sizeof(inpkt->seqno);
+ EVP_EncryptUpdate(&ctx, (char *)&outpkt->seqno, &outlen, (char *)&inpkt->seqno, inpkt->len);
+ EVP_EncryptFinal(&ctx, (char *)&outpkt->seqno + outlen, &outpad);
+
+ outpkt->len = outlen + outpad;
+ inpkt = outpkt;
}
+ /* Add the message authentication code */
+
if(n->digest && n->maclength)
{
- HMAC(n->digest, n->key, n->keylength, (char *)&outpkt.seqno, outlen, (char *)&outpkt.seqno + outlen, &outpad);
- outlen += n->maclength;
+ HMAC(n->digest, n->key, n->keylength, (char *)&inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len, &outlen);
+ inpkt->len += n->maclength;
}
+ /* Send the packet */
+
to.sin_family = AF_INET;
to.sin_addr.s_addr = htonl(n->address);
to.sin_port = htons(n->port);
- if((sendto(udp_socket, (char *)&outpkt.seqno, outlen, 0, (const struct sockaddr *)&to, tolen)) < 0)
+ if((sendto(udp_socket, (char *)&inpkt->seqno, inpkt->len, 0, (const struct sockaddr *)&to, tolen)) < 0)
{
syslog(LOG_ERR, _("Error sending packet to %s (%s): %m"),
n->name, n->hostname);
{
BN_hex2bn(&c->rsa_key->n, key);
BN_hex2bn(&c->rsa_key->e, "FFFF");
+ free(key);
return 0;
}
{
syslog(LOG_ERR, _("Error reading RSA public key file `%s': %m"),
fname);
+ free(fname);
return -1;
}
+ free(fname);
c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
fclose(fp);
if(!c->rsa_key)
return 0;
}
else
- return -1;
+ {
+ free(fname);
+ return -1;
+ }
}
/* Else, check if a harnessed public key is in the config file */
myself->connection->rsa_key = RSA_new();
BN_hex2bn(&myself->connection->rsa_key->d, key);
BN_hex2bn(&myself->connection->rsa_key->e, "FFFF");
+ free(key);
+ return 0;
}
- else if(get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
+
+ if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
+ asprintf(&fname, "%s/rsa_key.priv", confbase);
+
+ if(is_safe_path(fname))
{
if((fp = fopen(fname, "r")) == NULL)
{
syslog(LOG_ERR, _("Error reading RSA private key file `%s': %m"),
fname);
+ free(fname);
return -1;
}
+ free(fname);
myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
fclose(fp);
if(!myself->connection->rsa_key)
fname);
return -1;
}
+ return 0;
+ }
+
+ free(fname);
+ return -1;
+}
+
+int check_rsa_key(RSA *rsa_key)
+{
+ char *test1, *test2, *test3;
+cp
+ if(rsa_key->p && rsa_key->q)
+ {
+ if(RSA_check_key(rsa_key) != 1)
+ return -1;
}
else
{
- syslog(LOG_ERR, _("No private key for tinc daemon specified!"));
- return -1;
+ test1 = xmalloc(RSA_size(rsa_key));
+ test2 = xmalloc(RSA_size(rsa_key));
+ test3 = xmalloc(RSA_size(rsa_key));
+
+ if(RSA_public_encrypt(RSA_size(rsa_key), test1, test2, rsa_key, RSA_NO_PADDING) != RSA_size(rsa_key))
+ return -1;
+
+ if(RSA_private_decrypt(RSA_size(rsa_key), test2, test3, rsa_key, RSA_NO_PADDING) != RSA_size(rsa_key))
+ return -1;
+
+ if(memcmp(test1, test3, RSA_size(rsa_key)))
+ return -1;
}
cp
return 0;
return -1;
cp
-/*
- if(RSA_check_key(rsa_key) != 1)
+ if(check_rsa_key(myself->connection->rsa_key))
{
syslog(LOG_ERR, _("Invalid public/private keypair!"));
return -1;
}
-*/
+
if(!get_config_port(lookup_config(myself->connection->config_tree, "Port"), &myself->port))
myself->port = 655;
}
else
myself->maclength = 4;
+
+ /* Compression */
+
+ if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->compression))
+ {
+ if(myself->compression < 0 || myself->compression > 9)
+ {
+ syslog(LOG_ERR, _("Bogus compression level!"));
+ return -1;
+ }
+ }
+ else
+ myself->compression = 0;
cp
/* Done */