paulo@0: /* paulo@0: * $Id: gt_ban.c,v 1.7 2004/01/29 07:50:25 hipnod Exp $ paulo@0: * paulo@0: * Copyright (C) 2003 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: paulo@0: #include "gt_conf.h" paulo@0: #include "gt_ban.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* mask of bits that determines which bucket a ban goes into */ paulo@0: #define INDEX_MASK (0xff000000) paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: typedef struct ban_ipv4 paulo@0: { paulo@0: in_addr_t ipv4; paulo@0: uint32_t netmask; paulo@0: } ban_ipv4_t; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* ban list organize by the first 8 bits */ paulo@0: static Dataset *ipv4_ban_list; paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static char *net_mask_str (uint32_t netmask) paulo@0: { paulo@0: static char buf[128]; paulo@0: paulo@0: snprintf (buf, sizeof (buf) - 1, "%d.%d.%d.%d", paulo@0: (netmask & 0xff000000) >> 24, paulo@0: (netmask & 0x00ff0000) >> 16, paulo@0: (netmask & 0x0000ff00) >> 8, paulo@0: (netmask & 0x000000ff)); paulo@0: paulo@0: return buf; paulo@0: } paulo@0: paulo@0: static uint32_t net_mask_bin (char *netmask) paulo@0: { paulo@0: uint32_t a[4]; paulo@0: paulo@0: if (!netmask) paulo@0: return 0xFFFFffff; paulo@0: paulo@0: if (sscanf (netmask, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]) != 4) paulo@0: return 0xFFFFffff; paulo@0: paulo@0: return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: /* paulo@0: * Returns 0 if ban 'b' is contained within ban 'a'. paulo@0: */ paulo@0: static int find_superset_ban (ban_ipv4_t *a, ban_ipv4_t *b) paulo@0: { paulo@0: uint32_t sig1 = a->ipv4 & a->netmask; paulo@0: uint32_t sig2 = b->ipv4 & b->netmask; paulo@0: paulo@0: /* paulo@0: * If there are no bits in the significant address portions paulo@0: * that contradict within _a_'s netmask, then ban _b_ is a paulo@0: * subset of _a_. paulo@0: */ paulo@0: return ((sig2 ^ sig1) & a->netmask); paulo@0: } paulo@0: paulo@0: static void log_dup (ban_ipv4_t *orig_ban, ban_ipv4_t *b) paulo@0: { paulo@0: char *ip1, *ip2; paulo@0: char *n1, *n2; paulo@0: paulo@0: if (!orig_ban || !b) paulo@0: return; paulo@0: paulo@0: n1 = STRDUP (net_mask_str (b->netmask)); paulo@0: ip1 = STRDUP (net_ip_str (htonl (b->ipv4))); paulo@0: n2 = net_mask_str (orig_ban->netmask); paulo@0: ip2 = net_ip_str (htonl (orig_ban->ipv4)); paulo@0: paulo@0: if (BAN_DEBUG) paulo@0: GT->dbg (GT, "ban %s/%s is a subset of %s/%s", ip1, n1, ip2, n2); paulo@0: paulo@0: free (ip1); paulo@0: free (n1); paulo@0: } paulo@0: paulo@0: BOOL gt_ban_ipv4_add (in_addr_t address, uint32_t netmask) paulo@0: { paulo@0: uint32_t prefix; paulo@0: List *list; paulo@0: List *orig; paulo@0: ban_ipv4_t *ban; paulo@0: paulo@0: if (!(ban = MALLOC (sizeof (ban_ipv4_t)))) paulo@0: return FALSE; paulo@0: paulo@0: address = ntohl (address); paulo@0: paulo@0: ban->ipv4 = address; paulo@0: ban->netmask = netmask | INDEX_MASK; /* ensure we have at least 8 bits */ paulo@0: paulo@0: prefix = address & INDEX_MASK; paulo@0: paulo@0: list = dataset_lookup (ipv4_ban_list, &prefix, sizeof (prefix)); paulo@0: paulo@0: if ((orig = list_find_custom (list, ban, (ListForeachFunc)find_superset_ban))) paulo@0: { paulo@0: log_dup (list_nth_data (orig, 0), ban); paulo@0: free (ban); paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: list = list_prepend (list, ban); paulo@0: paulo@0: if (!dataset_insert (&ipv4_ban_list, &prefix, sizeof (prefix), list, 0)) paulo@0: return FALSE; paulo@0: paulo@0: if (BAN_DEBUG) paulo@0: { paulo@0: GT->dbg (GT, "*!*@%s/%s", net_ip_str (htonl (address)), paulo@0: net_mask_str (netmask)); paulo@0: } paulo@0: paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: BOOL gt_ban_ipv4_is_banned (in_addr_t address) paulo@0: { paulo@0: uint32_t prefix; paulo@0: List *list; paulo@0: ban_ipv4_t ban; paulo@0: paulo@0: address = ntohl (address); paulo@0: prefix = address & INDEX_MASK; paulo@0: paulo@0: if (!(list = dataset_lookup (ipv4_ban_list, &prefix, sizeof (prefix)))) paulo@0: return FALSE; paulo@0: paulo@0: ban.ipv4 = address; paulo@0: ban.netmask = 0xFFFFffff; paulo@0: paulo@0: if (list_find_custom (list, &ban, (ListForeachFunc)find_superset_ban)) paulo@0: return TRUE; paulo@0: paulo@0: return FALSE; paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static BOOL load_hostiles_txt (char *hostiles_filename) paulo@0: { paulo@0: FILE *f; paulo@0: char *hostiles_path; paulo@0: char *buf = NULL; paulo@0: char *p; paulo@0: paulo@0: hostiles_path = gift_conf_path ("%s/%s", GT->name, hostiles_filename); paulo@0: paulo@0: if (!(f = fopen (hostiles_path, "r"))) paulo@0: return FALSE; paulo@0: paulo@0: while (file_read_line (f, &buf)) paulo@0: { paulo@0: in_addr_t ipv4; paulo@0: uint32_t netmask; paulo@0: char *ipv4_str; paulo@0: char *mask_str; paulo@0: paulo@0: p = buf; paulo@0: paulo@0: /* divide the string into two sides */ paulo@0: ipv4_str = string_sep (&p, "/"); paulo@0: mask_str = p; paulo@0: paulo@0: if (!ipv4_str) paulo@0: continue; paulo@0: paulo@0: netmask = net_mask_bin (mask_str); paulo@0: ipv4 = net_ip (ipv4_str); paulo@0: paulo@0: if (!ipv4 || ipv4 == INADDR_NONE) paulo@0: continue; paulo@0: paulo@0: gt_ban_ipv4_add (ipv4, netmask); paulo@0: } paulo@0: paulo@0: fclose (f); paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: void gt_ban_init (void) paulo@0: { paulo@0: ipv4_ban_list = dataset_new (DATASET_HASH); paulo@0: paulo@0: if (!gt_config_load_file ("Gnutella/hostiles.txt", TRUE, FALSE)) paulo@0: GT->warn (GT, "couldn't load \"hostiles.txt\""); paulo@0: paulo@0: load_hostiles_txt ("hostiles.txt"); paulo@0: #ifndef WIN32 paulo@0: load_hostiles_txt ("Hostiles.txt"); /* case-sensitivite blah */ paulo@0: #endif paulo@0: } paulo@0: paulo@0: static int free_ban (ban_ipv4_t *ban, void *udata) paulo@0: { paulo@0: free (ban); paulo@0: return TRUE; paulo@0: } paulo@0: paulo@0: static int cleanup_lists (ds_data_t *data, ds_data_t *value, void *udata) paulo@0: { paulo@0: List *list = value->data; paulo@0: list_foreach_remove (list, (ListForeachFunc)free_ban, NULL); paulo@0: return DS_CONTINUE | DS_REMOVE; paulo@0: } paulo@0: paulo@0: void gt_ban_cleanup (void) paulo@0: { paulo@0: dataset_foreach_ex (ipv4_ban_list, DS_FOREACH_EX(cleanup_lists), NULL); paulo@0: dataset_clear (ipv4_ban_list); paulo@0: ipv4_ban_list = NULL; paulo@0: }