/***** * * Copyright (C) 2002 Vincent Glaume , Baptiste Malguy * All Rights Reserved * * This file is part of the Prelude program. * * 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, 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; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * *****/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "counter-measure.h" #include "cm-comm.h" static LIST_HEAD(cm_agent_list); static pthread_mutex_t list_mutex = PTHREAD_MUTEX_INITIALIZER; /* * For speed reason, the first matching agent is returned. * Moreover, we should not have several agents for a given area. */ cm_agent_t *cm_server_find_agent(struct in_addr req_net, struct in_addr req_mask, uint8_t cm_type) { struct list_head *tmp, *tmp2; cm_agent_t *agt = NULL; cm_agent_net_protect_t *canp; list_for_each(tmp, &cm_agent_list) { agt = list_entry(tmp, cm_agent_t, list); list_for_each(tmp2, &agt->np_list) { canp = list_entry(tmp2, cm_agent_net_protect_t, list); if ( ( counter_measure_is_subnet(req_net, req_mask, canp->np.net, canp->np.mask) > 0) && (canp->np.actions & cm_type)) return agt; } } return NULL; } static int get_option(prelude_msg_t *msg) { int ret; void *buf; uint8_t tag; uint32_t dlen; ret = prelude_msg_get(msg, &tag, &dlen, &buf); if ( ret < 0 ) { log(LOG_ERR, "error decoding message.\n"); return -1; } if ( ret == 0 ) { log(LOG_ERR, "end of message without end of option tag.\n"); return -1; } switch (tag) { case PRELUDE_OPTION_NAME: printf("option name = %s\n", (char *) buf); case PRELUDE_OPTION_END: printf("end option.\n"); return 0; default: log(LOG_ERR, "Unknow option tag %d.\n", tag); /* return -1; */ } return get_option(msg); } static int optlist_to_xml(prelude_msg_t *msg) { int ret; void *buf; uint8_t tag; uint32_t dlen; /* * Convert the Prelude option list to XML here. */ ret = prelude_msg_get(msg, &tag, &dlen, &buf); if ( ret < 0 ) { log(LOG_ERR, "error decoding message.\n"); return -1; } if ( ret == 0 ) { prelude_msg_destroy(msg); return 0; /* end of message do DTD validation here */ } switch (tag) { case PRELUDE_OPTION_START: printf("new option.\n"); ret = get_option(msg); if ( ret < 0 ) { prelude_msg_destroy(msg); return -1; } break; default: //log(LOG_ERR, "Unknow option tag %d.\n", tag); } return optlist_to_xml(msg); } static int get_cm_message(cm_agent_t *agt, prelude_msg_t *msg) { void *buf; uint8_t tag; uint32_t len; net_protect_t np; int ret; /* * Which kind of msg may we receive here ? mainly status message */ ret = prelude_msg_get(msg, &tag, &len, &buf); if ( ret != prelude_msg_unfinished ) return ret; switch ( tag ) { case PRELUDE_MSG_CM_FEATURE: if ( cm_comm_plugins_available() < 0 ) { log(LOG_INFO, "No CM communication plugin to process this message\n"); return -1; } if ( extract_uint8_safe(&np.actions, buf, len) < 0 ) return -1; /* * A feature msg HAS to be followed by a msg giving the net and then a msg giving the mask */ if ( prelude_msg_get(msg, &tag, &len, &buf) != prelude_msg_unfinished ) { log(LOG_ERR, "Malformed CM message: more information is expected.\n"); return -1; } if ( tag != PRELUDE_MSG_CM_NP_ADDR ) { log(LOG_ERR, "Malformed CM message: IP address was expected.\n"); return -1; } if ( extract_uint32_safe(&np.net.s_addr, buf, len) < 0 ) return -1; if ( prelude_msg_get(msg, &tag, &len, &buf) != prelude_msg_unfinished ) { log(LOG_ERR, "Malformed CM message: more information is expected.\n"); return -1; } if ( tag != PRELUDE_MSG_CM_NP_MASK ) { log(LOG_ERR, "Malformed CM message: netmask was expected.\n"); return -1; } if ( extract_uint32_safe(&np.mask.s_addr, buf, len) < 0 ) return -1; if ( cm_comm_plugins_process_feature(agt, &np) < 0 ) { log(LOG_ERR, "Error processing the CM feature message\n"); return -1; } break; default: log(LOG_INFO, "CM msg type unknown or unexpected: %d\n", tag); return -1; } return get_cm_message(agt, msg); } static int read_agent_identification(cm_agent_t *agt, prelude_msg_t *msg) { int ret; void *buf; uint8_t tag; uint32_t len; uint64_t id; ret = prelude_msg_get(msg, &tag, &len, &buf); if ( ret != prelude_msg_unfinished ) { printf("wazawouzou ?!\n"); return -1; } if ( ret == 0 ) return 0; switch (tag) { case PRELUDE_MSG_ID_DECLARE: ret = extract_uint64_safe(&id, buf, len); if ( ret < 0 ) return -1; log(LOG_INFO, "[%s] - agent declared ident %llu.\n", agt->addr, id); break; default: ret = -1; break; } return ret; } static int read_connection_cb(server_generic_client_t *client) { int ret = 0; prelude_msg_t *msg; prelude_msg_status_t status; cm_agent_t *agt = (cm_agent_t *) client; /* * We grab the message. */ status = prelude_msg_read(&agt->msg, agt->fd); if ( status == prelude_msg_eof || status == prelude_msg_error ) return -1; else if ( status == prelude_msg_unfinished ) return 0; msg = agt->msg; agt->msg = NULL; /* * If we get there, we have a whole message. */ switch ( prelude_msg_get_tag(msg) ) { case PRELUDE_MSG_CM: ret = get_cm_message(agt, msg); break; case PRELUDE_MSG_OPTION_LIST: return optlist_to_xml(msg); break; case PRELUDE_MSG_ID: ret = read_agent_identification(agt, msg); break; default: log(LOG_INFO, "[%s] - unknown or unexpected message id %d\n", agt->addr, prelude_msg_get_tag(msg)); ret = 0; break; } prelude_msg_destroy(msg); return ret; } static void close_connection_cb(server_generic_client_t *ptr) { cm_agent_t *agt = (cm_agent_t *) ptr; struct list_head *tmp; list_del(&agt->list); if ( agt->msg ) prelude_msg_destroy(agt->msg); list_for_each(tmp, &agt->np_list) { cm_agent_net_protect_t *canp = list_entry(tmp, cm_agent_net_protect_t, list); list_del(&canp->list); free(canp); } } static int accept_connection_cb(server_generic_client_t *ptr) { cm_agent_t *agt = (cm_agent_t *) ptr; INIT_LIST_HEAD(&agt->np_list); pthread_mutex_lock(&list_mutex); list_add(&agt->list, &cm_agent_list); pthread_mutex_unlock(&list_mutex); return 0; } server_generic_t *cm_server_new(const char *addr, uint16_t port) { server_generic_t *server; server = server_generic_new(addr, port, sizeof(cm_agent_t), accept_connection_cb, read_connection_cb, close_connection_cb); if ( ! server ) { log(LOG_ERR, "error creating a generic server.\n"); return NULL; } return server; } void cm_server_close(server_generic_t *server) { server_generic_close(server); }