2000-03-26 00:33:07 +00:00
|
|
|
/*
|
2002-02-10 21:57:54 +00:00
|
|
|
protocol.c -- handle the meta-protocol, basic functions
|
2001-01-07 17:09:07 +00:00
|
|
|
Copyright (C) 1999-2001 Ivo Timmermans <itimmermans@bigfoot.com>,
|
|
|
|
2000,2001 Guus Sliepen <guus@sliepen.warande.net>
|
2000-03-26 00:33:07 +00:00
|
|
|
|
|
|
|
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.
|
2000-05-29 21:01:26 +00:00
|
|
|
|
2002-03-22 13:31:18 +00:00
|
|
|
$Id: protocol.c,v 1.28.4.126 2002/03/22 13:31:18 guus Exp $
|
2000-03-26 00:33:07 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2000-05-04 23:17:02 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
2000-03-26 00:33:07 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <syslog.h>
|
2000-05-01 18:07:12 +00:00
|
|
|
#include <stdio.h>
|
2000-11-15 13:33:27 +00:00
|
|
|
#include <stdarg.h>
|
2001-02-25 11:09:29 +00:00
|
|
|
#include <errno.h>
|
2000-03-26 00:33:07 +00:00
|
|
|
|
|
|
|
#include <utils.h>
|
2002-03-21 23:11:53 +00:00
|
|
|
#include <xalloc.h>
|
2000-11-15 01:06:13 +00:00
|
|
|
|
2000-03-26 00:33:07 +00:00
|
|
|
#include "conf.h"
|
|
|
|
#include "protocol.h"
|
2000-09-26 14:06:11 +00:00
|
|
|
#include "meta.h"
|
2000-11-20 19:12:17 +00:00
|
|
|
#include "connection.h"
|
2000-03-26 00:33:07 +00:00
|
|
|
|
2000-05-29 21:01:26 +00:00
|
|
|
#include "system.h"
|
|
|
|
|
2002-03-21 23:11:53 +00:00
|
|
|
avl_tree_t *past_request_tree;
|
|
|
|
|
2000-09-15 12:58:40 +00:00
|
|
|
int check_id(char *id)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < strlen(id); i++)
|
2000-10-15 00:59:37 +00:00
|
|
|
if(!isalnum(id[i]) && id[i] != '_')
|
|
|
|
return -1;
|
2000-12-05 08:59:30 +00:00
|
|
|
|
2000-10-15 00:59:37 +00:00
|
|
|
return 0;
|
2000-09-15 12:58:40 +00:00
|
|
|
}
|
|
|
|
|
2000-12-05 08:59:30 +00:00
|
|
|
/* Generic request routines - takes care of logging and error
|
|
|
|
detection as well */
|
2000-05-01 18:07:12 +00:00
|
|
|
|
2001-10-27 12:13:17 +00:00
|
|
|
int send_request(connection_t *c, const char *format, ...)
|
2000-03-26 00:33:07 +00:00
|
|
|
{
|
2000-09-10 15:18:03 +00:00
|
|
|
va_list args;
|
2000-10-15 00:59:37 +00:00
|
|
|
char buffer[MAXBUFSIZE];
|
|
|
|
int len, request;
|
2000-09-17 21:42:05 +00:00
|
|
|
|
2000-04-25 18:57:23 +00:00
|
|
|
cp
|
2000-12-05 08:59:30 +00:00
|
|
|
/* Use vsnprintf instead of vasprintf: faster, no memory
|
|
|
|
fragmentation, cleanup is automatic, and there is a limit on the
|
|
|
|
input buffer anyway */
|
2000-09-10 15:18:03 +00:00
|
|
|
|
2000-10-15 00:59:37 +00:00
|
|
|
va_start(args, format);
|
|
|
|
len = vsnprintf(buffer, MAXBUFSIZE, format, args);
|
2000-09-10 15:18:03 +00:00
|
|
|
va_end(args);
|
2000-03-26 00:33:07 +00:00
|
|
|
|
2000-10-15 00:59:37 +00:00
|
|
|
if(len < 0 || len > MAXBUFSIZE-1)
|
2000-09-10 15:18:03 +00:00
|
|
|
{
|
2002-03-22 13:31:18 +00:00
|
|
|
syslog(LOG_ERR, _("Output buffer overflow while sending request to %s (%s)"), c->name, c->hostname);
|
2000-09-10 15:18:03 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2000-09-22 16:20:07 +00:00
|
|
|
if(debug_lvl >= DEBUG_PROTOCOL)
|
2001-05-25 11:54:28 +00:00
|
|
|
{
|
2002-02-27 22:37:55 +00:00
|
|
|
sscanf(buffer, "%d", &request);
|
2001-05-25 11:54:28 +00:00
|
|
|
if(debug_lvl >= DEBUG_META)
|
2001-10-27 12:13:17 +00:00
|
|
|
syslog(LOG_DEBUG, _("Sending %s to %s (%s): %s"), request_name[request], c->name, c->hostname, buffer);
|
2001-05-25 11:54:28 +00:00
|
|
|
else
|
2001-10-27 12:13:17 +00:00
|
|
|
syslog(LOG_DEBUG, _("Sending %s to %s (%s)"), request_name[request], c->name, c->hostname);
|
2001-05-25 11:54:28 +00:00
|
|
|
}
|
2000-10-15 00:59:37 +00:00
|
|
|
|
2001-05-25 11:54:28 +00:00
|
|
|
buffer[len++] = '\n';
|
2000-09-22 16:20:07 +00:00
|
|
|
cp
|
2001-10-27 12:13:17 +00:00
|
|
|
return send_meta(c, buffer, len);
|
2000-09-22 16:20:07 +00:00
|
|
|
}
|
|
|
|
|
2001-10-27 12:13:17 +00:00
|
|
|
int receive_request(connection_t *c)
|
2000-09-22 16:20:07 +00:00
|
|
|
{
|
2000-09-26 14:06:11 +00:00
|
|
|
int request;
|
2001-05-25 11:54:28 +00:00
|
|
|
cp
|
2001-10-27 12:13:17 +00:00
|
|
|
if(sscanf(c->buffer, "%d", &request) == 1)
|
2000-09-10 15:18:03 +00:00
|
|
|
{
|
2001-03-04 13:59:32 +00:00
|
|
|
if((request < 0) || (request >= LAST) || (request_handlers[request] == NULL))
|
2000-09-26 14:06:11 +00:00
|
|
|
{
|
2001-05-25 11:54:28 +00:00
|
|
|
if(debug_lvl >= DEBUG_META)
|
|
|
|
syslog(LOG_DEBUG, _("Unknown request from %s (%s): %s"),
|
2001-10-27 12:13:17 +00:00
|
|
|
c->name, c->hostname, c->buffer);
|
2001-05-25 11:54:28 +00:00
|
|
|
else
|
|
|
|
syslog(LOG_ERR, _("Unknown request from %s (%s)"),
|
2001-10-27 12:13:17 +00:00
|
|
|
c->name, c->hostname);
|
2001-05-25 11:54:28 +00:00
|
|
|
|
2000-09-26 14:06:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-10-21 11:52:08 +00:00
|
|
|
if(debug_lvl >= DEBUG_PROTOCOL)
|
2001-05-25 11:54:28 +00:00
|
|
|
{
|
|
|
|
if(debug_lvl >= DEBUG_META)
|
|
|
|
syslog(LOG_DEBUG, _("Got %s from %s (%s): %s"),
|
2001-10-27 12:13:17 +00:00
|
|
|
request_name[request], c->name, c->hostname, c->buffer);
|
2001-05-25 11:54:28 +00:00
|
|
|
else
|
|
|
|
syslog(LOG_DEBUG, _("Got %s from %s (%s)"),
|
2001-10-27 12:13:17 +00:00
|
|
|
request_name[request], c->name, c->hostname);
|
2001-05-25 11:54:28 +00:00
|
|
|
}
|
2000-09-26 14:06:11 +00:00
|
|
|
}
|
2000-10-29 00:02:20 +00:00
|
|
|
|
2001-10-27 12:13:17 +00:00
|
|
|
if((c->allow_request != ALL) && (c->allow_request != request))
|
2000-10-29 01:08:09 +00:00
|
|
|
{
|
2001-10-27 12:13:17 +00:00
|
|
|
syslog(LOG_ERR, _("Unauthorized request from %s (%s)"), c->name, c->hostname);
|
2000-10-29 01:08:09 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-10-27 12:13:17 +00:00
|
|
|
if(request_handlers[request](c))
|
2000-09-26 14:06:11 +00:00
|
|
|
/* Something went wrong. Probably scriptkiddies. Terminate. */
|
|
|
|
{
|
|
|
|
syslog(LOG_ERR, _("Error while processing %s from %s (%s)"),
|
2001-10-27 12:13:17 +00:00
|
|
|
request_name[request], c->name, c->hostname);
|
2000-09-26 14:06:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2000-09-10 15:18:03 +00:00
|
|
|
}
|
2000-09-26 14:06:11 +00:00
|
|
|
else
|
2000-03-26 00:33:07 +00:00
|
|
|
{
|
2000-09-26 14:06:11 +00:00
|
|
|
syslog(LOG_ERR, _("Bogus data received from %s (%s)"),
|
2001-10-27 12:13:17 +00:00
|
|
|
c->name, c->hostname);
|
2000-03-26 00:33:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2000-10-29 00:02:20 +00:00
|
|
|
cp
|
|
|
|
return 0;
|
2000-09-10 15:18:03 +00:00
|
|
|
}
|
|
|
|
|
2002-03-21 23:11:53 +00:00
|
|
|
int request_compare(past_request_t *a, past_request_t *b)
|
|
|
|
{
|
|
|
|
cp
|
|
|
|
return strcmp(a->request, b->request);
|
|
|
|
}
|
|
|
|
|
|
|
|
void init_requests(void)
|
|
|
|
{
|
|
|
|
cp
|
|
|
|
past_request_tree = avl_alloc_tree((avl_compare_t)request_compare, (avl_action_t)free);
|
|
|
|
cp
|
|
|
|
}
|
|
|
|
|
2002-03-22 11:43:48 +00:00
|
|
|
void exit_requests(void)
|
2002-03-21 23:11:53 +00:00
|
|
|
{
|
|
|
|
cp
|
|
|
|
avl_delete_tree(past_request_tree);
|
|
|
|
cp
|
|
|
|
}
|
|
|
|
|
|
|
|
int seen_request(char *request)
|
|
|
|
{
|
|
|
|
past_request_t p, *new;
|
|
|
|
cp
|
|
|
|
p.request = request;
|
|
|
|
|
|
|
|
if(avl_search(past_request_tree, &p))
|
2002-03-22 11:43:48 +00:00
|
|
|
{
|
|
|
|
if(debug_lvl >= DEBUG_SCARY_THINGS)
|
|
|
|
syslog(LOG_DEBUG, _("Already seen request"));
|
|
|
|
return 1;
|
|
|
|
}
|
2002-03-21 23:11:53 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
new = (past_request_t *)xmalloc(sizeof(*new));
|
|
|
|
new->request = xstrdup(request);
|
|
|
|
new->firstseen = now;
|
|
|
|
avl_insert(past_request_tree, new);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
cp
|
|
|
|
}
|
|
|
|
|
|
|
|
void age_past_requests(void)
|
|
|
|
{
|
|
|
|
avl_node_t *node, *next;
|
|
|
|
past_request_t *p;
|
|
|
|
int left = 0, deleted = 0;
|
|
|
|
cp
|
|
|
|
for(node = past_request_tree->head; node; node = next)
|
|
|
|
{
|
|
|
|
next = node->next;
|
|
|
|
p = (past_request_t *)node->data;
|
|
|
|
if(p->firstseen + pingtimeout < now)
|
|
|
|
avl_delete_node(past_request_tree, node), deleted++;
|
|
|
|
else
|
|
|
|
left++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(debug_lvl >= DEBUG_SCARY_THINGS && left + deleted)
|
|
|
|
syslog(LOG_DEBUG, _("Aging past requests: deleted %d, left %d\n"), deleted, left);
|
|
|
|
cp
|
|
|
|
}
|
|
|
|
|
2002-02-10 21:57:54 +00:00
|
|
|
/* Jumptable for the request handlers */
|
2001-10-30 12:59:12 +00:00
|
|
|
|
2002-02-10 21:57:54 +00:00
|
|
|
int (*request_handlers[])(connection_t*) = {
|
|
|
|
id_h, metakey_h, challenge_h, chal_reply_h, ack_h,
|
|
|
|
status_h, error_h, termreq_h,
|
|
|
|
ping_h, pong_h,
|
|
|
|
// add_node_h, del_node_h,
|
|
|
|
add_subnet_h, del_subnet_h,
|
|
|
|
add_edge_h, del_edge_h,
|
|
|
|
key_changed_h, req_key_h, ans_key_h,
|
|
|
|
tcppacket_h,
|
|
|
|
};
|
2001-10-30 12:59:12 +00:00
|
|
|
|
2002-02-10 21:57:54 +00:00
|
|
|
/* Request names */
|
2000-09-22 16:20:07 +00:00
|
|
|
|
2000-09-10 16:15:35 +00:00
|
|
|
char (*request_name[]) = {
|
2001-10-27 12:13:17 +00:00
|
|
|
"ID", "METAKEY", "CHALLENGE", "CHAL_REPLY", "ACK",
|
2000-09-10 16:15:35 +00:00
|
|
|
"STATUS", "ERROR", "TERMREQ",
|
|
|
|
"PING", "PONG",
|
2002-02-10 21:57:54 +00:00
|
|
|
// "ADD_NODE", "DEL_NODE",
|
2000-09-10 22:49:46 +00:00
|
|
|
"ADD_SUBNET", "DEL_SUBNET",
|
2001-10-28 08:41:19 +00:00
|
|
|
"ADD_EDGE", "DEL_EDGE",
|
2000-09-10 22:49:46 +00:00
|
|
|
"KEY_CHANGED", "REQ_KEY", "ANS_KEY",
|
2001-01-07 20:19:35 +00:00
|
|
|
"PACKET",
|
2000-03-26 00:33:07 +00:00
|
|
|
};
|