diff options
-rw-r--r-- | pttbbs/common/bbs/banip.c | 137 | ||||
-rwxr-xr-x | pttbbs/daemon/brcstored/brcstored.py | 4 | ||||
-rw-r--r-- | pttbbs/daemon/logind/logind.c | 5 | ||||
-rw-r--r-- | pttbbs/include/cmbbs.h | 4 | ||||
-rw-r--r-- | pttbbs/mbbsd/mbbsd.c | 13 |
5 files changed, 129 insertions, 34 deletions
diff --git a/pttbbs/common/bbs/banip.c b/pttbbs/common/bbs/banip.c index a281d03d..dc27a9e0 100644 --- a/pttbbs/common/bbs/banip.c +++ b/pttbbs/common/bbs/banip.c @@ -14,59 +14,108 @@ #include <sys/socket.h> #include <netinet/in.h> #include "cmbbs.h" -#define BANIP_ALLOC (128) + +#define BANIP_ALLOC (512) +#define BANIP_ALLOCMSG (1024) + +static const char *str_banned = "YOUR ARE USING A BANNED IP.\n\r"; + +typedef struct { + IPv4 addr; + size_t msg_offset; +} BanRecord; typedef struct { // table allocation size_t sz, alloc; - IPv4 *ar; + size_t szmsg, allocmsg; + char *msg; + BanRecord *ar; } IPv4List; static int compare_ipv4(const void *pa, const void *pb) { - const IPv4 *a = (const IPv4*)pa, *b = (const IPv4*)pb; + const BanRecord *a = (const BanRecord*)pa, *b = (const BanRecord*)pb; // Since IPv4 are all random number, we can't do simple a-b due to // underflow. - return (*a > *b) ? 1 : (*a == *b) ? 0 : -1; + return (a->addr > b->addr) ? 1 : (a->addr == b->addr) ? 0 : -1; } static void add_banip_list(IPv4List *list, IPv4 addr) { if (list->sz >= list->alloc) { list->alloc += BANIP_ALLOC; - list->ar = (IPv4*)realloc(list->ar, sizeof(IPv4) * list->alloc); + list->ar = (BanRecord*)realloc( + list->ar, sizeof(BanRecord) * list->alloc); assert(list->ar); } - list->ar[list->sz++] = addr; + list->ar[list->sz].msg_offset = list->szmsg; + list->ar[list->sz++].addr = addr; +} + +static void +add_banip_list_message(IPv4List *list, const char *msg) { + int len = strlen(msg); + char *p; + // Add more space for '\n\r\0' + while (list->szmsg + len + 3 >= list->allocmsg) { +#ifdef DEBUG + fprintf(stderr, "(banip) Allocate more msg buffer: %lu->%lu\n", + list->allocmsg, list->allocmsg + BANIP_ALLOCMSG); +#endif + list->allocmsg += BANIP_ALLOCMSG; + list->msg = (char*)realloc(list->msg, list->allocmsg); + assert(list->msg); + } + p = list->msg + list->szmsg; + strcpy(p, msg); + + // Remove trailing blank lines. + while (len > 0 && isascii(p[len - 1]) && isspace(p[len - 1])) { + p[--len] = 0; + } + assert(len > 0); + p[len++] = '\n'; + p[len++] = '\r'; + p[len++] = 0; +#ifdef DEBUG + fprintf(stderr, "(banip) Add new message: %s", p); +#endif + list->szmsg += len; } static void reset_banip_list(IPv4List *list) { list->sz = 0; + list->szmsg = 0; } static void sort_banip_list(IPv4List *list) { if (!list->ar) return; - qsort(list->ar, list->sz, sizeof(IPv4), compare_ipv4); + qsort(list->ar, list->sz, sizeof(BanRecord), compare_ipv4); } -int +const char * in_banip_list_addr(const BanIpList *blist, IPv4 addr) { const IPv4List *list = (const IPv4List*)blist; + BanRecord r = { .addr=addr }, *p; if (!list || !list->ar) - return 0; - return bsearch(&addr, list->ar, list->sz, - sizeof(IPv4), compare_ipv4) != NULL; + return NULL; + p = bsearch(&r, list->ar, list->sz, sizeof(BanRecord), compare_ipv4); + if (!p) + return NULL; + return (p->msg_offset < list->szmsg) ? + list->msg + p->msg_offset : str_banned; } -int +const char * in_banip_list(const BanIpList *blist, const char *ip) { struct in_addr addr; if (blist && inet_pton(AF_INET, ip, &addr) == 1) return in_banip_list_addr(blist, addr.s_addr); - return 0; + return NULL; } BanIpList* @@ -75,6 +124,7 @@ free_banip_list(BanIpList *blist) { if (!list) return NULL; free(list->ar); + free(list->msg); free(list); return NULL; } @@ -86,7 +136,9 @@ load_banip_list(const char *filename, FILE* err) { FILE *fp; char *p; char buf[PATHLEN]; + char msg[25 * ANSILINELEN]; struct in_addr addr; + int was_ip = 1; fp = fopen(filename, "rt"); if (!fp) @@ -97,15 +149,44 @@ load_banip_list(const char *filename, FILE* err) { reset_banip_list(list); while (fgets(buf, sizeof(buf), fp)) { - // only process lines starting with digits, - // and ignore all comments. - p = strchr(buf, '#'); - if (p) *p = 0; + // To allow client printing message to screen directly, + // always append \r. + strlcat(buf, "\r", sizeof(buf)); p = buf; while (*p && isascii(*p) && isspace(*p)) p++; - if (!(*p && isascii(*p) && isdigit(*p))) + // first, remove lines with only comments. + if (*p == '#') continue; + + // process IP entries, otherwise append text. + if (*p && isascii(*p) && isdigit(*p)) { + char *sharp = strchr(p, '#'); + if (sharp) *sharp = 0; + if (!was_ip) { + add_banip_list_message(list, msg); + was_ip = 1; + } + } else { + // For text entries, use raw input and ignore comments. + // Also ignore all blank lines before first data. + if (was_ip) { + if (!*p) + continue; + if (list->sz < 1) { + if (err) + fprintf(err, "(banip) WARN: Text before IP: %s", buf); + continue; + } + strlcpy(msg, buf, sizeof(msg)); + } + else + strlcat(msg, buf, sizeof(msg)); + was_ip = 0; + continue; + } + + // Parse and add IP records. for (p = strtok(p, " \t\r\n"); p; p = strtok(NULL, " \t\r\n")) { if (!(*p && isascii(*p) && isdigit(*p))) continue; @@ -121,6 +202,12 @@ load_banip_list(const char *filename, FILE* err) { add_banip_list(list, addr.s_addr); } } + if (was_ip) { + if (err) + fprintf(err, "(banip) WARN: Trailing IP records without text.\n"); + } else { + add_banip_list_message(list, msg); + } fclose(fp); sort_banip_list(list); if (err) @@ -140,7 +227,11 @@ cached_banip_list(const char *basefile, const char *cachefile) { if (m_base < 0) return NULL; - if (m_cache >= m_base && sz > 0 && sz % sizeof(IPv4) == 0) { + // TODO currently we only save the ipv4 address & index (BanRecord) without + // message body; in future we should also cache that, or throw everything + // into SHM, or set BanRecods.msg_offset to 0. + + if (m_cache >= m_base && sz > 0 && sz % sizeof(BanRecord) == 0) { // valid cache, load it. fp = fopen(cachefile, "rb"); if (fp) { @@ -152,10 +243,10 @@ cached_banip_list(const char *basefile, const char *cachefile) { assert(list); memset(list, 0, sizeof(*list)); reset_banip_list(list); - list->ar = (IPv4*)malloc(sz); - list->sz = sz / sizeof(IPv4); + list->ar = (BanRecord*)malloc(sz); + list->sz = sz / sizeof(BanRecord); list->alloc = list->sz; - fread(list->ar, sizeof(IPv4), list->sz, fp); + fread(list->ar, sizeof(BanRecord), list->sz, fp); fclose(fp); return list; } @@ -167,7 +258,7 @@ cached_banip_list(const char *basefile, const char *cachefile) { snprintf(tmpfn, sizeof(tmpfn), "%s.%d", cachefile, getpid()); fp = fopen(tmpfn, "wb"); if (fp) { - fwrite(list->ar, sizeof(IPv4), list->sz, fp); + fwrite(list->ar, sizeof(BanRecord), list->sz, fp); fclose(fp); Rename(tmpfn, cachefile); #ifdef DEBUG diff --git a/pttbbs/daemon/brcstored/brcstored.py b/pttbbs/daemon/brcstored/brcstored.py index bc9b6e67..4ab7e43c 100755 --- a/pttbbs/daemon/brcstored/brcstored.py +++ b/pttbbs/daemon/brcstored/brcstored.py @@ -38,7 +38,8 @@ def open_database(db_path): # BRCv3 max size = 49152 (8192*3*2), so let's increase block size. # LevelDB default I/O buffer size: R=8M, W=2M. g_db = leveldb.LevelDB(db_path, block_size=49152, - write_buffer_size=(8 * (2<< 20))) + block_cache_size=(16 * (2 << 20)), + write_buffer_size=(16 * (2 << 20))) def handle_request(sock, fd): @@ -99,5 +100,6 @@ def main(myname, argv): except (SystemExit, KeyboardInterrupt): break + if __name__ == '__main__': main(sys.argv[0], sys.argv[1:]) diff --git a/pttbbs/daemon/logind/logind.c b/pttbbs/daemon/logind/logind.c index 562b1e21..0274c9e9 100644 --- a/pttbbs/daemon/logind/logind.c +++ b/pttbbs/daemon/logind/logind.c @@ -1826,6 +1826,7 @@ static void listen_cb(int lfd, short event GCC_UNUSED, void *arg) { int fd; + const char *banmsg; struct sockaddr_in xsin = {0}; struct timeval idle_tv = { IDLE_TIMEOUT_SEC, 0}; socklen_t szxsin = sizeof(xsin); @@ -1894,9 +1895,9 @@ listen_cb(int lfd, short event GCC_UNUSED, void *arg) return; } - if (in_banip_list_addr(g_banip, xsin.sin_addr.s_addr)) + if ((banmsg = in_banip_list_addr(g_banip, xsin.sin_addr.s_addr))) { - draw_text_screen (conn, banip_screen); + draw_text_screen (conn, *banmsg ? banmsg : banip_screen); login_conn_remove(conn, fd, BAN_SLEEP_SEC); return; } diff --git a/pttbbs/include/cmbbs.h b/pttbbs/include/cmbbs.h index df941f02..762009c8 100644 --- a/pttbbs/include/cmbbs.h +++ b/pttbbs/include/cmbbs.h @@ -45,8 +45,8 @@ int log_payment(const char *filename, int money, int oldm, int newm, /* banip.c */ typedef unsigned long IPv4; // derived from in_addr.s_addr typedef void BanIpList; -int in_banip_list(const BanIpList *list, const char *ip); -int in_banip_list_addr(const BanIpList *list, IPv4 addr); +const char *in_banip_list(const BanIpList *list, const char *ip); +const char *in_banip_list_addr(const BanIpList *list, IPv4 addr); BanIpList *load_banip_list(const char *filename, FILE *err); BanIpList *free_banip_list(BanIpList *list); BanIpList *cached_banip_list(const char *basefile, const char *cachefile); diff --git a/pttbbs/mbbsd/mbbsd.c b/pttbbs/mbbsd/mbbsd.c index 710637ab..8f31dc84 100644 --- a/pttbbs/mbbsd/mbbsd.c +++ b/pttbbs/mbbsd/mbbsd.c @@ -2131,12 +2131,13 @@ check_ban_and_load(int fd, struct ProgramOption *option, * sec */ static int banned = 0; - if (banip && (override_ip ? in_banip_list(banip, override_ip) : - in_banip_list_addr(banip, addr))) { - const char *msg = "THIS IP IS BANNED.\r\n" - "此 IP 已被拒絕連線。\r\n"; - write(fd, msg, strlen(msg)); - return -1; + if (banip) { + const char *msg = override_ip ? in_banip_list(banip, override_ip) : + in_banip_list_addr(banip, addr); + if (msg) { + write(fd, msg, strlen(msg)); + return -1; + } } // if you have your own banner, define as INSCREEN in pttbbs.conf |