diff -urN irc2.10.3p5/common/common_def.h irc2.10.3p5+hemp2/common/common_def.h --- irc2.10.3p5/common/common_def.h 1999-02-05 00:26:35.000000000 +0100 +++ irc2.10.3p5+hemp2/common/common_def.h 2003-10-12 00:08:15.000000000 +0200 @@ -54,6 +54,7 @@ #define PUNCT 8 #define DIGIT 16 #define SPACE 32 +#define VALID 64 #define isalpha(c) (char_atribs[(u_char)(c)]&ALPHA) #define isspace(c) (char_atribs[(u_char)(c)]&SPACE) @@ -74,6 +75,9 @@ #define isgraph(c) ((char_atribs[(u_char)(c)]&PRINT) && \ ((u_char)(c) != (u_char)0x20)) #define ispunct(c) (!(char_atribs[(u_char)(c)]&(CNTRL|ALPHA|DIGIT))) +#ifdef RESTRICT_USERNAMES +#define isvaliduser(c) (char_atribs[(u_char)(c)]&VALID) +#endif #ifdef DEBUGMODE # define Debug(x) debug x diff -urN irc2.10.3p5/common/match.c irc2.10.3p5+hemp2/common/match.c --- irc2.10.3p5/common/match.c 2001-07-04 23:44:40.000000000 +0200 +++ irc2.10.3p5+hemp2/common/match.c 2003-10-12 00:08:15.000000000 +0200 @@ -110,34 +110,37 @@ /* 16-23 */ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, /* 24-31 */ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, /* space */ PRINT|SPACE, -/* !"#$%&'( */ PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, -/* )*+,-./ */ PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, -/* 0123 */ PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, -/* 4567 */ PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, -/* 89:; */ PRINT|DIGIT, PRINT|DIGIT, PRINT, PRINT, -/* <=>? */ PRINT, PRINT, PRINT, PRINT, -/* @ */ PRINT, -/* ABC */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* DEF */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* GHI */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* JKL */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* MNO */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* PQR */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* STU */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* VWX */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* YZ[ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* \]^ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* _` */ PRINT, PRINT, -/* abc */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* def */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* ghi */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* jkl */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* mno */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* pqr */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* stu */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* vwx */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* yz{ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, -/* \}~ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* !"#$ */ PRINT, PRINT, PRINT, PRINT, +/* %&'( */ PRINT, PRINT, PRINT, PRINT, +/* )*+ */ PRINT, PRINT, PRINT, +/* ,-. */ PRINT, PRINT|VALID, PRINT|VALID, +/* /01 */ PRINT, PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, +/* 234 */ PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, +/* 567 */ PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, +/* 89: */ PRINT|DIGIT|VALID, PRINT|DIGIT|VALID, PRINT, +/* ;<= */ PRINT, PRINT, PRINT, +/* >?@ */ PRINT, PRINT, PRINT, +/* ABC */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* DEF */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* GHI */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* JKL */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* MNO */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* PQR */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* STU */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* VWX */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* YZ[ */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* \]^ */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA, +/* _` */ PRINT|VALID,PRINT, +/* abc */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* def */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* ghi */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* jkl */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* mno */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* pqr */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* stu */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* vwx */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* yz{ */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, +/* \}~ */ PRINT|ALPHA|VALID, PRINT|ALPHA|VALID, PRINT|ALPHA, /* del */ 0, /* 80-8f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90-9f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff -urN irc2.10.3p5/common/msg_def.h irc2.10.3p5+hemp2/common/msg_def.h --- irc2.10.3p5/common/msg_def.h 1998-01-23 14:28:07.000000000 +0100 +++ irc2.10.3p5+hemp2/common/msg_def.h 2003-10-12 00:08:15.000000000 +0200 @@ -32,6 +32,12 @@ #define MSG_QUIT "QUIT" /* QUIT */ #define MSG_SQUIT "SQUIT" /* SQUI */ #define MSG_KILL "KILL" /* KILL */ +#if defined(OPER_KLINE) || defined(LOCOP_KLINE) +#define MSG_KLINE "KLINE" /* KLIN */ +#endif +#if defined(OPER_TKLINE) || defined(LOCOP_TKLINE) +#define MSG_TKLINE "TKLINE" /* TKLI */ +#endif #define MSG_INFO "INFO" /* INFO */ #define MSG_LINKS "LINKS" /* LINK */ #define MSG_SUMMON "SUMMON" /* SUMM */ @@ -73,5 +79,10 @@ #define MSG_DIE "DIE" #define MSG_HASH "HAZH" /* HASH */ #define MSG_DNS "DNS" /* DNS -> DNSS */ - -#define MAXPARA 15 +#ifdef SERVER_MAP +#define MSG_MAP "MAP" +#endif +#ifdef OPER_SET +#define MSG_SET "SET" /* SET */ +#endif +#define MAXPARA 15 diff -urN irc2.10.3p5/common/numeric_def.h irc2.10.3p5+hemp2/common/numeric_def.h --- irc2.10.3p5/common/numeric_def.h 2001-02-10 20:11:05.000000000 +0100 +++ irc2.10.3p5+hemp2/common/numeric_def.h 2003-10-12 00:08:15.000000000 +0200 @@ -123,8 +123,18 @@ #define RPL_YOURHOST 002 #define RPL_CREATED 003 #define RPL_MYINFO 004 +#ifdef SEND_ISUPPORT +#define RPL_ISUPPORT 005 +#define RPL_BOUNCE 10 +#else #define RPL_BOUNCE 005 - +#endif +#ifdef SERVER_MAP +#define RPL_MAP 15 /* Undernet extension */ +#define RPL_MAPMORE 16 /* Undernet extension */ +#define RPL_MAPEND 17 /* Undernet extension */ +#define RPL_MAPSTART 18 /* +hemp */ +#endif /* * Errors are in the range from 400-599 currently and are grouped by what * commands they come from. @@ -232,6 +242,7 @@ #define RPL_NOTOPIC 331 #define RPL_TOPIC 332 +#define RPL_TOPICWHOTIME 333 #define RPL_INVITING 341 #define RPL_SUMMONING 342 @@ -299,7 +310,7 @@ #define RPL_STATSQLINE 217 #define RPL_STATSYLINE 218 #define RPL_ENDOFSTATS 219 - +#define RPL_STATSPLINE 220 #define RPL_UMODEIS 221 #define RPL_SERVICEINFO 231 @@ -335,3 +346,5 @@ #define RPL_TRACEEND 262 #define RPL_TRYAGAIN 263 +#define RPL_LOCALUSERS 265 +#define RPL_GLOBALUSERS 266 diff -urN irc2.10.3p5/common/parse.c irc2.10.3p5+hemp2/common/parse.c --- irc2.10.3p5/common/parse.c 2000-05-16 19:53:13.000000000 +0200 +++ irc2.10.3p5+hemp2/common/parse.c 2003-10-12 00:08:15.000000000 +0200 @@ -64,6 +64,12 @@ { MSG_KILL, m_kill, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L}, #endif #ifndef CLIENT_COMPILE +#if defined(OPER_KLINE) || defined(LOCOP_KLINE) + { MSG_KLINE, m_kline, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L}, +#endif +#if defined(OPER_TKLINE) || defined(LOCOP_TKLINE) + { MSG_TKLINE, m_tkline, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L}, +#endif { MSG_USER, m_user, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L}, { MSG_AWAY, m_away, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, { MSG_UMODE, m_umode, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, @@ -121,6 +127,12 @@ # endif , 0, 0, 0L}, #endif +#ifdef SERVER_MAP + { MSG_MAP, m_map, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, +#endif +#ifdef OPER_SET + { MSG_SET, m_set, MAXPARA, MSG_LAG|MSG_REGU|MSG_OP|MSG_LOP , 0, 0, 0L}, +#endif #endif /* !CLIENT_COMPILE */ { (char *) 0, (int (*)()) 0, 0, 0, 0, 0, 0L} }; @@ -172,6 +184,71 @@ return acptr; } +aClient *find_matching_client(mask,cptr) +char *mask; +Reg aClient *cptr; +{ + aClient *acptr = cptr; + Reg char *ch; + int wild = 0; + + /* try to find exact match */ + acptr = find_client(mask,NULL); + if (!acptr) + { + aServer *asptr; + int wild = 0, dot = 0; + /* check if we should check against wilds */ + for (ch = mask; *ch; ch++) + { + if (*ch == '*' || *ch == '?') + { + wild = 1; + break; + } + if (*ch == '.') + { + dot = 1; + break; + } + } + + if (!wild && !dot) + { + return cptr; + } + (void) collapse(mask); + + /* try to match some servername against mask */ + for (asptr = svrtop; asptr; asptr = asptr->nexts) + { + if (!match(asptr->bcptr->name,mask) || + !match(mask,asptr->bcptr->name)) + { + acptr = asptr->bcptr; + break; + } + } + + /* no match, try services */ + if (!acptr) + { + aService *sp; + for (sp = svctop;sp;sp = sp->nexts) + { + if (!match(sp->bcptr->name,mask) || + !match(mask,sp->bcptr->name)) + { + acptr = sp->bcptr; + break; + } + } + } + + } + + return acptr ? acptr : cptr; +} #else /* CLIENT_COMPILE */ aClient *find_client(name, cptr) @@ -189,7 +266,7 @@ return cptr; } #endif /* CLIENT_COMPILE */ - +#ifndef CLIENT_COMPILE /* ** Find a user@host (server or user). ** @@ -208,20 +285,39 @@ *count = 0; if (user) - for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) - { - if (!MyClient(c2ptr)) /* implies mine and a user */ - continue; - if ((!host || !match(host, c2ptr->user->host)) && - mycmp(user, c2ptr->user->username) == 0) - { - (*count)++; - res = c2ptr; - } - } + { + if (host) + { + anUser *auptr; + for (auptr = hash_find_hostname(host,NULL); auptr; auptr = auptr->hnext) + { + if (MyConnect(auptr->bcptr) && !mycmp(user,auptr->username)) + { + (*count)++; + res = auptr->bcptr; + } + } + } + else + { + int i; + for (i = 0; i <= highest_fd; i++) + { + if (!(c2ptr = local[i]) || !IsRegisteredUser(c2ptr)) + { + continue; + } + if (!mycmp(user,c2ptr->user->username)) + { + (*count)++; + res = c2ptr; + } + } + } + } return res; } - +#endif /* !CLIENT_COMPILE */ /* ** Find server by name. ** @@ -765,7 +861,12 @@ if (index(sender, '.') /* <- buggy, it could be a service! */ && !index(sender, '@')) /* better.. */ { - sendto_flag(SCH_LOCAL, "Squitting unknown %s brought by %s.", +#ifdef LOCAL_REJECTIONS_ONLY + sendto_flag(SCH_NOTICE, +#else + sendto_flag(SCH_LOCAL, +#endif + "Squitting unknown %s brought by %s.", sender, get_client_name(cptr, FALSE)); sendto_one(cptr, ":%s SQUIT %s :(Unknown from %s)", me.name, sender, get_client_name(cptr, FALSE)); @@ -780,7 +881,12 @@ * if we get here and sender is a service, we should probably issue * a kill in this case! -krys */ - sendto_flag(SCH_LOCAL, "Dropping unknown %s brought by %s.", +#ifdef LOCAL_REJECTIONS_ONLY + sendto_flag(SCH_NOTICE, +#else + sendto_flag(SCH_LOCAL, +#endif + "Dropping unknown %s brought by %s.", sender, get_client_name(cptr, FALSE)); } #endif diff -urN irc2.10.3p5/common/parse_ext.h irc2.10.3p5+hemp2/common/parse_ext.h --- irc2.10.3p5/common/parse_ext.h 1997-09-03 19:45:17.000000000 +0200 +++ irc2.10.3p5+hemp2/common/parse_ext.h 2003-10-12 00:08:15.000000000 +0200 @@ -44,6 +44,7 @@ EXTERN aClient *find_mask __P((char *name, aClient *cptr)); EXTERN aServer *find_tokserver __P((int token, aClient *cptr, aClient *c2ptr)); EXTERN aClient *find_name __P((char *name, aClient *cptr)); +EXTERN aClient *find_matching_client __P((char *mask, aClient *cptr)); #else /* CLIENT_COMPILE */ EXTERN aClient *find_client __P((char *name, aClient *cptr)); EXTERN aClient *find_server __P((char *name, aClient *cptr)); diff -urN irc2.10.3p5/common/send.c irc2.10.3p5+hemp2/common/send.c --- irc2.10.3p5/common/send.c 2003-10-11 03:09:36.000000000 +0200 +++ irc2.10.3p5+hemp2/common/send.c 2003-10-12 00:08:24.000000000 +0200 @@ -1391,6 +1391,9 @@ { SCH_SERVICE, "&SERVICES", NULL }, { SCH_DEBUG, "&DEBUG", NULL }, { SCH_AUTH, "&AUTH", NULL }, +#ifdef CLIENTS_CHANNEL + { SCH_CLIENTS, "&CLIENTS", NULL }, +#endif }; @@ -1515,6 +1518,12 @@ ** And the rest... just count, I got 154 --Beeth */ char linebuf[1500]; +#ifdef LOG_IP + char *rip,*lip; +#ifndef INET6 + char tip[18]; +#endif +#endif /* LOG_IP */ /* ** This is a potential buffer overflow. ** I mean, when you manage to keep ircd @@ -1522,6 +1531,9 @@ */ char buf[12]; int logfile; +#ifdef LOG_IP + u_short rport,lport; +#endif /* LOG_IP */ logfile = msg ? connlog : userlog; @@ -1543,15 +1555,63 @@ (int) (duration % 60)); } +#ifdef LOG_IP + /*- + * New connection log format after looooong discussion: + * [ident@remoteip#remoteport,localip#localport] + * --Yegg, 2001-05-09 + */ + lport = cptr->acpt != NULL ? cptr->acpt->port : 0; + rport = cptr->port; + +#ifdef INET6 + lip = cptr->acpt != NULL ? inetntop(AF_INET6, (char *)&cptr->acpt->ip, + mydummy, MYDUMMY_SIZE) : ""; + rip = inetntop(AF_INET6, (char *)&cptr->ip, + mydummy2, MYDUMMY_SIZE); +#else + if (cptr->acpt != NULL) + { + lip = inetntoa((char *)&cptr->acpt->ip); + strncpyzt(tip, lip, 18); + lip = tip; + } + else + { + lip = ""; + } + rip = inetntoa((char *)&cptr->ip); +#endif + +#endif /* LOG_IP */ + /* ** Aha, cptr->firsttime is time when user connected, ** so we syslog() it anyway. I'm waving big ** "rewrite log format" flag --Beeth. */ (void)sprintf(linebuf, - "%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n", +#ifndef LOG_IP +#ifdef LOG_IRCNAME + "%s (%s): %s@%s [%s] [%s] %c %lu %luKb %lu %luKb\n", +#else + "%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n", +#endif +#else /* LOG_IP */ +#ifdef LOG_IRCNAME + "%s (%s): %s@%s [%s@%s#%u,%s#%u] [%s] %c %lu %luKb %lu %luKb\n", +#else + "%s (%s): %s@%s [%s@%s#%u,%s#%u] %c %lu %luKb %lu %luKb\n", +#endif +#endif /* LOG_IP */ myctime(cptr->firsttime), msg ? msg : buf, username, hostname, cptr->auth, +#ifdef LOG_IP + rip,rport,lip,lport, +#endif /* LOG_IP */ +#ifdef LOG_IRCNAME + cptr->info, +#endif cptr->exitc, cptr->sendM, cptr->sendK, cptr->receiveM, cptr->receiveK); diff -urN irc2.10.3p5/common/struct_def.h irc2.10.3p5+hemp2/common/struct_def.h --- irc2.10.3p5/common/struct_def.h 2001-05-14 14:02:08.000000000 +0200 +++ irc2.10.3p5+hemp2/common/struct_def.h 2003-10-12 03:32:26.000000000 +0200 @@ -25,6 +25,7 @@ typedef struct Server aServer; typedef struct Service aService; typedef struct SLink Link; +typedef struct invSLink invLink; typedef struct SMode Mode; typedef struct fdarray FdAry; typedef struct CPing aCPing; @@ -47,7 +48,7 @@ */ #define USERLEN 10 #define REALLEN 50 -#define TOPICLEN 80 +#define TOPICLEN 160 #define CHANNELLEN 50 #define PASSWDLEN 20 #define KEYLEN 23 @@ -60,7 +61,8 @@ #define CHIDLEN 5 /* WARNING: *DONT* CHANGE THIS!!!! */ #define READBUF_SIZE 16384 /* used in s_bsd.c *AND* s_zip.c ! */ - + +#define MAXMODEPARAMS 3 /* do _!not!_ change this */ /* * Make up some numbers which should reflect average leaf server connect * queue max size. @@ -166,6 +168,9 @@ #define FLAGS_ZIP 0x400000 /* link is zipped */ #define FLAGS_ZIPRQ 0x800000 /* zip requested */ #define FLAGS_ZIPSTART 0x1000000 /* start of zip (ignore any CRLF) */ +#ifdef SPLIT_HANDLE +#define FLAGS_EOBWAIT 0x2000000 /* waiting for EOB */ +#endif #define FLAGS_HELD 0x8000000 /* connection held and reconnect try */ #define FLAGS_OPER 0x0001 /* Operator */ @@ -175,6 +180,11 @@ #define FLAGS_RESTRICTED 0x0010 /* Restricted user */ #define FLAGS_AWAY 0x0020 /* user is away */ +#define FLAGS_BADBOY 0x10000 /* delay close this client */ +#ifdef ILINE_FLAGS +#define FLAGS_EXEMPT 0x20000 /* user is exempt from k-lines */ + +#endif #define SEND_UMODES (FLAGS_INVISIBLE|FLAGS_OPER|FLAGS_WALLOP|FLAGS_AWAY) #define ALL_UMODES (SEND_UMODES|FLAGS_LOCOP|FLAGS_RESTRICTED) @@ -222,6 +232,14 @@ #define ClearXAuth(x) ((x)->flags &= ~FLAGS_XAUTH) #define ClearWXAuth(x) ((x)->flags &= ~FLAGS_WXAUTH) +#ifdef SPLIT_HANDLE +#define SetBurst(x) ((x)->flags |= FLAGS_EOBWAIT) +#define ClearBurst(x) ((x)->flags &= ~FLAGS_EOBWAIT) +#define IsBurst(x) ((x)->flags & FLAGS_EOBWAIT) +#endif +#ifdef ILINE_FLAGS +#define IsKlineExempt(x) ((x)->user && (x)->user->flags & FLAGS_EXEMPT) +#endif /* * defined debugging levels */ @@ -268,6 +286,7 @@ u_int pref; /* preference value */ struct CPing *ping; time_t hold; /* Hold action until this time (calendar time) */ + char *source_ip; #ifndef VMSP aClass *class; /* Class of connection */ #endif @@ -276,6 +295,15 @@ #define CONF_ILLEGAL 0x80000000 #define CONF_MATCH 0x40000000 +#ifdef DELAY_ACCEPT +#define CONF_DELAY 0x20000000 +#define CONF_ACTIVE 0x10000000 +#define CONF_SERVERONLY 0x8000000 +#endif +#ifdef ILINE_FLAGS +#define CONF_EXEMPT 0x4000000 /* user is exempted from K: */ +#define CONF_RNODNS 0x2000000 +#endif #define CONF_QUARANTINED_SERVER 0x000001 #define CONF_CLIENT 0x000002 #define CONF_RCLIENT 0x000004 @@ -307,7 +335,6 @@ CONF_SERVER_MASK) #define IsIllegal(x) ((x)->status & CONF_ILLEGAL) - typedef struct { u_long pi_id; u_long pi_seq; @@ -345,7 +372,7 @@ */ struct User { Link *channel; /* chain of channel pointer blocks */ - Link *invited; /* chain of invite pointer blocks */ + invLink *invited; /* chain of invite pointer blocks */ Link *uwas; /* chain of whowas pointer blocks */ char *away; /* pointer to away message */ time_t last; /* "idle" time */ @@ -368,6 +395,8 @@ char username[USERLEN+1]; char host[HOSTLEN+1]; char *server; + struct User *hnext; + int hashv; }; struct Server { @@ -382,6 +411,10 @@ ** from anUser (field servp), aService (field ** servp) and aClient (field serv) */ + int usercnt[3]; /* # of clients - all, invisible, opers */ +#ifdef EXTRA_STATISTICS + int usermax; /* max # of users on this server */ +#endif struct Server *nexts, *prevs, *shnext; aClient *bcptr; char by[NICKLEN+1]; @@ -389,6 +422,7 @@ time_t lastload; /* penalty like counters, see s_serv.c ** should be in the local part, but.. */ + Link *down; /* list of downlinks */ }; struct Service { @@ -451,6 +485,7 @@ ** accepted. */ char passwd[PASSWDLEN+1]; + char *reason; /* internal quit reason */ char exitc; }; @@ -531,6 +566,16 @@ u_long bytes; }; +#ifdef SPLIT_HANDLE +#define SET_TYPE_INT 0 +#define SET_TYPE_STRING 1 +struct Set_Message { + char *cmd; + int *value; + char **values; +}; +#endif + #define MSG_LAG 0x0001 #define MSG_NOU 0x0002 /* Not available to users */ #define MSG_SVC 0x0004 /* Services only */ @@ -563,6 +608,20 @@ int flags; }; +/* invite link structure used for chains */ +struct invSLink { + struct invSLink *next; + union { + aClient *cptr; + aChannel *chptr; + aConfItem *aconf; + char *cp; + int i; + } value; + int flags; + char *who; +}; + /* channel structure */ struct Channel { @@ -570,6 +629,10 @@ u_int hashv; /* raw hash value */ Mode mode; char topic[TOPICLEN+1]; +#ifdef TOPICWHOTIME + char topic_nuh[BANLEN+1]; + time_t topic_time; +#endif int users; /* current membership total */ Link *members; /* channel members */ Link *invites; /* outstanding invitations */ @@ -674,6 +737,16 @@ x->prev->service->servp == x->serv))) typedef struct { +#ifdef EXTRA_STATISTICS + time_t is_last_cnt_t; /* timestamp for last count */ + u_long is_last_cnt; /* last count */ + u_long is_m_users; /* maximum users connected */ + u_long is_m_serv; /* maximum servers connected */ + u_long is_m_service; /* maximum services connected */ + u_long is_m_myclnt; /* maximum local clients */ + u_long is_m_myserv; /* maximum local servers */ + u_long is_m_myservice; /* maximum local services */ +#endif u_long is_user[2]; /* users, non[0] invis and invis[1] */ u_long is_serv; /* servers */ u_long is_service; /* services */ @@ -715,8 +788,21 @@ u_int is_dbufmin; /* min number of dbuf in use */ u_int is_dbufmax; /* max number of dbuf in use */ u_int is_dbufmore; /* how many times we increased the bufferpool*/ +#ifdef DELAY_CLOSE + u_long is_delayclosed; +#endif +#ifdef SPLIT_HANDLE + u_long is_eobservers; /* # of servers which sent EOB */ +#endif } istat_t; +typedef struct { + u_int split; + u_int aconnect; /* if we want aconnect or not */ +#ifdef DELAY_ACCEPT + u_int caccept; /* enable/disable client ports */ +#endif +} iconf_t; /* String manipulation macros */ /* strncopynt --> strncpyzt to avoid confusion, sematics changed @@ -771,8 +857,13 @@ #define SCH_SERVICE 9 #define SCH_DEBUG 10 #define SCH_AUTH 11 -#define SCH_MAX 11 +#ifdef CLIENTS_CHANNEL +#define SCH_CLIENTS 12 +#define SCH_MAX 13 +#else +#define SCH_MAX 12 +#endif /* used for async dns values */ #define ASYNC_NONE (-1) diff -urN irc2.10.3p5/common/support.c irc2.10.3p5+hemp2/common/support.c --- irc2.10.3p5/common/support.c 2001-05-31 16:00:02.000000000 +0200 +++ irc2.10.3p5+hemp2/common/support.c 2003-10-12 13:49:01.000000000 +0200 @@ -849,7 +849,7 @@ char *make_version() { int ve, re, mi, dv, pl; - char ver[15]; + char ver[50]; sscanf(PATCHLEVEL, "%2d%2d%2d%2d%2d", &ve, &re, &mi, &dv, &pl); /* version & revision */ @@ -861,9 +861,30 @@ sprintf(ver + strlen(ver), "%c%d", DEVLEVEL, dv); if (pl) /* patchlevel */ sprintf(ver + strlen(ver), "p%d", pl); + strcat(ver,"+hemp2"); return mystrdup(ver); } +#ifndef CLIENTCOMPILE +#ifdef SEND_ISUPPORT +/* + * Make ISUPPORT string + */ + +char *make_isupport() +{ + char tisupport[200]; + char *p = tisupport; +#ifdef SERVER_MAP + strcpy(tisupport,"MAP "); + p +=4; +#endif + SPRINTF(p,"PREFIX=(ov)@+ MODES=%d CHANTYPES=#&!+ MAXCHANNELS=%d NICKLEN=%d TOPICLEN=%d KICKLEN=%d NETWORK=%s CHANMODES=beI,k,l,imnpstaqr", + MAXMODEPARAMS, MAXCHANNELSPERUSER, NICKLEN, TOPICLEN, TOPICLEN,NETWORKNAME); + return mystrdup(tisupport); +} +#endif +#endif #ifndef HAVE_TRUNCATE /* truncate: set a file to a specified length * I don't know of any UNIX that doesn't have truncate, but CYGWIN32 beta18 diff -urN irc2.10.3p5/common/support_ext.h irc2.10.3p5+hemp2/common/support_ext.h --- irc2.10.3p5/common/support_ext.h 2000-12-08 23:15:21.000000000 +0100 +++ irc2.10.3p5+hemp2/common/support_ext.h 2003-10-12 00:08:16.000000000 +0200 @@ -72,6 +72,9 @@ #endif /* USE_STDARG */ EXTERN int dgets __P((int fd, char *buf, int num)); EXTERN char *make_version(); +#ifdef SEND_ISUPPORT +EXTERN char *make_isupport(); +#endif #if SOLARIS_2_3 EXTERN struct hostent *solaris_gethostbyname __P((const char *name)); #endif /* SOLARIS_2_3 */ diff -urN irc2.10.3p5/iauth/a_conf.c irc2.10.3p5+hemp2/iauth/a_conf.c --- irc2.10.3p5/iauth/a_conf.c 2003-10-11 16:22:56.000000000 +0200 +++ irc2.10.3p5+hemp2/iauth/a_conf.c 2003-10-12 00:08:24.000000000 +0200 @@ -26,6 +26,7 @@ #define A_CONF_C #include "a_externs.h" #undef A_CONF_C +#undef USE_DSM static aModule *Mlist[16]; @@ -87,6 +88,7 @@ Mlist[Mcnt++] = &Module_rfc931; Mlist[Mcnt++] = &Module_socks; + Mlist[Mcnt++] = &Module_webproxy; Mlist[Mcnt++] = &Module_pipe; Mlist[Mcnt++] = &Module_lhex; Mlist[Mcnt] = NULL; @@ -248,6 +250,7 @@ (*last)->hostname = NULL; (*last)->address = NULL; (*last)->timeout = timeout; + (*last)->reason = NULL; if (Mlist[i] == &Module_rfc931) ident = *last; @@ -291,6 +294,17 @@ mystrdup(buffer + 10); continue; } + if (!strncasecmp(buffer+1, "reason = ", 9)) + { + if ((*last)->reason) + conf_err(lnnb, + "Duplicate reason keyword: ignored.", + cfile); + else + (*last)->reason = + mystrdup(buffer + 10); + continue; + } if (!strncasecmp(buffer+1, "host = ", 7)) { needh = 1; diff -urN irc2.10.3p5/iauth/a_conf_def.h irc2.10.3p5+hemp2/iauth/a_conf_def.h --- irc2.10.3p5/iauth/a_conf_def.h 1999-07-05 00:09:09.000000000 +0200 +++ irc2.10.3p5+hemp2/iauth/a_conf_def.h 2003-10-12 00:08:16.000000000 +0200 @@ -40,6 +40,7 @@ u_char in; /* instance number */ aModule *mod; /* module */ char *opt; /* options read from file */ + char *reason; /* reject reason */ char *popt; /* options to send to ircd */ void *data; /* private data: stats, ... */ aTarget *address; diff -urN irc2.10.3p5/iauth/a_externs.h irc2.10.3p5+hemp2/iauth/a_externs.h --- irc2.10.3p5/iauth/a_externs.h 1999-04-12 21:45:04.000000000 +0200 +++ irc2.10.3p5+hemp2/iauth/a_externs.h 2003-10-12 00:08:16.000000000 +0200 @@ -30,5 +30,6 @@ #include "mod_rfc931_ext.h" #include "mod_socks_ext.h" +#include "mod_webproxy_ext.h" #include "mod_pipe_ext.h" #include "mod_lhex_ext.h" diff -urN irc2.10.3p5/iauth/a_log_def.h irc2.10.3p5+hemp2/iauth/a_log_def.h --- irc2.10.3p5/iauth/a_log_def.h 2001-10-18 21:51:08.000000000 +0200 +++ irc2.10.3p5+hemp2/iauth/a_log_def.h 2003-10-12 00:08:16.000000000 +0200 @@ -37,5 +37,7 @@ #define ALOG_DSOCKSC 0x040000 /* debug: module socks cache */ #define ALOG_DPIPE 0x080000 /* debug: module pipe */ #define ALOG_DLHEX 0x100000 /* debug: module pipe */ +#define ALOG_DWEBPROXY 0x200000 /* debug: module webproxy */ +#define ALOG_DWEBPROXYC 0x400000 /* debug: module webproxy */ -#define ALOG_DALL 0x1F3700 /* any debug flag */ +#define ALOG_DALL 0x7F3700 /* any debug flag */ diff -urN irc2.10.3p5/iauth/iauth.c irc2.10.3p5+hemp2/iauth/iauth.c --- irc2.10.3p5/iauth/iauth.c 2001-05-16 12:42:51.000000000 +0200 +++ irc2.10.3p5+hemp2/iauth/iauth.c 2003-10-12 14:53:10.000000000 +0200 @@ -135,6 +135,24 @@ #endif } +void write_pidfile() +{ + int fd; + char buff[20]; + (void)truncate(IAUTHPID_PATH, 0); + if ((fd = open(IAUTHPID_PATH, O_CREAT|O_WRONLY, 0600))>=0) + { + bzero(buff, sizeof(buff)); + (void)sprintf(buff,"%5d\n", (int)getpid()); + if (write(fd, buff, strlen(buff)) == -1) + (void)printf("Error writing to pid file %s", + IAUTHPID_PATH); + (void)close(fd); + return; + } +} + + int main(argc, argv) int argc; char *argv[]; @@ -197,6 +215,7 @@ #endif sendto_ircd("G 0"); + write_pidfile(); while (1) { loop_io(); diff -urN irc2.10.3p5/iauth/mod_socks.c irc2.10.3p5+hemp2/iauth/mod_socks.c --- irc2.10.3p5/iauth/mod_socks.c 2001-05-31 01:40:00.000000000 +0200 +++ irc2.10.3p5+hemp2/iauth/mod_socks.c 2003-10-12 00:08:16.000000000 +0200 @@ -62,6 +62,7 @@ struct socks_private { struct proxylog *cache; + char *reason; u_int lifetime; u_char options; /* stats */ @@ -81,13 +82,19 @@ char *strver; { struct socks_private *mydata = cldata[cl].instance->data; + char *reason = mydata->reason; +#ifdef IAUTH_VERBOSE_REJECTS + char verbose = 'K'; +#else + char verbose = 'k'; +#endif /* open proxy */ if (mydata->options & OPT_DENY) { cldata[cl].state |= A_DENY; - sendto_ircd("k %d %s %u ", cl, cldata[cl].itsip, - cldata[cl].itsport); + sendto_ircd("%c %d %s %u #socks %s", verbose, cl, cldata[cl].itsip, + cldata[cl].itsport,reason ? reason : ""); } if (mydata->options & OPT_LOG) sendto_log(ALOG_FLOG, LOG_INFO, "socks%s: open proxy: %s[%s]", @@ -525,7 +532,10 @@ sprintf(cbuf, ", Cache %d (min)", mydata->lifetime); strcat(txtbuf, cbuf); mydata->lifetime *= 60; - + if (self->reason) + { + mydata->reason = mystrdup(self->reason); + } self->popt = mystrdup(tmpbuf+1); self->data = mydata; return txtbuf+2; diff -urN irc2.10.3p5/iauth/mod_webproxy.c irc2.10.3p5+hemp2/iauth/mod_webproxy.c --- irc2.10.3p5/iauth/mod_webproxy.c 1970-01-01 01:00:00.000000000 +0100 +++ irc2.10.3p5+hemp2/iauth/mod_webproxy.c 2003-10-12 00:43:21.000000000 +0200 @@ -0,0 +1,597 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_webproxy.c + * Copyright (C) 2001 Dan Merillat + * + * Original code (iauth/mod_socks.c) is + * Copyright (C) 1998 Christophe Kalt + * + * 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef lint +static char rcsid[] = +"@(#)$Id: mod_webproxy.c,v 1.25 1999/08/13 21:06:30 chopin Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define MOD_WEBGATE_C +#include "a_externs.h" + +/****************************** PRIVATE *************************************/ + +#define CACHETIME 30 + +struct proxylog { + struct proxylog *next; + char ip[HOSTLEN + 1]; + u_char state; /* 0 = no proxy, 1 = open proxy, 2 = closed proxy */ + time_t expire; + u_int port; +}; + +#define OPT_LOG 0x001 +#define OPT_DENY 0x002 +#define OPT_PARANOID 0x004 +#define OPT_CAREFUL 0x008 +#define OPT_V4ONLY 0x010 +#define OPT_V5ONLY 0x020 +#define OPT_PROTOCOL 0x100 + +#define PROXY_NONE 0 +#define PROXY_OPEN 1 +#define PROXY_CLOSE 2 +#define PROXY_UNEXPECTED 3 +#define PROXY_BADPROTO 4 + +struct webproxy_private { + struct proxylog *cache; + u_int lifetime; + u_char options; + char *reason; + u_int ports[128]; + u_int portcount; + /* stats */ + u_int chitc, chito, chitn, cmiss, cnow, cmax; + u_int open[128], closed, noproxy; +}; +int webproxy_start(u_int); + +/* + * webproxy_open_proxy + * + * Found an open proxy for cl: deal with it! + */ + +static void +webproxy_open_proxy(cl,port) +int cl; +u_int port; +{ + struct webproxy_private *mydata = cldata[cl].instance->data; + char *reason = mydata->reason; +#ifdef IAUTH_VERBOSE_REJECTS + char verbose = 'K'; +#else + char verbose = 'k'; +#endif + char myreason[BUFSIZE]; + if (reason) + { + if (strstr(reason,"%d")) + { + sprintf(myreason,reason,port); + } + else + { + strcpy(myreason,reason); + } + myreason[300] = '\0'; + } + /* open proxy */ + if (mydata->options & OPT_DENY) { + cldata[cl].state |= A_DENY; + sendto_ircd("%c %d %s %u %s%d %s", verbose,cl, cldata[cl].itsip, + cldata[cl].itsport,"#webproxy-",port, + reason ? myreason : ""); + } + if (mydata->options & OPT_LOG) + sendto_log(ALOG_FLOG, LOG_INFO, "webproxy: open proxy: %s[%s], port %u", + cldata[cl].host, cldata[cl].itsip, + port); +} + +/* + * webproxy_add_cache + * + * Add an entry to the cache. + */ + +static void +webproxy_add_cache(cl, state) +int cl, state; +{ + struct webproxy_private *mydata = cldata[cl].instance->data; + struct proxylog *next; + + + if (state == PROXY_OPEN) { + if (cldata[cl].mod_status < mydata->portcount) + mydata->open[cldata[cl].mod_status] += 1; + + } else if (state == PROXY_NONE) + mydata->noproxy += 1; + else + /* state == PROXY_CLOSE|PROXY_UNEXPECTED|PROXY_BADPROTO */ + mydata->closed += 1; + + if (mydata->lifetime == 0) + return; + + mydata->cnow += 1; + if (mydata->cnow > mydata->cmax) + mydata->cmax = mydata->cnow; + + next = mydata->cache; + mydata->cache = (struct proxylog *) malloc(sizeof(struct proxylog)); + mydata->cache->expire = time(NULL) + mydata->lifetime; + strcpy(mydata->cache->ip, cldata[cl].itsip); + mydata->cache->port = mydata->ports[cldata[cl].mod_status - 1]; + mydata->cache->state = state; + mydata->cache->next = next; + DebugLog( + (ALOG_DWEBPROXYC, 0, + "webproxy_add_cache(%d): new cache %s, open=%d", cl, + mydata->cache->ip, state)); +} + +/* + * webproxy_check_cache + * + * Check cache for an entry. + */ +static int +webproxy_check_cache(cl) +{ + struct webproxy_private *mydata = cldata[cl].instance->data; + struct proxylog **last, *pl; + time_t now = time(NULL); + + if (!mydata || mydata->lifetime == 0) + return 0; + + DebugLog( + (ALOG_DWEBPROXYC, 0, + "webproxy_check_cache(%d): Checking cache for %s", cl, + cldata[cl].itsip)); + + last = &(mydata->cache); + while ((pl = *last)) { + DebugLog((ALOG_DWEBPROXYC, 0, "webproxy_check_cache(%d): cache %s", + cl, pl->ip)); + if (pl->expire < now) { + DebugLog((ALOG_DWEBPROXYC, 0, + "webproxy_check_cache(%d): free %s (%d < %d)", + cl, pl->ip, pl->expire, now)); + *last = pl->next; + free(pl); + mydata->cnow -= 1; + continue; + } + if (!strcasecmp(pl->ip, cldata[cl].itsip)) { + DebugLog((ALOG_DWEBPROXYC, 0, + "webproxy_check_cache(%d): match (%u)", cl, + pl->state)); + pl->expire = now + mydata->lifetime; /* dubious */ + if (pl->state == 1) { + webproxy_open_proxy(cl,pl->port); + mydata->chito += 1; + } else if (pl->state == 0) + mydata->chitn += 1; + else + mydata->chitc += 1; + return -1; + } + last = &(pl->next); + } + mydata->cmiss += 1; + return 0; +} + +static int +webproxy_write(u_int cl) +{ + + struct webproxy_private *mydata = cldata[cl].instance->data; + static u_char query[64]; /* big enough to hold all queries */ + static int query_len; /* lenght of socks4 query */ + static int wlen; + + + + query_len=snprintf(query, 64, "CONNECT %s:%d HTTP/1.0\r\n\r\n", + cldata[cl].ourip, cldata[cl].ourport); + + DebugLog((ALOG_DWEBPROXY, 0, "webproxy_write(%d): Checking %s:%u", + cl, cldata[cl].itsip, mydata->ports[cldata[cl].mod_status])); + if ((wlen=write(cldata[cl].wfd, query, query_len)) != query_len) { + /* most likely the connection failed */ + DebugLog( + (ALOG_DWEBPROXY, 0, + "webproxy_write(%d): write() failed: %d %s", cl, + wlen, strerror(errno))); + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; + cldata[cl].buflen=0; + if (++cldata[cl].mod_status < mydata->portcount) + return webproxy_start(cl); + else + return 1; + } + cldata[cl].rfd = cldata[cl].wfd; + cldata[cl].wfd = 0; + return 0; +} + +static int +webproxy_read(u_int cl) +{ + /* Looking for "Connection established" + * HTTP/1.0 200 Connection established" */ + + struct webproxy_private *mydata = cldata[cl].instance->data; + int again = 1; + u_char state = PROXY_CLOSE; + char *lookfor="HTTP/1.0 200"; + + u_int looklen=strlen(lookfor); + /* data's in from the other end */ + if (cldata[cl].buflen < looklen) + return 0; + + /* zero it out so the debug log is sane */ + cldata[cl].inbuffer[cldata[cl].buflen]=0; + + /* got all we need */ + DebugLog( + (ALOG_DWEBPROXY, 0, "webproxy_read(%d): %d Got [%s]", + cl, mydata->ports[cldata[cl].mod_status], cldata[cl].inbuffer)); + + + if (!strstr(cldata[cl].inbuffer, "Date:") && + (!strncmp(cldata[cl].inbuffer, lookfor, looklen) || + !strncmp(cldata[cl].inbuffer, "HTTP/1.1 200",looklen)) + ) { /* got it! */ + DebugLog((ALOG_DWEBPROXY, 0, "webproxy_read(%d): Open proxy on %s:%u", + cl, cldata[cl].itsip, mydata->ports[cldata[cl].mod_status])); + state = PROXY_OPEN; + webproxy_open_proxy(cl,mydata->ports[cldata[cl].mod_status]); + again = 0; + } + + cldata[cl].mod_status++; + close(cldata[cl].rfd); + cldata[cl].rfd = 0; + + if (again && cldata[cl].mod_status < mydata->portcount) { + cldata[cl].buflen = 0; + return webproxy_start(cl); + } + else { + webproxy_add_cache(cl, state); + return -1; + } + return 0; +} + +/******************************** PUBLIC ************************************/ + +/* + * webproxy_init + * + * This procedure is called when a particular module is loaded. + * Returns NULL if everything went fine, + * an error message otherwise. + */ + +char * +webproxy_init(AnInstance * self) +{ + struct webproxy_private *mydata; + char tmpbuf[80], cbuf[32]; + static char txtbuf[80]; + u_int portcount = 0; + + tmpbuf[0] = txtbuf[0] = '\0'; + + mydata = + (struct webproxy_private *) + malloc(sizeof(struct webproxy_private)); + bzero((char *) mydata, sizeof(struct webproxy_private)); + mydata->cache = NULL; + mydata->lifetime = CACHETIME; + if (!self->opt) + { + /* using default config: + ** log,deny,ports=3128;8080 + */ + mydata->options=OPT_DENY|OPT_LOG; + mydata->ports[portcount++] = 3128; + mydata->ports[portcount++] = 8080; + mydata->portcount=portcount; + strcat(tmpbuf, ",log"); + strcat(txtbuf, ", Log"); + strcat(tmpbuf, ",reject"); + strcat(txtbuf, ", Reject"); + strcat(tmpbuf, ",ports=3128;8080"); + strcat(txtbuf, ", Ports=3128;8080"); + + } + else + { + + char *ch = NULL, *portsp = NULL; + + if ((portsp=strstr(self->opt, "ports"))) + + { + char xbuf[128]; + char *c; + size_t slen; + bzero(xbuf,sizeof(xbuf)); + ch = strchr(portsp, '='); + if (!ch) + { + mydata->ports[portcount++] = 3128; + mydata->ports[portcount++] = 8080; + mydata->portcount=portcount; + } + else + { + c=index(ch, ','); + if (!c) + c=ch+strlen(ch); + /* now ch is at = and c is at the end of the ports line */ + ch++; + slen = (size_t) c - (size_t) ch; + if (slen > 30) + { + slen = 30; + } + memcpy(xbuf, ch, slen); + strcat(tmpbuf,",ports="); + + strcat(tmpbuf,xbuf); + ch=xbuf; + while((c=index(ch, ';'))) { + *c=0; + mydata->ports[portcount++]=atoi(ch); + ch=c+1; + } + mydata->ports[portcount++]=atoi(ch); + mydata->portcount=portcount; + } + } + if (strstr(self->opt, "log")) { + mydata->options |= OPT_LOG; + strcat(tmpbuf, ",log"); + strcat(txtbuf, ", Log"); + } + if (strstr(self->opt, "reject")) { + mydata->options |= OPT_DENY; + strcat(tmpbuf, ",reject"); + strcat(txtbuf, ", Reject"); + } + if (strstr(self->opt, "cache")) { + char *ch = index(self->opt, '='); + + if (ch) + mydata->lifetime = atoi(ch + 1); + } + } + sprintf(cbuf, ",cache=%d", mydata->lifetime); + strcat(tmpbuf, cbuf); + sprintf(cbuf, ", Cache %d (min)", mydata->lifetime); + strcat(txtbuf, cbuf); + mydata->lifetime *= 60; + if (self->reason) + { + mydata->reason = mystrdup(self->reason); + } + self->popt = mystrdup(tmpbuf + 1); + self->data = mydata; + return txtbuf + 2; +} + +/* + * webproxy_release + * + * This procedure is called when a particular module is unloaded. + */ +void +webproxy_release(self) +AnInstance *self; +{ + struct webproxy_private *mydata = self->data; + free(mydata); + free(self->popt); +} + +/* + * webproxy_stats + * + * This procedure is called regularly to update statistics sent to ircd. + */ +void +webproxy_stats(self) +AnInstance *self; +{ + struct webproxy_private *mydata = self->data; + char mybuf[256]; + int len; + int i; + + len=snprintf(mybuf, 256, "S webproxy port:open"); + for (i=0;iportcount;i++) + len+=snprintf(mybuf+len, 256-len, " %u:%u", + mydata->ports[i], mydata->open[i]); + + len+=snprintf(mybuf+len, 256-len, " closed %u noproxy %u", + mydata->closed, mydata->noproxy); + + sendto_ircd(mybuf); + + sendto_ircd + ("S webproxy cache open %u closed %u noproxy %u miss %u (%u <= %u)", + mydata->chito, mydata->chitc, mydata->chitn, mydata->cmiss, + mydata->cnow, mydata->cmax); +} + +/* + * webproxy_start + * + * This procedure is called to start the socks check procedure. + * Returns 0 if everything went fine, + * -1 otherwise (nothing to be done, or failure) + * + * It is responsible for sending error messages where appropriate. + * In case of failure, it's responsible for cleaning up (e.g. webproxy_clean + * will NOT be called) + */ +int +webproxy_start(cl) +u_int cl; +{ + + struct webproxy_private *mydata = cldata[cl].instance->data; + char *error; + int fd; + + if (cldata[cl].state & A_DENY) { + /* no point of doing anything */ + DebugLog((ALOG_DWEBPROXY, 0, + "webproxy_start(%d): A_DENY alredy set ", cl)); + return -1; + } + if (cldata[cl].mod_status == 0) + if (webproxy_check_cache(cl)) + return -1; + + if (strchr(cldata[cl].itsip,':')) + return -1; + + while (cldata[cl].mod_status < mydata->portcount) { + DebugLog( + (ALOG_DWEBPROXY, 0, "webproxy_start(%d): Connecting to %s:%u", + cl, cldata[cl].itsip, mydata->ports[cldata[cl].mod_status])); + fd = tcp_connect(cldata[cl].ourip, cldata[cl].itsip, + mydata->ports[cldata[cl].mod_status], + &error); + if (fd > 0) { + /*so that webproxy_work() is called when connected */ + cldata[cl].wfd = fd; + return 0; + } + DebugLog((ALOG_DWEBPROXY, 0, + "webproxy_start(%d): tcp_connect() reported %s", cl, + error)); + cldata[cl].mod_status++; + continue; + + } + + return -1; +} + +/* + * webproxy_work + * + * This procedure is called whenever there's new data in the buffer. + * Returns 0 if everything went fine, and there is more work to be done, + * Returns -1 if the module has finished its work (and cleaned up). + * + * It is responsible for sending error messages where appropriate. + */ +int +webproxy_work(cl) +u_int cl; +{ + struct webproxy_private *mydata = cldata[cl].instance->data; + + if (!mydata) + return -1; + + DebugLog( + (ALOG_DWEBPROXY, 0, "webproxy_work(%d): %d %d %d buflen=%d", + cl, mydata->ports[cldata[cl].mod_status], + cldata[cl].rfd, cldata[cl].wfd, + cldata[cl].buflen)); + + if (cldata[cl].wfd > 0) + /* + ** We haven't sent the query yet, the connection was just + ** established. + */ + return webproxy_write(cl); + else + return webproxy_read(cl); +} + +/* + * webproxy_clean + * + * This procedure is called whenever the module should interrupt its work. + * It is responsible for cleaning up any allocated data, and in particular + * closing file descriptors. + */ +void +webproxy_clean(cl) +u_int cl; +{ + DebugLog((ALOG_DWEBPROXY, 0, "webproxy_clean(%d): cleaning up", cl)); + /* + ** only one of rfd and wfd may be set at the same time, + ** in any case, they would be the same fd, so only close() once + */ + if (cldata[cl].rfd) + close(cldata[cl].rfd); + else if (cldata[cl].wfd) + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; +} + +/* + * webproxy_timeout + * + * This procedure is called whenever the timeout set by the module is + * reached. + * + * Returns 0 if things are okay, -1 if check was aborted. + */ +int +webproxy_timeout(cl) +u_int cl; +{ + DebugLog( + (ALOG_DWEBPROXY, 0, + "webproxy_timeout(%d): calling webproxy_clean ", cl)); + webproxy_clean(cl); + return -1; +} + +aModule Module_webproxy = +{"webproxy", webproxy_init, webproxy_release, webproxy_stats, + webproxy_start, webproxy_work, webproxy_timeout, webproxy_clean +}; diff -urN irc2.10.3p5/iauth/mod_webproxy_ext.h irc2.10.3p5+hemp2/iauth/mod_webproxy_ext.h --- irc2.10.3p5/iauth/mod_webproxy_ext.h 1970-01-01 01:00:00.000000000 +0100 +++ irc2.10.3p5+hemp2/iauth/mod_webproxy_ext.h 2003-10-12 00:08:16.000000000 +0200 @@ -0,0 +1,3 @@ +#ifndef MOD_WEBPROXY_C +extern aModule Module_webproxy; +#endif /* MOD_WEBPROXY_C */ diff -urN irc2.10.3p5/ircd/channel.c irc2.10.3p5+hemp2/ircd/channel.c --- irc2.10.3p5/ircd/channel.c 2003-10-11 13:03:23.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/channel.c 2003-10-12 13:47:17.000000000 +0200 @@ -43,7 +43,7 @@ aChannel *channel = NullChn; -static void add_invite __P((aClient *, aChannel *)); +static void add_invite __P((aClient *, aClient *, aChannel *)); static int can_join __P((aClient *, aChannel *, char *)); void channel_modes __P((aClient *, char *, char *, aChannel *)); static int check_channelmask __P((aClient *, aClient *, char *)); @@ -55,6 +55,7 @@ static int add_modeid __P((int, aClient *, aChannel *, char *)); static int del_modeid __P((int, aChannel *, char *)); static Link *match_modeid __P((int, aClient *, aChannel *)); +static void send_names_one __P((aClient *,aClient *,char *,aChannel *,int)); static char *PartFmt = ":%s PART %s :%s"; @@ -611,6 +612,13 @@ add_user_to_channel(chptr, mp, CHFL_CHANOP); chptr->mode.mode = smode|MODE_SECRET; +#ifdef CLIENTS_CHANNEL + chptr = get_channel(mp, "&CLIENTS", CREATE); + strcpy(chptr->topic,"SERVER MESSAGES: client activities [various]"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode|MODE_SECRET; +#endif + setup_svchans(); } @@ -1004,6 +1012,7 @@ aClient *who; Mode *mode, oldm; Link *plp = NULL; + char buf[KEYLEN+1]; int compat = -1; /* to prevent mixing old/new modes */ *mbuf = *pbuf = '\0'; @@ -1166,8 +1175,17 @@ break; case 'k': *penalty += 1; - if (--parc <= 0) - break; + if (--parc <= 0) { /* a channel key query --fiction */ + *(curr+1) = '\0'; /* Stop MODE # bb.. */ + if ((*chptr->mode.key) && IsMember(sptr, chptr)) { + strncpy(buf, chptr->mode.key, KEYLEN); + } + else { *buf = '\0'; }; + + sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS, sptr->name), + chptr->chname, (*chptr->mode.key) ? "+k" : "+", buf); + break; + } parv++; /* check now so we eat the parameter if present */ if (keychange) @@ -1366,7 +1384,33 @@ * limit 'l' to only *1* change per mode command but * eat up others. */ - if (limitset || !ischop) + + /* channel limit query ("mode -l" is an exception to also unset limit + * without extra parameter). To not break stuff. --fiction + */ + + if ((parc-1 <= 0) && (whatt != MODE_DEL)) { + *(curr+1) = '\0'; /* Stop MODE # bb.. */ + if ((chptr->mode.limit) && IsMember(sptr, chptr)) { + SPRINTF(buf, "%d", chptr->mode.limit); + } + else { *buf = '\0'; }; + + sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS, sptr->name), + chptr->chname, (chptr->mode.limit) ? "+l" : "+" , buf); + break; + } + + /* just pretend that there was a mode change to be able to + * return an error later --fiction + */ + + if (!ischop) { + count++; + break; + } + + if (limitset) { if (whatt == MODE_ADD && --parc > 0) parv++; @@ -1398,9 +1442,14 @@ *penalty += 2; break; } - sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS, - cptr->name), "MODE +l"); - break; +/* sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS, + cptr->name), "MODE +l"); + break; + +Obosleted by new syntax - "mode +l" or just +"mode l" gives current limit --fiction +*/ + case 'i' : /* falls through for default case */ if (whatt == MODE_DEL && ischop) while ((lp = chptr->invites)) @@ -1452,9 +1501,13 @@ if (whatt == MODE_ADD) { if (*ip == MODE_PRIVATE) + { new &= ~MODE_SECRET; + } else if (*ip == MODE_SECRET) + { new &= ~MODE_PRIVATE; + } new |= *ip; } else @@ -1469,6 +1522,7 @@ break; } curr++; + /* * Make sure modes strings such as "+m +t +p +i" are parsed * fully. @@ -1745,7 +1799,9 @@ Reg aChannel *chptr; char *key; { - Link *lp = NULL, *banned; + invLink *lp = NULL; + Link *banned; + int limit = 0; if (chptr->users == 0 && (bootopt & BOOT_PROT) && chptr->history != 0 && *chptr->chname != '!') @@ -1761,6 +1817,12 @@ else if (lp == NULL) return (ERR_BANNEDFROMCHAN); +#ifdef CLIENTS_CHANNEL + if (chptr->chname[0]=='&') { + if (!strcmp(chptr->chname,"&CLIENTS") && !IsAnOper(sptr)) + return (ERR_INVITEONLYCHAN); + } +#endif if ((chptr->mode.mode & MODE_INVITEONLY) && !match_modeid(CHFL_INVITE, sptr, chptr) && (lp == NULL)) @@ -1769,15 +1831,31 @@ if (*chptr->mode.key && (BadPtr(key) || mycmp(chptr->mode.key, key))) return (ERR_BADCHANNELKEY); - if (chptr->mode.limit && (chptr->users >= chptr->mode.limit) && - (lp == NULL)) + if (chptr->mode.limit && (chptr->users >= chptr->mode.limit)) + { + if (lp == NULL) return (ERR_CHANNELISFULL); + else + limit = 1; + } + if (banned) + { sendto_channel_butone(&me, &me, chptr, - ":%s NOTICE %s :%s carries an invitation (overriding ban on %s).", - ME, chptr->chname, sptr->name, - banned->value.cp); + ":%s NOTICE %s :%s carries an invitation from %s" + " (overriding%s ban on %s).", + ME, chptr->chname, sptr->name, lp->who, + limit ? " channel limit and" : "", + banned->value.cp); + } + else if (limit) + { + sendto_channel_butone(&me, &me, chptr, + ":%s NOTICE %s :%s carries an invitation from %s" + " (overriding channel limit).", ME, chptr->chname, + sptr->name, lp->who); + } return 0; } @@ -1867,11 +1945,12 @@ return chptr; } -static void add_invite(cptr, chptr) + +static void add_invite(sptr, cptr, chptr) +aClient *sptr; aClient *cptr; aChannel *chptr; { - Reg Link *inv, **tmp; del_invite(cptr, chptr); /* @@ -1889,21 +1968,36 @@ /* * add client to channel invite list */ - inv = make_link(); - inv->value.cptr = cptr; - inv->next = chptr->invites; - chptr->invites = inv; - istat.is_useri++; + { + Reg Link *inv; + + inv = make_link(); + inv->value.cptr = cptr; + inv->next = chptr->invites; + chptr->invites = inv; + istat.is_useri++; + } /* * add channel to the end of the client invite list */ - for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next)) - ; - inv = make_link(); - inv->value.chptr = chptr; - inv->next = NULL; - (*tmp) = inv; - istat.is_invite++; + { + Reg invLink *inv, **tmp; + char who[NICKLEN+USERLEN+HOSTLEN+3]; + int len; + + for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next)) + ; + inv = make_invlink(); + inv->value.chptr = chptr; + inv->next = NULL; + len = sprintf(who, "%s!%s@%s", sptr->name, + sptr->user->username, sptr->user->host); + inv->who = (char *)MyMalloc(len + 1); + istat.is_banmem += len; + strcpy(inv->who, who); + (*tmp) = inv; + istat.is_invite++; + } } /* @@ -1913,25 +2007,36 @@ aClient *cptr; aChannel *chptr; { - Reg Link **inv, *tmp; + { + Reg Link **inv, *tmp; - for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next) - if (tmp->value.cptr == cptr) - { - *inv = tmp->next; - free_link(tmp); - istat.is_invite--; - break; - } + for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next) + { + if (tmp->value.cptr == cptr) + { + *inv = tmp->next; + free_link(tmp); + istat.is_invite--; + break; + } + } + } + { + Reg invLink **inv, *tmp; - for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next) - if (tmp->value.chptr == chptr) - { - *inv = tmp->next; - free_link(tmp); - istat.is_useri--; - break; - } + for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next) + { + if (tmp->value.chptr == chptr) + { + *inv = tmp->next; + istat.is_banmem -= (strlen(tmp->who)+1); + free(tmp->who); + free_invlink(tmp); + istat.is_useri--; + break; + } + } + } } /* @@ -2237,11 +2342,32 @@ ** channel so make them (rightfully) the Channel ** Operator. */ + /* do not make them Channel Operator if the server seems + ** to be splitted (i.e. if total server count is less + ** than a given number and channel count is less + ** than another given number or user count is + ** less than a third number. (francesco) + */ flags = 0; chop[0] = '\0'; - if (MyConnect(sptr) && UseModes(name) && - (!IsRestricted(sptr) || (*name == '&')) && !chptr->users && - !(chptr->history && *chptr->chname == '!')) +#ifdef SPLIT_HANDLE + if (MyConnect(sptr) && UseModes(name) && + ((*name != '#') || !iconf.split) && +#else + if ( + MyConnect(sptr) && + UseModes(name) && +#endif + ( + !IsRestricted(sptr) || + (*name == '&') + ) && + !chptr->users && + !( + chptr->history && + *chptr->chname == '!' + ) + ) { if (*name == '!') strcpy(chop, "\007O"); @@ -2298,10 +2424,20 @@ { del_invite(sptr, chptr); if (chptr->topic[0] != '\0') + { sendto_one(sptr, rpl_str(RPL_TOPIC, parv[0]), name, chptr->topic); +#ifdef TOPICWHOTIME + if (chptr->topic_time>0) + { + sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME, parv[0]), + name, IsAnonymous(chptr) ? "Anonymous!Anonymous@Anomyous" : chptr->topic_nuh, + chptr->topic_time); + } +#endif + } parv[1] = name; - (void)m_names(cptr, sptr, 2, parv); + send_names_one(cptr,sptr,parv[0],chptr,1); if (IsAnonymous(chptr) && !IsQuiet(chptr)) { sendto_one(sptr, ":%s NOTICE %s :Channel %s has the anonymous flag set.", ME, chptr->chname, chptr->chname); @@ -2722,27 +2858,6 @@ return penalty; } -int count_channels(sptr) -aClient *sptr; -{ -Reg aChannel *chptr; - Reg int count = 0; - - for (chptr = channel; chptr; chptr = chptr->nextch) - { - if (chptr->users) /* don't count channels in history */ -#ifdef SHOW_INVISIBLE_LUSERS - if (SecretChannel(chptr)) - { - if (IsAnOper(sptr)) - count++; - } - else -#endif - count++; - } - return (count); -} /* ** m_topic @@ -2802,14 +2917,28 @@ if (chptr->topic[0] == '\0') sendto_one(sptr, rpl_str(RPL_NOTOPIC, parv[0]), chptr->chname); - else + else { sendto_one(sptr, rpl_str(RPL_TOPIC, parv[0]), chptr->chname, chptr->topic); +#ifdef TOPICWHOTIME + sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME, parv[0]), + chptr->chname, IsAnonymous(chptr) ? "Anonymous!anonymous@anonymous" : chptr->topic_nuh, + chptr->topic_time); +#endif + } } else if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || is_chan_op(sptr, chptr)) { /* setting a topic */ strncpyzt(chptr->topic, topic, sizeof(chptr->topic)); +#ifdef TOPICWHOTIME + strcpy(chptr->topic_nuh, sptr->name); + strcat(chptr->topic_nuh, "!"); + strcat(chptr->topic_nuh, sptr->user->username); + strcat(chptr->topic_nuh, "@"); + strcat(chptr->topic_nuh, sptr->user->host); + chptr->topic_time = timeofday; +#endif sendto_match_servs(chptr, cptr,":%s TOPIC %s :%s", parv[0], chptr->chname, chptr->topic); @@ -2914,14 +3043,13 @@ if (MyConnect(acptr)) if (chptr && /* (chptr->mode.mode & MODE_INVITEONLY) && */ sptr->user && is_chan_op(sptr, chptr)) - add_invite(acptr, chptr); + add_invite(sptr, acptr, chptr); sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",parv[0], acptr->name, ((chptr) ? (chptr->chname) : parv[2])); return 2; } - /* ** m_list ** parv[0] = sender prefix @@ -2938,22 +3066,90 @@ if (parc > 2 && hunt_server(cptr, sptr, ":%s LIST %s %s", 2, parc, parv)) - return 10; + return MAXPENALTY; + if (BadPtr(parv[1])) + { + int maxsendq = 0; + Reg Link *lp; + int listedchannels = 0; + + if (!sptr->user) + { + sendto_one(sptr, rpl_str(RPL_LISTEND, parv[0])); + return 2; + } + +#ifdef LIST_ALIS_NOTE + if (MyConnect(sptr)) + { + sendto_one(sptr,":%s NOTICE %s :%s",ME,parv[0],LIST_ALIS_NOTE); + } +#endif + + /* Keep 10% of sendQ free + * Note: Definition of LIST command prevents obtaining + * of complete LIST from remote server, if this + * behaviour is changed, MyConnect() check needs to be added + * here and within following loops as well. - jv + */ + maxsendq = (int) ((float) get_sendq(sptr) * (float) 0.9); + /* First, show all +s/+p user is on */ + for (lp = sptr->user->channel; lp; lp = lp->next) + { + chptr = lp->value.chptr; + if (SecretChannel(chptr) || HiddenChannel(chptr)) + { + sendto_one(sptr, rpl_str(RPL_LIST, parv[0]), + chptr->chname,chptr->users, + chptr->topic); + listedchannels++; + if (DBufLength(&sptr->sendQ) > maxsendq) + { + sendto_one(sptr, + err_str(ERR_TOOMANYMATCHES, + parv[0]), "LIST"); + goto end_of_list; + } + } + } + + /* Second, show all visible channels + * +p channels users is not on, are not reported anymore - jv + */ for (chptr = channel; chptr; chptr = chptr->nextch) - { - if (!sptr->user || - !chptr->users || /* empty locked channel */ - (SecretChannel(chptr) && !IsMember(sptr, chptr))) + { + if (!chptr->users || /* empty locked channel */ + SecretChannel(chptr) || HiddenChannel(chptr)) continue; - name = ShowChannel(sptr, chptr) ? chptr->chname : NULL; - rlen += sendto_one(sptr, rpl_str(RPL_LIST, parv[0]), - name ? name : "*", chptr->users, - name ? chptr->topic : ""); - if (!MyConnect(sptr) && rlen > CHREPLLEN) + + sendto_one(sptr, rpl_str(RPL_LIST, parv[0]), + chptr->chname, chptr->users, + chptr->topic); + listedchannels++; + if (DBufLength(&sptr->sendQ) > maxsendq) + { + sendto_one(sptr, + err_str(ERR_TOOMANYMATCHES, parv[0]), + "LIST"); break; - } - else { + } + + } +end_of_list: +#ifdef LIST_ALIS_NOTE + /* Send second notice if we listed more than 24 channels + * - usual height of irc client in text mode. + */ + if (MyConnect(sptr) && (listedchannels > 24)) + { + sendto_one(sptr, ":%s NOTICE %s :%s", ME, parv[0], + LIST_ALIS_NOTE); + } +#endif + } + else + { parv[1] = canonize(parv[1]); for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL) { @@ -2995,9 +3191,138 @@ return 2; } +/* + * send_names_one - send NAMES for one specific channel + * sends RPL_ENDOFNAMES when sendeon > 0 + */ +static void send_names_one(cptr,sptr,to,chptr,sendeon) +aClient *cptr,*sptr; +char *to; +aChannel *chptr; +int sendeon; +{ + Reg Link *lp; + Reg aClient *acptr; + char *pbuf = buf; + int pxlen,ismember,nlen,maxlen,showusers = 1, sent = 0; + + if (!chptr->users) /* channel in ND */ + { + showusers = 0; + } + else + { + ismember = (lp = find_channel_link(sptr->user->channel,chptr)) ? 1 : 0; + } + if (SecretChannel(chptr)) + { + if (!ismember) + { + showusers = 0; + } + else + { + *pbuf++ = '@'; + } + } + else if (HiddenChannel(chptr)) + { + *pbuf++ = '*'; + } + else + { + *pbuf++ = '='; + } + + if (showusers) + { + *pbuf++ = ' '; + pxlen = strlen(chptr->chname); + memcpy(pbuf,chptr->chname,pxlen); + pbuf += pxlen; + *pbuf++ = ' '; + *pbuf++ = ':'; + *pbuf = 0; + pxlen += 4; + if (IsAnonymous(chptr)) + { + if (ismember) + { + if (lp->flags & CHFL_CHANOP) + { + *pbuf++ = '@'; + } + else if (lp->flags & CHFL_VOICE) + { + *pbuf++ = '+'; + } + strcpy(pbuf,to); + } + sendto_one(sptr, rpl_str(RPL_NAMREPLY, to), buf); + } + else + { + /* server names + : : + spaces + "353" + nick length +\r\n + space for last + * entry. + */ + maxlen = BUFSIZE - 2 - 1 - strlen(ME) - 5 - strlen(to) - pxlen - NICKLEN - 2; + + for (lp = chptr->members;lp;lp=lp->next) + { + acptr = lp->value.cptr; + if (!ismember && IsInvisible(acptr)) + { + continue; + } + if (lp->flags & CHFL_CHANOP) + { + *pbuf++ = '@'; + } + else if (lp->flags & CHFL_VOICE) + { + *pbuf++ = '+'; + } + nlen = strlen(acptr->name); + /* This check is needed for server channels + * when someone removes +a mode from them. + * (server is member of such channel). + */ + if (nlen > NICKLEN) + { + nlen = NICKLEN; + } + memcpy(pbuf,acptr->name,nlen); + pbuf +=nlen; + *pbuf++ = ' '; + sent = 0; + if (((size_t) pbuf - (size_t) buf) > maxlen) + { + *pbuf = '\0'; + sendto_one(sptr, rpl_str(RPL_NAMREPLY, to), buf); + pbuf = buf + pxlen; + pbuf[0] = '\0'; + sent = 1; + } + } + if (!sent) + { + *pbuf = '\0'; + sendto_one(sptr, rpl_str(RPL_NAMREPLY, to), buf); + } + } + } + if (sendeon) + { + sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, to), chptr->chname); + } + return; + +} + /************************************************************************ * m_names() - Added by Jto 27 Apr 1989 + * Rewritten by jv 27 Apr 2001 ************************************************************************/ /* @@ -3009,184 +3334,124 @@ aClient *cptr, *sptr; int parc; char *parv[]; -{ +{ Reg aChannel *chptr; - Reg aClient *c2ptr; + Reg aClient *acptr; Reg Link *lp; - aChannel *ch2ptr = NULL; - int idx, flag, len, mlen, rlen = 0; - char *s, *para = parc > 1 ? parv[1] : NULL; - + int maxlen ,pxlen,nlen,cansend = 0, sent = 1; + char *para = parc > 1 ? parv[1] : NULL,*name, *p = NULL, *pbuf = buf; + if (parc > 2 && hunt_server(cptr, sptr, ":%s NAMES %s %s", 2, parc, parv)) - return 10; - - mlen = strlen(ME) + 10; /* server names + : : + spaces + "353" */ - mlen += strlen(parv[0]); + { + return MAXPENALTY; + } + if (!BadPtr(para)) - { - s = index(para, ','); - if (s && MyConnect(sptr) && s != para) - { - parv[1] = ++s; - (void)m_names(cptr, sptr, parc, parv); - } - clean_channelname(para); - ch2ptr = find_channel(para, (aChannel *)NULL); - } - - *buf = '\0'; - - /* - * First, do all visible channels (public and the one user self is) + { + for (; (name = strtoken(&p,parv[1], ",")); parv[1] = NULL) + { + clean_channelname(name); + if BadPtr(name) + { + continue; + } + chptr = find_channel(name, NULL); + if (chptr) + { + send_names_one(cptr,sptr,parv[0],chptr,1); + } + else + { + sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), name); + } + sent++; + if (!MyConnect(sptr) || sent > MAXPENALTY / 3) + { + break; + } + } + return sent ? 2 * sent : 2; + } + /* Client wants all nicks/channels which is seriously cpu intensive + * Allowed for local clients only. + * First, list all secret channels user is on */ - + for (lp = sptr->user->channel; lp; lp = lp->next) + { + chptr = lp->value.chptr; + if (SecretChannel(chptr)) + { + send_names_one(cptr,sptr,parv[0],chptr,0); + } + } + + /* Second, list all non-secret channels */ for (chptr = channel; chptr; chptr = chptr->nextch) - { - if (!chptr->users || /* locked empty channel */ - ((chptr != ch2ptr) && !BadPtr(para))) /* 'wrong' channel */ - continue; - if (!MyConnect(sptr) && (BadPtr(para) || (rlen > CHREPLLEN))) - break; - if ((BadPtr(para) || !HiddenChannel(chptr)) && - !ShowChannel(sptr, chptr)) - continue; /* -- users on this are not listed */ - - /* Find users on same channel (defined by chptr) */ - - (void)strcpy(buf, "* "); - len = strlen(chptr->chname); - (void)strcpy(buf + 2, chptr->chname); - (void)strcpy(buf + 2 + len, " :"); - - if (PubChannel(chptr)) - *buf = '='; - else if (SecretChannel(chptr)) - *buf = '@'; - - if (IsAnonymous(chptr)) - { - if ((lp = find_user_link(chptr->members, sptr))) - { - if (lp->flags & CHFL_CHANOP) - (void)strcat(buf, "@"); - else if (lp->flags & CHFL_VOICE) - (void)strcat(buf, "+"); - (void)strcat(buf, parv[0]); - } - rlen += strlen(buf); - sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf); + { + if (!chptr->users || /* channel in CD */ + SecretChannel(chptr)) + { continue; - } - idx = len + 4; /* channel name + [@=] + 2?? */ - flag = 1; - for (lp = chptr->members; lp; lp = lp->next) - { - c2ptr = lp->value.cptr; - if (IsInvisible(c2ptr) && !IsMember(sptr,chptr)) - continue; - if (lp->flags & CHFL_CHANOP) - { - (void)strcat(buf, "@"); - idx++; - } - else if (lp->flags & CHFL_VOICE) - { - (void)strcat(buf, "+"); - idx++; - } - (void)strncat(buf, c2ptr->name, NICKLEN); - idx += strlen(c2ptr->name) + 1; - flag = 1; - (void)strcat(buf," "); - if (mlen + idx + NICKLEN + 1 > BUFSIZE - 2) - { - sendto_one(sptr, rpl_str(RPL_NAMREPLY, - parv[0]), buf); - (void)strncpy(buf, "* ", 3); - (void)strncpy(buf+2, chptr->chname, - len + 1); - (void)strcat(buf, " :"); - if (PubChannel(chptr)) - *buf = '='; - else if (SecretChannel(chptr)) - *buf = '@'; - idx = len + 4; - flag = 0; - } - } - if (flag) - { - rlen += strlen(buf); - sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf); - } - } /* for(channels) */ - if (!BadPtr(para)) - { - if (!MyConnect(sptr) && (rlen > CHREPLLEN)) - sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]), - para); - sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), para); - return(1); - } - - /* Second, do all non-public, non-secret channels in one big sweep */ - - (void)strncpy(buf, "* * :", 6); - idx = 5; - flag = 0; - for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) - { - aChannel *ch3ptr; - int showflag = 0, secret = 0; - - if (!IsPerson(c2ptr) || IsInvisible(c2ptr)) + } + send_names_one(cptr,sptr,parv[0],chptr,0); + } + /* Third, list all remaining users + * ie, those which aren't on any channel, or are at Anonymous one + */ + strcpy(pbuf,"* * :"); + pxlen = 5; + pbuf += pxlen; + maxlen = BUFSIZE - 2 - 1 - strlen(ME) - 5 - strlen(parv[0]) - 5 - NICKLEN - 2; + for (acptr = client; acptr ;acptr = acptr->next) + { + if (!IsPerson(acptr) || IsInvisible(acptr)) + { continue; - if (!MyConnect(sptr) && (BadPtr(para) || (rlen > CHREPLLEN))) - break; - lp = c2ptr->user->channel; - /* - * don't show a client if they are on a secret channel or - * they are on a channel sptr is on since they have already - * been show earlier. -avalon - */ + } + + lp = acptr->user->channel; + cansend = 1; while (lp) - { - ch3ptr = lp->value.chptr; - if (PubChannel(ch3ptr) || IsMember(sptr, ch3ptr)) - showflag = 1; - if (SecretChannel(ch3ptr)) - secret = 1; + { + chptr = lp->value.chptr; + if (PubChannel(chptr) || SecretChannel(chptr) || IsMember(sptr,chptr)) + { /* already shown */ + cansend = 0; + break; + } lp = lp->next; - } - if (showflag) /* have we already shown them ? */ - continue; - if (secret) /* on any secret channels ? */ + } + if (!cansend) + { continue; - (void)strncat(buf, c2ptr->name, NICKLEN); - idx += strlen(c2ptr->name) + 1; - (void)strcat(buf," "); - flag = 1; - if (mlen + idx + NICKLEN > BUFSIZE - 2) - { - rlen += strlen(buf); - sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf); - (void)strncpy(buf, "* * :", 6); - idx = 5; - flag = 0; - } - } - if (flag) - { - rlen += strlen(buf); - sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf); - } - if (!MyConnect(sptr) && rlen > CHREPLLEN) - sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]), - para ? para : "*"); - /* This is broken.. remove the recursion? */ + } + nlen = strlen(acptr->name); + if (nlen > NICKLEN) + { + nlen = NICKLEN; + } + + memcpy(pbuf, acptr->name, nlen); + pbuf += nlen; + *pbuf++ = ' '; + sent = 0; + if ((size_t) pbuf - (size_t) buf > maxlen) + { + *pbuf = '\0'; + sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf,0); + sent = 1; + pbuf = buf + pxlen; + pbuf[0] = '\0'; + } + } + if (!sent) + { + *pbuf = '\0'; + sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf,0); + } sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), "*"); - return 2; + return MAXPENALTY; } void send_user_joins(cptr, user) @@ -3429,7 +3694,11 @@ if (curh_nb == 0) { #ifdef DEBUGMODE +#ifdef LOCAL_REJECTIONS_ONLY + sendto_flag(SCH_NOTICE, +#else sendto_flag(SCH_LOCAL, +#endif "Channel garbage: live %u (max %u), hist %u (extended)", cur_nb - 1, max_nb - 1, curh_nb); #endif @@ -3466,7 +3735,11 @@ } #ifdef DEBUGMODE +#ifdef LOCAL_REJECTIONS_ONLY + sendto_flag(SCH_NOTICE, +#else sendto_flag(SCH_LOCAL, +#endif "Channel garbage: live %u (max %u), hist %u (removed %u)%s", cur_nb - 1, max_nb - 1, curh_nb, del - istat.is_hchan, (split) ? " split detected" : ""); diff -urN irc2.10.3p5/ircd/channel_def.h irc2.10.3p5+hemp2/ircd/channel_def.h --- irc2.10.3p5/ircd/channel_def.h 1997-09-03 19:45:47.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/channel_def.h 2003-10-12 00:08:16.000000000 +0200 @@ -25,5 +25,3 @@ #define NullChn ((aChannel *)0) #define ChannelExists(n) (find_channel(n, NullChn) != NullChn) - -#define MAXMODEPARAMS 3 diff -urN irc2.10.3p5/ircd/channel_ext.h irc2.10.3p5+hemp2/ircd/channel_ext.h --- irc2.10.3p5/ircd/channel_ext.h 1998-01-23 14:28:13.000000000 +0100 +++ irc2.10.3p5+hemp2/ircd/channel_ext.h 2003-10-12 00:08:16.000000000 +0200 @@ -53,7 +53,6 @@ char *parv[])); EXTERN int m_part __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); EXTERN int m_kick __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); -EXTERN int count_channels __P((aClient *sptr)); EXTERN int m_topic __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); EXTERN int m_invite __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); diff -urN irc2.10.3p5/ircd/hash.c irc2.10.3p5+hemp2/ircd/hash.c --- irc2.10.3p5/ircd/hash.c 2003-10-11 00:32:05.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/hash.c 2003-10-12 00:08:24.000000000 +0200 @@ -29,13 +29,16 @@ static aHashEntry *clientTable = NULL; static aHashEntry *channelTable = NULL; static aHashEntry *serverTable = NULL; +static aHashEntry *hostnameTable = NULL; static unsigned int *hashtab = NULL; static int clhits = 0, clmiss = 0, clsize = 0; static int chhits = 0, chmiss = 0, chsize = 0; +static int cnhits = 0, cnmiss = 0 ,cnsize = 0; static int svsize = 0; int _HASHSIZE = 0; int _CHANNELHASHSIZE = 0; int _SERVERSIZE = 0; +int _HOSTNAMEHASHSIZE = 0; /* * Hashing. @@ -74,6 +77,7 @@ char *nname; int *store; { + Reg u_char *name = (u_char *)nname; Reg u_char ch; Reg u_int hash = 1; @@ -123,6 +127,31 @@ return (hash); } + + +/* + * hash_host_name + */ +static u_int hash_host_name(hname, store) +char *hname; +int *store; +{ + + Reg u_char *name = (u_char *)hname; + Reg u_int hash = 0; + + for (; *name; name++) + { + hash = 31 * hash + hashtab[*name]; + } + + if (store) + *store = hash; + hash %= _HOSTNAMEHASHSIZE; + return (hash); +} + + /* bigger prime * * given a positive integer, return a prime number that's larger @@ -195,6 +224,21 @@ Debug((DEBUG_DEBUG, "Channel Hash Table Init: %d (%d)", _CHANNELHASHSIZE, size)); } +static void clear_hostname_hash_table(size) +int size; +{ + _HOSTNAMEHASHSIZE = bigger_prime(size); + cnhits = 0; + cnmiss = 0; + cnsize = 0; + if (!hostnameTable) + hostnameTable = (aHashEntry *)MyMalloc(_HOSTNAMEHASHSIZE * + sizeof(aHashEntry)); + bzero((char *)hostnameTable, sizeof(aHashEntry) * _HOSTNAMEHASHSIZE); + Debug((DEBUG_DEBUG, "Client Hash Table Init: %d (%d)", + _HOSTNAMEHASHSIZE, size)); +} + static void clear_server_hash_table(size) int size; @@ -218,6 +262,7 @@ : CHANNELHASHSIZE); clear_server_hash_table((_SERVERSIZE) ? _SERVERSIZE : SERVERSIZE); + clear_hostname_hash_table((_HOSTNAMEHASHSIZE) ? _HOSTNAMEHASHSIZE : HOSTNAMEHASHSIZE); /* * Moved multiplication out from the hashfunctions and into * a pre-generated lookup table. Should save some CPU usage @@ -236,6 +281,8 @@ Reg aClient *cptr; Reg aChannel *chptr; Reg aServer *sptr; + Reg anUser *user; + aHashEntry *otab = table; int osize = *size; @@ -282,19 +329,44 @@ clhits = 0; clsize = 0; clientTable = table; - + for (i = 0; i < osize; i++) { for (cptr = (aClient *)otab[i].list; cptr; cptr = next) { next = cptr->hnext; - (void)add_to_client_hash_table(cptr->name, + (void)add_to_client_hash_table(cptr->name, cptr); } } MyFree(otab); } + else if (otab == hostnameTable) + { + int i; + anUser *next; + Debug((DEBUG_ERROR, "Hostname Hash Table from %d to %d (%d)", + osize, new, clsize)); + sendto_flag(SCH_HASH, "Hostname Hash Table from %d to %d (%d)", + osize, new, clsize); + cnmiss = 0; + cnhits = 0; + cnsize = 0; + hostnameTable = table; + + for (i = 0; i < osize; i++) + { + for (user = (anUser *)otab[i].list; user; + user = next) + { + next = user->hnext; + (void)add_to_hostname_hash_table(user->host, + user); + } + } + MyFree(otab); + } else if (otab == serverTable) { Debug((DEBUG_ERROR, "Server Hash Table from %d to %d (%d)", @@ -352,6 +424,26 @@ } /* + * add_to_client_hash_table + */ +int add_to_hostname_hash_table(hostname, user) +char *hostname; +anUser *user; +{ + Reg u_int hashv; + + hashv = hash_host_name(hostname, &user->hashv); + user->hnext = (anUser *)hostnameTable[hashv].list; + hostnameTable[hashv].list = (void *)user; + hostnameTable[hashv].links++; + hostnameTable[hashv].hits++; + cnsize++; + if (cnsize > _HOSTNAMEHASHSIZE) + bigger_hash_table(&_HOSTNAMEHASHSIZE, hostnameTable, 0); + return 0; +} + +/* * add_to_server_hash_table */ int add_to_server_hash_table(sptr, cptr) @@ -456,7 +548,49 @@ } return 0; } +/* + * del_from_hostname_hash_table + */ +int del_from_hostname_hash_table(hostname, user) +char *hostname; +anUser *user; +{ + Reg anUser *tmp, *prev = NULL; + Reg u_int hashv; + hashv = user->hashv; + hashv %= _HOSTNAMEHASHSIZE; + for (tmp = (anUser *)hostnameTable[hashv].list; tmp; tmp = tmp->hnext) + { + if (tmp == user) + { + if (prev) + prev->hnext = tmp->hnext; + else + hostnameTable[hashv].list = (void *)tmp->hnext; + tmp->hnext = NULL; + if (hostnameTable[hashv].links > 0) + { + hostnameTable[hashv].links--; + cnsize--; + return 1; + } + else + { + sendto_flag(SCH_ERROR, "hn-hash table failure"); + Debug((DEBUG_ERROR, "hn-hash table failure")); + /* + * Should never actually return from here and + * if we do it is an error/inconsistency in the + * hash table. + */ + return -1; + } + } + prev = tmp; + } + return 0; +} /* * del_from_server_hash_table @@ -649,6 +783,30 @@ chmiss++; return chptr; } +/* + * hash_find_hostname + */ +anUser *hash_find_hostname(hostname, user) +char *hostname; +anUser *user; +{ + Reg anUser *tmp, *prv = NULL; + Reg aHashEntry *tmp3; + u_int hashv, hv; + + hashv = hash_host_name(hostname, &hv); + tmp3 = &hostnameTable[hashv]; + + for (tmp = (anUser *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext) + if (hv == tmp->hashv && !mycmp(hostname, tmp->host)) + { + cnhits++; + return (tmp); + } + cnmiss++; + return user; +} + /* * hash_find_channels @@ -746,14 +904,23 @@ if (parc > 1) { ch = *parv[1]; - if (islower(ch)) - table = clientTable; - else { - table = channelTable; - size = _CHANNELHASHSIZE; + switch (tolower(ch)) + { + case 'c': + table = channelTable; + size = _CHANNELHASHSIZE; + break; + case 'q': + table = hostnameTable; + size = _HOSTNAMEHASHSIZE; + break; + default: + table = clientTable; } - if (ch == 'L' || ch == 'l') + if (isupper(ch)) + { showlist = 1; + } } else { ch = '\0'; table = clientTable; @@ -950,6 +1117,8 @@ parv[0], clhits, clmiss); sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d", parv[0], chhits, chmiss); + sendto_one(sptr,"NOTICE %s :Hostnames hits %d miss %d", + parv[0], cnhits, cnmiss); return 2; #endif } diff -urN irc2.10.3p5/ircd/hash_def.h irc2.10.3p5+hemp2/ircd/hash_def.h --- irc2.10.3p5/ircd/hash_def.h 1997-09-03 19:45:50.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/hash_def.h 2003-10-12 00:08:16.000000000 +0200 @@ -30,3 +30,5 @@ #define HASHSIZE ((int)((float)MAXCONNECTIONS*1.75)) #define CHANNELHASHSIZE ((int)(((float)MAXCONNECTIONS*1.75)/2.0)) #define SERVERSIZE (MAXCONNECTIONS/10) +#define HOSTNAMEHASHSIZE ((int)((float)MAXCONNECTIONS*1.75)) + diff -urN irc2.10.3p5/ircd/hash_ext.h irc2.10.3p5+hemp2/ircd/hash_ext.h --- irc2.10.3p5/ircd/hash_ext.h 1999-01-17 02:13:54.000000000 +0100 +++ irc2.10.3p5+hemp2/ircd/hash_ext.h 2003-10-12 00:08:16.000000000 +0200 @@ -40,10 +40,13 @@ EXTERN int add_to_client_hash_table __P((char *name, aClient *cptr)); EXTERN int add_to_channel_hash_table __P((char *name, aChannel *chptr)); EXTERN int add_to_server_hash_table __P((aServer *sptr, aClient *cptr)); +EXTERN int add_to_hostname_hash_table __P((char *hostname, anUser *user)); EXTERN int del_from_client_hash_table __P((char *name, aClient *cptr)); EXTERN int del_from_channel_hash_table __P((char *name, aChannel *chptr)); EXTERN int del_from_server_hash_table __P((aServer *sptr, aClient *cptr)); +EXTERN int del_from_hostname_hash_table __P((char *hostname, anUser *user)); EXTERN aClient *hash_find_client __P((char *name, aClient *cptr)); +EXTERN anUser *hash_find_hostname __P((char *hostname, anUser *user)); EXTERN aClient *hash_find_server __P((char *server, aClient *cptr)); EXTERN aChannel *hash_find_channel __P((char *name, aChannel *chptr)); EXTERN aChannel *hash_find_channels __P((char *name, aChannel *chptr)); diff -urN irc2.10.3p5/ircd/ircd.c irc2.10.3p5+hemp2/ircd/ircd.c --- irc2.10.3p5/ircd/ircd.c 2003-10-11 19:13:03.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/ircd.c 2003-10-12 00:44:48.000000000 +0200 @@ -33,7 +33,13 @@ static void open_debugfile(), setup_signals(), io_loop(); +#if defined(OPER_KLINE) || defined(LOCOP_KLINE) || \ + defined(OPER_TKLINE) || defined(LOCOP_TKLINE) +int kline_added = 0; +#endif + istat_t istat; +iconf_t iconf; char **myargv; int rehashed = 0; int portnum = -1; /* Server port number, listening this */ @@ -43,6 +49,7 @@ char *debugmode = ""; /* -"- -"- -"- -"- */ char *sbrk0; /* initial sbrk(0) */ char *tunefile = IRCDTUNE_PATH; +int initialconf = 1; static int dorehash = 0, dorestart = 0, restart_iauth = 0; @@ -54,6 +61,10 @@ time_t nextexpire = 1; /* next expire run on the dns cache */ time_t nextiarestart = 1; /* next time to check if iauth is alive */ +#ifdef DELAY_CLOSE +time_t nextdelayclose = 0; +#endif + #ifdef PROFIL extern etext(); @@ -337,6 +348,147 @@ return; } } +#ifdef DELAY_CLOSE +time_t delay_close(fd,reason) +int fd; +char *reason; +{ + struct fdlog + { + struct fdlog *next; + int fd; + time_t time; + char reason[BUFSIZE]; + }; + static struct fdlog *first = NULL, *last = NULL; + static int delayedfdnum = 0; + struct fdlog *next = first, *tmp; + + while (tmp = next) + if ((fd == -2) || (delayedfdnum == MAXCONNECTIONS / 10) + || tmp->time + DELAYCLOSETIME < timeofday) + { + next = tmp->next; + if (*(tmp->reason)) + { + send(tmp->fd,tmp->reason,strlen(tmp->reason),0); + } + close(tmp->fd); + delayedfdnum--; + MyFree(tmp); + if (!next) + { + if (first != last) + abort(); + first = last = NULL; + break; + } + first = next; + } + else + break; + + if (fd == -2) + { + nextdelayclose = 0; + return 0; + } + if (fd < 0) + return first ? first->time + DELAYCLOSETIME : 0; + /* disallow further receives */ + /* this should be shutdown(fd, SHUT_RD) but some OSes do- + * not define this. Check shutdown(2) if it matches. + * -- Beeth + */ +#ifndef SHUT_RD +#define SHUT_RD 0 +#endif + shutdown(fd, SHUT_RD); + + /* first create a new entry with fd and time */ + tmp = (struct fdlog *)MyMalloc(sizeof(*tmp)); + tmp->next = NULL; + tmp->fd = fd; + tmp->time = timeofday; + if (reason) + { + strncpy(tmp->reason,reason,BUFSIZE-3); + tmp->reason[BUFSIZE-3] = 0; + strcat(tmp->reason,"\r\n"); + } + delayedfdnum++; + istat.is_delayclosed++; + /* then add it to the list */ + if (last) + { + last->next = tmp; + last = tmp; + } + else + first = last = tmp; + + nextdelayclose = first ? first->time + DELAYCLOSETIME : 0; + return nextdelayclose; + +} + +#endif /* DELAY_CLOSE */ + +#if defined(OPER_KLINE) || defined(LOCOP_KLINE) || \ + defined(OPER_TKLINE) || defined(LOCOP_TKLINE) +void check_klines(void) +{ + Reg aClient *cptr; + int kflag, i; + char *reason; + + kline_added=0; + + for (i = highest_fd ; i>=0; i--) + { + + if (!(cptr = local[i]) || IsListening(cptr) || IsLog(cptr) || + IsHeld(cptr)) + continue; +#ifdef ILINE_FLAGS + if (IsKlineExempt(cptr)) + { + continue; + } +#endif + if ( IsPerson(cptr) +#ifdef ILINE_FLAGS + && !IsKlineExempt(cptr) +#endif + ) + { + kflag = find_kill(cptr, 1, &reason); + } + else + { + kflag = 0; + reason = NULL; + } + + if (kflag && IsPerson(cptr)) + { + char buf[100]; + + sendto_flag(SCH_NOTICE, + "Kill line active for %s", + get_client_name(cptr, FALSE)); + cptr->exitc = EXITC_KLINE; + if (reason) + sprintf(buf, "Kill line active: %.80s", + reason); + (void)exit_client(cptr, cptr, &me, (reason) ? + buf : "Kill line active"); + } + } + + return; +} +#endif static time_t check_pings(currenttime) @@ -354,7 +506,6 @@ if (!(cptr = local[i]) || IsListening(cptr) || IsLog(cptr) || IsHeld(cptr)) continue; - /* * K and R lines once per minute, max. This is the max. * granularity in K-lines anyway (with time field). @@ -365,7 +516,11 @@ #endif /* TIMEDKLINES */ rehashed) { - if (IsPerson(cptr)) + if (IsPerson(cptr) +#ifdef ILINE_FLAGS + && !IsKlineExempt(cptr) +#endif + ) { kflag = find_kill(cptr, rehashed, &reason); #ifdef R_LINES_OFTEN @@ -680,7 +835,9 @@ bzero((char *)&me, sizeof(me)); version = make_version(); /* Generate readable version string */ - +#ifdef SEND_ISUPPORT + isupport = make_isupport(); /* generate 005 numeric */ +#endif /* ** All command line parameters have the syntax "-fstring" ** or "-f string" (e.g. the space is optional). String may @@ -908,7 +1065,7 @@ if (!find_me()) exit(-1); } - + initialconf = 0; dbuf_init(); setup_me(&me); check_class(); @@ -984,7 +1141,11 @@ ** active C lines, this call to Tryconnections is ** made once only; it will return 0. - avalon */ +#ifdef OPER_SET + if (iconf.aconnect && nextconnect && timeofday >= nextconnect) +#else if (nextconnect && timeofday >= nextconnect) +#endif nextconnect = try_connections(timeofday); /* ** Every once in a while, hunt channel structures that @@ -1066,6 +1227,19 @@ rehashed = 0; } +#ifdef DELAY_CLOSE + if (nextdelayclose && (timeofday >= nextdelayclose)) + { + nextdelayclose = delay_close(-1,NULL); + } +#endif + +#if defined(OPER_KLINE) || defined(LOCOP_KLINE) || \ + defined(OPER_TKLINE) || defined(LOCOP_TKLINE) + if (kline_added) + check_klines(); +#endif + if (dorestart) restart("Caught SIGINT"); if (dorehash) diff -urN irc2.10.3p5/ircd/ircd_ext.h irc2.10.3p5+hemp2/ircd/ircd_ext.h --- irc2.10.3p5/ircd/ircd_ext.h 1999-02-12 05:00:47.000000000 +0100 +++ irc2.10.3p5+hemp2/ircd/ircd_ext.h 2003-10-12 00:08:16.000000000 +0200 @@ -27,6 +27,7 @@ extern aClient me; extern aClient *client; extern istat_t istat; +extern iconf_t iconf; extern char **myargv; extern int rehashed; extern int portnum; @@ -41,6 +42,10 @@ extern time_t nextping; extern time_t nextdnscheck; extern time_t nextexpire; +extern int initialconf; +#ifdef DELAY_CLOSE +extern time_t nextdelayclose; +#endif #endif /* IRCD_C */ /* External definitions for global functions. @@ -59,4 +64,7 @@ EXTERN void server_reboot(); EXTERN void ircd_writetune __P((char *filename)); EXTERN void ircd_readtune __P((char *filename)); +#ifdef DELAY_CLOSE +EXTERN time_t delay_close __P((int fd,char *reason)); +#endif #undef EXTERN diff -urN irc2.10.3p5/ircd/list.c irc2.10.3p5+hemp2/ircd/list.c --- irc2.10.3p5/ircd/list.c 2001-05-06 23:36:55.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/list.c 2003-10-12 13:38:03.000000000 +0200 @@ -147,6 +147,11 @@ istat.is_auth -= 1; MyFree(cptr->auth); } + if (cptr->hopcount == 0) + { + if (cptr->reason) + MyFree(cptr->reason); + } MyFree((char *)cptr); } @@ -190,6 +195,7 @@ if (!serv) { serv = (aServer *)MyMalloc(sizeof(aServer)); + memset((char *) serv, 0, sizeof(aServer)); #ifdef DEBUGMODE servs.inuse++; #endif @@ -201,8 +207,11 @@ serv->up = NULL; serv->refcnt = 1; serv->nexts = NULL; +#ifdef SERVER_MAP + serv->down = NULL; +#endif cptr->serv = serv; - + bzero((void *)serv->usercnt,3*sizeof(int)); for (sp = svrtop; sp; spp = sp, sp = sp->nexts) if (spp && ((spp->ltok) + 1 < sp->ltok)) break; @@ -309,6 +318,10 @@ cptr, cptr ? cptr->name : "", buf); #endif } + if (serv->up && serv->up != ME) + { + MyFree((char *)serv->up); + } MyFree((char *)serv); } } @@ -497,6 +510,18 @@ return lp; } +invLink *make_invlink() +{ + Reg invLink *lp; + + lp = (invLink *)MyMalloc(sizeof(invLink)); +#ifdef DEBUGMODE + links.inuse++; +#endif + lp->flags = 0; + return lp; +} + void free_link(lp) Reg Link *lp; { @@ -506,6 +531,14 @@ #endif } +void free_invlink(lp) +Reg invLink *lp; +{ + MyFree((char *)lp); +#ifdef DEBUGMODE + links.inuse--; +#endif +} aClass *make_class() { @@ -547,6 +580,7 @@ aconf->status = CONF_ILLEGAL; aconf->pref = -1; aconf->hold = time(NULL); + aconf->source_ip = NULL; Class(aconf) = NULL; return (aconf); } @@ -584,6 +618,8 @@ bzero(aconf->passwd, strlen(aconf->passwd)); if (aconf->ping) MyFree((char *)aconf->ping); + if (aconf->source_ip) + MyFree(aconf->source_ip); MyFree(aconf->passwd); MyFree(aconf->name); MyFree((char *)aconf); diff -urN irc2.10.3p5/ircd/list_ext.h irc2.10.3p5+hemp2/ircd/list_ext.h --- irc2.10.3p5/ircd/list_ext.h 1999-07-02 18:49:37.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/list_ext.h 2003-10-12 13:38:22.000000000 +0200 @@ -55,7 +55,9 @@ EXTERN Link *find_user_link __P((Reg Link *lp, Reg aClient *ptr)); EXTERN Link *find_channel_link __P((Reg Link *lp, Reg aChannel *ptr)); EXTERN Link *make_link(); +EXTERN invLink *make_invlink(); EXTERN void free_link __P((Reg Link *lp)); +EXTERN void free_invlink __P((Reg invLink *lp)); EXTERN aClass *make_class(); EXTERN void free_class __P((Reg aClass *tmp)); EXTERN aConfItem *make_conf(); diff -urN irc2.10.3p5/ircd/res.c irc2.10.3p5+hemp2/ircd/res.c --- irc2.10.3p5/ircd/res.c 2003-10-11 15:25:14.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/res.c 2003-10-12 00:22:56.000000000 +0200 @@ -497,7 +497,8 @@ (u_int)(cp[1]&0xf), (u_int)(cp[1]>>4), (u_int)(cp[0]&0xf), (u_int)(cp[0]>>4), #ifdef SIXBONE_HACK - (cp[0] == 0x3f && cp[1] == 0xfe) ? "int" : + ((cp[0] == 0x3f && cp[1] == 0xfe) || + (cp[0] == 0x20 && cp[1] == 0x02)) ? "int" : #endif "arpa"); } diff -urN irc2.10.3p5/ircd/s_auth.c irc2.10.3p5+hemp2/ircd/s_auth.c --- irc2.10.3p5/ircd/s_auth.c 2003-10-11 22:04:29.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/s_auth.c 2003-10-12 00:08:24.000000000 +0200 @@ -291,15 +291,15 @@ } iauth_stats = (aExtData *) MyMalloc(sizeof(aExtData)); - iauth_stats->line = MyMalloc(60); + iauth_stats->line = MyMalloc(80); sprintf(iauth_stats->line, "iauth modules statistics (%s)", myctime(timeofday)); iauth_stats->next = (aExtData *) MyMalloc(sizeof(aExtData)); - iauth_stats->next->line = MyMalloc(60); + iauth_stats->next->line = MyMalloc(80); sprintf(iauth_stats->next->line, - "spawned: %d, current options: %X (%.11s)", + "spawned: %d, current options: %X (%.20s)", iauth_spawn, iauth_options, (iauth_version) ? iauth_version : "???"); iauth_stats->next->next = NULL; @@ -459,6 +459,13 @@ ** yet: we don't even know if this is a server ** or a user connection! */ + int i; + char *reason; + reason = strchr(start,'#'); + if (reason) + { + cptr->reason = mystrdup(reason+1); + } if (start[0] == 'K') cptr->exitc = EXITC_AREF; else diff -urN irc2.10.3p5/ircd/s_bsd.c irc2.10.3p5+hemp2/ircd/s_bsd.c --- irc2.10.3p5/ircd/s_bsd.c 2003-10-11 15:57:53.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/s_bsd.c 2003-10-12 02:06:15.000000000 +0200 @@ -321,7 +321,6 @@ #endif if (inetport(cptr, aconf->host, aconf->name, aconf->port)) cptr->fd = -2; - if (cptr->fd >= 0) { cptr->confs = make_link(); @@ -335,7 +334,32 @@ free_client(cptr); return 0; } - +#ifdef DELAY_ACCEPT +void activate_delayed_listeners() +{ + aConfItem *aconf = NULL; + int pcnt = 0; + + for (aconf = conf; aconf; aconf = aconf->next) + { + if (!(aconf->status & CONF_LISTEN_PORT) + || (conf->status & CONF_ILLEGAL)) + { + continue; + } + if (!(aconf->status & CONF_ACTIVE)) + { + aconf->status |= CONF_ACTIVE; + pcnt++; + add_listener(aconf); + } + } + if (pcnt) + { + sendto_flag(SCH_NOTICE,"Activating delayed listening ports"); + } +} +#endif #ifdef UNIXPORT /* * unixport @@ -1317,8 +1341,21 @@ } del_fd(i, &fdall); local[i] = NULL; - (void)close(i); - +#ifdef DELAY_CLOSE + if (cptr->user && (cptr->user->flags & FLAGS_BADBOY)) + { + delay_close(i,cptr->buffer); + if (!nextdelayclose) + { + nextdelayclose = timeofday + DELAYCLOSETIME; + } + } + else +#endif + { + (void)close(i); + } + cptr->fd = -2; DBufClear(&cptr->sendQ); DBufClear(&cptr->recvQ); @@ -1577,15 +1614,23 @@ report_error("Failed in connecting to %s :%s", cptr); add_con_refuse: + (void)close(fd); +add_con_delay_refuse: ircstp->is_ref++; acptr->fd = -2; free_client(acptr); - (void)close(fd); return NULL; } /* don't want to add "Failed in connecting to" here.. */ if (aconf && IsIllegal(aconf)) goto add_con_refuse; +#ifdef DELAY_ACCEPT + /* we are not accepting connections because of split */ + if (aconf && (aconf->status & CONF_DELAY) && (iconf.caccept < 2)) + { + goto add_con_refuse; + } +#endif /* Copy ascii address to 'sockhost' just in case. Then we * have something valid to put into error messages... */ @@ -1627,10 +1672,15 @@ (acptr->hostp) ? acptr->hostp->h_name : acptr->sockhost); del_queries((char *)acptr); +#ifdef DELAY_CLOSE + delay_close(fd,"ERROR :Too rapid connections from your host"); + goto add_con_delay_refuse; +#else (void)send(fd, "ERROR :Too rapid connections from your host\r\n", 46, 0); goto add_con_refuse; +#endif } #endif acptr->fd = fd; @@ -2537,6 +2587,8 @@ int *lenp; { static struct SOCKADDR_IN server; + struct SOCKADDR_IN outip; + Reg struct hostent *hp; aClient *acptr; int i; @@ -2556,7 +2608,25 @@ bzero((char *)&server, sizeof(server)); server.SIN_FAMILY = AFINET; get_sockhost(cptr, aconf->host); - + + if (aconf->source_ip) + { + memset(&outip, 0, sizeof(outip)); + outip.SIN_PORT = 0; + outip.SIN_FAMILY = AFINET; +#ifdef INET6 + if (!inetpton(AF_INET6, aconf->source_ip, outip.sin6_addr.s6_addr)) +#else + if ((outip.sin_addr.s_addr = inetaddr(aconf->source_ip)) == -1) +#endif + { + memcpy(&mysk, &outip, sizeof(mysk)); + } + } + else + { + memcpy(&outip, &mysk, sizeof(mysk)); + } if (cptr->fd == -1) { report_error("opening stream socket to server %s:%s", cptr); @@ -2568,7 +2638,7 @@ ** with more than one IP#. ** With VIFs, M:line defines outgoing IP# and initialises mysk. */ - if (bind(cptr->fd, (SAP)&mysk, sizeof(mysk)) == -1) + if (bind(cptr->fd, (SAP)&outip, sizeof(outip)) == -1) { report_error("error binding to local port for %s:%s", cptr); return NULL; diff -urN irc2.10.3p5/ircd/s_bsd_ext.h irc2.10.3p5+hemp2/ircd/s_bsd_ext.h --- irc2.10.3p5/ircd/s_bsd_ext.h 1999-02-05 00:50:21.000000000 +0100 +++ irc2.10.3p5+hemp2/ircd/s_bsd_ext.h 2003-10-12 00:08:16.000000000 +0200 @@ -61,6 +61,9 @@ EXTERN void get_my_name __P((aClient *cptr, char *name, int len)); EXTERN int setup_ping __P((aConfItem *aconf)); EXTERN void send_ping __P((aConfItem *aconf)); +#ifdef DELAY_ACCEPT +EXTERN void activate_delayed_listeners(); +#endif #if defined(ENABLE_SUMMON) || defined(ENABLE_USERS) EXTERN int utmp_open(); EXTERN int utmp_read __P((int fd, char *name, char *line, char *host, diff -urN irc2.10.3p5/ircd/s_conf.c irc2.10.3p5+hemp2/ircd/s_conf.c --- irc2.10.3p5/ircd/s_conf.c 2003-10-11 11:59:59.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/s_conf.c 2003-10-12 01:05:02.000000000 +0200 @@ -177,8 +177,9 @@ for (aconf = conf; aconf; aconf = aconf->next) { - if ((aconf->status != CONF_CLIENT) && - (aconf->status != CONF_RCLIENT)) + if (IsIllegal(aconf)) + continue; + if (!(aconf->status & (CONF_CLIENT | CONF_RCLIENT))) continue; if (aconf->port && aconf->port != cptr->acpt->port) continue; @@ -229,6 +230,16 @@ attach_iline: if (aconf->status & CONF_RCLIENT) SetRestricted(cptr); +#ifdef ILINE_FLAGS + if (aconf->status & CONF_EXEMPT) + { + cptr->user->flags |= FLAGS_EXEMPT; + } + if (!hp && (aconf->status & CONF_RNODNS)) + { + SetRestricted(cptr); + } +#endif get_sockhost(cptr, uhost); if ((i = attach_conf(cptr, aconf)) < -1) find_bounce(cptr, ConfClass(aconf), -1); @@ -301,6 +312,7 @@ *aconf2 = aconf3->next; aconf3->next = NULL; free_conf(aconf); + } else { @@ -345,7 +357,7 @@ aClient *cptr; { Reg Link *lp; - + if (is_attached(aconf, cptr)) return 1; if (IsIllegal(aconf)) @@ -358,9 +370,10 @@ return -3; /* Use this for printing error message */ } if ((aconf->status & (CONF_CLIENT | CONF_RCLIENT))) - { + { int hcnt = 0, ucnt = 0; - + int ghcnt = 0, gucnt = 0; + Reg anUser *user = NULL; /* check on local/global limits per host and per user@host */ /* @@ -368,7 +381,64 @@ ** host check is done on the IP address. ** user check is done on the IDENT reply. */ - if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0) { + if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0 || + ConfMaxHGlobal(aconf) > 0 || ConfMaxUHGlobal(aconf) > 0 ) + { + for ((user = hash_find_hostname(cptr->sockhost,NULL));user;user=user->hnext) + { + if (!mycmp(cptr->sockhost,user->host)) + { + ghcnt++; + if (MyConnect(user->bcptr)) + { + hcnt++; + if (!mycmp(user->bcptr->auth,cptr->auth)) + { + ucnt++; + gucnt++; + } + } + else + { + if (!mycmp(user->username,cptr->user->username)) + { + gucnt++; + } + } + if (ConfMaxUHLocal(aconf) > 0 && + ucnt >= ConfMaxUHLocal(aconf)) + { + return -5; + } + + if (ConfMaxHLocal(aconf) > 0 && + hcnt >= ConfMaxHLocal(aconf)) + { + return -4; + } + if (ConfMaxUHGlobal(aconf) > 0 && + gucnt >= ConfMaxUHGlobal(aconf)) + { + return -7; + } + if (ConfMaxHGlobal(aconf) > 0 && + ghcnt >= ConfMaxHGlobal(aconf)) + { + return -6; + } + } + } + } +#ifndef NO_EXTENSIVE_LOCAL_LIMIT_CHECK + /* Part of old cpu intensive code which is checking user's + * ip against all all other local clients. Needed only when + * client changes it's hostname between connects. + * Won't be needed on pure 2.11 net -- jv + */ + + /* now, check local IP too */ + if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0) + { Reg aClient *acptr; Reg int i; @@ -390,38 +460,8 @@ ucnt >= ConfMaxUHLocal(aconf)) return -5; /* for error message */ } - /* - ** Global limits - ** host check is done on the hostname (IP if unresolved) - ** user check is done on username - */ - if (ConfMaxHGlobal(aconf) > 0 || ConfMaxUHGlobal(aconf) > 0) - { - Reg aClient *acptr; - Reg int ghcnt = hcnt, gucnt = ucnt; - - for (acptr = client; acptr; acptr = acptr->next) - { - if (!IsPerson(acptr)) - continue; - if (MyConnect(acptr) && - (ConfMaxHLocal(aconf) > 0 || - ConfMaxUHLocal(aconf) > 0)) - continue; - if (!strcmp(cptr->sockhost, acptr->user->host)) - { - if (ConfMaxHGlobal(aconf) > 0 && - ++ghcnt >= ConfMaxHGlobal(aconf)) - return -6; - if (ConfMaxUHGlobal(aconf) > 0 && - !strcmp(cptr->user->username, - acptr->user->username) && - (++gucnt >=ConfMaxUHGlobal(aconf))) - return -7; - } - } - } - } +#endif + } lp = make_link(); istat.is_conflink++; @@ -739,12 +779,20 @@ if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host)) continue; +#ifdef DELAY_ACCEPT + /* ignore ->passwd field */ + if (!(aconf->status & CONF_LISTEN_PORT)) + { +#endif if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) || (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd))) continue; if (!BadPtr(bconf->passwd) && mycmp(bconf->passwd, aconf->passwd)) continue; +#ifdef DELAY_ACCEPT + } +#endif if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) || (BadPtr(aconf->name) && !BadPtr(bconf->name))) @@ -860,12 +908,11 @@ if (!(tmp2->status & CONF_ILLEGAL) || tmp2->clients) tmp = &tmp2->next; else - { + { *tmp = tmp2->next; tmp2->next = NULL; free_conf(tmp2); - } - + } #ifdef CACHED_MOTD read_motd(IRCDMOTD_PATH); #endif @@ -1199,7 +1246,27 @@ DupString(aconf->passwd, tmp); if ((tmp = getfield(NULL)) == NULL) break; - DupString(aconf->name, tmp); +#ifdef ILINE_FLAGS + if ((aconf->status & (CONF_CLIENT | CONF_RCLIENT))) + { + int shiftname = 0; + if (*tmp == '<' || (*tmp && *(tmp + 1) == '<')) + { + shiftname++; + aconf->status |= CONF_EXEMPT; + } + if (*tmp == '+' || (*tmp && *(tmp + 1) == '+')) + { + shiftname++; + aconf->status |= CONF_RNODNS; + } + DupString(aconf->name,tmp+shiftname); + } + else +#endif + { + DupString(aconf->name, tmp); + } if ((tmp = getfield(NULL)) == NULL) break; aconf->port = 0; @@ -1258,26 +1325,109 @@ if (MaxLinks(Class(aconf)) < 0) Class(aconf) = find_class(0); } +#ifdef DELAY_ACCEPT + if (aconf->status & (CONF_LISTEN_PORT)) + { + if (aconf->passwd && strchr(aconf->passwd,'D')) + { + aconf->status |= CONF_DELAY; + } + if (aconf->passwd && strchr(aconf->passwd,'S')) + { + aconf->status |= CONF_SERVERONLY; + /* feature, remove delay if serveronly */ + aconf->status &= ~CONF_DELAY; + } + } +#endif + if (aconf->status & (CONF_LISTEN_PORT|CONF_CLIENT|CONF_RCLIENT)) { - aConfItem *bconf; + aConfItem *bconf = NULL; if ((bconf = find_conf_entry(aconf, aconf->status))) { delist_conf(bconf); bconf->status &= ~CONF_ILLEGAL; - if (aconf->status == CONF_CLIENT) + if (aconf->status & (CONF_CLIENT | CONF_RCLIENT)) { +#ifdef ILINE_FLAGS + if (aconf->status & CONF_EXEMPT) + { + bconf->status |= CONF_EXEMPT; + } + else + { + bconf->status &= ~CONF_EXEMPT; + } + if (aconf->status & CONF_RNODNS) + { + bconf->status |= CONF_RNODNS; + } + else + { + bconf->status &= ~CONF_RNODNS; + } +#endif bconf->class->links -= bconf->clients; bconf->class = aconf->class; bconf->class->links += bconf->clients; } +#ifdef DELAY_ACCEPT + if (aconf->status & CONF_LISTEN_PORT) + { + if (aconf->status & CONF_DELAY) + { + bconf->status &= ~CONF_SERVERONLY; + bconf->status |= CONF_DELAY; + } + else + { + bconf->status &= ~CONF_DELAY; + } + if (aconf->status & CONF_SERVERONLY) + { + bconf->status &= ~CONF_DELAY; + bconf->status |= CONF_SERVERONLY; + } + else + { + bconf->status &= ~CONF_SERVERONLY; + } + } +#endif + free_conf(aconf); aconf = bconf; } - else if (aconf->host && - aconf->status == CONF_LISTEN_PORT) - (void)add_listener(aconf); + + if (aconf->host && + aconf->status & CONF_LISTEN_PORT) + { +#ifdef DELAY_ACCEPT + if (aconf->status & CONF_DELAY) + { + /* we have Delayed ports and we + * are starting, don't bind them. + */ + if (initialconf) + iconf.caccept = 1; + } + if (!((iconf.caccept < 2) && + (aconf->status & CONF_DELAY))) + { + aconf->status |= CONF_ACTIVE; + } + + if (aconf->status & CONF_ACTIVE) +#endif + { + if (!bconf) + { + add_listener(aconf); + } + } + } } if (aconf->status & CONF_SERVICE) aconf->port &= SERVICE_MASK_ALL; @@ -1322,6 +1472,10 @@ MyFree(tmp2); tmp2 = NULL; } + if (tmp3) + { + DupString(aconf->source_ip, tmp3); + } } /* diff -urN irc2.10.3p5/ircd/s_debug.c irc2.10.3p5+hemp2/ircd/s_debug.c --- irc2.10.3p5/ircd/s_debug.c 2001-10-19 20:44:27.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/s_debug.c 2003-10-12 00:08:16.000000000 +0200 @@ -36,6 +36,9 @@ #ifndef NO_IDENT 'a', #endif +#ifdef MIN_CHANOP_SERV +'B', +#endif #ifdef CHROOTDIR 'c', #endif @@ -88,6 +91,9 @@ 'K', # endif #endif +#ifdef FAILED_OPERLOG +'l', +#endif #ifdef LEAST_IDLE 'L', #endif @@ -123,6 +129,9 @@ #endif #ifdef OPER_REMOTE 't', +#ifdef TOPICWHOTIME +'T', +#endif #endif #ifndef NO_PREFIX 'u', @@ -150,6 +159,113 @@ #endif '\0'}; +/* + * Option string. Must be before #ifdef DEBUGMODE. + * spaces are not allowed. + */ +char cropts[] = { +#ifdef EXTRA_STATISTICS +'E', +#endif +#ifdef FAILED_OPERLOG +'F', +#endif +#ifdef LOG_IP +'I', +#endif +#ifdef OPER_KLINE +'K', +#endif +#ifdef LOCOP_KLINE +'k', +#endif +#ifdef OPER_TKLINE +'T', +#endif +#ifdef LOCOP_TKLINE +'t', +#endif +#ifdef RESTRICT_USERNAMES +'u', +#endif +'\0'}; + +char flopts[] = { +#ifdef CLIENTS_CHANNEL +'C', +#endif +'\0'}; + +char scopts[] = { +#ifdef EXTRA_STATISTICS +'C', +#endif +#ifdef FAILED_OPERLOG +'f', +#endif +#ifdef OPER_KLINE +# ifdef LOCOP_KLINE +'K', +# else +'k', +# endif +#endif +#ifdef LOCAL_REJECTIONS_ONLY +'r', +#endif +#ifdef TOPICWHOTIME +'t', +#endif +'\0' }; + +char jvopts[] = { +#ifdef NO_EXTENSIVE_LOCAL_LIMIT_CHECK +'L', +#endif +#ifdef STATS_F +'F', +#endif +#ifdef WHOIS_SIGNON_TIME +'s', +#endif +#ifdef NO_OPER_TRYAGAIN +'N', +#endif +#ifdef DELAY_ACCEPT +'d', +#endif +#ifdef DELAY_CLOSE +'D', +#endif +#ifdef SEND_ISUPPORT +'5', +#endif +#ifdef STATS_QMARK +'?', +#endif +#ifdef SERVER_MAP +'M', +#endif +#ifdef LIST_ALIS_NOTE +'A', +#endif +#ifdef SPLIT_HANDLE +'S', +#endif +#ifdef OPER_SET +'o', +#endif +#ifdef ILINE_FLAGS +'I', +#endif +#ifdef IAUTH_VERBOSE_REJECTS +'v', +#endif +#ifdef LOG_IRCNAME +'i', +#endif +'\0' +}; #ifdef DEBUGMODE static char debugbuf[2*READBUF_SIZE]; /* needs to be big.. */ @@ -358,6 +474,26 @@ -1, -1 #endif ); + sendto_one(cptr, ":%s %d %s :Sc:%s", ME, RPL_STATSDEFINE, nick, + scopts); +#ifdef EXTRA_STATISTICS + sendto_one(cptr, ":%s %d %s :Cr:%s %d/%d/%d/%d/%d/%d Fl:%s", + ME, RPL_STATSDEFINE, nick, cropts, + istat.is_m_users, istat.is_m_myclnt, + istat.is_m_service, istat.is_m_myservice, + istat.is_m_serv, istat.is_m_myserv,flopts); +#else + sendto_one(cptr, ":%s %d %s :Cr:%s Fl:%s", + ME, RPL_STATSDEFINE, nick, cropts,flopts); +#endif + sendto_one(cptr, ":%s %d %s :jv:%s Split Servers: %d (%d) Users: %d", + ME, RPL_STATSDEFINE,nick,jvopts, +#ifdef SPLIT_HANDLE + SPLIT_SERV,istat.is_eobservers,SPLIT_USERS +#else + -1,-1,-1 +#endif + ); } void count_memory(cptr, nick, debug) diff -urN irc2.10.3p5/ircd/s_err.c irc2.10.3p5+hemp2/ircd/s_err.c --- irc2.10.3p5/ircd/s_err.c 2003-10-11 00:30:37.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/s_err.c 2003-10-12 15:03:24.000000000 +0200 @@ -41,7 +41,31 @@ /* 002 */ { RPL_YOURHOST, ":Your host is %s, running version %s" }, /* 003 */ { RPL_CREATED, ":This server was created %s" }, /* 004 */ { RPL_MYINFO, "%s %s aoOirw abeiIklmnoOpqrstv" }, +#ifdef SEND_ISUPPORT +/* 005 */ //{ RPL_ISUPPORT, "MAP PREFIX=(ov)@+ MODES=3 CHANTYPES=#&!+ MAXCHANNELS=%d NICKLEN=%d TOPICLEN=%d KICKLEN=%d NETWORK=%s CHANMODES=beI,k,l,imnpstaqr :are supported by this server" }, +/* 005 */ { RPL_ISUPPORT, "%s :are supported by this server" }, +#else /* 005 */ { RPL_BOUNCE, ":Try server %s, port %d" }, +#endif +/* 006 */ { 0, (char *)NULL }, +/* 007 */ { 0, (char *)NULL }, +/* 008 */ { 0, (char *)NULL }, +/* 009 */ { 0, (char *)NULL }, +#ifdef SEND_ISUPPORT +/* 010 */ { RPL_BOUNCE, "%s %d :Please use this Server/Port instead" }, +#else +/* 010 */ { 0, (char *)NULL }, +#endif +/* 011 */ { 0, (char *)NULL }, +/* 012 */ { 0, (char *)NULL }, +/* 013 */ { 0, (char *)NULL }, +#ifdef SERVER_MAP +/* 014 */ { 0, (char *)NULL }, +/* 015 */ { RPL_MAP, ":%s" }, +/* 016 */ { 0, (char *)NULL }, +/* 017 */ { RPL_MAPEND, ":End of /MAP" }, +/* 018 */ { RPL_MAPSTART, ":%-53s | %s" }, +#endif { 0, (char *)NULL } }; @@ -62,7 +86,7 @@ /* 413 */ { ERR_NOTOPLEVEL, "%s :No toplevel domain specified" }, /* 414 */ { ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain" }, /* 415 */ { ERR_BADMASK, "%s :Bad Server/host mask" }, -/* 416 */ { ERR_TOOMANYMATCHES, "%s :Output too long (try locally)" }, +/* 416 */ { ERR_TOOMANYMATCHES, "%s :Output too long." }, { 0, (char *)NULL }, { 0, (char *)NULL }, { 0, (char *)NULL }, @@ -183,7 +207,11 @@ /* 314 */ { RPL_WHOWASUSER, "%s %s %s * :%s" }, /* 315 */ { RPL_ENDOFWHO, "%s :End of WHO list." }, /* 316 */ { RPL_WHOISCHANOP, (char *)NULL }, +#ifdef WHOIS_SIGNON_TIME +/* 317 */ { RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time" }, +#else /* 317 */ { RPL_WHOISIDLE, "%s %ld :seconds idle" }, +#endif /* 318 */ { RPL_ENDOFWHOIS, "%s :End of WHOIS list." }, /* 319 */ { RPL_WHOISCHANNELS, "%s :%s" }, { 0, (char *)NULL }, @@ -199,7 +227,11 @@ { 0, (char *)NULL }, /* 331 */ { RPL_NOTOPIC, "%s :No topic is set." }, /* 332 */ { RPL_TOPIC, "%s :%s" }, +#ifdef TOPICWHOTIME +/* 333 */ { RPL_TOPICWHOTIME, "%s %s %lu" }, +#else { 0, (char *)NULL }, +#endif { 0, (char *)NULL }, { 0, (char *)NULL }, { 0, (char *)NULL }, @@ -247,7 +279,8 @@ { 0, (char *)NULL }, { 0, (char *)NULL }, { 0, (char *)NULL }, -/* 381 */ { RPL_YOUREOPER, ":You are now an IRC Operator" }, +/* 381 */ { RPL_YOUREOPER, ":You are now known as an IRC supermouse\ + ~(,,^>." }, /* 382 */ { RPL_REHASHING, "%s :Rehashing" }, /* 383 */ { RPL_YOURESERVICE, ":You are service %s" }, /* 384 */ { RPL_MYPORTIS, "%d :Port to local server is\r\n" }, @@ -293,7 +326,7 @@ /* 217 */ { RPL_STATSQLINE, "%c %s %s %s %d %d" }, /* 218 */ { RPL_STATSYLINE, "%c %d %d %d %d %ld %d.%d %d.%d" }, /* 219 */ { RPL_ENDOFSTATS, "%c :End of STATS report" }, - { 0, (char *)NULL }, +/* 220 */ { RPL_STATSPLINE, "%c %d %s %d :%s %s" }, /* 221 */ { RPL_UMODEIS, "%s" }, { 0, (char *)NULL }, { 0, (char *)NULL }, @@ -338,7 +371,13 @@ /* 261 */ { RPL_TRACELOG, "File %s %d" }, /* 262 */ { RPL_TRACEEND, "%s %s.%s :End of TRACE" }, /* 263 */ { RPL_TRYAGAIN, "%s :Please wait a while and try again." }, +#ifdef EXTRA_STATISTICS + { 0, (char *)NULL }, +/* 265 */ { RPL_LOCALUSERS, ":Current local users: %d Max: %d" }, +/* 266 */ { RPL_GLOBALUSERS, ":Current global users: %d Max: %d" } +#else { 0, (char *)NULL } +#endif }; char *err_str(numeric, to) diff -urN irc2.10.3p5/ircd/s_misc.c irc2.10.3p5+hemp2/ircd/s_misc.c --- irc2.10.3p5/ircd/s_misc.c 2001-10-19 20:44:27.000000000 +0200 +++ irc2.10.3p5+hemp2/ircd/s_misc.c 2003-10-12 00:50:59.000000000 +0200 @@ -370,7 +370,11 @@ { if (sptr->flags & FLAGS_KILLED) { +#ifdef LOCAL_REJECTIONS_ONLY + sendto_flag(SCH_NOTICE, "Killed: %s.", +#else sendto_flag(SCH_LOCAL, "Killed: %s.", +#endif get_client_name(sptr, TRUE)); sptr->exitc = EXITC_KILL; } @@ -386,6 +390,11 @@ sendto_flog(sptr, NULL, sptr->user->username, sptr->user->host); # endif +#ifdef CLIENTS_CHANNEL + sendto_flag(SCH_CLIENTS, "Client exiting: %s was %s from %s reason: %s", + sptr->name,sptr->user->username,sptr->user->host,comment); + +#endif } else if (sptr->exitc != EXITC_REF && sptr->exitc != EXITC_AREF) { @@ -408,16 +417,30 @@ istat.is_myservice--; else istat.is_unknown--; - - if (cptr != NULL && sptr != cptr) - sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)", - get_client_name(sptr,FALSE), - cptr->name, comment); - else - sendto_one(sptr, "ERROR :Closing Link: %s (%s)", - get_client_name(sptr,FALSE), comment); - - if (sptr->auth != sptr->username) +#ifdef DELAY_CLOSE + if (cptr && cptr->user && (cptr->user->flags + & FLAGS_BADBOY)) + { + SPRINTF(cptr->buffer, "ERROR :Closing Link: %s (%s)", + get_client_name(sptr,FALSE), comment); + } + else +#endif + { + if (cptr != NULL && sptr != cptr) + { + sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)", + get_client_name(sptr,FALSE), + cptr->name, comment); + } + else + { + sendto_one(sptr, "ERROR :Closing Link: %s (%s)", + get_client_name(sptr,FALSE), comment); + + } + } + if (sptr->auth != sptr->username) { istat.is_authmem -= strlen(sptr->auth) + 1; istat.is_auth -= 1; @@ -504,6 +527,15 @@ } } } /* If (IsServer(sptr)) */ +#ifdef SPLIT_HANDLE + if ((istat.is_user[0] + istat.is_user[1]) < SPLIT_USERS || istat.is_eobservers < SPLIT_SERV) + { + if (!iconf.split) + { + check_split(); + } + } +#endif } /* if (MyConnect(sptr) || (sptr->flags & FLAGS_HELD)) */ if (IsServer(sptr) && GotDependantClient(sptr)) @@ -531,6 +563,16 @@ acptr->flags |= flags; exit_one_client(cptr, acptr, &me, comment1); } +#ifdef SPLIT_HANDLE + if ((istat.is_user[0] + istat.is_user[1]) < SPLIT_USERS || istat.is_eobservers < SPLIT_SERV) + { + if (!iconf.split) + { + check_split(); + } + } +#endif + } /* @@ -577,6 +619,15 @@ cptr->name, comment); exit_one_client(cptr, sptr, from, (*comment1) ? comment1 : comment); +#ifdef SPLIT_HANDLE + if ((istat.is_user[0] + istat.is_user[1]) < SPLIT_USERS || istat.is_eobservers < SPLIT_SERV) + { + if (!iconf.split) + { + check_split(); + } + } +#endif return cptr == sptr ? FLUSH_BUFFER : 0; } @@ -604,13 +655,65 @@ "ERROR: tried to exit me! : %s", comment); return; /* ...must *never* exit self!! */ } - else if (IsServer(sptr)) { + else if (IsServer(sptr)) + { + Link *lpu,**tmp; + aClient *auptr; + int dcnt = 0; + + /* ** Old sendto_serv_but_one() call removed because we now ** need to send different names to different servers ** (domain name matching) */ istat.is_serv--; +#ifdef SPLIT_HANDLE + if (!IsBurst(sptr)) + { + istat.is_eobservers--; + } +#endif + /* we have also remove the server from ->down */ + auptr = find_client(sptr->serv->up,NULL); + /* hmm.. if it doesn't exist, it means it squitted before */ + if (auptr) + { + lpu = auptr->serv->down; + if (lpu) + { + dcnt = --lpu->flags; + } + for (tmp = &(auptr->serv->down); (lpu = *tmp); tmp = &lpu->next) + { + if (lpu->value.cptr == sptr) + { + *tmp = lpu->next; + free_link(lpu); + break; + } + } + if (auptr->serv->down) + { + auptr->serv->down->flags = dcnt; + } + } + /* and free my downlinks. The squit code is SOOO broken btw */ + if (sptr->serv->down) + { + Link *lp2; + lp2 = sptr->serv->down; + while (lp2) + { + lpu = lp2; + lp2 = lp2->next; + free_link(lpu); + } + sptr->serv->down = NULL; + } +#ifdef EXTRA_STATISTICS + save_server_max(sptr->name,sptr->serv->usermax); +#endif for (i = fdas.highest; i >= 0; i--) { Reg aConfItem *aconf; @@ -696,11 +799,21 @@ if (sptr->user) { if (IsInvisible(sptr)) + { istat.is_user[1]--; - else - istat.is_user[0]--; + sptr->user->servp->usercnt[1]--; + } + else + { + sptr->user->servp->usercnt[0]--; + istat.is_user[0]--; + } + if (IsAnOper(sptr)) + { istat.is_oper--; + sptr->user->servp->usercnt[2]--; + } sendto_common_channels(sptr, ":%s QUIT :%s", sptr->name, comment); @@ -745,6 +858,8 @@ add_history(sptr, (sptr == cptr) ? &me : NULL); #endif off_history(sptr); + del_from_hostname_hash_table(sptr->user->host,sptr->user); + } } else if (sptr->name[0] && IsService(sptr)) @@ -825,16 +940,33 @@ istat.is_serv = 1; istat.is_remc = 1; /* don't ask me why, I forgot. */ bzero((char *)&ircst, sizeof(ircst)); + + bzero((char *)&iconf, sizeof(iconf)); + iconf.aconnect = 1; + iconf.split = 1; +#ifdef DELAY_ACCEPT + iconf.caccept = 2; +#endif } +#ifdef EXTRA_STATISTICS +void tstats(cptr, name, level) +aClient *cptr; +char *name; +int level; +#else void tstats(cptr, name) aClient *cptr; char *name; +#endif { Reg aClient *acptr; Reg int i; Reg struct stats *sp; struct stats tmp; +#ifdef EXTRA_STATISTICS + Reg time_t now; +#endif sp = &tmp; bcopy((char *)ircstp, (char *)sp, sizeof(*sp)); @@ -884,6 +1016,173 @@ sp->is_ni++; } +#ifdef EXTRA_STATISTICS + switch (level) { + case 2: now = timeofday - me.since; + if (now == 0) + now = 1; + + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Current uptime: %4d day%s, %2d:%02d:%02d%s %10d s", + ME, RPL_STATSDEBUG, name, now/86400, ( now/86400 == 1 ? "" : "s"), + (now/3600)%24, (now/60)%60, now%60, ( now/86400 == 1 ? " " : ""), now); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Connected Current Highest Average Total NetHigh", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Clients: %6u %8u %8.1f %8u %8u", + ME, RPL_STATSDEBUG, name, istat.is_myclnt, istat.is_m_myclnt, + (float )((double ) sp->is_cti / (double ) (now)), sp->is_cl, + istat.is_m_users); + if (istat.is_m_myservice != 0) + sendto_one(cptr, + ":%s %d %s :Services: %6u %8u %8u", + ME, RPL_STATSDEBUG, name, istat.is_myservice, + istat.is_m_myservice, istat.is_m_service); + sendto_one(cptr, + ":%s %d %s :Servers: %6u %8u %8.1f %8u %8u", + ME, RPL_STATSDEBUG, name, istat.is_myserv, istat.is_m_myserv, + ((float ) sp->is_sti / (float ) (now)), sp->is_sv, istat.is_m_serv); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Duration Average Total", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Clients: %4d:%02d:%02d %12lu s", + ME, RPL_STATSDEBUG, name, + ((sp->is_cti / (sp->is_cl ? sp->is_cl : 1))/3600), + (((sp->is_cti / (sp->is_cl ? sp->is_cl : 1))/60)%60), + ((sp->is_cti / (sp->is_cl ? sp->is_cl : 1))%60), sp->is_cti); + sendto_one(cptr, + ":%s %d %s :Servers: %4d:%02d:%02d %12lu s", + ME, RPL_STATSDEBUG, name, + ((sp->is_sti / (sp->is_sv ? sp->is_sv : 1))/3600), + (((sp->is_sti / (sp->is_sv ? sp->is_sv : 1))/60)%60), + ((sp->is_sti / (sp->is_sv ? sp->is_sv : 1))%60), sp->is_sti); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Data received Average Rate Total", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Clients: %8lu Kb %6.2f Kb/s %10lu Kb", + ME, RPL_STATSDEBUG, name, (sp->is_ckr / ( sp->is_cl ? sp->is_cl : 1 )), + ((double ) sp->is_ckr / (double ) (now)), sp->is_ckr); + sendto_one(cptr, + ":%s %d %s :Servers: %8lu Kb %6.2f Kb/s %10lu Kb", + ME, RPL_STATSDEBUG, name, + ( sp->is_skr / ( sp->is_sv ? sp->is_sv : 1 )), + (float )((double ) sp->is_skr / (double ) (now)), sp->is_skr); + sendto_one(cptr, + ":%s %d %s :UDP: %8u", + ME, RPL_STATSDEBUG, name, sp->is_udpok); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Data sent Average Rate Total", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Clients: %8lu Kb %6.2f Kb/s %10lu Kb", + ME, RPL_STATSDEBUG, name, (sp->is_cks / (sp->is_cl ? sp->is_cl : 1)), + (float )((double ) sp->is_cks / (double ) (now)), sp->is_cks); + sendto_one(cptr, + ":%s %d %s :Servers: %8lu Kb %6.2f Kb/s %10lu Kb", + ME, RPL_STATSDEBUG, name, (sp->is_sks / (sp->is_sv ? sp->is_sv : 1)), + (float )((double ) sp->is_sks / (double ) (now)), sp->is_sks); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); + return; + + case 1: sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); +#if !defined(USE_IAUTH) + sendto_one(cptr, + ":%s %d %s :Authorization fails: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_abad); + sendto_one(cptr, + ":%s %d %s :Authorization successes: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_asuc); +#endif + sendto_one(cptr, + ":%s %d %s :Connections accepted: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_ac); + sendto_one(cptr, + ":%s %d %s :Connections refused: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_ref); + sendto_one(cptr, + ":%s %d %s :Local connections made: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_loc); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Fakes: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_fake); + sendto_one(cptr, + ":%s %d %s :Nick Collisions: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_kill); + sendto_one(cptr, + ":%s %d %s :Unknown connections dropped: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_ni); + sendto_one(cptr, + ":%s %d %s :Users without servers: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_nosrv); + sendto_one(cptr, + ":%s %d %s :Empty messages: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_empt); + sendto_one(cptr, + ":%s %d %s :Numerics seen: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_num); + sendto_one(cptr, + ":%s %d %s :Unknown commands: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_unco); + sendto_one(cptr, + ":%s %d %s :Unknown prefixes: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_unpf); + sendto_one(cptr, + ":%s %d %s :Wrong directions: %8lu", + ME, RPL_STATSDEBUG, name, sp->is_wrdi); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Elapsed time Minimum Average Maximum Limit", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, + ":%s %d %s :Nick Delay: %8lu %8lu %8lu %8lu", + ME, RPL_STATSDEBUG, name, sp->is_wwmt, + (u_int) (sp->is_wwt / (sp->is_wwcnt ? sp->is_wwcnt : 1 )), + sp->is_wwMt, KILLCHASETIMELIMIT); + sendto_one(cptr, + ":%s %d %s :Whowas: %8lu %8lu %8lu %8lu", + ME, RPL_STATSDEBUG, name, sp->is_lkmt, + (u_int) (sp->is_lkt / (sp->is_lkcnt ? sp->is_lkcnt : 1)), + sp->is_lkMt, DELAYCHASETIMELIMIT); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); +#if defined(USE_IAUTH) + report_iauth_stats(cptr, name); + sendto_one(cptr, + ":%s %d %s :------------------------------------------------------", + ME, RPL_STATSDEBUG, name); +#endif + return; + } +#endif + sendto_one(cptr, ":%s %d %s :accepts %lu refused %lu", ME, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref); sendto_one(cptr, ":%s %d %s :unknown: commands %lu prefixes %lu", @@ -931,6 +1230,13 @@ sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr); sendto_one(cptr, ":%s %d %s :time connected %lu %lu", ME, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti); +#ifdef DELAY_CLOSE + if (IsAnOper(cptr)) + { + sendto_one(cptr, ":%s %d %s :delay closed %lu", + ME,RPL_STATSDEBUG, name, istat.is_delayclosed); + } +#endif #if defined(USE_IAUTH) report_iauth_stats(cptr, name); #endif @@ -986,3 +1292,339 @@ close(fd); } #endif + + +#if defined(OPER_KLINE) || defined(LOCOP_KLINE) +int m_kline(cptr,sptr,parc,parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + +#if defined(OPER_KLINE) && defined(LOCOP_KLINE) + if (!MyClient(sptr) || !IsAnOper(sptr)) +#else +# if defined(OPER_KLINE) + if (!MyClient(sptr) || !IsOper(sptr)) +# else + if (!MyClient(sptr) || !IsLocOp(sptr)) +# endif +#endif + { + sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]), me.name, + parv[0]); + return 0; + } + + return m_dokline(cptr,sptr,parc,parv,1); +} +#endif + + +#if defined(OPER_TKLINE) || defined(LOCOP_TKLINE) +int m_tkline(cptr,sptr,parc,parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + +#if defined(OPER_TKLINE) && defined(LOCOP_TKLINE) + if (!MyClient(sptr) || !IsAnOper(sptr)) +#else +# if defined(OPER_TKLINE) + if (!MyClient(sptr) || !IsOper(sptr)) +# else + if (!MyClient(sptr) || !IsLocOp(sptr)) +# endif +#endif + { + sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]), me.name, + parv[0]); + return 0; + } + + return m_dokline(cptr,sptr,parc,parv,0); +} +#endif + + +#if defined(OPER_KLINE) || defined(LOCOP_KLINE) || \ + defined(OPER_TKLINE) || defined(LOCOP_TKLINE) +extern int kline_added; + +int m_dokline(cptr, sptr, parc, parv, perm) +aClient *cptr, *sptr; +int parc; +char *parv[]; +int perm; +{ + aConfItem *aconf; + aClient *acptr; + int out, i; + char buffer[1024]; + char *user, *host; + char kline_reason[256]; + time_t current_time; + + if (parc < 3) + { + sendto_one(sptr, ":%s NOTICE %s :Not enough parameters", + me.name, parv[0]); + return 0; + } + + if (match("*@*", parv[1])) + { + sendto_one(sptr, + ":%s NOTICE %s :Sorry but \"%s\" needs to be of the format\ + of user@host", me.name, parv[0], parv[1]); + return 0; + } + + user = parv[1]; + while (*user) + { + if ((*user == ' ') || (*user =='#') || +#ifdef INET6 + (*user == '%') +#else + (*user == ':') +#endif + ) + break; + user++; + } + + if (*user && (*user != ' ')) + { + sendto_one(sptr, + ":%s NOTICE %s :The user@host may not contain '%c'", + me.name, parv[0], *user); + return 0; + } + + host = strchr(parv[1], '@'); + *(host++) = '\0'; + + if ((user = strchr(host, ' ')) != NULL) + *user = '\0'; + user = parv[1]; + + if (!match(user, "dummyuser") && !match(host, "dumm.ystring.xx")) + { + sendto_one(sptr, + ":%s NOTICE %s :Sorry can not %skline *@*", + me.name, parv[0], ( perm ? "" : "t" )); + return 0; + } + + kline_reason[0] = '\0'; + if (isdigit(*parv[2])) + { + sendto_one(sptr, + ":%s NOTICE %s :The %skline reason may not start\ + with a digit", + me.name, parv[0], ( perm ? "" : "t" )); + return 0; + } + + for (i = 2; i < parc; i++) + { + if (strlen(parv[i]) + strlen(kline_reason) + 2 < 256) + { + strcat(kline_reason, parv[i]); + strcat(kline_reason, "\240"); + } + } + kline_reason[strlen(kline_reason) - 1] = '\0'; + + for (i = strlen(kline_reason) - 1; i >= 0; i--) + { + if ((kline_reason[i] == '#') || +#ifdef INET6 + (kline_reason[i] == '%') +#else + (kline_reason[i] == ':') +#endif + ) + { + sendto_one(sptr, + ":%s NOTICE %s :The %skline reason may not\ + contain '%c'", + me.name, parv[0], ( perm ? "" : "t" ), + kline_reason[i]); + return 0; + } + } + + aconf = make_conf(); + aconf->status = CONF_KILL; + DupString(aconf->host, host); + DupString(aconf->passwd, kline_reason); + DupString(aconf->name, user); + aconf->port = 0; + Class(aconf) = find_class(0); + aconf->next = kconf; + kconf = aconf; + aconf = NULL; + + kline_added = 1; + rehashed = 1; + + if (perm) + { + if ((out = open(KLINE_FILE, O_WRONLY|O_APPEND))==-1) + { + sendto_one(sptr, + ":%s NOTICE %s :Problem opening server configfile", + me.name, parv[0]); + return 0; + } + + time(¤t_time); + + sprintf(buffer, "# Added by %s (%s@%s) on %s", + sptr->name, sptr->user->username, sptr->user->host, + asctime(localtime(¤t_time))); + if (write(out, buffer, strlen(buffer)) <= 0) + { + sendto_one(sptr, + ":%s NOTICE %s :Problem writing to the configfile", + me.name, parv[0]); + close(out); + return 0; + } + +#ifdef INET6 + sprintf(buffer, "K%%%s%%%s%%%s%%\n\n", host, kline_reason, user); +#else + sprintf(buffer, "K:%s:%s:%s:\n\n", host, kline_reason, user); +#endif + if (write(out, buffer, strlen(buffer)) <= 0) + { + sendto_one(sptr, + ":%s NOTICE %s :Problem writing to the configfile", + me.name, parv[0]); + close(out); + return 0; + } + close(out); + } + + sendto_flag(SCH_LOCAL, "%s added a %skline for %s@%s with reason: %s", + parv[0], ( perm ? "" : "t" ), user, host, kline_reason); + sendto_one(sptr, + ":%s NOTICE %s :Added %skline for %s@%s%s with reason: %s", + me.name, parv[0], ( perm ? "" : "t" ), user, host, + ( perm ? " to the server configfile" : "" ), kline_reason); +#if defined(USE_SYSLOG) && defined(SYSLOG_KLINE) + syslog(LOG_INFO, "%s!%s@%s %skline %s@%s (%s)", + sptr->name, sptr->user->username, sptr->user->host, + ( perm ? "" : "t" ), user, host, kline_reason); +#endif + + + return 0; +} +#endif + +#ifdef EXTRA_STATISTICS +static Link *saved_servers = NULL; +void save_server_max(server,clients) +char *server; +int clients; +{ + Link *lp; + char *servername; + + for (lp = saved_servers; lp ; lp = lp->next) + { + if (!mycmp(lp->value.cp,server)) + { + sendto_flag(SCH_ERROR,"Tried to save server's user maximum for already saved server"); + return; + } + } + + servername = mystrdup(server); + lp = make_link(); + lp->value.cp = servername; + lp->flags = clients; + lp->next = saved_servers; + saved_servers = lp; +} + + +int restore_server_max(server) +char *server; +{ + Link *lp, **curr; + int users = 0; + + for (curr = &saved_servers ; (lp = *curr); curr = &lp->next) + { + if (!mycmp(lp->value.cp,server)) + { + users = lp->flags; + *curr = lp->next; + free_link(lp); + break; + } + } + return users; +} +#endif + +#ifdef SPLIT_HANDLE +void check_split() +{ + if (istat.is_eobservers < SPLIT_SERV || + (istat.is_user[0] + istat.is_user[1] < SPLIT_USERS)) + { + if (!iconf.split) + { + sendto_flag(SCH_NOTICE,"Network split detected, split mode activated"); + } + iconf.split = 1; + } + else + { + if (iconf.split) + { + sendto_flag(SCH_NOTICE,"Network rejoined, split mode deactivated"); +#ifdef DELAY_ACCEPT + if (iconf.caccept == 1) + { + activate_delayed_listeners(); + iconf.caccept = 2; + } +#endif + } + iconf.split = 0; + + } + +} +void bubble_eob(sptr) +aClie