Forgot to merge new files from pre5.
This commit is contained in:
		
							parent
							
								
									f0aa9641e8
								
							
						
					
					
						commit
						5bf4b88666
					
				
					 7 changed files with 1705 additions and 0 deletions
				
			
		
							
								
								
									
										109
									
								
								src/event.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/event.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,109 @@ | |||
| /*
 | ||||
|     event.c -- event queue | ||||
|     Copyright (C) 2002 Guus Sliepen <guus@sliepen.warande.net>, | ||||
|                   2002 Ivo Timmermans <itimmermans@bigfoot.com> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| 
 | ||||
|     $Id: event.c,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $ | ||||
| */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <xalloc.h> | ||||
| #include <string.h> | ||||
| #include <utils.h> | ||||
| #include <avl_tree.h> | ||||
| #include <time.h> | ||||
| 
 | ||||
| #include "event.h" | ||||
| 
 | ||||
| #include "system.h" | ||||
| 
 | ||||
| avl_tree_t *event_tree; | ||||
| 
 | ||||
| int id; | ||||
| 
 | ||||
| int event_compare(event_t *a, event_t *b) | ||||
| { | ||||
|   if(a->time > b->time) | ||||
|     return 1; | ||||
|   if(a->time < b->time) | ||||
|     return -1; | ||||
|   return a->id - b->id;  | ||||
| } | ||||
| 
 | ||||
| void init_events(void) | ||||
| { | ||||
| cp | ||||
|   event_tree = avl_alloc_tree((avl_compare_t)event_compare, NULL); | ||||
| cp | ||||
| } | ||||
| 
 | ||||
| void exit_events(void) | ||||
| { | ||||
| cp | ||||
|   avl_delete_tree(event_tree); | ||||
| cp | ||||
| } | ||||
| 
 | ||||
| event_t *new_event(void) | ||||
| { | ||||
|   event_t *event; | ||||
| cp | ||||
|   event = (event_t *)xmalloc_and_zero(sizeof(*event)); | ||||
| cp | ||||
|   return event; | ||||
| } | ||||
| 
 | ||||
| void free_event(event_t *event) | ||||
| { | ||||
| cp | ||||
|   free(event); | ||||
| cp | ||||
| } | ||||
| 
 | ||||
| void event_add(event_t *event) | ||||
| { | ||||
| cp | ||||
|   event->id = ++id; | ||||
|   avl_insert(event_tree, event); | ||||
| cp | ||||
| } | ||||
| 
 | ||||
| void event_del(event_t *event) | ||||
| { | ||||
| cp | ||||
|   avl_delete(event_tree, event); | ||||
| cp | ||||
| } | ||||
| 
 | ||||
| event_t *get_expired_event(void) | ||||
| { | ||||
|   event_t *event; | ||||
| cp | ||||
|   if(event_tree->head) | ||||
|   { | ||||
|     event = (event_t *)event_tree->head->data; | ||||
|     if(event->time < time(NULL)) | ||||
|     { | ||||
|       avl_delete(event_tree, event); | ||||
|       return event; | ||||
|     } | ||||
|   } | ||||
| cp   | ||||
|   return NULL; | ||||
| } | ||||
							
								
								
									
										48
									
								
								src/event.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/event.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| /*
 | ||||
|     event.h -- header for event.c | ||||
|     Copyright (C) 2002 Guus Sliepen <guus@sliepen.warande.net>, | ||||
|                   2002 Ivo Timmermans <itimmermans@bigfoot.com> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| 
 | ||||
|     $Id: event.h,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $ | ||||
| */ | ||||
| 
 | ||||
| #ifndef __TINC_EVENT_H__ | ||||
| #define __TINC_EVENT_H__ | ||||
| 
 | ||||
| #include <time.h> | ||||
| #include <avl_tree.h> | ||||
| 
 | ||||
| avl_tree_t *event_tree; | ||||
| 
 | ||||
| typedef void (*event_handler_t)(void *); | ||||
| 
 | ||||
| typedef struct { | ||||
|   time_t time; | ||||
|   int id; | ||||
|   event_handler_t handler; | ||||
|   void *data; | ||||
| } event_t; | ||||
| 
 | ||||
| extern void init_events(void); | ||||
| extern void exit_events(void); | ||||
| extern event_t *new_event(void); | ||||
| extern void free_event(event_t *); | ||||
| extern void event_add(event_t *); | ||||
| extern void event_del(event_t *); | ||||
| extern event_t *get_expired_event(void); | ||||
| 
 | ||||
| #endif /* __TINC_EVENT_H__ */ | ||||
							
								
								
									
										561
									
								
								src/protocol_auth.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										561
									
								
								src/protocol_auth.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,561 @@ | |||
| /*
 | ||||
|     protocol_auth.c -- handle the meta-protocol, authentication | ||||
|     Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>, | ||||
|                   2000-2002 Guus Sliepen <guus@sliepen.warande.net> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| 
 | ||||
|     $Id: protocol_auth.c,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $ | ||||
| */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <syslog.h> | ||||
| #include <stdio.h> | ||||
| #include <stdarg.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include <utils.h> | ||||
| #include <xalloc.h> | ||||
| #include <avl_tree.h> | ||||
| 
 | ||||
| #include <openssl/sha.h> | ||||
| #include <openssl/rand.h> | ||||
| #include <openssl/evp.h> | ||||
| 
 | ||||
| #ifndef HAVE_RAND_PSEUDO_BYTES | ||||
| #define RAND_pseudo_bytes RAND_bytes | ||||
| #endif | ||||
| 
 | ||||
| #include "conf.h" | ||||
| #include "net.h" | ||||
| #include "netutl.h" | ||||
| #include "protocol.h" | ||||
| #include "meta.h" | ||||
| #include "connection.h" | ||||
| #include "node.h" | ||||
| #include "edge.h" | ||||
| #include "graph.h" | ||||
| 
 | ||||
| #include "system.h" | ||||
| 
 | ||||
| int send_id(connection_t *c) | ||||
| { | ||||
| cp | ||||
|   return send_request(c, "%d %s %d", ID, myself->connection->name, myself->connection->protocol_version); | ||||
| } | ||||
| 
 | ||||
| int id_h(connection_t *c) | ||||
| { | ||||
|   char name[MAX_STRING_SIZE]; | ||||
|   int bla; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING" %d", name, &c->protocol_version) != 2) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ID", c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if identity is a valid name */ | ||||
| 
 | ||||
|   if(check_id(name)) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ID", c->name, c->hostname, "invalid name"); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* If we set c->name in advance, make sure we are connected to the right host */ | ||||
|    | ||||
|   if(c->name) | ||||
|     { | ||||
|       if(strcmp(c->name, name)) | ||||
|         { | ||||
|           syslog(LOG_ERR, _("Peer %s is %s instead of %s"), c->hostname, name, c->name); | ||||
|           return -1; | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|     c->name = xstrdup(name); | ||||
| 
 | ||||
|   /* Check if version matches */ | ||||
| 
 | ||||
|   if(c->protocol_version != myself->connection->protocol_version) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Peer %s (%s) uses incompatible version %d"), | ||||
|              c->name, c->hostname, c->protocol_version); | ||||
|       return -1; | ||||
|     } | ||||
|    | ||||
|   if(bypass_security) | ||||
|     { | ||||
|       if(!c->config_tree) | ||||
|         init_configuration(&c->config_tree); | ||||
|       c->allow_request = ACK; | ||||
|       return send_ack(c); | ||||
|     } | ||||
| 
 | ||||
|   if(!c->config_tree) | ||||
|     { | ||||
|       init_configuration(&c->config_tree); | ||||
| 
 | ||||
|       if((bla = read_connection_config(c))) | ||||
|         { | ||||
|           syslog(LOG_ERR, _("Peer %s had unknown identity (%s)"), c->hostname, c->name); | ||||
|           return -1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   if(read_rsa_public_key(c)) | ||||
|     { | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check some options */ | ||||
|    | ||||
|   if((get_config_bool(lookup_config(c->config_tree, "IndirectData"), &bla) && bla) || myself->options & OPTION_INDIRECT) | ||||
|         c->options |= OPTION_INDIRECT; | ||||
| 
 | ||||
|   if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &bla) && bla) || myself->options & OPTION_TCPONLY) | ||||
|         c->options |= OPTION_TCPONLY | OPTION_INDIRECT; | ||||
| 
 | ||||
|   c->allow_request = METAKEY; | ||||
| cp | ||||
|   return send_metakey(c); | ||||
| } | ||||
| 
 | ||||
| int send_metakey(connection_t *c) | ||||
| { | ||||
|   char buffer[MAX_STRING_SIZE]; | ||||
|   int len, x; | ||||
| cp | ||||
|   len = RSA_size(c->rsa_key); | ||||
| 
 | ||||
|   /* Allocate buffers for the meta key */ | ||||
| 
 | ||||
|   if(!c->outkey) | ||||
|     c->outkey = xmalloc(len); | ||||
|      | ||||
|   if(!c->outctx) | ||||
|     c->outctx = xmalloc(sizeof(*c->outctx)); | ||||
| cp | ||||
|   /* Copy random data to the buffer */ | ||||
| 
 | ||||
|   RAND_bytes(c->outkey, len); | ||||
| 
 | ||||
|   /* The message we send must be smaller than the modulus of the RSA key.
 | ||||
|      By definition, for a key of k bits, the following formula holds: | ||||
|       | ||||
|        2^(k-1) <= modulus < 2^(k) | ||||
|       | ||||
|      Where ^ means "to the power of", not "xor". | ||||
|      This means that to be sure, we must choose our message < 2^(k-1). | ||||
|      This can be done by setting the most significant bit to zero. | ||||
|   */ | ||||
|    | ||||
|   c->outkey[0] &= 0x7F; | ||||
|    | ||||
|   if(debug_lvl >= DEBUG_SCARY_THINGS) | ||||
|     { | ||||
|       bin2hex(c->outkey, buffer, len); | ||||
|       buffer[len*2] = '\0'; | ||||
|       syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer); | ||||
|     } | ||||
| 
 | ||||
|   /* Encrypt the random data
 | ||||
|    | ||||
|      We do not use one of the PKCS padding schemes here. | ||||
|      This is allowed, because we encrypt a totally random string | ||||
|      with a length equal to that of the modulus of the RSA key. | ||||
|   */ | ||||
| 
 | ||||
|   if(RSA_public_encrypt(len, c->outkey, buffer, c->rsa_key, RSA_NO_PADDING) != len) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); | ||||
|       return -1; | ||||
|     } | ||||
| cp | ||||
|   /* Convert the encrypted random data to a hexadecimal formatted string */ | ||||
| 
 | ||||
|   bin2hex(buffer, buffer, len); | ||||
|   buffer[len*2] = '\0'; | ||||
| 
 | ||||
|   /* Send the meta key */ | ||||
| 
 | ||||
|   x = send_request(c, "%d %s", METAKEY, buffer); | ||||
| 
 | ||||
|   /* Further outgoing requests are encrypted with the key we just generated */ | ||||
| 
 | ||||
|   EVP_EncryptInit(c->outctx, EVP_bf_cfb(), | ||||
|                   c->outkey + len - EVP_bf_cfb()->key_len, | ||||
|                   c->outkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len); | ||||
| 
 | ||||
|   c->status.encryptout = 1; | ||||
| cp | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
| int metakey_h(connection_t *c) | ||||
| { | ||||
|   char buffer[MAX_STRING_SIZE]; | ||||
|   int len; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING, buffer) != 1) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| cp | ||||
|   len = RSA_size(myself->connection->rsa_key); | ||||
| 
 | ||||
|   /* Check if the length of the meta key is all right */ | ||||
| 
 | ||||
|   if(strlen(buffer) != len*2) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength"); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Allocate buffers for the meta key */ | ||||
| cp | ||||
|   if(!c->inkey) | ||||
|     c->inkey = xmalloc(len); | ||||
| 
 | ||||
|   if(!c->inctx) | ||||
|     c->inctx = xmalloc(sizeof(*c->inctx)); | ||||
| 
 | ||||
|   /* Convert the challenge from hexadecimal back to binary */ | ||||
| cp | ||||
|   hex2bin(buffer,buffer,len); | ||||
| 
 | ||||
|   /* Decrypt the meta key */ | ||||
| cp   | ||||
|   if(RSA_private_decrypt(len, buffer, c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len)	/* See challenge() */ | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   if(debug_lvl >= DEBUG_SCARY_THINGS) | ||||
|     { | ||||
|       bin2hex(c->inkey, buffer, len); | ||||
|       buffer[len*2] = '\0'; | ||||
|       syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer); | ||||
|     } | ||||
| 
 | ||||
|   /* All incoming requests will now be encrypted. */ | ||||
| cp | ||||
|   EVP_DecryptInit(c->inctx, EVP_bf_cfb(), | ||||
|                   c->inkey + len - EVP_bf_cfb()->key_len, | ||||
|                   c->inkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len); | ||||
|    | ||||
|   c->status.decryptin = 1; | ||||
| 
 | ||||
|   c->allow_request = CHALLENGE; | ||||
| cp | ||||
|   return send_challenge(c); | ||||
| } | ||||
| 
 | ||||
| int send_challenge(connection_t *c) | ||||
| { | ||||
|   char buffer[MAX_STRING_SIZE]; | ||||
|   int len, x; | ||||
| cp | ||||
|   /* CHECKME: what is most reasonable value for len? */ | ||||
| 
 | ||||
|   len = RSA_size(c->rsa_key); | ||||
| 
 | ||||
|   /* Allocate buffers for the challenge */ | ||||
| 
 | ||||
|   if(!c->hischallenge) | ||||
|     c->hischallenge = xmalloc(len); | ||||
| cp | ||||
|   /* Copy random data to the buffer */ | ||||
| 
 | ||||
|   RAND_bytes(c->hischallenge, len); | ||||
| 
 | ||||
| cp | ||||
|   /* Convert to hex */ | ||||
| 
 | ||||
|   bin2hex(c->hischallenge, buffer, len); | ||||
|   buffer[len*2] = '\0'; | ||||
| 
 | ||||
| cp | ||||
|   /* Send the challenge */ | ||||
| 
 | ||||
|   x = send_request(c, "%d %s", CHALLENGE, buffer); | ||||
| cp | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
| int challenge_h(connection_t *c) | ||||
| { | ||||
|   char buffer[MAX_STRING_SIZE]; | ||||
|   int len; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING, buffer) != 1) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "CHALLENGE", c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   len = RSA_size(myself->connection->rsa_key); | ||||
| 
 | ||||
|   /* Check if the length of the challenge is all right */ | ||||
| 
 | ||||
|   if(strlen(buffer) != len*2) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong challenge length"); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Allocate buffers for the challenge */ | ||||
| 
 | ||||
|   if(!c->mychallenge) | ||||
|     c->mychallenge = xmalloc(len); | ||||
| 
 | ||||
|   /* Convert the challenge from hexadecimal back to binary */ | ||||
| 
 | ||||
|   hex2bin(buffer,c->mychallenge,len); | ||||
| 
 | ||||
|   c->allow_request = CHAL_REPLY; | ||||
| 
 | ||||
|   /* Rest is done by send_chal_reply() */ | ||||
| cp | ||||
|   return send_chal_reply(c); | ||||
| } | ||||
| 
 | ||||
| int send_chal_reply(connection_t *c) | ||||
| { | ||||
|   char hash[SHA_DIGEST_LENGTH*2+1]; | ||||
| cp | ||||
|   /* Calculate the hash from the challenge we received */ | ||||
| 
 | ||||
|   SHA1(c->mychallenge, RSA_size(myself->connection->rsa_key), hash); | ||||
| 
 | ||||
|   /* Convert the hash to a hexadecimal formatted string */ | ||||
| 
 | ||||
|   bin2hex(hash,hash,SHA_DIGEST_LENGTH); | ||||
|   hash[SHA_DIGEST_LENGTH*2] = '\0'; | ||||
| 
 | ||||
|   /* Send the reply */ | ||||
| 
 | ||||
| cp | ||||
|   return send_request(c, "%d %s", CHAL_REPLY, hash); | ||||
| } | ||||
| 
 | ||||
| int chal_reply_h(connection_t *c) | ||||
| { | ||||
|   char hishash[MAX_STRING_SIZE]; | ||||
|   char myhash[SHA_DIGEST_LENGTH]; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING, hishash) != 1) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "CHAL_REPLY", c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if the length of the hash is all right */ | ||||
| 
 | ||||
|   if(strlen(hishash) != SHA_DIGEST_LENGTH*2) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply length")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Convert the hash to binary format */ | ||||
| 
 | ||||
|   hex2bin(hishash, hishash, SHA_DIGEST_LENGTH); | ||||
| 
 | ||||
|   /* Calculate the hash from the challenge we sent */ | ||||
| 
 | ||||
|   SHA1(c->hischallenge, RSA_size(c->rsa_key), myhash); | ||||
| 
 | ||||
|   /* Verify the incoming hash with the calculated hash */ | ||||
| 
 | ||||
|   if(memcmp(hishash, myhash, SHA_DIGEST_LENGTH)) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, _("wrong challenge reply")); | ||||
|       if(debug_lvl >= DEBUG_SCARY_THINGS) | ||||
|         { | ||||
|           bin2hex(myhash, hishash, SHA_DIGEST_LENGTH); | ||||
|           hishash[SHA_DIGEST_LENGTH*2] = '\0'; | ||||
|           syslog(LOG_DEBUG, _("Expected challenge reply: %s"), hishash); | ||||
|         } | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Identity has now been positively verified.
 | ||||
|      Send an acknowledgement with the rest of the information needed. | ||||
|    */ | ||||
| 
 | ||||
|   c->allow_request = ACK; | ||||
| cp | ||||
|   return send_ack(c); | ||||
| } | ||||
| 
 | ||||
| int send_ack(connection_t *c) | ||||
| { | ||||
|   /* ACK message contains rest of the information the other end needs
 | ||||
|      to create node_t and edge_t structures. */ | ||||
| 
 | ||||
|   int x; | ||||
|   char *addrstr; | ||||
|   struct timeval now; | ||||
| cp | ||||
|   /* Estimate weight */ | ||||
|    | ||||
|   gettimeofday(&now, NULL); | ||||
|   c->estimated_weight = (now.tv_sec - c->start.tv_sec) * 1000 + (now.tv_usec - c->start.tv_usec) / 1000; | ||||
|   addrstr = address2str(c->address); | ||||
|   x = send_request(c, "%d %hd %s %d %d", ACK, myself->port, addrstr, c->estimated_weight, c->options); | ||||
|   free(addrstr); | ||||
| cp | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
| void send_everything(connection_t *c) | ||||
| { | ||||
|   avl_node_t *node, *node2; | ||||
|   node_t *n; | ||||
|   subnet_t *s; | ||||
|   edge_t *e; | ||||
| 
 | ||||
|   /* Send all known subnets */ | ||||
|    | ||||
|   for(node = node_tree->head; node; node = node->next) | ||||
|     { | ||||
|       n = (node_t *)node->data; | ||||
| 
 | ||||
|       for(node2 = n->subnet_tree->head; node2; node2 = node2->next) | ||||
|         { | ||||
|           s = (subnet_t *)node2->data; | ||||
|           send_add_subnet(c, s); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   /* Send all known edges */ | ||||
| 
 | ||||
|   for(node = edge_tree->head; node; node = node->next) | ||||
|     { | ||||
|       e = (edge_t *)node->data; | ||||
| 
 | ||||
|       if(e == c->edge) | ||||
|         continue; | ||||
| 
 | ||||
|       send_add_edge(c, e); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int ack_h(connection_t *c) | ||||
| { | ||||
|   port_t hisport; | ||||
|   char addrstr[MAX_STRING_SIZE]; | ||||
|   int weight; | ||||
|   int options; | ||||
|   node_t *n; | ||||
|   connection_t *other; | ||||
|   avl_node_t *node; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d %hd "MAX_STRING" %d %d", &hisport, addrstr, &weight, &options) != 4) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if we already have a node_t for him */ | ||||
| 
 | ||||
|   n = lookup_node(c->name); | ||||
|    | ||||
|   if(!n) | ||||
|     { | ||||
|       n = new_node(); | ||||
|       n->name = xstrdup(c->name); | ||||
|       n->address = c->address; | ||||
|       n->hostname = xstrdup(c->hostname); | ||||
|       n->port = hisport; | ||||
| 
 | ||||
|       /* FIXME: Also check if no other tinc daemon uses the same IP and port for UDP traffic */ | ||||
| 
 | ||||
|       node_add(n); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       if(n->connection) | ||||
|         { | ||||
|           /* Oh dear, we already have a connection to this node. */ | ||||
| 	  if(debug_lvl >= DEBUG_CONNECTIONS) | ||||
|             syslog(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"), n->name, n->hostname); | ||||
|           terminate_connection(n->connection, 0); | ||||
|         } | ||||
|            | ||||
|       /* FIXME: check if information in existing node matches that of the other end of this connection */ | ||||
|     } | ||||
|    | ||||
|   n->connection = c; | ||||
|   c->node = n; | ||||
|   c->options |= options; | ||||
| 
 | ||||
|   /* Create an edge_t for this connection */ | ||||
| 
 | ||||
|   c->edge = new_edge(); | ||||
|    | ||||
|   c->edge->from.node = myself; | ||||
|   c->edge->from.address = str2address(addrstr); | ||||
|   c->edge->from.port = myself->port; | ||||
|   c->edge->to.node = n; | ||||
|   c->edge->to.address = c->address; | ||||
|   c->edge->to.port = hisport; | ||||
|   c->edge->weight = (weight + c->estimated_weight) / 2; | ||||
|   c->edge->connection = c; | ||||
|   c->edge->options = c->options; | ||||
| 
 | ||||
|   edge_add(c->edge); | ||||
| 
 | ||||
|   /* Activate this connection */ | ||||
| 
 | ||||
|   c->allow_request = ALL; | ||||
|   c->status.active = 1; | ||||
| 
 | ||||
|   if(debug_lvl >= DEBUG_CONNECTIONS) | ||||
|     syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), c->name, c->hostname); | ||||
| 
 | ||||
| cp | ||||
|   /* Send him everything we know */ | ||||
| 
 | ||||
|   send_everything(c); | ||||
| 
 | ||||
|   /* Notify others of this connection */ | ||||
| 
 | ||||
|   for(node = connection_tree->head; node; node = node->next) | ||||
|     { | ||||
|       other = (connection_t *)node->data; | ||||
| 
 | ||||
|       if(other->status.active && other != c) | ||||
|         send_add_edge(other, c->edge); | ||||
|     } | ||||
| 
 | ||||
|   /* Run MST and SSSP algorithms */ | ||||
|   | ||||
|   graph(); | ||||
| 
 | ||||
|   /* Succesful connection, reset timeout if this is an outgoing connection. */ | ||||
|    | ||||
|   if(c->outgoing) | ||||
|     c->outgoing->timeout = 0; | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										291
									
								
								src/protocol_edge.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								src/protocol_edge.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,291 @@ | |||
| /*
 | ||||
|     protocol_edge.c -- handle the meta-protocol, edges | ||||
|     Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>, | ||||
|                   2000-2002 Guus Sliepen <guus@sliepen.warande.net> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| 
 | ||||
|     $Id: protocol_edge.c,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $ | ||||
| */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <syslog.h> | ||||
| #include <stdio.h> | ||||
| #include <stdarg.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include <utils.h> | ||||
| #include <xalloc.h> | ||||
| #include <avl_tree.h> | ||||
| 
 | ||||
| #include "conf.h" | ||||
| #include "net.h" | ||||
| #include "netutl.h" | ||||
| #include "protocol.h" | ||||
| #include "meta.h" | ||||
| #include "connection.h" | ||||
| #include "node.h" | ||||
| #include "edge.h" | ||||
| #include "graph.h" | ||||
| 
 | ||||
| #include "system.h" | ||||
| 
 | ||||
| int send_add_edge(connection_t *c, edge_t *e) | ||||
| { | ||||
|   int x; | ||||
|   char *from_addrstr, *to_addrstr; | ||||
| cp | ||||
|   from_addrstr = address2str(e->from.address); | ||||
|   to_addrstr = address2str(e->to.address); | ||||
|   x = send_request(c, "%d %s %s %hd %s %s %hd %lx %d", ADD_EDGE, | ||||
|                       e->from.node->name, from_addrstr, e->from.port, | ||||
| 		      e->to.node->name, to_addrstr, e->to.port, | ||||
| 		      e->options, e->weight); | ||||
|   free(from_addrstr); | ||||
|   free(to_addrstr); | ||||
| cp | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
| int add_edge_h(connection_t *c) | ||||
| { | ||||
|   connection_t *other; | ||||
|   edge_t *e; | ||||
|   node_t *from, *to; | ||||
|   char from_name[MAX_STRING_SIZE]; | ||||
|   char to_name[MAX_STRING_SIZE]; | ||||
|   char from_addrstr[MAX_STRING_SIZE]; | ||||
|   char to_addrstr[MAX_STRING_SIZE]; | ||||
|   ipv4_t from_address, to_address; | ||||
|   port_t from_port, to_port; | ||||
|   long int options; | ||||
|   int weight; | ||||
|   avl_node_t *node; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" %hd "MAX_STRING" "MAX_STRING" %hd %lx %d", | ||||
|             from_name, from_addrstr, &from_port, | ||||
| 	    to_name, to_addrstr, &to_port, | ||||
| 	    &options, &weight) != 8) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_EDGE", c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if names are valid */ | ||||
| 
 | ||||
|   if(check_id(from_name)) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name, c->hostname, _("invalid name")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   if(check_id(to_name)) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name, c->hostname, _("invalid name")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Lookup nodes */ | ||||
| 
 | ||||
|   from = lookup_node(from_name); | ||||
|    | ||||
|   if(!from) | ||||
|     { | ||||
|       from = new_node(); | ||||
|       from->name = xstrdup(from_name); | ||||
|       node_add(from); | ||||
|     } | ||||
| 
 | ||||
|   to = lookup_node(to_name); | ||||
|    | ||||
|   if(!to) | ||||
|     { | ||||
|       to = new_node(); | ||||
|       to->name = xstrdup(to_name); | ||||
|       node_add(to); | ||||
|     } | ||||
| 
 | ||||
|   /* Convert addresses */ | ||||
|    | ||||
|   from_address = str2address(from_addrstr); | ||||
|   to_address = str2address(to_addrstr); | ||||
| 
 | ||||
|   /* Check if edge already exists */ | ||||
|    | ||||
|   e = lookup_edge(from, to); | ||||
|    | ||||
|   if(e) | ||||
|   { | ||||
|     if(e->weight != weight || e->options != options | ||||
|        || ((e->from.node == from) && (e->from.address != from_address || e->from.port != from_port || e->to.address != to_address || e->to.port != to_port)) | ||||
|        || ((e->from.node == to) && (e->from.address != to_address || e->from.port != to_port || e->to.address != from_address || e->to.port != from_port)) | ||||
|       )      | ||||
|     { | ||||
|       if(from == myself || to == myself) | ||||
|       { | ||||
|         if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|           syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not match existing entry"), "ADD_EDGE", c->name, c->hostname); | ||||
|         send_add_edge(c, e); | ||||
|         return 0; | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|         if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|           syslog(LOG_WARNING, _("Got %s from %s (%s) which does not match existing entry"), "ADD_EDGE", c->name, c->hostname); | ||||
|         edge_del(e); | ||||
|       } | ||||
|     } | ||||
|     else | ||||
|       return 0; | ||||
|   } | ||||
|   else if(from == myself || to == myself) | ||||
|   { | ||||
|     if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not exist"), "ADD_EDGE", c->name, c->hostname); | ||||
|     e = new_edge(); | ||||
|     e->from.node = from; | ||||
|     e->to.node = to; | ||||
|     send_del_edge(c, e); | ||||
|     free_edge(e); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   e = new_edge(); | ||||
|   e->from.node = from; | ||||
|   e->from.address = from_address; | ||||
|   e->from.port = from_port; | ||||
|   e->to.node = to; | ||||
|   e->to.address = to_address; | ||||
|   e->to.port = to_port; | ||||
|   e->options = options; | ||||
|   e->weight = weight; | ||||
|   edge_add(e); | ||||
| 
 | ||||
|   /* Tell the rest about the new edge */ | ||||
| 
 | ||||
|   for(node = connection_tree->head; node; node = node->next) | ||||
|     { | ||||
|       other = (connection_t *)node->data; | ||||
|       if(other->status.active && other != c) | ||||
|         send_add_edge(other, e); | ||||
|     } | ||||
| 
 | ||||
|   /* Run MST before or after we tell the rest? */ | ||||
| 
 | ||||
|   graph(); | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int send_del_edge(connection_t *c, edge_t *e) | ||||
| { | ||||
| cp | ||||
|   return send_request(c, "%d %s %s", DEL_EDGE, | ||||
|                       e->from.node->name, e->to.node->name); | ||||
| } | ||||
| 
 | ||||
| int del_edge_h(connection_t *c) | ||||
| { | ||||
|   edge_t *e; | ||||
|   char from_name[MAX_STRING_SIZE]; | ||||
|   char to_name[MAX_STRING_SIZE]; | ||||
|   node_t *from, *to; | ||||
|   connection_t *other; | ||||
|   avl_node_t *node; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING"", from_name, to_name) != 2) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE", | ||||
|              c->name, c->hostname); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if names are valid */ | ||||
| 
 | ||||
|   if(check_id(from_name)) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name, c->hostname, _("invalid name")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   if(check_id(to_name)) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name, c->hostname, _("invalid name")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Lookup nodes */ | ||||
| 
 | ||||
|   from = lookup_node(from_name); | ||||
|    | ||||
|   if(!from) | ||||
|     { | ||||
|       if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|         syslog(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   to = lookup_node(to_name); | ||||
|    | ||||
|   if(!to) | ||||
|     { | ||||
|       if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|         syslog(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if edge exists */ | ||||
|    | ||||
|   e = lookup_edge(from, to); | ||||
|    | ||||
|   if(!e) | ||||
|   { | ||||
|     if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|       syslog(LOG_WARNING, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   if(e->from.node == myself || e->to.node == myself) | ||||
|   { | ||||
|     if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "DEL_EDGE", c->name, c->hostname); | ||||
|     send_add_edge(c, e); /* Send back a correction */ | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   /* Tell the rest about the deleted edge */ | ||||
| 
 | ||||
|   for(node = connection_tree->head; node; node = node->next) | ||||
|     { | ||||
|       other = (connection_t *)node->data; | ||||
|       if(other->status.active && other != c) | ||||
|         send_del_edge(other, e); | ||||
|     } | ||||
| 
 | ||||
|   /* Delete the edge */ | ||||
|    | ||||
|   edge_del(e); | ||||
| 
 | ||||
|   /* Run MST before or after we tell the rest? */ | ||||
| 
 | ||||
|   graph(); | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										272
									
								
								src/protocol_key.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								src/protocol_key.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,272 @@ | |||
| /*
 | ||||
|     protocol_key.c -- handle the meta-protocol, key exchange | ||||
|     Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>, | ||||
|                   2000-2002 Guus Sliepen <guus@sliepen.warande.net> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| 
 | ||||
|     $Id: protocol_key.c,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $ | ||||
| */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <syslog.h> | ||||
| #include <stdio.h> | ||||
| #include <stdarg.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include <utils.h> | ||||
| #include <xalloc.h> | ||||
| #include <avl_tree.h> | ||||
| 
 | ||||
| #include "conf.h" | ||||
| #include "net.h" | ||||
| #include "netutl.h" | ||||
| #include "protocol.h" | ||||
| #include "meta.h" | ||||
| #include "connection.h" | ||||
| #include "node.h" | ||||
| #include "edge.h" | ||||
| \ | ||||
| #include "system.h" | ||||
| 
 | ||||
| int mykeyused = 0; | ||||
| 
 | ||||
| int send_key_changed(connection_t *c, node_t *n) | ||||
| { | ||||
|   connection_t *other; | ||||
|   avl_node_t *node; | ||||
| cp | ||||
|   /* Only send this message if some other daemon requested our key previously.
 | ||||
|      This reduces unnecessary key_changed broadcasts. | ||||
|   */ | ||||
| 
 | ||||
|   if(n == myself && !mykeyused) | ||||
|     return 0; | ||||
| 
 | ||||
|   for(node = connection_tree->head; node; node = node->next) | ||||
|     { | ||||
|       other = (connection_t *)node->data; | ||||
|       if(other->status.active && other->status.mst && other != c) | ||||
|         send_request(other, "%d %s", KEY_CHANGED, n->name); | ||||
|     } | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int key_changed_h(connection_t *c) | ||||
| { | ||||
|   char name[MAX_STRING_SIZE]; | ||||
|   node_t *n; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING, name) != 1) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "KEY_CHANGED", | ||||
|              c->name, c->hostname); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   n = lookup_node(name); | ||||
| 
 | ||||
|   if(!n) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist"), "KEY_CHANGED", | ||||
|              c->name, c->hostname, name); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   n->status.validkey = 0; | ||||
|   n->status.waitingforkey = 0; | ||||
|   n->sent_seqno = 0; | ||||
| 
 | ||||
|   send_key_changed(c, n); | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int send_req_key(connection_t *c, node_t *from, node_t *to) | ||||
| { | ||||
| cp | ||||
|   return send_request(c, "%d %s %s", REQ_KEY, | ||||
|                       from->name, to->name); | ||||
| } | ||||
| 
 | ||||
| int req_key_h(connection_t *c) | ||||
| { | ||||
|   char from_name[MAX_STRING_SIZE]; | ||||
|   char to_name[MAX_STRING_SIZE]; | ||||
|   node_t *from, *to; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING, from_name, to_name) != 2) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "REQ_KEY", | ||||
|               c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   from = lookup_node(from_name); | ||||
| 
 | ||||
|   if(!from) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"), "REQ_KEY", | ||||
|              c->name, c->hostname, from_name); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   to = lookup_node(to_name); | ||||
|    | ||||
|   if(!to) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"), "REQ_KEY", | ||||
|              c->name, c->hostname, to_name); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if this key request is for us */ | ||||
| 
 | ||||
|   if(to == myself)	/* Yes, send our own key back */ | ||||
|     { | ||||
|       mykeyused = 1; | ||||
|       from->received_seqno = 0; | ||||
|       send_ans_key(c, myself, from); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
| /* Proxy keys
 | ||||
|       if(to->status.validkey) | ||||
|         { | ||||
|           send_ans_key(c, to, from); | ||||
|         } | ||||
|       else | ||||
| */ | ||||
|         send_req_key(to->nexthop->connection, from, to); | ||||
|     } | ||||
| 
 | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int send_ans_key(connection_t *c, node_t *from, node_t *to) | ||||
| { | ||||
|   char key[MAX_STRING_SIZE]; | ||||
| cp | ||||
|   bin2hex(from->key, key, from->keylength); | ||||
|   key[from->keylength * 2] = '\0'; | ||||
| cp | ||||
|   return send_request(c, "%d %s %s %s %d %d %d", ANS_KEY, | ||||
|                       from->name, to->name, key, from->cipher?from->cipher->nid:0, from->digest?from->digest->type:0, from->maclength); | ||||
| } | ||||
| 
 | ||||
| int ans_key_h(connection_t *c) | ||||
| { | ||||
|   char from_name[MAX_STRING_SIZE]; | ||||
|   char to_name[MAX_STRING_SIZE]; | ||||
|   char key[MAX_STRING_SIZE]; | ||||
|   int cipher, digest, maclength; | ||||
|   node_t *from, *to; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d", from_name, to_name, key, &cipher, &digest, &maclength) != 6) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ANS_KEY", | ||||
|               c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   from = lookup_node(from_name); | ||||
| 
 | ||||
|   if(!from) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"), "ANS_KEY", | ||||
|              c->name, c->hostname, from_name); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   to = lookup_node(to_name); | ||||
| 
 | ||||
|   if(!to) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"), "ANS_KEY", | ||||
|              c->name, c->hostname, to_name); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Forward it if necessary */ | ||||
| 
 | ||||
|   if(to != myself) | ||||
|     { | ||||
|       return send_request(to->nexthop->connection, c->buffer); | ||||
|     } | ||||
| 
 | ||||
|   /* Update our copy of the origin's packet key */ | ||||
| 
 | ||||
|   if(from->key) | ||||
|     free(from->key); | ||||
| 
 | ||||
|   from->key = xstrdup(key); | ||||
|   from->keylength = strlen(key) / 2; | ||||
|   hex2bin(from->key, from->key, from->keylength); | ||||
|   from->key[from->keylength] = '\0'; | ||||
| 
 | ||||
|   from->status.validkey = 1; | ||||
|   from->status.waitingforkey = 0; | ||||
|    | ||||
|   /* Check and lookup cipher and digest algorithms */ | ||||
| 
 | ||||
|   if(cipher) | ||||
|     { | ||||
|       from->cipher = EVP_get_cipherbynid(cipher); | ||||
|       if(!from->cipher) | ||||
| 	{ | ||||
| 	  syslog(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name, from->hostname); | ||||
| 	  return -1; | ||||
| 	} | ||||
|       if(from->keylength != from->cipher->key_len + from->cipher->iv_len) | ||||
| 	{ | ||||
| 	  syslog(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname); | ||||
| 	  return -1; | ||||
|         } | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       from->cipher = NULL; | ||||
|     } | ||||
| 
 | ||||
|   if(digest) | ||||
|     { | ||||
|       from->digest = EVP_get_digestbynid(digest); | ||||
|       if(!from->digest) | ||||
| 	{ | ||||
| 	  syslog(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name, from->hostname); | ||||
| 	  return -1; | ||||
| 	} | ||||
|       from->maclength = maclength; | ||||
|       if(from->maclength > from->digest->md_size || from->maclength < 0) | ||||
| 	{ | ||||
| 	  syslog(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname); | ||||
| 	  return -1; | ||||
| 	} | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       from->digest = NULL; | ||||
|       from->maclength = maclength; | ||||
|     } | ||||
|    | ||||
|   flush_queue(from); | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
							
								
								
									
										193
									
								
								src/protocol_misc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								src/protocol_misc.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,193 @@ | |||
| /*
 | ||||
|     protocol_misc.c -- handle the meta-protocol, miscellaneous functions | ||||
|     Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>, | ||||
|                   2000-2002 Guus Sliepen <guus@sliepen.warande.net> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| 
 | ||||
|     $Id: protocol_misc.c,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $ | ||||
| */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <syslog.h> | ||||
| #include <stdio.h> | ||||
| #include <stdarg.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include <utils.h> | ||||
| 
 | ||||
| #include "conf.h" | ||||
| #include "net.h" | ||||
| #include "netutl.h" | ||||
| #include "protocol.h" | ||||
| #include "meta.h" | ||||
| #include "connection.h" | ||||
| 
 | ||||
| #include "system.h" | ||||
| 
 | ||||
| /* Status and error notification routines */ | ||||
| 
 | ||||
| int send_status(connection_t *c, int statusno, char *statusstring) | ||||
| { | ||||
| cp | ||||
|   if(!statusstring) | ||||
|     statusstring = status_text[statusno]; | ||||
| cp | ||||
|   return send_request(c, "%d %d %s", STATUS, statusno, statusstring); | ||||
| } | ||||
| 
 | ||||
| int status_h(connection_t *c) | ||||
| { | ||||
|   int statusno; | ||||
|   char statusstring[MAX_STRING_SIZE]; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d %d "MAX_STRING, &statusno, statusstring) != 2) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "STATUS", | ||||
|               c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   if(debug_lvl >= DEBUG_STATUS) | ||||
|     { | ||||
|       syslog(LOG_NOTICE, _("Status message from %s (%s): %s: %s"), | ||||
|              c->name, c->hostname, status_text[statusno], statusstring); | ||||
|     } | ||||
| 
 | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int send_error(connection_t *c, int err, char *errstring) | ||||
| { | ||||
| cp | ||||
|   if(!errstring) | ||||
|     errstring = strerror(err); | ||||
|   return send_request(c, "%d %d %s", ERROR, err, errstring); | ||||
| } | ||||
| 
 | ||||
| int error_h(connection_t *c) | ||||
| { | ||||
|   int err; | ||||
|   char errorstring[MAX_STRING_SIZE]; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d %d "MAX_STRING, &err, errorstring) != 2) | ||||
|     { | ||||
|        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ERROR", | ||||
|               c->name, c->hostname); | ||||
|        return -1; | ||||
|     } | ||||
| 
 | ||||
|   if(debug_lvl >= DEBUG_ERROR) | ||||
|     { | ||||
|       syslog(LOG_NOTICE, _("Error message from %s (%s): %s: %s"), | ||||
|              c->name, c->hostname, strerror(err), errorstring); | ||||
|     } | ||||
| 
 | ||||
|   terminate_connection(c, c->status.active); | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int send_termreq(connection_t *c) | ||||
| { | ||||
| cp | ||||
|   return send_request(c, "%d", TERMREQ); | ||||
| } | ||||
| 
 | ||||
| int termreq_h(connection_t *c) | ||||
| { | ||||
| cp | ||||
|   terminate_connection(c, c->status.active); | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int send_ping(connection_t *c) | ||||
| { | ||||
| cp | ||||
|   c->status.pinged = 1; | ||||
|   c->last_ping_time = time(NULL); | ||||
| cp | ||||
|   return send_request(c, "%d", PING); | ||||
| } | ||||
| 
 | ||||
| int ping_h(connection_t *c) | ||||
| { | ||||
| cp | ||||
|   return send_pong(c); | ||||
| } | ||||
| 
 | ||||
| int send_pong(connection_t *c) | ||||
| { | ||||
| cp | ||||
|   return send_request(c, "%d", PONG); | ||||
| } | ||||
| 
 | ||||
| int pong_h(connection_t *c) | ||||
| { | ||||
| cp | ||||
|   c->status.pinged = 0; | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /* Sending and receiving packets via TCP */ | ||||
| 
 | ||||
| int send_tcppacket(connection_t *c, vpn_packet_t *packet) | ||||
| { | ||||
|   int x; | ||||
| cp   | ||||
|   /* Evil hack. */ | ||||
| 
 | ||||
|   x = send_request(c, "%d %hd", PACKET, packet->len); | ||||
| 
 | ||||
|   if(x) | ||||
|     return x; | ||||
| cp | ||||
|   return send_meta(c, packet->data, packet->len); | ||||
| } | ||||
| 
 | ||||
| int tcppacket_h(connection_t *c) | ||||
| { | ||||
|   short int len; | ||||
| cp   | ||||
|   if(sscanf(c->buffer, "%*d %hd", &len) != 1) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "PACKET", c->name, c->hostname); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Set reqlen to len, this will tell receive_meta() that a tcppacket is coming. */ | ||||
| 
 | ||||
|   c->tcplen = len; | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /* Status strings */ | ||||
| 
 | ||||
| char (*status_text[]) = { | ||||
|   "Warning", | ||||
| }; | ||||
| 
 | ||||
| /* Error strings */ | ||||
| 
 | ||||
| char (*error_text[]) = { | ||||
|   "Error", | ||||
| }; | ||||
							
								
								
									
										231
									
								
								src/protocol_subnet.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								src/protocol_subnet.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,231 @@ | |||
| /*
 | ||||
|     protocol_subnet.c -- handle the meta-protocol, subnets | ||||
|     Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>, | ||||
|                   2000-2002 Guus Sliepen <guus@sliepen.warande.net> | ||||
| 
 | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program; if not, write to the Free Software | ||||
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||||
| 
 | ||||
|     $Id: protocol_subnet.c,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $ | ||||
| */ | ||||
| 
 | ||||
| #include "config.h" | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <syslog.h> | ||||
| #include <stdio.h> | ||||
| #include <stdarg.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include <utils.h> | ||||
| #include <xalloc.h> | ||||
| #include <avl_tree.h> | ||||
| 
 | ||||
| #include "conf.h" | ||||
| #include "net.h" | ||||
| #include "netutl.h" | ||||
| #include "protocol.h" | ||||
| #include "meta.h" | ||||
| #include "connection.h" | ||||
| #include "node.h" | ||||
| #include "edge.h" | ||||
| #include "graph.h" | ||||
| 
 | ||||
| #include "system.h" | ||||
| 
 | ||||
| int send_add_subnet(connection_t *c, subnet_t *subnet) | ||||
| { | ||||
|   int x; | ||||
|   char *netstr; | ||||
| cp | ||||
|   x = send_request(c, "%d %s %s", ADD_SUBNET, | ||||
|                       subnet->owner->name, netstr = net2str(subnet)); | ||||
|   free(netstr); | ||||
| cp | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
| int add_subnet_h(connection_t *c) | ||||
| { | ||||
|   char subnetstr[MAX_STRING_SIZE]; | ||||
|   char name[MAX_STRING_SIZE]; | ||||
|   node_t *owner; | ||||
|   connection_t *other; | ||||
|   subnet_t *s; | ||||
|   avl_node_t *node; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_SUBNET", c->name, c->hostname); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if owner name is a valid */ | ||||
| 
 | ||||
|   if(check_id(name)) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name, c->hostname, _("invalid name")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if subnet string is valid */ | ||||
| 
 | ||||
|   if(!(s = str2net(subnetstr))) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name, c->hostname, _("invalid subnet string")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if the owner of the new subnet is in the connection list */ | ||||
| 
 | ||||
|   owner = lookup_node(name); | ||||
| 
 | ||||
|   if(!owner) | ||||
|     { | ||||
|       owner = new_node(); | ||||
|       owner->name = xstrdup(name); | ||||
|       node_add(owner); | ||||
|     } | ||||
| 
 | ||||
|   /* Check if we already know this subnet */ | ||||
|    | ||||
|   if(lookup_subnet(owner, s)) | ||||
|     { | ||||
|       free_subnet(s); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   /* If we don't know this subnet, but we are the owner, retaliate with a DEL_SUBNET */ | ||||
| 
 | ||||
|   if(owner == myself) | ||||
|   { | ||||
|     if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "ADD_SUBNET", c->name, c->hostname); | ||||
|     s->owner = myself; | ||||
|     send_del_subnet(c, s); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   /* If everything is correct, add the subnet to the list of the owner */ | ||||
| 
 | ||||
|   subnet_add(owner, s); | ||||
| 
 | ||||
|   /* Tell the rest */ | ||||
|    | ||||
|   for(node = connection_tree->head; node; node = node->next) | ||||
|     { | ||||
|       other = (connection_t *)node->data; | ||||
|       if(other->status.active && other != c) | ||||
|         send_add_subnet(other, s); | ||||
|     } | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| int send_del_subnet(connection_t *c, subnet_t *s) | ||||
| { | ||||
|   int x; | ||||
|   char *netstr; | ||||
| cp | ||||
|   netstr = net2str(s); | ||||
|   x = send_request(c, "%d %s %s", DEL_SUBNET, s->owner->name, netstr); | ||||
|   free(netstr); | ||||
| cp | ||||
|   return x; | ||||
| } | ||||
| 
 | ||||
| int del_subnet_h(connection_t *c) | ||||
| { | ||||
|   char subnetstr[MAX_STRING_SIZE]; | ||||
|   char name[MAX_STRING_SIZE]; | ||||
|   node_t *owner; | ||||
|   connection_t *other; | ||||
|   subnet_t *s, *find; | ||||
|   avl_node_t *node; | ||||
| cp | ||||
|   if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING, name, subnetstr) != 2) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_SUBNET", c->name, c->hostname); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if owner name is a valid */ | ||||
| 
 | ||||
|   if(check_id(name)) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name, c->hostname, _("invalid name")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if the owner of the new subnet is in the connection list */ | ||||
| 
 | ||||
|   if(!(owner = lookup_node(name))) | ||||
|     { | ||||
|       if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|         syslog(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"), | ||||
|              "DEL_SUBNET", c->name, c->hostname, name); | ||||
|       return 0; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if subnet string is valid */ | ||||
| 
 | ||||
|   if(!(s = str2net(subnetstr))) | ||||
|     { | ||||
|       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name, c->hostname, _("invalid subnet string")); | ||||
|       return -1; | ||||
|     } | ||||
| 
 | ||||
|   /* If everything is correct, delete the subnet from the list of the owner */ | ||||
| 
 | ||||
|   s->owner = owner; | ||||
| 
 | ||||
|   find = lookup_subnet(owner, s); | ||||
|    | ||||
|   free_subnet(s); | ||||
| 
 | ||||
|   if(!find) | ||||
|     { | ||||
|       if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|         syslog(LOG_WARNING, _("Got %s from %s (%s) for %s which does not appear in his subnet tree"), | ||||
|              "DEL_SUBNET", c->name, c->hostname, name); | ||||
|       return 0; | ||||
|     } | ||||
|    | ||||
|   /* If we are the owner of this subnet, retaliate with an ADD_SUBNET */ | ||||
|    | ||||
|   if(owner == myself) | ||||
|   { | ||||
|     if(debug_lvl >= DEBUG_PROTOCOL) | ||||
|       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "DEL_SUBNET", c->name, c->hostname); | ||||
|     send_add_subnet(c, find); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   /* Tell the rest */ | ||||
|    | ||||
|   for(node = connection_tree->head; node; node = node->next) | ||||
|     { | ||||
|       other = (connection_t *)node->data; | ||||
|       if(other->status.active && other != c) | ||||
|         send_del_subnet(other, find); | ||||
|     } | ||||
| 
 | ||||
|   /* Finally, delete it. */ | ||||
| 
 | ||||
|   subnet_del(owner, find); | ||||
| 
 | ||||
| cp | ||||
|   return 0; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue