summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pttbbs/common/bbs/banip.c137
-rwxr-xr-xpttbbs/daemon/brcstored/brcstored.py4
-rw-r--r--pttbbs/daemon/logind/logind.c5
-rw-r--r--pttbbs/include/cmbbs.h4
-rw-r--r--pttbbs/mbbsd/mbbsd.c13
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