📄 ipban.c
字号:
/* * Copyright (C) 2000 Gediminas (gugini@fortas.ktu.lt) * Copyright (C) 2002 Bart硂miej Butyn (bartek@milc.com.pl) * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#define IPBAN_INTERNAL_ACCESS#include "common/setup_before.h"#include <stdio.h>#ifdef HAVE_STDDEF_H# include <stddef.h>#else# ifndef NULL# define NULL ((void *)0)# endif#endif#ifdef STDC_HEADERS# include <stdlib.h>#else# ifdef HAVE_MALLOC_H# include <malloc.h># endif#endif#ifdef HAVE_STRING_H# include <string.h>#else# ifdef HAVE_STRINGS_H# include <strings.h># endif#endif#include <ctype.h>#include "compat/strchr.h"#include "compat/strdup.h"#include "compat/strcasecmp.h"#include "compat/strsep.h"#include <errno.h>#include "compat/strerror.h"#ifdef TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# ifdef HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#include "common/eventlog.h"#include "common/util.h"#include "connection.h"#include "message.h"#include "prefs.h"#include "common/list.h"#include "common/xalloc.h"#include "server.h"#include "ipban.h"#include "common/setup_after.h"static int identify_ipban_function(const char * funcstr);static int ipban_func_del(t_connection * c, char const * cp);static int ipban_func_list(t_connection * c);static int ipban_func_check(t_connection * c, char const * cp);static int ipban_unload_entry(t_ipban_entry * e);static int ipban_identical_entry(t_ipban_entry * e1, t_ipban_entry * e2);static t_ipban_entry * ipban_str_to_ipban_entry(char const * cp);static char * ipban_entry_to_str(t_ipban_entry const * entry);static unsigned long ipban_str_to_ulong(char const * ipaddr);static int ipban_could_be_exact_ip_str(char const * str);static int ipban_could_be_ip_str(char const * ipstr);static void ipban_usage(t_connection * c);static t_list * ipbanlist_head = NULL;static time_t lastchecktime = 0;extern int ipbanlist_create(void){ ipbanlist_head = list_create(); return 0;}extern int ipbanlist_destroy(void){ t_elem * curr; t_ipban_entry * entry; if (ipbanlist_head) { LIST_TRAVERSE(ipbanlist_head,curr) { entry = elem_get_data(curr); if (!entry) /* should not happen */ { eventlog(eventlog_level_error,__FUNCTION__,"ipbanlist contains NULL item"); continue; } if (list_remove_elem(ipbanlist_head,&curr)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not remove item from list"); ipban_unload_entry(entry); } if (list_destroy(ipbanlist_head)<0) return -1; ipbanlist_head = NULL; } return 0;}extern int ipbanlist_load(char const * filename){ FILE * fp; char * buff; char * ip; char * timestr; unsigned int currline; unsigned int endtime; if (!filename) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL filename"); return -1; } if (!(fp = fopen(filename,"r"))) { eventlog(eventlog_level_error,__FUNCTION__,"could not open banlist file \"%s\" for reading (fopen: %s)",filename,pstrerror(errno)); return -1; } for (currline=1; (buff = file_get_line(fp)); currline++) { ip = buff; /* eat whitespace in front */ while (*ip=='\t' || *ip==' ') ip++; if (*ip=='\0' || *ip=='#') { continue; } /* eat whitespace in back */ while (ip[strlen(ip)-1]==' ' || ip[strlen(ip)-1]=='\t') ip[strlen(ip)-1] = '\0'; if (strchr(ip,' ') || strchr(ip,'\t')) { timestr = ip; while (*timestr!=' ' && *timestr!='\t') timestr++; *timestr = '\0'; timestr++; while (*timestr==' ' || *timestr=='\t') timestr++; } else timestr = NULL; if (!timestr) endtime = 0; else if (clockstr_to_seconds(timestr,&endtime)<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not convert to seconds. Banning pernamently."); endtime = 0; } if (ipbanlist_add(NULL,ip,endtime)!=0) { eventlog(eventlog_level_warn,__FUNCTION__,"error in %.64s at line %u",filename,currline); continue; } } file_get_line(NULL); // clear file_get_line buffer if (fclose(fp)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not close banlist file \"%s\" after reading (fclose: %s)",filename,pstrerror(errno)); return 0;}extern int ipbanlist_save(char const * filename){ t_elem const * curr; t_ipban_entry * entry; FILE * fp; char * ipstr; char line[1024]; if (!filename) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL filename"); return -1; } if (!(fp = fopen(filename,"w"))) { eventlog(eventlog_level_error,__FUNCTION__,"could not open banlist file \"%s\" for writing (fopen: %s)",filename,pstrerror(errno)); return -1; }/* if (ftruncate(fp,0)<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not truncate banlist file \"%s\" (ftruncate: %s)",filename,pstrerror(errno)); return -1; }*/ LIST_TRAVERSE_CONST(ipbanlist_head,curr) { entry = elem_get_data(curr); if (!entry) { eventlog(eventlog_level_error,__FUNCTION__,"ipbanlist contains NULL element"); continue; } if (!(ipstr = ipban_entry_to_str(entry))) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL ipstr"); continue; } if (entry->endtime == 0) sprintf(line,"%s\n",ipstr); else sprintf(line,"%s %ld\n",ipstr,entry->endtime); if (!(fwrite(line,strlen(line),1,fp))) eventlog(eventlog_level_error,__FUNCTION__,"could not write to banlist file (write: %s)",pstrerror(errno)); xfree(ipstr); } if (fclose(fp)<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not close banlist file \"%s\" after writing (fclose: %s)",filename,pstrerror(errno)); return -1; } return 0; }extern int ipbanlist_check(char const * ipaddr){ t_elem const * curr; t_ipban_entry * entry; char * whole; char const * ip1; char const * ip2; char const * ip3; char const * ip4; int counter; if (!ipaddr) { eventlog(eventlog_level_warn,__FUNCTION__,"got NULL ipaddr"); return -1; } whole = xstrdup(ipaddr); eventlog(eventlog_level_debug,__FUNCTION__,"lastcheck: %u, now: %u, now-lc: %u.",(unsigned)lastchecktime,(unsigned)now,(unsigned)(now-lastchecktime)); if (now - lastchecktime >= (signed)prefs_get_ipban_check_int()) /* unsigned; no need to check prefs < 0 */ { ipbanlist_unload_expired(); lastchecktime = now; } ip1 = strtok(whole,"."); ip2 = strtok(NULL,"."); ip3 = strtok(NULL,"."); ip4 = strtok(NULL,"."); if (!ip1 || !ip2 || !ip3 || !ip4) { eventlog(eventlog_level_warn,__FUNCTION__,"got bad IP address \"%s\"",ipaddr); xfree(whole); return -1; } eventlog(eventlog_level_debug,__FUNCTION__,"checking %s.%s.%s.%s",ip1,ip2,ip3,ip4); counter = 0; LIST_TRAVERSE_CONST(ipbanlist_head,curr) { entry = elem_get_data(curr); if (!entry) { eventlog(eventlog_level_error,__FUNCTION__,"ipbanlist contains NULL item"); return -1; } counter++; switch (entry->type) { case ipban_type_exact: if (strcmp(entry->info1,ipaddr)==0) { eventlog(eventlog_level_debug,__FUNCTION__,"address %s matched exact %s",ipaddr,entry->info1); xfree(whole); return counter; } eventlog(eventlog_level_debug,__FUNCTION__,"address %s does not match exact %s",ipaddr,entry->info1); continue; case ipban_type_wildcard: if (strcmp(entry->info1,"*")!=0 && strcmp(ip1,entry->info1)!=0) { eventlog(eventlog_level_debug,__FUNCTION__,"address %s does not match part 1 of wildcard %s.%s.%s.%s",ipaddr,entry->info1,entry->info2,entry->info3,entry->info4); continue; } if (strcmp(entry->info2,"*")!=0 && strcmp(ip2,entry->info2)!=0) { eventlog(eventlog_level_debug,__FUNCTION__,"address %s does not match part 2 of wildcard %s.%s.%s.%s",ipaddr,entry->info1,entry->info2,entry->info3,entry->info4); continue; } if (strcmp(entry->info3,"*")!=0 && strcmp(ip3,entry->info3)!=0) { eventlog(eventlog_level_debug,__FUNCTION__,"address %s does not match part 3 of wildcard %s.%s.%s.%s",ipaddr,entry->info1,entry->info2,entry->info3,entry->info4); continue; } if (strcmp(entry->info4,"*")!=0 && strcmp(ip4,entry->info4)!=0) { eventlog(eventlog_level_debug,__FUNCTION__,"address %s does not match part 4 of wildcard %s.%s.%s.%s",ipaddr,entry->info1,entry->info2,entry->info3,entry->info4); continue; } eventlog(eventlog_level_debug,__FUNCTION__,"address %s matched wildcard %s.%s.%s.%s",ipaddr,entry->info1,entry->info2,entry->info3,entry->info4); xfree(whole); return counter; case ipban_type_range: if ((ipban_str_to_ulong(ipaddr) >= ipban_str_to_ulong(entry->info1)) && (ipban_str_to_ulong(ipaddr) <= ipban_str_to_ulong(entry->info2))) { eventlog(eventlog_level_debug,__FUNCTION__,"address %s matched range %s-%s",ipaddr,entry->info1,entry->info2); xfree(whole); return counter; } eventlog(eventlog_level_debug,__FUNCTION__,"address %s does not match range %s-%s",ipaddr,entry->info1,entry->info2); continue; case ipban_type_netmask: { unsigned long lip1; unsigned long lip2; unsigned long netmask; if (!(lip1 = ipban_str_to_ulong(ipaddr))) return -1; if (!(lip2 = ipban_str_to_ulong(entry->info1))) return -1; if (!(netmask = ipban_str_to_ulong(entry->info2))) return -1; lip1 = lip1 & netmask; lip2 = lip2 & netmask; if (lip1 == lip2) { eventlog(eventlog_level_debug,__FUNCTION__,"address %s matched netmask %s/%s",ipaddr,entry->info1,entry->info2); xfree(whole); return counter; } eventlog(eventlog_level_debug,__FUNCTION__,"address %s does not match netmask %s/%s",ipaddr,entry->info1,entry->info2); continue; } case ipban_type_prefix: { unsigned long lip1; unsigned long lip2; int prefix; if (!(lip1 = ipban_str_to_ulong(ipaddr))) return -1; if (!(lip2 = ipban_str_to_ulong(entry->info1))) return -1; prefix = atoi(entry->info2); lip1 = lip1 >> (32 - prefix); lip2 = lip2 >> (32 - prefix); if (lip1 == lip2) { eventlog(eventlog_level_debug,__FUNCTION__,"address %s matched prefix %s/%s",ipaddr,entry->info1,entry->info2); xfree(whole); return counter; } eventlog(eventlog_level_debug,__FUNCTION__,"address %s does not match prefix %s/%s",ipaddr,entry->info1,entry->info2); continue; } default: /* unknown type */ eventlog(eventlog_level_warn,__FUNCTION__,"found bad ban type %d",(int)entry->type); } } xfree(whole); return 0;}extern int ipbanlist_add(t_connection * c, char const * cp, time_t endtime){ t_ipban_entry * entry; char tstr[MAX_MESSAGE_LEN]; if (!(entry = ipban_str_to_ipban_entry(cp))) { if (c) message_send_text(c,message_type_error,c,"Bad IP."); eventlog(eventlog_level_error,__FUNCTION__,"could not convert to t_ipban_entry: \"%s\"",cp); return -1; } entry->endtime = endtime; list_append_data(ipbanlist_head,entry); if (c) { if (endtime == 0) { sprintf(tstr,"%s banned permamently by %s.",cp,conn_get_username(c)); eventlog(eventlog_level_info,__FUNCTION__,tstr); message_send_admins(c,message_type_info,tstr); sprintf(tstr,"%s banned permamently.",cp); message_send_text(c,message_type_info,c,tstr); } else { sprintf(tstr,"%s banned for %.48s by %s.",cp,seconds_to_timestr(entry->endtime - now),conn_get_username(c)); eventlog(eventlog_level_info,__FUNCTION__,tstr); message_send_admins(c,message_type_info,tstr); sprintf(tstr,"%s banned for %.48s.",cp,seconds_to_timestr(entry->endtime - now)); message_send_text(c,message_type_info,c,tstr); } } return 0;}extern int ipbanlist_unload_expired(void){ t_elem * curr; t_ipban_entry * entry; char removed; removed = 0; LIST_TRAVERSE(ipbanlist_head,curr) { entry = elem_get_data(curr); if (!entry) { eventlog(eventlog_level_error,__FUNCTION__,"ipbanlist_contains NULL element"); return -1; } if ((entry->endtime - now <= 0) && (entry->endtime != 0)) { eventlog(eventlog_level_debug,__FUNCTION__,"removing item: %s",entry->info1); removed = 1; if (list_remove_elem(ipbanlist_head,&curr)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not remove item"); else ipban_unload_entry(entry); } } if (removed==1) ipbanlist_save(prefs_get_ipbanfile()); return 0;}extern time_t ipbanlist_str_to_time_t(t_connection * c, char const * timestr){ unsigned int bmin; char minstr[MAX_TIME_STR]; unsigned int i; char tstr[MAX_MESSAGE_LEN]; for (i=0; isdigit((int)timestr[i]) && i<sizeof(minstr)-1; i++) minstr[i] = timestr[i]; minstr[i] = '\0'; if (timestr[i]!='\0') { if (c) { if (strlen(minstr)<1) message_send_text(c,message_type_info,c,"There was an error in time."); else { sprintf(tstr,"There was an error in time. Banning only for: %s minutes.",minstr); message_send_text(c,message_type_info,c,tstr); } } } if (clockstr_to_seconds(minstr,&bmin)<0) /* it thinks these are seconds but we treat them as minutes */ { eventlog(eventlog_level_error,__FUNCTION__,"could not convert to minutes: \"%s\"",timestr); return -1; } if (bmin == 0) return 0; else { return now + bmin*60; }}extern int handle_ipban_command(t_connection * c, char const * text){ char subcommand[MAX_FUNC_LEN]; char ipstr[MAX_IP_STR]; unsigned int i,j; for (i=0; text[i]!=' ' && text[i]!='\0'; i++); /* skip command */ for (; text[i]==' '; i++); for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get subcommand */ if (j<sizeof(subcommand)-1) subcommand[j++] = text[i]; subcommand[j] = '\0'; for (; text[i]==' '; i++); for (j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get ip address */ if (j<sizeof(ipstr)-1) ipstr[j++] = text[i]; ipstr[j] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -