diff options
author | kcwu <kcwu@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2006-03-30 01:14:01 +0800 |
---|---|---|
committer | kcwu <kcwu@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2006-03-30 01:14:01 +0800 |
commit | fd8c79217d534ad45ac189b9f78ad49157dd24b1 (patch) | |
tree | 3bdcbefeee197843efe650e4df775b6b83a2ef9e | |
parent | 99cefa7694fc89c2830341b2f4d41c0e9ee571a1 (diff) | |
download | pttbbs-fd8c79217d534ad45ac189b9f78ad49157dd24b1.tar pttbbs-fd8c79217d534ad45ac189b9f78ad49157dd24b1.tar.gz pttbbs-fd8c79217d534ad45ac189b9f78ad49157dd24b1.tar.bz2 pttbbs-fd8c79217d534ad45ac189b9f78ad49157dd24b1.tar.lz pttbbs-fd8c79217d534ad45ac189b9f78ad49157dd24b1.tar.xz pttbbs-fd8c79217d534ad45ac189b9f78ad49157dd24b1.tar.zst pttbbs-fd8c79217d534ad45ac189b9f78ad49157dd24b1.zip |
prevent multi-login and slow login flooding.
WARRNING, utmpserver protocol is incompatiable with old mbbsd.
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/pttbbs@3312 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
-rw-r--r-- | cacheserver/utmpserver2.c | 110 | ||||
-rw-r--r-- | mbbsd/mbbsd.c | 43 | ||||
-rw-r--r-- | mbbsd/talk.c | 106 |
3 files changed, 154 insertions, 105 deletions
diff --git a/cacheserver/utmpserver2.c b/cacheserver/utmpserver2.c index c38855f9..3ad6c4c3 100644 --- a/cacheserver/utmpserver2.c +++ b/cacheserver/utmpserver2.c @@ -18,32 +18,47 @@ time_t begin_time; int count_flooding, count_login; #ifdef NOFLOODING -#define MAXWAIT 1024 -#define FLUSHTIME (3600*6) +/* 0 ok, 1 delay action, 2 reject */ +int action_frequently(int uid) +{ + int i; + time_t now = time(NULL); + time_t minute = now/60; + time_t hour = minute/60; -struct { - time_t lasttime; - int count; -} flooding[MAX_USERS]; + static time_t flood_base_minute; + static time_t flood_base_hour; + static struct { + unsigned short minute_count; + unsigned short hour_count; + } flooding[MAX_USERS]; -int nWaits, lastflushtime; -struct { - int uid; - int fd; - int index; -} waitqueue[MAXWAIT]; + if(minute!=flood_base_minute) { + for(i=0; i<MAX_USERS; i++) + flooding[i].minute_count=0; + flood_base_minute=minute; + } + if(hour!=flood_base_hour) { + for(i=0; i<MAX_USERS; i++) + flooding[i].hour_count=0; + flood_base_hour=hour; + } -void processlogin(int cfd, int uid, int index); -void flushwaitqueue(void) -{ - int i; - for( i = 0 ; i < nWaits ; ++i ) { - processlogin(waitqueue[i].fd, waitqueue[i].uid, waitqueue[i].index); - close(waitqueue[i].fd); + if(flooding[uid].minute_count>30 || + flooding[uid].hour_count>60) { + count_flooding++; + return 2; + } + if(flooding[uid].minute_count>5 || + flooding[uid].hour_count>20) { + count_flooding++; + return 1; } - lastflushtime = time(NULL); - nWaits = 0; - memset(flooding, 0, sizeof(flooding)); + + flooding[uid].minute_count++; + flooding[uid].hour_count++; + + return 0; } #endif /* NOFLOODING */ @@ -106,6 +121,7 @@ void processlogin(int cfd, int uid, int index) /* 因為 logout 的時候並不會通知 utmpserver , 可能會查到一些 已經 logout 的帳號。所以不能只取 MAX_FRIEND 而要多取一些 */ #define MAX_FS (2 * MAX_FRIEND) + int res; int nfs; ocfs_t fs[MAX_FS]; @@ -131,6 +147,12 @@ void processlogin(int cfd, int uid, int index) utmplogin(uid, index, like, hate); nfs=genfriendlist(uid, index, fs, MAX_FS); #ifndef FAKEDATA + res=0; +#ifdef NOFLOODING + res=action_frequently(uid); +#endif + towrite(cfd, &res, sizeof(res)); + towrite(cfd, &nfs, sizeof(nfs)); towrite(cfd, fs, sizeof(ocfs_t) * nfs); #endif } @@ -162,6 +184,7 @@ int main(int argc, char *argv[]) int cmd; int uid,index; int fail; + int firstsync=0; #ifdef UTMPLOG logfp = fopen("utmp.log","a"); @@ -192,15 +215,7 @@ int main(int argc, char *argv[]) if( (sfd = tobind(iface_ip, port)) < 0 ) return 1; #endif -#ifdef NOFLOODING - lastflushtime = time(NULL); -#endif while(1) { -#ifdef NOFLOODING - if( lastflushtime < (time(NULL) - 1800) ) - flushwaitqueue(); -#endif - #ifdef FAKEDATA if(fread(&cmd, sizeof(cmd), 1, fp)==0) break; #else @@ -218,6 +233,12 @@ int main(int argc, char *argv[]) #ifndef FAKEDATA close(cfd); #endif + firstsync=1; + continue; + } + if(!firstsync) { + // don't accept client before first sync, to prevent incorrect friend data + close(cfd); continue; } @@ -226,9 +247,17 @@ int main(int argc, char *argv[]) fread(&uid, sizeof(uid), 1, fp); fread(&index, sizeof(index), 1, fp); #else - index=cmd; // bad protocol - if(toread(cfd, &uid, sizeof(uid)) <= 0) + if(cmd==-2) { + if(toread(cfd, &index, sizeof(index)) <= 0) + fail=1; + if(toread(cfd, &uid, sizeof(uid)) <= 0) + fail=1; + } else if(cmd>=0) { + // old client fail=1; + } else { + printf("unknown cmd=%d\n",cmd); + } #endif if(index>=USHM_SIZE) { fprintf(stderr, "bad index=%d\n",index); @@ -242,23 +271,6 @@ int main(int argc, char *argv[]) continue; } -#ifdef NOFLOODING - if( (time(NULL) - flooding[uid].lasttime) < 20 ) - ++flooding[uid].count; - if( flooding[uid].count > 10 ){ - count_flooding++; - if( nWaits == MAXWAIT ) - flushwaitqueue(); - waitqueue[nWaits].uid = uid; - waitqueue[nWaits].index = index; - waitqueue[nWaits].fd = cfd; - ++nWaits; - - continue; - } - flooding[uid].lasttime = time(NULL); -#endif - count_login++; processlogin(cfd, uid, index); if(count_login>=4000 || time(NULL)-begin_time>30*60) diff --git a/mbbsd/mbbsd.c b/mbbsd/mbbsd.c index 19709aa8..5ce3af8a 100644 --- a/mbbsd/mbbsd.c +++ b/mbbsd/mbbsd.c @@ -522,21 +522,18 @@ write_request(int sig) } static userinfo_t* -getotherlogin(void) +getotherlogin(int num) { userinfo_t *ui; - if (!(ui = (userinfo_t *) search_ulist(usernum))) - return NULL; /* user isn't logged in */ + do { + if (!(ui = (userinfo_t *) search_ulistn(usernum, num))) + return NULL; /* user isn't logged in */ -#ifdef DEBUGSLEEP - /* skip sleeping process */ - while (ui->pid && - (ui->uid == usernum && ui->mode == DEBUGSLEEPING)) - ui++; + /* skip sleeping process, this is slow if lots */ + if(ui->mode == DEBUGSLEEPING) + num++; + } while (ui->mode == DEBUGSLEEPING); - if(ui->uid != usernum) - return NULL; -#endif return ui; } @@ -550,7 +547,7 @@ multi_user_check(void) return; /* don't check sysops */ if (cuser.userlevel) { - ui = getotherlogin(); + ui = getotherlogin(1); if(ui == NULL) return; if (!ui->pid /* || (kill(pid, 0) == -1) */ ) @@ -562,16 +559,22 @@ multi_user_check(void) if (genbuf[0] != 'n') { // race condition here, sleep may help..? usleep(random()%1000000+100000); // 0.1~1.1s - // scan again, old ui may be invalid - ui = getotherlogin(); - if(ui == NULL) - return; - if (ui->pid > 0) - kill(ui->pid, SIGHUP); - log_usies("KICK ", cuser.nickname); + do { + // scan again, old ui may be invalid + ui = getotherlogin(1); + if(ui==NULL) + return; + if (ui->pid > 0) { + kill(ui->pid, SIGHUP); + log_usies("KICK ", cuser.nickname); + } else { + fprintf(stderr, "id=%s ui->pid=0\n", cuser.userid); + } + sleep(1); + } while(getotherlogin(3) != NULL); } else { /* deny login if still have 3 */ - if (search_ulistn(usernum, 3) != NULL) + if (getotherlogin(3) != NULL) abort_bbs(0); /* Goodbye(); */ } } else { diff --git a/mbbsd/talk.c b/mbbsd/talk.c index 9d627ab2..e177822d 100644 --- a/mbbsd/talk.c +++ b/mbbsd/talk.c @@ -237,6 +237,70 @@ void verbose_progress(int em, int *i, int *dir, int max) *dir *= -1; } +#ifdef OUTTACACHE +int sync_outta_server(int sfd) +{ + int i; + int offset = (int)(currutmp - &SHM->uinfo[0]); + + int cmd, res; + int nfs; + ocfs_t fs[MAX_FRIEND*2]; + + int iBar = 0, barMax = t_columns/2, dir = 1; + + verbose_progress(0, &iBar, &dir, barMax); + cmd = -2; + if(towrite(sfd, &cmd, sizeof(cmd))<0 || + towrite(sfd, &offset, sizeof(offset))<0 || + towrite(sfd, &currutmp->uid, sizeof(currutmp->uid)) < 0 || + towrite(sfd, currutmp->myfriend, sizeof(currutmp->myfriend))<0 || + towrite(sfd, currutmp->reject, sizeof(currutmp->reject))<0) + return -1; + + verbose_progress(0, &iBar, &dir, barMax); + if(toread(sfd, &res, sizeof(res))<0) + return -1; + + if(res<0) + return -1; + if(res==2) { + outs("nJWc, קKtέtL, еyA\n"); + refresh(); + sleep(10); + abort_bbs(0); + } + + verbose_progress(0, &iBar, &dir, barMax); + if(toread(sfd, &nfs, sizeof(nfs))<0) + return -1; + if(nfs<0 || nfs>=MAX_FRIEND) { + fprintf(stderr, "invalid nfs=%d\n",nfs); + return -1; + } + + if(toread(sfd, fs, sizeof(fs[0])*nfs)<0) + return -1; + + verbose_progress(0, &iBar, &dir, barMax); + for(i=0; i<nfs; i++) { + if( SHM->uinfo[fs[i].index].uid != fs[i].uid ) + continue; // double check, server may not know user have logout + currutmp->friend_online[currutmp->friendtotal++] + = fs[i].friendstat; + /* XXX: race here */ + if( SHM->uinfo[fs[i].index].friendtotal < MAX_FRIEND ) + SHM->uinfo[fs[i].index].friend_online[ SHM->uinfo[fs[i].index].friendtotal++ ] = fs[i].rfriendstat; + } + verbose_progress(1, &iBar, &dir, barMax); + + if(res==1) { + vmsg("ФWcnJHKytιLt"); + } + return 0; +} +#endif + void login_friend_online(void) { userinfo_t *uentp; @@ -244,48 +308,18 @@ void login_friend_online(void) int offset = (int)(currutmp - &SHM->uinfo[0]); #ifdef OUTTACACHE - int sfd; - - int iBar = 0, barMax = t_columns/2, dir = 1; - + int sfd; /* OUTTACACHE is TOO slow, let's prompt user here. */ move(b_lines-2, 0); clrtobot(); outs("\nbsPPBuWϥΪ̤ΦnͦWAtέtqjɷ|ݮɸ[...\n"); refresh(); - verbose_progress(0, &iBar, &dir, barMax); - if( (sfd = toconnect(OUTTACACHEHOST, OUTTACACHEPORT)) > 0 ){ - - verbose_progress(0, &iBar, &dir, barMax); - if( towrite(sfd, &offset, sizeof(offset)) > 0 && - towrite(sfd, &currutmp->uid, sizeof(currutmp->uid)) > 0 && - towrite(sfd, currutmp->myfriend, sizeof(currutmp->myfriend)) > 0 && - towrite(sfd, currutmp->reject, sizeof(currutmp->reject)) > 0 ){ - - ocfs_t fs; - while( currutmp->friendtotal < MAX_FRIEND && - toread(sfd, &fs, sizeof(fs)) > 0 ) - { - verbose_progress(0, &iBar, &dir, barMax); - if( SHM->uinfo[fs.index].uid == fs.uid ) - { - currutmp->friend_online[currutmp->friendtotal++] - = fs.friendstat; - /* XXX: race here */ - if( SHM->uinfo[fs.index].friendtotal < MAX_FRIEND ) - SHM->uinfo[fs.index].friend_online[ SHM->uinfo[fs.index].friendtotal++ ] = fs.rfriendstat; - } - } - verbose_progress(1, &iBar, &dir, barMax); - - /* nѤU, nM|d utmpserver */ - if( currutmp->friendtotal == MAX_FRIEND ) - while( toread(sfd, &fs, sizeof(fs)) > 0 ) - verbose_progress(1, &iBar, &dir, barMax); - close(sfd); - return; - } + sfd = toconnect(OUTTACACHEHOST, OUTTACACHEPORT); + if(sfd>=0) { + int res=sync_outta_server(sfd); close(sfd); + if(res==0) + return; } #endif |