/***** * * Copyright (C) 2002 Vincent Glaume * 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 "pconfig.h" #include "comm-agent.h" #include "plugin-firewall.h" #include "plugin-island.h" #include "cm.h" #define MAX_FD 1024 struct client_tbl_s { prelude_msg_t *msg; prelude_client_t *client; }; static int pfd_index = 0; extern config_agent_t config; static struct pollfd pfd[MAX_FD]; static struct client_tbl_s client_tbl[MAX_FD]; static void print_firewall_rule(cm_firewall_msg_t *fwr) { const char *cmd; cm_firewall_rule_t r; const char *dr = "Drop"; const char *ac = "Accept"; const char *re = "Reject"; const char *un = "Unknown"; int n; char *saddr = NULL; if ( !fwr ) return; r = fwr->rule; switch (r.rule_cmd) { case CM_FW_RULE_ACCEPT: cmd = ac; break; case CM_FW_RULE_DROP: cmd = dr; break; case CM_FW_RULE_REJECT: cmd = re; break; default: cmd = un; } n = strlen(inet_ntoa(r.saddr)); saddr = malloc(n + 1); if ( !saddr ) return; strcpy(saddr, inet_ntoa(r.saddr)); log(LOG_INFO, "\n********** Firewalling rule **********\n\n" "TTL = 0x%08x\nRank = 0x%x\nOptions = 0x%x\n\n" "Rule:\n\tProtocol = 0x%x\n" "\tFrom:\n\t\tAddr = %s\n\t\tMask = 0x%08x\n\t\tPort = %u - %u\n" "\tTo:\n\t\tAddr = %s\n\t\tMask = 0x%08x\n\t\tPort = %u - %u\n" "\tCommand: %s\n" "\n**************************************\n", fwr->rule_ttl, fwr->rule_rank, fwr->rule_options, r.rule_proto, saddr, ntohl(r.smask.s_addr), r.sport[0], r.sport[1], inet_ntoa(r.daddr), ntohl(r.dmask.s_addr), r.dport[0], r.dport[1], cmd); free(saddr); } static int extract_fw_msg(cm_firewall_msg_t *fw, prelude_msg_t *msg) { void *data; uint8_t tag; uint32_t len; int ret; ret = prelude_msg_get(msg, &tag, &len, &data); if ( ret != prelude_msg_unfinished ) return ret; switch ( tag ) { case CM_FW_RULE_PROTO: if ( extract_uint8_safe(&fw->rule.rule_proto, data, len) < 0 ) return -1; break; case CM_FW_RULE_SADDR: if ( extract_uint32_safe(&fw->rule.saddr.s_addr, data, len) < 0 ) return -1; break; case CM_FW_RULE_SPORT_1: if ( extract_uint16_safe(&fw->rule.sport[0], data, len) < 0 ) return -1; break; case CM_FW_RULE_SPORT_2: if ( extract_uint16_safe(&fw->rule.sport[1], data, len) < 0 ) return -1; break; case CM_FW_RULE_SMASK: if ( extract_uint32_safe(&fw->rule.smask.s_addr, data, len) < 0 ) return -1; break; case CM_FW_RULE_DADDR: if ( extract_uint32_safe(&fw->rule.daddr.s_addr, data , len) < 0 ) return -1; break; case CM_FW_RULE_DPORT_1: if ( extract_uint16_safe(&fw->rule.dport[0], data, len) < 0 ) return -1; break; case CM_FW_RULE_DPORT_2: if ( extract_uint16_safe(&fw->rule.dport[1], data, len) < 0 ) return -1; break; case CM_FW_RULE_DMASK: if ( extract_uint32_safe(&fw->rule.dmask.s_addr, data, len) < 0 ) return -1; break; case CM_FW_RULE_CMD: if ( extract_uint8_safe(&fw->rule.rule_cmd, data, len) < 0 ) return -1; break; case CM_FW_TTL: if ( extract_uint32_safe(&fw->rule_ttl, data, len) < 0 ) return -1; break; case CM_FW_RANK: if ( extract_uint32_safe(&fw->rule_rank, data, len) < 0 ) return -1; break; case CM_FW_OPTIONS: if ( extract_uint32_safe(&fw->rule_options, data, len) < 0 ) return -1; break; } return extract_fw_msg(fw, msg); } static int handle_firewall_msg(prelude_msg_t *msg) { int ret; cm_firewall_msg_t *fwr = NULL; ret = firewall_plugins_available(); if ( ret < 0 ) return -1; fwr = calloc(1, sizeof(cm_firewall_msg_t)); if ( ! fwr ) { log(LOG_ERR, "memory exhausted.\n"); return -1; } ret = extract_fw_msg(fwr, msg); if ( ret < 0 ) { free(fwr); return -1; } if ( config.debug ) print_firewall_rule(fwr); ret = firewall_plugins_run(fwr); free(fwr); return ret; } static int extract_island_msg(cm_island_msg_t *isl, prelude_msg_t *msg) { void *data; uint8_t tag; uint32_t len; int ret; ret = prelude_msg_get(msg, &tag, &len, &data); if ( ret != prelude_msg_unfinished ) return ret; switch ( tag ) { case CM_ISL_TTL: if ( extract_uint32_safe(&isl->down_ttl, data, len) < 0 ) return -1; break; } return extract_island_msg(isl, msg); } static int handle_island_msg(prelude_msg_t *msg) { int ret; cm_island_msg_t *isl = NULL; ret = island_plugins_available(); if ( ret < 0 ) return -1; isl = calloc(1, sizeof(cm_firewall_msg_t)); if ( ! isl ) { log(LOG_ERR, "memory exhausted.\n"); return -1; } ret = extract_island_msg(isl, msg); if ( ret < 0 ) { free(isl); return -1; } ret = island_plugins_run(isl); free(isl); return ret; } static int process_manager_msg(prelude_msg_t *msg) { uint8_t tag; int len, ret; uint32_t msg_id; void *data = NULL; if ( prelude_msg_get_tag(msg) != PRELUDE_MSG_CM ) { log(LOG_INFO, "Not a CM message as expected\n"); return -1; } ret = prelude_msg_get(msg, &tag, &len, &data); if ( ret < 0 ) return -1; /* * Data here must be a 4-byte unsigned integer, which is the msg id */ if ( extract_uint32_safe(&msg_id, data, len) < 0 ) return -1; switch (tag) { case PRELUDE_MSG_CM_FIREWALL: ret = handle_firewall_msg(msg); break; case PRELUDE_MSG_CM_THROTTLE: log(LOG_INFO, "CM Throttling message not implemented yet\n"); break; case PRELUDE_MSG_CM_ISLAND: ret = handle_island_msg(msg); break; case PRELUDE_MSG_CM_FEATURE: log(LOG_INFO, "CM Feature... not done yet\n"); break; default: log(LOG_INFO, "CM msg type unknown : %d\n", tag); return -1; } return ret; } static int prelude_client_recv_msg(int *timeout) { int i, ret; prelude_io_t *fd; int poll_timeout = -1; if ( timeout && *timeout ) poll_timeout = *timeout; ret = poll(pfd, pfd_index, poll_timeout); if ( ret < 0 ) return -1; /* if it timed out, we should have something to clean in the fw rules */ if ( ret == 0 ) return firewall_plugins_clean(timeout); for ( i = 0; i < pfd_index; i++ ) { if ( pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL) ) continue; if ( !(pfd[i].revents & POLLIN) ) continue; fd = prelude_client_get_fd(client_tbl[i].client); ret = prelude_msg_read(&client_tbl[i].msg, fd); if ( ret == prelude_msg_unfinished ) continue; else if ( ret == prelude_msg_eof ) continue; else if ( ret == prelude_msg_error ) { /* * error, make sure we abort communication. */ prelude_client_close(client_tbl[i].client); pfd[i].fd = -1; } else { ret = process_manager_msg(client_tbl[i].msg); prelude_msg_destroy(client_tbl[i].msg); client_tbl[i].msg = NULL; firewall_plugins_clean(timeout); } } return ret; } static int build_np_msg(prelude_msg_t *msg) { net_protect_list_t *npl = config.npl; uint32_t tmp; if ( ! msg ) return -1; while ( npl ) { prelude_msg_set(msg, PRELUDE_MSG_CM_FEATURE, sizeof(uint8_t), &npl->np.actions); tmp = htonl(npl->np.net.s_addr); prelude_msg_set(msg, PRELUDE_MSG_CM_NP_ADDR, sizeof(uint32_t), &tmp); tmp = htonl(npl->np.mask.s_addr); prelude_msg_set(msg, PRELUDE_MSG_CM_NP_MASK, sizeof(uint32_t), &tmp); npl = npl->next; } return 1; } static int register_connection(prelude_client_t *client) { int ret; const char *daddr; prelude_msg_t *msg = NULL; if ( pfd_index == MAX_FD ) { log(LOG_ERR, "too many connection.\n"); return -1; } msg = prelude_msg_new(3 * config.net_num, config.net_num * ( 2 * sizeof(uint32_t) + sizeof(uint8_t) ), PRELUDE_MSG_CM, PRELUDE_MSG_PRIORITY_HIGH); if ( ! msg ) { log(LOG_ERR, "Could not create Net Protection Message\n"); return -1; } ret = build_np_msg(msg); if ( ret < 0 ) { prelude_msg_destroy(msg); return -1; } ret = prelude_client_send_msg(client, msg); prelude_msg_destroy(msg); daddr = prelude_client_get_daddr(client); if ( ret < 0 ) log(LOG_ERR, "error sending initialisation message to %s.\n", daddr); pfd[pfd_index].events = POLLIN; client_tbl[pfd_index].client = client; pfd[pfd_index++].fd = prelude_io_get_fd(prelude_client_get_fd(client)); log(LOG_INFO, "- agent successfully registered to %s.\n", daddr); return 0; } static void notify_connection(struct list_head *clist) { int ret; struct list_head *tmp; prelude_client_t *client; pfd_index = 0; list_for_each(tmp, clist) { client = prelude_list_get_object(tmp, prelude_client_t); /* * this client is dead (no connection). */ if ( prelude_client_is_alive(client) < 0 ) continue; ret = register_connection(client); if ( ret < 0 ) continue; } } int comm_agent_listen_manager(void) { static int timeout = -1; memset(client_tbl, 0, sizeof(client_tbl)); notify_connection(prelude_sensor_get_client_list()); prelude_sensor_notify_mgr_connection(notify_connection); while ( 1 ) { prelude_client_recv_msg(&timeout); /* printf("coucou [0x%08x]!\n", timeout); */ /* log(LOG_INFO, "CM message received and processed\n"); */ } return -1; }