diff --git a/include/config.h b/include/config.h
@@ -162,11 +162,11 @@
(defined(HAVE_POLL) || defined(HAVE_EPOLL) || defined(HAVE_KQUEUE))
/* Have poll/epoll/kqueue and either no --with-maxconnections or
* --with-maxconnections=0, either of which indicates 'automatic' mode.
- * At the time of writing we will try a limit of 8192.
+ * At the time of writing we will try a limit of 16384.
* It will automatically be lowered at boottime if we can only use
* 4096, 2048 or 1024. No problem.
*/
- #define MAXCONNECTIONS 8192
+ #define MAXCONNECTIONS 16384
#elif defined(MAXCONNECTIONS_REQUEST) && (MAXCONNECTIONS_REQUEST >= 1)
/* --with-maxconnections=something */
#define MAXCONNECTIONS MAXCONNECTIONS_REQUEST
diff --git a/include/dynconf.h b/include/dynconf.h
@@ -113,8 +113,9 @@ struct Configuration {
char *restrict_channelmodes;
char *restrict_extendedbans;
char *channel_command_prefix;
- long unknown_flood_bantime;
- long unknown_flood_amount;
+ long handshake_data_flood_amount;
+ long handshake_data_flood_ban_time;
+ int handshake_data_flood_ban_action;
struct ChMode modes_on_join;
int level_on_join;
unsigned char away_count;
@@ -230,8 +231,6 @@ extern MODVAR int ipv6_disabled;
#define THROTTLING_PERIOD iConf.throttle_period
#define THROTTLING_COUNT iConf.throttle_count
#define USE_BAN_VERSION iConf.use_ban_version
-#define UNKNOWN_FLOOD_BANTIME iConf.unknown_flood_bantime
-#define UNKNOWN_FLOOD_AMOUNT iConf.unknown_flood_amount
#define MODES_ON_JOIN iConf.modes_on_join.mode
#define LEVEL_ON_JOIN iConf.level_on_join
@@ -326,8 +325,9 @@ struct SetCheck {
unsigned has_restrict_channelmodes:1;
unsigned has_restrict_extendedbans:1;
unsigned has_channel_command_prefix:1;
- unsigned has_anti_flood_unknown_flood_bantime:1;
- unsigned has_anti_flood_unknown_flood_amount:1;
+ unsigned has_anti_flood_handshake_data_flood_amount:1;
+ unsigned has_anti_flood_handshake_data_flood_ban_action:1;
+ unsigned has_anti_flood_handshake_data_flood_ban_time:1;
unsigned has_modes_on_join:1;
unsigned has_level_on_join:1;
unsigned has_anti_flood_away_count:1;
diff --git a/include/fdlist.h b/include/fdlist.h
@@ -32,18 +32,6 @@ extern int fd_fileopen(const char *path, unsigned int flags);
#define FD_SELECT_READ 0x1
#define FD_SELECT_WRITE 0x2
-/* Socket buffer sizes for clients and servers
- * Note that these have been carefully chosen so you shouldn't touch these.
- * If you make these much higher then be aware that this means you loose
- * send queue / receive queue protection, otherwise known as "Excess flood"
- * and "SendQ Exceeded", since these queues are ON TOP of UnrealIRCd's
- * own queueing mechanism, it uses the OS TCP Socket queue.
- */
-#define USER_SOCKET_RECEIVE_BUFFER 8192
-#define USER_SOCKET_SEND_BUFFER 32768
-#define SERVER_SOCKET_RECEIVE_BUFFER 131072
-#define SERVER_SOCKET_SEND_BUFFER 131072
-
extern void fd_setselect(int fd, int flags, IOCallbackFunc iocb, void *data);
extern void fd_select(time_t delay); /* backend-specific */
extern void fd_refresh(int fd); /* backend-specific */
diff --git a/include/h.h b/include/h.h
@@ -113,7 +113,6 @@ extern void config_error_empty(const char *filename, int line, const char *block
extern void config_warn_duplicate(const char *filename, int line, const char *entry);
extern int config_is_blankorempty(ConfigEntry *cep, const char *block);
extern MODVAR int config_verbose;
-extern void config_progress(FORMAT_STRING(const char *format), ...) __attribute__((format(printf,1,2)));
extern void config_entry_free(ConfigEntry *ce);
extern void config_entry_free_all(ConfigEntry *ce);
extern ConfigFile *config_load(char *filename, char *displayname);
@@ -886,7 +885,6 @@ extern CMD_FUNC(cmd_rehash);
extern CMD_FUNC(cmd_die);
extern CMD_FUNC(cmd_restart);
extern void cmd_alias(Client *client, MessageTag *recv_mtags, int parc, char *parv[], char *cmd); /* special! */
-extern void ban_flooder(Client *cptr);
extern char *pcre2_version(void);
extern int get_terminal_width(void);
extern int has_common_channels(Client *c1, Client *c2);
@@ -1000,3 +998,9 @@ extern void free_security_group(SecurityGroup *s);
extern void set_security_group_defaults(void);
extern int user_allowed_by_security_group(Client *client, SecurityGroup *s);
extern int user_allowed_by_security_group_name(Client *client, char *secgroupname);
+extern void add_nvplist(NameValuePrioList **lst, int priority, char *name, char *value);
+extern void add_fmt_nvplist(NameValuePrioList **lst, int priority, char *name, FORMAT_STRING(const char *format), ...) __attribute__((format(printf,4,5)));
+extern NameValuePrioList *find_nvplist(NameValuePrioList *list, char *name);
+extern void free_nvplist(NameValuePrioList *lst);
+extern char *get_connect_extinfo(Client *client);
+extern char *unreal_strftime(char *str);
diff --git a/include/modules.h b/include/modules.h
@@ -1124,12 +1124,12 @@ extern void SavePersistentLongX(ModuleInfo *modinfo, char *varshortname, long va
#define HOOKTYPE_ACCOUNT_LOGIN 102
/** See hooktype_close_connection() */
#define HOOKTYPE_CLOSE_CONNECTION 103
-
+/** See hooktype_connect_extinfo() */
+#define HOOKTYPE_CONNECT_EXTINFO 104
/* Adding a new hook here?
* 1) Add the #define HOOKTYPE_.... with a new number
* 2) Add a hook prototype (see below)
* 3) Add type checking (even more below)
- * 4) Document the hook at https://www.unrealircd.org/docs/Dev:Hook_API
*/
/* Hook prototypes */
@@ -2056,6 +2056,15 @@ int hooktype_account_login(Client *client, MessageTag *mtags);
*/
int hooktype_close_connection(Client *client);
+/** Called when a user connects to add extra information (function prototype for HOOKTYPE_CONNECT_EXTINFO).
+ * If you want to use this, then use the nvplist_add() or nvplist_add_fmt() function
+ * to add the information to the list. See also get_connect_extinfo() for inspiration.
+ * @param client The client
+ * @param list The name/value/prio list that you can add information to
+ * @return The return value is ignored (use return 0)
+ */
+int hooktype_connect_extinfo(Client *client, NameValuePrioList **list);
+
/** @} */
#ifdef GCC_TYPECHECKING
@@ -2164,7 +2173,8 @@ _UNREAL_ERROR(_hook_error_incompatible, "Incompatible hook function. Check argum
((hooktype == HOOKTYPE_IDENT_LOOKUP) && !ValidateHook(hooktype_ident_lookup, func)) || \
((hooktype == HOOKTYPE_CONFIGRUN_EX) && !ValidateHook(hooktype_configrun_ex, func)) || \
((hooktype == HOOKTYPE_ACCOUNT_LOGIN) && !ValidateHook(hooktype_account_login, func)) || \
- ((hooktype == HOOKTYPE_CLOSE_CONNECTION) && !ValidateHook(hooktype_close_connection, func)) ) \
+ ((hooktype == HOOKTYPE_CLOSE_CONNECTION) && !ValidateHook(hooktype_close_connection, func)) || \
+ ((hooktype == HOOKTYPE_CONNECT_EXTINFO) && !ValidateHook(hooktype_connect_extinfo, func)) ) \
_hook_error_incompatible();
#endif /* GCC_TYPECHECKING */
diff --git a/include/struct.h b/include/struct.h
@@ -321,6 +321,7 @@ typedef enum ClientStatus {
#define CLIENT_FLAG_DCCBLOCK 0x04000000 /**< Block all DCC send requests */
#define CLIENT_FLAG_MAP 0x08000000 /**< Show this entry in /MAP (only used in map module) */
#define CLIENT_FLAG_PINGWARN 0x10000000 /**< Server ping warning (remote server slow with responding to PINGs) */
+#define CLIENT_FLAG_NOHANDSHAKEDELAY 0x20000000 /**< No handshake delay */
/** @} */
#define SNO_DEFOPER "+kscfvGqobS"
@@ -421,6 +422,7 @@ typedef enum ClientStatus {
#define IsOutgoing(x) ((x)->flags & CLIENT_FLAG_OUTGOING)
#define IsPingSent(x) ((x)->flags & CLIENT_FLAG_PINGSENT)
#define IsPingWarning(x) ((x)->flags & CLIENT_FLAG_PINGWARN)
+#define IsNoHandshakeDelay(x) ((x)->flags & CLIENT_FLAG_NOHANDSHAKEDELAY)
#define IsProtoctlReceived(x) ((x)->flags & CLIENT_FLAG_PROTOCTL)
#define IsQuarantined(x) ((x)->flags & CLIENT_FLAG_QUARANTINE)
#define IsShunned(x) ((x)->flags & CLIENT_FLAG_SHUNNED)
@@ -451,6 +453,7 @@ typedef enum ClientStatus {
#define SetOutgoing(x) do { (x)->flags |= CLIENT_FLAG_OUTGOING; } while(0)
#define SetPingSent(x) do { (x)->flags |= CLIENT_FLAG_PINGSENT; } while(0)
#define SetPingWarning(x) do { (x)->flags |= CLIENT_FLAG_PINGWARN; } while(0)
+#define SetNoHandshakeDelay(x) do { (x)->flags |= CLIENT_FLAG_NOHANDSHAKEDELAY; } while(0)
#define SetProtoctlReceived(x) do { (x)->flags |= CLIENT_FLAG_PROTOCTL; } while(0)
#define SetQuarantined(x) do { (x)->flags |= CLIENT_FLAG_QUARANTINE; } while(0)
#define SetShunned(x) do { (x)->flags |= CLIENT_FLAG_SHUNNED; } while(0)
@@ -480,6 +483,7 @@ typedef enum ClientStatus {
#define ClearOutgoing(x) do { (x)->flags &= ~CLIENT_FLAG_OUTGOING; } while(0)
#define ClearPingSent(x) do { (x)->flags &= ~CLIENT_FLAG_PINGSENT; } while(0)
#define ClearPingWarning(x) do { (x)->flags &= ~CLIENT_FLAG_PINGWARN; } while(0)
+#define ClearNoHandshakeDelay(x) do { (x)->flags &= ~CLIENT_FLAG_NOHANDSHAKEDELAY; } while(0)
#define ClearProtoctlReceived(x) do { (x)->flags &= ~CLIENT_FLAG_PROTOCTL; } while(0)
#define ClearQuarantined(x) do { (x)->flags &= ~CLIENT_FLAG_QUARANTINE; } while(0)
#define ClearShunned(x) do { (x)->flags &= ~CLIENT_FLAG_SHUNNED; } while(0)
@@ -876,7 +880,7 @@ typedef void (*OverrideCmdFunc)(CommandOverride *ovr, Client *client, MessageTag
#define TKL_BLACKLIST 0x0001000
#define TKL_CONNECT_FLOOD 0x0002000
#define TKL_MAXPERIP 0x0004000
-#define TKL_UNKNOWN_DATA_FLOOD 0x0008000
+#define TKL_HANDSHAKE_DATA_FLOOD 0x0008000
#define TKL_ANTIRANDOM 0x0010000
#define TKL_ANTIMIXEDUTF8 0x0020000
#define TKL_BAN_VERSION 0x0040000
@@ -1014,6 +1018,21 @@ struct IRCCounts {
/** The /LUSERS stats information */
extern MODVAR IRCCounts irccounts;
+typedef struct NameValueList NameValueList;
+struct NameValueList {
+ NameValueList *prev, *next;
+ char *name;
+ char *value;
+};
+
+typedef struct NameValuePrioList NameValuePrioList;
+struct NameValuePrioList {
+ NameValuePrioList *prev, *next;
+ int priority;
+ char *name;
+ char *value;
+};
+
#include "modules.h"
/** A "real" command (internal interface, not for modules) */
@@ -1176,7 +1195,7 @@ struct User {
Link *invited; /**< Channels has the user been invited to (linked list) */
Link *dccallow; /**< DCCALLOW list (linked list) */
char *away; /**< AWAY message, or NULL if not away */
- char svid[SVIDLEN + 1]; /**< Unique value assigned by services (SVID) */
+ char svid[SVIDLEN + 1]; /**< Services account name or ID (SVID) */
unsigned short joined; /**< Number of channels joined */
char username[USERLEN + 1]; /**< Username, the user portion in nick!user@host. */
char realhost[HOSTLEN + 1]; /**< Realhost, the real host of the user (IP or hostname) - usually this is not shown to other users */
@@ -1230,13 +1249,6 @@ struct MessageTag {
char *value;
};
-typedef struct NameValueList NameValueList;
-struct NameValueList {
- NameValueList *prev, *next;
- char *name;
- char *value;
-};
-
/* conf preprocessor */
typedef enum PreprocessorItem {
PREPROCESSOR_ERROR = 0,
@@ -1387,15 +1399,19 @@ struct ConfigFlag_allow {
unsigned reject_on_auth_failure :1;
};
+/** allow { } block settings */
struct ConfigItem_allow {
- ConfigItem_allow *prev, *next;
- ConfigFlag flag;
- char *ip, *hostname, *server;
- AuthConfig *auth;
- unsigned short maxperip;
- int port;
- ConfigItem_class *class;
- ConfigFlag_allow flags;
+ ConfigItem_allow *prev, *next;
+ ConfigFlag flag;
+ char *ip;
+ char *hostname;
+ char *server;
+ AuthConfig *auth;
+ int maxperip; /**< Maximum connections permitted per IP address (locally) */
+ int global_maxperip; /**< Maximum connections permitted per IP address (globally) */
+ int port;
+ ConfigItem_class *class;
+ ConfigFlag_allow flags;
unsigned short ipv6_clone_mask;
};
@@ -1630,7 +1646,8 @@ struct ConfigItem_allow_dcc {
struct ConfigItem_log {
ConfigItem_log *prev, *next;
ConfigFlag flag;
- char *file;
+ char *file; /**< Filename to log to (either generated or specified) */
+ char *filefmt; /**< Filename with dynamic % stuff */
long maxsize;
int flags;
int logfd;
diff --git a/include/windows/setup.h b/include/windows/setup.h
@@ -63,7 +63,7 @@
#define UNREAL_VERSION_MAJOR 0
/* Minor version number (e.g.: 1 for Unreal3.2.1) */
-#define UNREAL_VERSION_MINOR 8
+#define UNREAL_VERSION_MINOR 9
/* Version suffix such as a beta marker or release candidate marker. (e.g.:
-rcX for unrealircd-3.2.9-rcX) */
diff --git a/src/conf.c b/src/conf.c
@@ -1374,10 +1374,6 @@ void config_error(FORMAT_STRING(const char *format), ...)
va_end(ap);
if ((ptr = strchr(buffer, '\n')) != NULL)
*ptr = '\0';
-#ifdef _WIN32
- if (!loop.ircd_booted)
- win_log("[error] %s", buffer);
-#endif
ircd_log(LOG_ERROR, "config error: %s", buffer);
sendto_realops("error: %s", buffer);
if (remote_rehash_client)
@@ -1437,10 +1433,6 @@ void config_status(FORMAT_STRING(const char *format), ...)
va_end(ap);
if ((ptr = strchr(buffer, '\n')) != NULL)
*ptr = '\0';
-#ifdef _WIN32
- if (!loop.ircd_booted)
- win_log("* %s", buffer);
-#endif
ircd_log(LOG_ERROR, "%s", buffer);
sendto_realops("%s", buffer);
if (remote_rehash_client)
@@ -1458,10 +1450,6 @@ void config_warn(FORMAT_STRING(const char *format), ...)
va_end(ap);
if ((ptr = strchr(buffer, '\n')) != NULL)
*ptr = '\0';
-#ifdef _WIN32
- if (!loop.ircd_booted)
- win_log("[warning] %s", buffer);
-#endif
ircd_log(LOG_ERROR, "[warning] %s", buffer);
sendto_realops("[warning] %s", buffer);
if (remote_rehash_client)
@@ -1556,24 +1544,6 @@ int config_test_openfile(ConfigEntry *cep, int flags, mode_t mode, const char *e
return 0;
}
-void config_progress(FORMAT_STRING(const char *format), ...)
-{
- va_list ap;
- char buffer[1024];
- char *ptr;
-
- va_start(ap, format);
- vsnprintf(buffer, 1023, format, ap);
- va_end(ap);
- if ((ptr = strchr(buffer, '\n')) != NULL)
- *ptr = '\0';
-#ifdef _WIN32
- if (!loop.ircd_booted)
- win_log("* %s", buffer);
-#endif
- sendto_realops("%s", buffer);
-}
-
int config_is_blankorempty(ConfigEntry *cep, const char *block)
{
if (!cep->ce_vardata)
@@ -1655,8 +1625,9 @@ void config_setdefaultsettings(Configuration *i)
{
char tmp[512];
- i->unknown_flood_amount = 4;
- i->unknown_flood_bantime = 600;
+ i->handshake_data_flood_amount = 4096;
+ i->handshake_data_flood_ban_action = BAN_ACT_ZLINE;
+ i->handshake_data_flood_ban_time = 600;
safe_strdup(i->oper_snomask, SNO_DEFOPER);
i->ident_read_timeout = 7;
i->ident_connect_timeout = 3;
@@ -5333,6 +5304,8 @@ int _conf_allow(ConfigFile *conf, ConfigEntry *ce)
}
else if (!strcmp(cep->ce_varname, "maxperip"))
allow->maxperip = atoi(cep->ce_vardata);
+ else if (!strcmp(cep->ce_varname, "global-maxperip"))
+ allow->global_maxperip = atoi(cep->ce_vardata);
else if (!strcmp(cep->ce_varname, "redirect-server"))
safe_strdup(allow->server, cep->ce_vardata);
else if (!strcmp(cep->ce_varname, "redirect-port"))
@@ -5368,6 +5341,14 @@ int _conf_allow(ConfigFile *conf, ConfigEntry *ce)
if (!allow->ip)
safe_strdup(allow->ip, "*@NOMATCH");
+ /* Default: global-maxperip = maxperip+1 */
+ if (allow->global_maxperip == 0)
+ allow->global_maxperip = allow->maxperip+1;
+
+ /* global-maxperip < maxperip makes no sense */
+ if (allow->global_maxperip < allow->maxperip)
+ allow->global_maxperip = allow->maxperip;
+
AddListItem(allow, conf_allow);
return 1;
}
@@ -5377,7 +5358,7 @@ int _test_allow(ConfigFile *conf, ConfigEntry *ce)
ConfigEntry *cep, *cepp;
int errors = 0;
Hook *h;
- char has_ip = 0, has_hostname = 0, has_maxperip = 0, has_password = 0, has_class = 0;
+ char has_ip = 0, has_hostname = 0, has_maxperip = 0, has_global_maxperip = 0, has_password = 0, has_class = 0;
char has_redirectserver = 0, has_redirectport = 0, has_options = 0;
int hostname_possible_silliness = 0;
@@ -5450,9 +5431,26 @@ int _test_allow(ConfigFile *conf, ConfigEntry *ce)
continue;
}
has_maxperip = 1;
- if ((v <= 0) || (v > 65535))
+ if ((v <= 0) || (v > 1000000))
{
- config_error("%s:%i: allow::maxperip with illegal value (must be 1-65535)",
+ config_error("%s:%i: allow::maxperip with illegal value (must be 1-1000000)",
+ cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
+ errors++;
+ }
+ }
+ else if (!strcmp(cep->ce_varname, "global-maxperip"))
+ {
+ int v = atoi(cep->ce_vardata);
+ if (has_global_maxperip)
+ {
+ config_warn_duplicate(cep->ce_fileptr->cf_filename,
+ cep->ce_varlinenum, "allow::global-maxperip");
+ continue;
+ }
+ has_global_maxperip = 1;
+ if ((v <= 0) || (v > 1000000))
+ {
+ config_error("%s:%i: allow::global-maxperip with illegal value (must be 1-1000000)",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
errors++;
}
@@ -6096,7 +6094,10 @@ int _conf_log(ConfigFile *conf, ConfigEntry *ce)
ca = safe_alloc(sizeof(ConfigItem_log));
ca->logfd = -1;
- safe_strdup(ca->file, ce->ce_vardata);
+ if (strchr(ce->ce_vardata, '%'))
+ safe_strdup(ca->filefmt, ce->ce_vardata);
+ else
+ safe_strdup(ca->file, ce->ce_vardata);
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
@@ -6122,6 +6123,7 @@ int _test_log(ConfigFile *conf, ConfigEntry *ce) {
int fd, errors = 0;
ConfigEntry *cep, *cepp;
char has_flags = 0, has_maxsize = 0;
+ char *fname;
if (!ce->ce_vardata)
{
@@ -6192,21 +6194,25 @@ int _test_log(ConfigFile *conf, ConfigEntry *ce) {
continue;
}
}
+
if (!has_flags)
{
config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
"log::flags");
errors++;
}
- if ((fd = fd_fileopen(ce->ce_vardata, O_WRONLY|O_CREAT)) == -1)
+
+ fname = unreal_strftime(ce->ce_vardata);
+ if ((fd = fd_fileopen(fname, O_WRONLY|O_CREAT)) == -1)
{
config_error("%s:%i: Couldn't open logfile (%s) for writing: %s",
ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
- ce->ce_vardata, strerror(errno));
+ fname, strerror(errno));
errors++;
- }
- else
+ } else
+ {
fd_close(fd);
+ }
return errors;
}
@@ -6622,7 +6628,7 @@ int _conf_ban(ConfigFile *conf, ConfigEntry *ce)
else if (!strcmp(cep->ce_varname, "reason"))
safe_strdup(ca->reason, cep->ce_vardata);
else if (!strcmp(cep->ce_varname, "action"))
- ca ->action = banact_stringtoval(cep->ce_vardata);
+ ca->action = banact_stringtoval(cep->ce_vardata);
}
AddListItem(ca, conf_ban);
return 0;
@@ -7498,11 +7504,20 @@ int _conf_set(ConfigFile *conf, ConfigEntry *ce)
}
}
else if (!strcmp(cep->ce_varname, "anti-flood")) {
- for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
- if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
- tempiConf.unknown_flood_bantime = config_checkval(cepp->ce_vardata,CFG_TIME);
- else if (!strcmp(cepp->ce_varname, "unknown-flood-amount"))
- tempiConf.unknown_flood_amount = atol(cepp->ce_vardata);
+ for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
+ {
+ if (!strcmp(cepp->ce_varname, "handshake-data-flood"))
+ {
+ for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
+ {
+ if (!strcmp(ceppp->ce_varname, "amount"))
+ tempiConf.handshake_data_flood_amount = config_checkval(ceppp->ce_vardata, CFG_SIZE);
+ else if (!strcmp(ceppp->ce_varname, "ban-time"))
+ tempiConf.handshake_data_flood_ban_time = config_checkval(ceppp->ce_vardata, CFG_TIME);
+ else if (!strcmp(ceppp->ce_varname, "ban-action"))
+ tempiConf.handshake_data_flood_ban_action = banact_stringtoval(ceppp->ce_vardata);
+ }
+ }
else if (!strcmp(cepp->ce_varname, "away-count"))
tempiConf.away_count = atol(cepp->ce_vardata);
else if (!strcmp(cepp->ce_varname, "away-period"))
@@ -8321,8 +8336,10 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
need_34_upgrade = 1;
continue;
}
- else if (!strcmp(cep->ce_varname, "anti-flood")) {
- for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
+ else if (!strcmp(cep->ce_varname, "anti-flood"))
+ {
+ for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
+ {
if (!strcmp(cepp->ce_varname, "max-concurrent-conversations"))
{
for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
@@ -8359,15 +8376,56 @@ int _test_set(ConfigFile *conf, ConfigEntry *ce)
}
continue; /* required here, due to checknull directly below */
}
- if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
+ else if (!strcmp(cepp->ce_varname, "unknown-flood-amount") ||
+ !strcmp(cepp->ce_varname, "unknown-flood-bantime"))
{
- CheckNull(cepp);
- CheckDuplicate(cepp, anti_flood_unknown_flood_bantime, "anti-flood::unknown-flood-bantime");
+ config_error("%s:%i: set::anti-flood::%s: this setting has been moved. "
+ "See https://www.unrealircd.org/docs/Set_block#set::anti-flood::handshake-data-flood",
+ cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname);
+ errors++;
+ continue;
}
- else if (!strcmp(cepp->ce_varname, "unknown-flood-amount"))
+ else if (!strcmp(cepp->ce_varname, "handshake-data-flood"))
{
- CheckNull(cepp);
- CheckDuplicate(cepp, anti_flood_unknown_flood_amount, "anti-flood::unknown-flood-amount");
+ for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
+ {
+ if (!strcmp(ceppp->ce_varname, "amount"))
+ {
+ long v;
+ CheckNull(ceppp);
+ CheckDuplicate(ceppp, anti_flood_handshake_data_flood_amount, "anti-flood::handshake-data-flood::amount");
+ v = config_checkval(ceppp->ce_vardata, CFG_SIZE);
+ if (v < 1024)
+ {
+ config_error("%s:%i: set::anti-flood::handshake-data-flood::amount must be at least 1024 bytes",
+ ceppp->ce_fileptr->cf_filename, ceppp->ce_varlinenum);
+ errors++;
+ }
+ } else
+ if (!strcmp(ceppp->ce_varname, "ban-action"))
+ {
+ CheckNull(ceppp);
+ CheckDuplicate(ceppp, anti_flood_handshake_data_flood_ban_action, "anti-flood::handshake-data-flood::ban-action");
+ if (!banact_stringtoval(ceppp->ce_vardata))
+ {
+ config_error("%s:%i: set::anti-flood::handshake-data-flood::ban-action has unknown action type '%s'",
+ ceppp->ce_fileptr->cf_filename, ceppp->ce_varlinenum,
+ ceppp->ce_vardata);
+ errors++;
+ }
+ } else
+ if (!strcmp(ceppp->ce_varname, "ban-time"))
+ {
+ CheckNull(ceppp);
+ CheckDuplicate(ceppp, anti_flood_handshake_data_flood_ban_time, "anti-flood::handshake-data-flood::ban-time");
+ } else
+ {
+ config_error_unknownopt(ceppp->ce_fileptr->cf_filename,
+ ceppp->ce_varlinenum, "set::anti-flood::handshake-data-flood",
+ ceppp->ce_varname);
+ errors++;
+ }
+ }
}
else if (!strcmp(cepp->ce_varname, "away-count"))
{
diff --git a/src/crashreport.c b/src/crashreport.c
@@ -292,7 +292,7 @@ int crash_report_asan_log(FILE *reportfd, char *coredump)
coretime = get_file_time(coredump);
asantime = get_file_time(asan_log);
- fprintf(reportfd, "ASan log file found '%s' which is %ld newer than core file\n",
+ fprintf(reportfd, "ASan log file found '%s' which is %ld seconds older than core file\n",
asan_log,
(long)((long)(coretime) - (long)asantime));
@@ -719,6 +719,15 @@ void mark_coredump_as_read(char *coredump)
static int report_pref = REPORT_ASK;
+void report_crash_not_sent(char *fname)
+{
+ printf("Crash report will not be sent to UnrealIRCd Team.\n"
+ "\n"
+ "Feel free to read the report at %s and delete it.\n"
+ "Or, if you change your mind, you can submit it anyway at https://bugs.unrealircd.org/\n"
+ " (if you do, please set the option 'View Status' at the end of the bug report page to 'private'!!)\n", fname);
+}
+
void report_crash(void)
{
char *coredump, *fname;
@@ -761,8 +770,8 @@ void report_crash(void)
if (report_pref == REPORT_NEVER)
{
- printf("Crash report will not be sent to UnrealIRCd Team.\n\n");
- printf("Feel free to read the report at %s and if you change your mind you can submit it anyway at https://bugs.unrealircd.org/\n", fname);
+ report_crash_not_sent(fname);
+ return;
} else
if (report_pref == REPORT_ASK)
{
@@ -780,8 +789,7 @@ void report_crash(void)
if (answer && (toupper(*answer) == 'N'))
{
- printf("Ok, not sending bug report.\n\n");
- printf("Feel free to read the report at %s and if you change your mind you can submit it anyway at https://bugs.unrealircd.org/\n", fname);
+ report_crash_not_sent(fname);
return;
}
if (answer && (toupper(*answer) == 'Y'))
diff --git a/src/ircd.c b/src/ircd.c
@@ -1120,6 +1120,19 @@ int InitUnrealIRCd(int argc, char *argv[])
generate_cloakkeys();
exit(0);
#endif
+ case 'K':
+ {
+ char *p = NULL;
+ if (chdir(TMPDIR) < 0)
+ {
+ fprintf(stderr, "Could not change to directory '%s'\n", TMPDIR);
+ exit(1);
+ }
+ fprintf(stderr, "Starting crash test!\n");
+ *p = 'a';
+ fprintf(stderr, "It is impossible to get here\n");
+ exit(0);
+ }
case 'U':
if (chdir(CONFDIR) < 0)
{
diff --git a/src/list.c b/src/list.c
@@ -244,11 +244,6 @@ Server *make_server(Client *client)
del_from_id_hash_table(client->id, client);
*client->id = '\0';
}
- if (MyConnect(client) && (client->local->fd >= 0))
- {
- /* Give servers a large socket buffer for performance */
- set_socket_buffers(client->local->fd, SERVER_SOCKET_RECEIVE_BUFFER, SERVER_SOCKET_SEND_BUFFER);
- }
return client->serv;
}
@@ -550,7 +545,7 @@ NameList *find_name_list(NameList *list, char *name)
return NULL;
}
-/** Find an entry in a NameList by running match_simpl() on it.
+/** Find an entry in a NameList by running match_simple() on it.
* @ingroup ListFunctions
*/
NameList *find_name_list_match(NameList *list, char *name)
@@ -567,3 +562,52 @@ NameList *find_name_list_match(NameList *list, char *name)
return NULL;
}
+void add_nvplist(NameValuePrioList **lst, int priority, char *name, char *value)
+{
+ va_list vl;
+ NameValuePrioList *e = safe_alloc(sizeof(NameValuePrioList));
+ safe_strdup(e->name, name);
+ if (value && *value)
+ safe_strdup(e->value, value);
+ AddListItemPrio(e, *lst, priority);
+}
+
+NameValuePrioList *find_nvplist(NameValuePrioList *list, char *name)
+{
+ NameValuePrioList *e;
+
+ for (e = list; e; e = e->next)
+ {
+ if (!strcasecmp(e->name, name))
+ {
+ return e;
+ }
+ }
+ return NULL;
+}
+
+void add_fmt_nvplist(NameValuePrioList **lst, int priority, char *name, FORMAT_STRING(const char *format), ...)
+{
+ char value[512];
+ va_list vl;
+ *value = '\0';
+ if (format)
+ {
+ va_start(vl, format);
+ vsnprintf(value, sizeof(value), format, vl);
+ va_end(vl);
+ }
+ add_nvplist(lst, priority, name, value);
+}
+
+void free_nvplist(NameValuePrioList *lst)
+{
+ NameValuePrioList *e, *e_next;
+ for (e = lst; e; e = e_next)
+ {
+ e_next = e->next;
+ safe_free(e->name);
+ safe_free(e->value);
+ safe_free(e);
+ }
+}
diff --git a/src/misc.c b/src/misc.c
@@ -137,7 +137,13 @@ void ircd_log(int flags, FORMAT_STRING(const char *format), ...)
strlcat(buf, "\n", sizeof(buf));
if (!loop.ircd_forked && (flags & LOG_ERROR))
+ {
+#ifdef _WIN32
+ win_log("* %s", buf);
+#else
fprintf(stderr, "%s", buf);
+#endif
+ }
/* In case of './unrealircd configtest': don't write to log file, only to stderr */
if (loop.config_test)
@@ -146,83 +152,66 @@ void ircd_log(int flags, FORMAT_STRING(const char *format), ...)
return;
}
- for (logs = conf_log; logs; logs = logs->next) {
+ for (logs = conf_log; logs; logs = logs->next)
+ {
+ if (!(logs->flags & flags))
+ continue;
+
#ifdef HAVE_SYSLOG
- if (!strcasecmp(logs->file, "syslog") && logs->flags & flags) {
+ if (logs->file && !strcasecmp(logs->file, "syslog"))
+ {
syslog(LOG_INFO, "%s", buf);
written++;
continue;
}
#endif
- if (logs->flags & flags)
+
+ /* This deals with dynamic log file names, such as ircd.%Y-%m-%d.log */
+ if (logs->filefmt)
{
- if (stat(logs->file, &fstats) != -1 && logs->maxsize && fstats.st_size >= logs->maxsize)
+ char *fname = unreal_strftime(logs->filefmt);
+ if (logs->file && (logs->logfd != -1) && strcmp(logs->file, fname))
{
- char oldlog[512];
- if (logs->logfd == -1)
- {
- /* Try to open, so we can write the 'Max file size reached' message. */
-#ifndef _WIN32
- logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY);
-#else
- logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY);
-#endif
- }
- if (logs->logfd != -1)
- {
- if (write(logs->logfd, "Max file size reached, starting new log file\n", 45) < 0)
- {
- /* We already handle the unable to write to log file case for normal data.
- * I think we can get away with not handling this one.
- */
- ;
- }
- fd_close(logs->logfd);
- }
-
- /* Rename log file to xxxxxx.old */
- snprintf(oldlog, sizeof(oldlog), "%s.old", logs->file);
- rename(logs->file, oldlog);
-
- logs->logfd = fd_fileopen(logs->file, O_CREAT|O_WRONLY|O_TRUNC);
- if (logs->logfd == -1)
- continue;
+ /* We are logging already and need to switch over */
+ fd_close(logs->logfd);
+ logs->logfd = -1;
}
- else if (logs->logfd == -1) {
-#ifndef _WIN32
- logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY);
-#else
- logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY);
-#endif
- if (logs->logfd == -1)
- {
- if (!loop.ircd_booted)
- {
- config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO));
- } else {
- if (last_log_file_warning + 300 < TStime())
- {
- config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO));
- last_log_file_warning = TStime();
- }
- }
- continue;
- }
- }
- /* this shouldn't happen, but lets not waste unnecessary syscalls... */
+ safe_strdup(logs->file, fname);
+ }
+
+ /* log::maxsize code */
+ if (logs->maxsize && (stat(logs->file, &fstats) != -1) && fstats.st_size >= logs->maxsize)
+ {
+ char oldlog[512];
if (logs->logfd == -1)
- continue;
- if (write(logs->logfd, timebuf, strlen(timebuf)) < 0)
{
- /* Let's ignore any write errors for this one. Next write() will catch it... */
- ;
+ /* Try to open, so we can write the 'Max file size reached' message. */
+ logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY);
}
- n = write(logs->logfd, buf, strlen(buf));
- if (n == strlen(buf))
+ if (logs->logfd != -1)
{
- written++;
+ if (write(logs->logfd, "Max file size reached, starting new log file\n", 45) < 0)
+ {
+ /* We already handle the unable to write to log file case for normal data.
+ * I think we can get away with not handling this one.
+ */
+ ;
+ }
+ fd_close(logs->logfd);
}
- else
+ logs->logfd = -1;
+
+ /* Rename log file to xxxxxx.old */
+ snprintf(oldlog, sizeof(oldlog), "%s.old", logs->file);
+ unlink(oldlog); /* windows rename cannot overwrite, so unlink here.. ;) */
+ rename(logs->file, oldlog);
+ }
+
+ /* generic code for opening log if not open yet.. */
+ if (logs->logfd == -1)
+ {
+ logs->logfd = fd_fileopen(logs->file, O_CREAT|O_APPEND|O_WRONLY);
+ if (logs->logfd == -1)
{
if (!loop.ircd_booted)
{
@@ -234,6 +223,32 @@ void ircd_log(int flags, FORMAT_STRING(const char *format), ...)
last_log_file_warning = TStime();
}
}
+ continue;
+ }
+ }
+
+ /* Now actually WRITE to the log... */
+ if (write(logs->logfd, timebuf, strlen(timebuf)) < 0)
+ {
+ /* Let's ignore any write errors for this one. Next write() will catch it... */
+ ;
+ }
+ n = write(logs->logfd, buf, strlen(buf));
+ if (n == strlen(buf))
+ {
+ written++;
+ }
+ else
+ {
+ if (!loop.ircd_booted)
+ {
+ config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO));
+ } else {
+ if (last_log_file_warning + 300 < TStime())
+ {
+ config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO));
+ last_log_file_warning = TStime();
+ }
}
}
}
@@ -754,14 +769,14 @@ void exit_client(Client *client, MessageTag *recv_mtags, char *comment)
hash_del_watch_list(client);
on_for = TStime() - client->local->firsttime;
if (IsHidden(client))
- ircd_log(LOG_CLIENT, "Disconnect - (%lld:%lld:%lld) %s!%s@%s [VHOST %s] (%s)",
+ ircd_log(LOG_CLIENT, "Disconnect - (%lld:%lld:%lld) %s!%s@%s [%s] [vhost: %s] (%s)",
on_for / 3600, (on_for % 3600) / 60, on_for % 60,
client->name, client->user->username,
- client->user->realhost, client->user->virthost, comment);
+ client->user->realhost, GetIP(client), client->user->virthost, comment);
else
- ircd_log(LOG_CLIENT, "Disconnect - (%lld:%lld:%lld) %s!%s@%s (%s)",
+ ircd_log(LOG_CLIENT, "Disconnect - (%lld:%lld:%lld) %s!%s@%s [%s] (%s)",
on_for / 3600, (on_for % 3600) / 60, on_for % 60,
- client->name, client->user->username, client->user->realhost, comment);
+ client->name, client->user->username, client->user->realhost, GetIP(client), comment);
} else
if (IsUnknown(client))
{
diff --git a/src/modules/blacklist.c b/src/modules/blacklist.c
@@ -558,9 +558,15 @@ int blacklist_start_check(Client *client)
{
Blacklist *bl;
- /* If the user is on 'except blacklist' then don't bother checking... */
if (find_tkl_exception(TKL_BLACKLIST, client))
+ {
+ /* If the user is exempt from DNSBL checking then:
+ * 1) Don't bother checking DNSBL's
+ * 2) Disable handshake delay for this user, since it serves no purpose.
+ */
+ SetNoHandshakeDelay(client);
return 0;
+ }
if (!BLUSER(client))
{
diff --git a/src/modules/chanmodes/floodprot.c b/src/modules/chanmodes/floodprot.c
@@ -45,6 +45,28 @@ struct {
long modef_boot_delay;
} cfg;
+typedef struct FloodType {
+ char letter;
+ int index;
+ char *description;
+ char default_action;
+ char *actions;
+ int timedban_required;
+} FloodType;
+
+/* All the floodtypes that are tracked.
+ * IMPORTANT: MUST be in alphabetic order!!
+ */
+FloodType floodtypes[] = {
+ { 'c', FLD_CTCP, "CTCPflood", 'C', "mM", 0, },
+ { 'j', FLD_JOIN, "joinflood", 'i', "R", 0, },
+ { 'k', FLD_KNOCK, "knockflood", 'K', "", 0, },
+ { 'm', FLD_MSG, "msg/noticeflood", 'm', "M", 0, },
+ { 'n', FLD_NICK, "nickflood", 'N', "", 0, },
+ { 't', FLD_TEXT, "msg/noticeflood", '\0', "bd", 1, },
+ { 'r', FLD_REPEAT, "repeating", '\0', "bd", 1, },
+};
+
#define MODEF_DEFAULT_UNSETTIME cfg.modef_default_unsettime
#define MODEF_MAX_UNSETTIME cfg.modef_max_unsettime
#define MODEF_BOOT_DELAY cfg.modef_boot_delay
@@ -102,9 +124,9 @@ void floodprottimer_del(Channel *channel, char mflag);
void floodprottimer_stopchantimers(Channel *channel);
static inline char *chmodefstrhelper(char *buf, char t, char tdef, unsigned short l, unsigned char a, unsigned char r);
static int compare_floodprot_modes(ChannelFloodProtection *a, ChannelFloodProtection *b);
-static int do_floodprot(Channel *channel, int what);
+static int do_floodprot(Channel *channel, Client *client, int what);
char *channel_modef_string(ChannelFloodProtection *x, char *str);
-void do_floodprot_action(Channel *channel, int what, char *text);
+void do_floodprot_action(Channel *channel, int what);
void floodprottimer_add(Channel *channel, char mflag, time_t when);
uint64_t gen_floodprot_msghash(char *text);
int cmodef_is_ok(Client *client, Channel *channel, char mode, char *para, int type, int what);
@@ -299,6 +321,26 @@ int floodprot_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
return 1;
}
+FloodType *find_floodprot_by_letter(char c)
+{
+ int i;
+ for (i=0; i < ARRAY_SIZEOF(floodtypes); i++)
+ if (floodtypes[i].letter == c)
+ return &floodtypes[i];
+
+ return NULL;
+}
+
+FloodType *find_floodprot_by_index(int index)
+{
+ int i;
+ for (i=0; i < ARRAY_SIZEOF(floodtypes); i++)
+ if (floodtypes[i].index == index)
+ return &floodtypes[i];
+
+ return NULL;
+}
+
int cmodef_is_ok(Client *client, Channel *channel, char mode, char *param, int type, int what)
{
if ((type == EXCHK_ACCESS) || (type == EXCHK_ACCESS_ERR))
@@ -316,6 +358,8 @@ int cmodef_is_ok(Client *client, Channel *channel, char mode, char *param, int t
int v;
unsigned short warnings = 0, breakit;
unsigned char r;
+ FloodType *floodtype;
+ int index;
memset(&newf, 0, sizeof(newf));
@@ -338,24 +382,21 @@ int cmodef_is_ok(Client *client, Channel *channel, char mode, char *param, int t
/* <number><1 letter>[optional: '#'+1 letter] */
p = x;
while(isdigit(*p)) { p++; }
- if ((*p == '\0') ||
- !((*p == 'c') || (*p == 'j') || (*p == 'k') ||
- (*p == 'm') || (*p == 'n') || (*p == 't') ||
- (*p == 'r')))
+ c = *p;
+ floodtype = find_floodprot_by_letter(c);
+ if (!floodtype)
{
if (MyUser(client) && *p && (warnings++ < 3))
sendnotice(client, "warning: channelmode +f: floodtype '%c' unknown, ignored.", *p);
continue; /* continue instead of break for forward compatability. */
}
- c = *p;
*p = '\0';
v = atoi(x);
if ((v < 1) || (v > 999)) /* out of range... */
{
if (MyUser(client))
{
- sendnumeric(client, ERR_CANNOTCHANGECHANMODE,
- 'f', "value should be from 1-999");
+ sendnumeric(client, ERR_CANNOTCHANGECHANMODE, 'f', "value should be from 1-999");
goto invalidsyntax;
} else
continue; /* just ignore for remote servers */
@@ -383,59 +424,14 @@ int cmodef_is_ok(Client *client, Channel *channel, char mode, char *param, int t
}
}
- switch(c)
- {
- case 'c':
- newf.limit[FLD_CTCP] = v;
- if ((a == 'm') || (a == 'M'))
- newf.action[FLD_CTCP] = a;
- else
- newf.action[FLD_CTCP] = 'C';
- newf.remove_after[FLD_CTCP] = r;
- break;
- case 'j':
- newf.limit[FLD_JOIN] = v;
- if (a == 'R')
- newf.action[FLD_JOIN] = a;
- else
- newf.action[FLD_JOIN] = 'i';
- newf.remove_after[FLD_JOIN] = r;
- break;
- case 'k':
- newf.limit[FLD_KNOCK] = v;
- newf.action[FLD_KNOCK] = 'K';
- newf.remove_after[FLD_KNOCK] = r;
- break;
- case 'm':
- newf.limit[FLD_MSG] = v;
- if (a == 'M')
- newf.action[FLD_MSG] = a;
- else
- newf.action[FLD_MSG] = 'm';
- newf.remove_after[FLD_MSG] = r;
- break;
- case 'n':
- newf.limit[FLD_NICK] = v;
- newf.action[FLD_NICK] = 'N';
- newf.remove_after[FLD_NICK] = r;
- break;
- case 't':
- newf.limit[FLD_TEXT] = v;
- if (a == 'b' || a == 'd')
- newf.action[FLD_TEXT] = a;
- if (timedban_available)
- newf.remove_after[FLD_TEXT] = r;
- break;
- case 'r':
- newf.limit[FLD_REPEAT] = v;
- if (a == 'b' || a == 'd')
- newf.action[FLD_REPEAT] = a;
- if (timedban_available)
- newf.remove_after[FLD_REPEAT] = r;
- break;
- default:
- goto invalidsyntax;
- }
+ index = floodtype->index;
+ newf.limit[index] = v;
+ if (a && strchr(floodtype->actions, a))
+ newf.action[index] = a;
+ else
+ newf.action[index] = floodtype->default_action;
+ if (!floodtype->timedban_required || (floodtype->timedban_required && timedban_available))
+ newf.remove_after[index] = r;
} /* for */
/* parse 'per' */
p2++;
@@ -448,8 +444,7 @@ int cmodef_is_ok(Client *client, Channel *channel, char mode, char *param, int t
if ((v < 1) || (v > 999)) /* 'per' out of range */
{
if (MyUser(client))
- sendnumeric(client, ERR_CANNOTCHANGECHANMODE, 'f',
- "time range should be 1-999");
+ sendnumeric(client, ERR_CANNOTCHANGECHANMODE, 'f', "time range should be 1-999");
goto invalidsyntax;
}
newf.per = v;
@@ -479,14 +474,13 @@ void *cmodef_put_param(void *fld_in, char *param)
int v;
unsigned short breakit;
unsigned char r;
+ FloodType *floodtype;
+ int index;
strlcpy(xbuf, param, sizeof(xbuf));
if (!fld)
- {
- /* Need to create one */
fld = safe_alloc(sizeof(ChannelFloodProtection));
- }
/* always reset settings (l, a, r) */
for (v=0; v < NUMFLD; v++)
@@ -499,31 +493,21 @@ void *cmodef_put_param(void *fld_in, char *param)
/* '['<number><1 letter>[optional: '#'+1 letter],[next..]']'':'<number> */
p2 = strchr(xbuf+1, ']');
if (!p2)
- {
- memset(fld, 0, sizeof(ChannelFloodProtection));
- return fld; /* FAIL */
- }
+ goto fail_cmodef_put_param; /* FAIL */
*p2 = '\0';
if (*(p2+1) != ':')
- {
- memset(fld, 0, sizeof(ChannelFloodProtection));
- return fld; /* FAIL */
- }
+ goto fail_cmodef_put_param; /* FAIL */
+
breakit = 0;
for (x = strtok(xbuf+1, ","); x; x = strtok(NULL, ","))
{
/* <number><1 letter>[optional: '#'+1 letter] */
p = x;
while(isdigit(*p)) { p++; }
- if ((*p == '\0') ||
- !((*p == 'c') || (*p == 'j') || (*p == 'k') ||
- (*p == 'm') || (*p == 'n') || (*p == 't') ||
- (*p == 'r')))
- {
- /* (unknown type) */
- continue; /* continue instead of break for forward compatability. */
- }
c = *p;
+ floodtype = find_floodprot_by_letter(c);
+ if (!floodtype)
+ continue; /* continue instead of break for forward compatability. */
*p = '\0';
v = atoi(x);
if (v < 1)
@@ -549,78 +533,28 @@ void *cmodef_put_param(void *fld_in, char *param)
}
}
- switch(c)
- {
- case 'c':
- fld->limit[FLD_CTCP] = v;
- if ((a == 'm') || (a == 'M'))
- fld->action[FLD_CTCP] = a;
- else
- fld->action[FLD_CTCP] = 'C';
- fld->remove_after[FLD_CTCP] = r;
- break;
- case 'j':
- fld->limit[FLD_JOIN] = v;
- if (a == 'R')
- fld->action[FLD_JOIN] = a;
- else
- fld->action[FLD_JOIN] = 'i';
- fld->remove_after[FLD_JOIN] = r;
- break;
- case 'k':
- fld->limit[FLD_KNOCK] = v;
- fld->action[FLD_KNOCK] = 'K';
- fld->remove_after[FLD_KNOCK] = r;
- break;
- case 'm':
- fld->limit[FLD_MSG] = v;
- if (a == 'M')
- fld->action[FLD_MSG] = a;
- else
- fld->action[FLD_MSG] = 'm';
- fld->remove_after[FLD_MSG] = r;
- break;
- case 'n':
- fld->limit[FLD_NICK] = v;
- fld->action[FLD_NICK] = 'N';
- fld->remove_after[FLD_NICK] = r;
- break;
- case 't':
- fld->limit[FLD_TEXT] = v;
- if (a == 'b' || a == 'd')
- fld->action[FLD_TEXT] = a;
- if (timedban_available)
- fld->remove_after[FLD_TEXT] = r;
- break;
- case 'r':
- fld->limit[FLD_REPEAT] = v;
- if (a == 'b' || a == 'd')
- fld->action[FLD_REPEAT] = a;
- if (timedban_available)
- fld->remove_after[FLD_REPEAT] = r;
- break;
- default:
- /* NOOP */
- break;
- }
+ index = floodtype->index;
+ fld->limit[index] = v;
+ if (a && strchr(floodtype->actions, a))
+ fld->action[index] = a;
+ else
+ fld->action[index] = floodtype->default_action;
+ if (!floodtype->timedban_required || (floodtype->timedban_required && timedban_available))
+ fld->remove_after[index] = r;
} /* for */
+
/* parse 'per' */
p2++;
if (*p2 != ':')
- {
- memset(fld, 0, sizeof(ChannelFloodProtection));
- return fld; /* FAIL */
- }
+ goto fail_cmodef_put_param; /* FAIL */
p2++;
if (!*p2)
- {
- memset(fld, 0, sizeof(ChannelFloodProtection));
- return fld; /* FAIL */
- }
+ goto fail_cmodef_put_param; /* FAIL */
v = atoi(p2);
if (v < 1)
v = 1;
- /* if new 'per xxx seconds' is smaller than current 'per' then reset timers/counters (t, c) */
+
+ /* If new 'per xxx seconds' is smaller than current 'per' then reset timers/counters (t, c) */
if (v < fld->per)
{
int i;
@@ -638,12 +572,13 @@ void *cmodef_put_param(void *fld_in, char *param)
if (fld->limit[v])
breakit=0;
if (breakit)
- {
- memset(fld, 0, sizeof(ChannelFloodProtection));
- return fld; /* FAIL */
- }
+ goto fail_cmodef_put_param; /* FAIL */
return (void *)fld;
+
+fail_cmodef_put_param:
+ memset(fld, 0, sizeof(ChannelFloodProtection));
+ return fld; /* FAIL */
}
char *cmodef_get_param(void *r_in)
@@ -671,6 +606,8 @@ char *cmodef_conv_param(char *param_in, Client *client)
int v;
unsigned short breakit;
unsigned char r;
+ FloodType *floodtype;
+ int index;
memset(&newf, 0, sizeof(newf));
@@ -694,15 +631,10 @@ char *cmodef_conv_param(char *param_in, Client *client)
/* <number><1 letter>[optional: '#'+1 letter] */
p = x;
while(isdigit(*p)) { p++; }
- if ((*p == '\0') ||
- !((*p == 'c') || (*p == 'j') || (*p == 'k') ||
- (*p == 'm') || (*p == 'n') || (*p == 't') ||
- (*p == 'r')))
- {
- /* (unknown type) */
- continue; /* continue instead of break for forward compatability. */
- }
c = *p;
+ floodtype = find_floodprot_by_letter(c);
+ if (!floodtype)
+ continue; /* continue instead of break for forward compatability. */
*p = '\0';
v = atoi(x);
if ((v < 1) || (v > 999)) /* out of range... */
@@ -733,59 +665,14 @@ char *cmodef_conv_param(char *param_in, Client *client)
}
}
- switch(c)
- {
- case 'c':
- newf.limit[FLD_CTCP] = v;
- if ((a == 'm') || (a == 'M'))
- newf.action[FLD_CTCP] = a;
- else
- newf.action[FLD_CTCP] = 'C';
- newf.remove_after[FLD_CTCP] = r;
- break;
- case 'j':
- newf.limit[FLD_JOIN] = v;
- if (a == 'R')
- newf.action[FLD_JOIN] = a;
- else
- newf.action[FLD_JOIN] = 'i';
- newf.remove_after[FLD_JOIN] = r;
- break;
- case 'k':
- newf.limit[FLD_KNOCK] = v;
- newf.action[FLD_KNOCK] = 'K';
- newf.remove_after[FLD_KNOCK] = r;
- break;
- case 'm':
- newf.limit[FLD_MSG] = v;
- if (a == 'M')
- newf.action[FLD_MSG] = a;
- else
- newf.action[FLD_MSG] = 'm';
- newf.remove_after[FLD_MSG] = r;
- break;
- case 'n':
- newf.limit[FLD_NICK] = v;
- newf.action[FLD_NICK] = 'N';
- newf.remove_after[FLD_NICK] = r;
- break;
- case 't':
- newf.limit[FLD_TEXT] = v;
- if (a == 'b' || a == 'd')
- newf.action[FLD_TEXT] = a;
- if (timedban_available)
- newf.remove_after[FLD_TEXT] = r;
- break;
- case 'r':
- newf.limit[FLD_REPEAT] = v;
- if (a == 'b' || a == 'd')
- newf.action[FLD_REPEAT] = a;
- if (timedban_available)
- newf.remove_after[FLD_REPEAT] = r;
- break;
- default:
- return NULL;
- }
+ index = floodtype->index;
+ newf.limit[index] = v;
+ if (a && strchr(floodtype->actions, a))
+ newf.action[index] = a;
+ else
+ newf.action[index] = floodtype->default_action;
+ if (!floodtype->timedban_required || (floodtype->timedban_required && timedban_available))
+ newf.remove_after[index] = r;
} /* for */
/* parse 'per' */
p2++;
@@ -864,11 +751,9 @@ int floodprot_join(Client *client, Channel *channel, MessageTag *mtags, char *pa
if (IsFloodLimit(channel) &&
(MyUser(client) || client->srvptr->serv->flags.synced) &&
(client->srvptr->serv->boottime && (TStime() - client->srvptr->serv->boottime >= MODEF_BOOT_DELAY)) &&
- !IsULine(client) &&
- do_floodprot(channel, FLD_JOIN) &&
- MyUser(client))
+ !IsULine(client))
{
- do_floodprot_action(channel, FLD_JOIN, "join");
+ do_floodprot(channel, client, FLD_JOIN);
}
return 0;
}
@@ -913,25 +798,18 @@ char tmpbuf[16], *p2 = tmpbuf;
*/
char *channel_modef_string(ChannelFloodProtection *x, char *retbuf)
{
+ int i;
char *p = retbuf;
+ FloodType *f;
*p++ = '[';
- /* (alphabetized) */
- if (x->limit[FLD_CTCP])
- p = chmodefstrhelper(p, 'c', 'C', x->limit[FLD_CTCP], x->action[FLD_CTCP], x->remove_after[FLD_CTCP]);
- if (x->limit[FLD_JOIN])
- p = chmodefstrhelper(p, 'j', 'i', x->limit[FLD_JOIN], x->action[FLD_JOIN], x->remove_after[FLD_JOIN]);
- if (x->limit[FLD_KNOCK])
- p = chmodefstrhelper(p, 'k', 'K', x->limit[FLD_KNOCK], x->action[FLD_KNOCK], x->remove_after[FLD_KNOCK]);
- if (x->limit[FLD_MSG])
- p = chmodefstrhelper(p, 'm', 'm', x->limit[FLD_MSG], x->action[FLD_MSG], x->remove_after[FLD_MSG]);
- if (x->limit[FLD_NICK])
- p = chmodefstrhelper(p, 'n', 'N', x->limit[FLD_NICK], x->action[FLD_NICK], x->remove_after[FLD_NICK]);
- if (x->limit[FLD_TEXT])
- p = chmodefstrhelper(p, 't', '\0', x->limit[FLD_TEXT], x->action[FLD_TEXT], x->remove_after[FLD_TEXT]);
- if (x->limit[FLD_REPEAT])
- p = chmodefstrhelper(p, 'r', '\0', x->limit[FLD_REPEAT], x->action[FLD_REPEAT], x->remove_after[FLD_REPEAT]);
+ for (i=0; i < ARRAY_SIZEOF(floodtypes); i++)
+ {
+ f = &floodtypes[i];
+ if (x->limit[f->index])
+ p = chmodefstrhelper(p, f->letter, f->default_action, x->limit[f->index], x->action[f->index], x->remove_after[f->index]);
+ }
if (*(p - 1) == ',')
p--;
@@ -1074,22 +952,18 @@ int floodprot_post_chanmsg(Client *client, Channel *channel, int sendflags, int
/* HINT: don't be so stupid to reorder the items in the if's below.. you'll break things -- Syzop. */
- if (do_floodprot(channel, FLD_MSG) && MyUser(client))
- do_floodprot_action(channel, FLD_MSG, "msg/notice");
+ do_floodprot(channel, client, FLD_MSG);
- if ((text[0] == '\001') && strncmp(text+1, "ACTION ", 7) &&
- do_floodprot(channel, FLD_CTCP) && MyUser(client))
- {
- do_floodprot_action(channel, FLD_CTCP, "CTCP");
- }
+ if ((text[0] == '\001') && strncmp(text+1, "ACTION ", 7))
+ do_floodprot(channel, client, FLD_CTCP);
return 0;
}
int floodprot_knock(Client *client, Channel *channel, MessageTag *mtags, char *comment)
{
- if (IsFloodLimit(channel) && !IsULine(client) && do_floodprot(channel, FLD_KNOCK) && MyUser(client))
- do_floodprot_action(channel, FLD_KNOCK, "knock");
+ if (IsFloodLimit(channel) && !IsULine(client))
+ do_floodprot(channel, client, FLD_KNOCK);
return 0;
}
@@ -1104,10 +978,9 @@ int floodprot_nickchange(Client *client, char *oldnick)
{
Channel *channel = mp->channel;
if (channel && IsFloodLimit(channel) &&
- !(mp->flags & (CHFL_CHANOP|CHFL_VOICE|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_CHANADMIN)) &&
- do_floodprot(channel, FLD_NICK) && MyUser(client))
+ !(mp->flags & (CHFL_CHANOP|CHFL_VOICE|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_CHANADMIN)))
{
- do_floodprot_action(channel, FLD_NICK, "nick");
+ do_floodprot(channel, client, FLD_NICK);
}
}
return 0;
@@ -1316,42 +1189,46 @@ void floodprottimer_stopchantimers(Channel *channel)
}
}
-int do_floodprot(Channel *channel, int what)
+int do_floodprot(Channel *channel, Client *client, int what)
{
ChannelFloodProtection *chp = (ChannelFloodProtection *)GETPARASTRUCT(channel, 'f');
- if (!chp || !chp->limit[what]) /* no +f or not restricted */
- return 0;
- if (TStime() - chp->timer[what] >= chp->per)
- {
- chp->timer[what] = TStime();
- chp->counter[what] = 1;
- } else
+ if (!chp)
+ return 0; /* no +f active */
+
+ if (chp->limit[what])
{
- chp->counter[what]++;
- if ((chp->counter[what] > chp->limit[what]) &&
- (TStime() - chp->timer[what] < chp->per))
+ if (TStime() - chp->timer[what] >= chp->per)
+ {
+ chp->timer[what] = TStime();
+ chp->counter[what] = 1;
+ } else
{
- /* reset it too (makes it easier for chanops to handle the situation) */
- /*
- *XXchp->timer[what] = TStime();
- *XXchp->counter[what] = 1;
- *
- * BAD.. there are some situations where we might 'miss' a flood
- * because of this. The reset has been moved to -i,-m,-N,-C,etc.
- */
- return 1; /* flood detected! */
+ chp->counter[what]++;
+ if ((chp->counter[what] > chp->limit[what]) &&
+ (TStime() - chp->timer[what] < chp->per))
+ {
+ if (MyUser(client))
+ do_floodprot_action(channel, what);
+ return 1; /* flood detected! */
+ }
}
}
return 0;
}
-void do_floodprot_action(Channel *channel, int what, char *text)
+void do_floodprot_action(Channel *channel, int what)
{
char m;
int mode = 0;
Cmode_t extmode = 0;
ChannelFloodProtection *chp = (ChannelFloodProtection *)GETPARASTRUCT(channel, 'f');
+ FloodType *floodtype = find_floodprot_by_index(what);
+ char *text;
+
+ if (!floodtype)
+ return;
+ text = floodtype->description;
m = chp->action[what];
if (!m)
@@ -1379,7 +1256,7 @@ void do_floodprot_action(Channel *channel, int what, char *text)
/* First the notice to the chanops */
mtags = NULL;
new_message(&me, NULL, &mtags);
- ircsnprintf(comment, sizeof(comment), "*** Channel %sflood detected (limit is %d per %d seconds), setting mode +%c",
+ ircsnprintf(comment, sizeof(comment), "*** Channel %s detected (limit is %d per %d seconds), setting mode +%c",
text, chp->limit[what], chp->per, m);
ircsnprintf(target, sizeof(target), "%%%s", channel->chname);
sendto_channel(channel, &me, NULL, PREFIX_HALFOP|PREFIX_OP|PREFIX_ADMIN|PREFIX_OWNER,
diff --git a/src/modules/channeldb.c b/src/modules/channeldb.c
@@ -14,8 +14,15 @@ ModuleHeader MOD_HEADER = {
"unrealircd-5",
};
+/* Database version */
#define CHANNELDB_VERSION 100
-#define CHANNELDB_SAVE_EVERY 299
+/* Save channels to file every <this> seconds */
+#define CHANNELDB_SAVE_EVERY 300
+/* The very first save after boot, apply this delta, this
+ * so we don't coincide with other (potentially) expensive
+ * I/O events like saving tkldb.
+ */
+#define CHANNELDB_SAVE_EVERY_DELTA -15
#define MAGIC_CHANNEL_START 0x11111111
#define MAGIC_CHANNEL_END 0x22222222
@@ -102,7 +109,7 @@ MOD_LOAD()
else
config_warn("[channeldb] Failed to rename database from %s to %s: %s", cfg.database, fname, strerror(errno));
}
- channeldb_next_event = TStime() + CHANNELDB_SAVE_EVERY;
+ channeldb_next_event = TStime() + CHANNELDB_SAVE_EVERY + CHANNELDB_SAVE_EVERY_DELTA;
}
EventAdd(modinfo->handle, "channeldb_write_channeldb", write_channeldb_evt, NULL, 1000, 0);
if (ModuleGetError(modinfo->handle) != MODERR_NOERROR)
@@ -209,7 +216,7 @@ int write_channeldb(void)
#endif
// Write to a tempfile first, then rename it if everything succeeded
- snprintf(tmpfname, sizeof(tmpfname), "%s.tmp", cfg.database);
+ snprintf(tmpfname, sizeof(tmpfname), "%s.%x.tmp", cfg.database, getrandom32());
fd = fopen(tmpfname, "wb");
if (!fd)
{
diff --git a/src/modules/nick.c b/src/modules/nick.c
@@ -679,13 +679,14 @@ nickkill2done:
register_user(client, client->name, username, umodes, virthost, ip);
if (IsDead(client))
return;
- if (!IsULine(serv) && IsSynched(serv))
- sendto_fconnectnotice(client, 0, NULL);
if (client->user->svid[0] != '0')
user_account_login(recv_mtags, client);
RunHook(HOOKTYPE_REMOTE_CONNECT, client);
+
+ if (!IsULine(serv) && IsSynched(serv))
+ sendto_fconnectnotice(client, 0, NULL);
}
/** The NICK command.
@@ -945,11 +946,14 @@ int _register_user(Client *client, char *nick, char *username, char *umode, char
}
if (IsHidden(client))
- ircd_log(LOG_CLIENT, "Connect - %s!%s@%s [VHOST %s]", nick,
- user->username, user->realhost, user->virthost);
- else
- ircd_log(LOG_CLIENT, "Connect - %s!%s@%s", nick, user->username,
- user->realhost);
+ {
+ ircd_log(LOG_CLIENT, "Connect - %s!%s@%s [%s] [vhost: %s] %s",
+ nick, user->username, user->realhost, GetIP(client), user->virthost, get_connect_extinfo(client));
+ } else
+ {
+ ircd_log(LOG_CLIENT, "Connect - %s!%s@%s [%s] %s",
+ nick, user->username, user->realhost, GetIP(client), get_connect_extinfo(client));
+ }
RunHook2(HOOKTYPE_WELCOME, client, 0);
sendnumeric(client, RPL_WELCOME, ircnetwork, nick, user->username, user->realhost);
@@ -1278,17 +1282,24 @@ int check_init(Client *client, char *sockn, size_t size)
int exceeds_maxperip(Client *client, ConfigItem_allow *aconf)
{
Client *acptr;
- int cnt = 1;
+ int local_cnt = 1;
+ int global_cnt = 1;
if (find_tkl_exception(TKL_MAXPERIP, client))
return 0; /* exempt */
- list_for_each_entry(acptr, &lclient_list, lclient_node)
+ list_for_each_entry(acptr, &client_list, client_node)
{
if (IsUser(acptr) && !strcmp(GetIP(acptr), GetIP(client)))
{
- cnt++;
- if (cnt > aconf->maxperip)
+ if (MyUser(acptr))
+ {
+ local_cnt++;
+ if (local_cnt > aconf->maxperip)
+ return 1;
+ }
+ global_cnt++;
+ if (global_cnt > aconf->global_maxperip)
return 1;
}
}
@@ -1412,7 +1423,7 @@ int AllowClient(Client *client, char *username)
strlcpy(uhost, sockhost, sizeof(uhost));
set_sockhost(client, uhost);
- if (aconf->maxperip && exceeds_maxperip(client, aconf))
+ if (exceeds_maxperip(client, aconf))
{
/* Already got too many with that ip# */
exit_client(client, NULL, iConf.reject_message_too_many_connections);
diff --git a/src/modules/nocodes.c b/src/modules/nocodes.c
@@ -23,8 +23,8 @@
ModuleHeader MOD_HEADER
= {
"nocodes", /* Name of module */
- "1.2", /* Version */
- "Strip/block bold/underline/reverse - by Syzop", /* Short description of module */
+ "1.3", /* Version */
+ "Strip/block color/bold/underline/italic/reverse - by Syzop", /* Short description of module */
"UnrealIRCd Team", /* Author */
"unrealircd-5",
};
@@ -95,7 +95,7 @@ int nocodes_can_send_to_channel(Client *client, Channel *channel, Membership *lp
break;
}
- *errmsg = "Control codes (bold/underline/reverse) are not permitted in this channel";
+ *errmsg = "Control codes (color/bold/underline/italic/reverse) are not permitted in this channel";
return HOOK_DENY;
}
return HOOK_CONTINUE;
diff --git a/src/modules/reputation.c b/src/modules/reputation.c
@@ -117,6 +117,7 @@ CMD_FUNC(reputationunperm);
int reputation_whois(Client *client, Client *target);
int reputation_set_on_connect(Client *client);
int reputation_pre_lconnect(Client *client);
+int reputation_connect_extinfo(Client *client, NameValuePrioList **list);
int reputation_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs);
int reputation_config_run(ConfigFile *cf, ConfigEntry *ce, int type);
int reputation_config_posttest(int *errs);
@@ -165,6 +166,7 @@ MOD_INIT()
HookAdd(modinfo->handle, HOOKTYPE_HANDSHAKE, 0, reputation_set_on_connect);
HookAdd(modinfo->handle, HOOKTYPE_PRE_LOCAL_CONNECT, 2000000000, reputation_pre_lconnect); /* (prio: last) */
HookAdd(modinfo->handle, HOOKTYPE_REMOTE_CONNECT, -1000000000, reputation_set_on_connect); /* (prio: near-first) */
+ HookAdd(modinfo->handle, HOOKTYPE_CONNECT_EXTINFO, 0, reputation_connect_extinfo); /* (prio: near-first) */
CommandAdd(ModInf.handle, "REPUTATION", reputation_cmd, MAXPARA, CMD_USER|CMD_SERVER);
CommandAdd(ModInf.handle, "REPUTATIONUNPERM", reputationunperm, MAXPARA, CMD_USER|CMD_SERVER);
return MOD_SUCCESS;
@@ -399,7 +401,7 @@ void save_db(void)
#endif
/* We write to a temporary file. Only to rename it later if everything was ok */
- snprintf(tmpfname, sizeof(tmpfname), "%s.tmp", cfg.database);
+ snprintf(tmpfname, sizeof(tmpfname), "%s.%x.tmp", cfg.database, getrandom32());
fd = fopen(tmpfname, "w");
if (!fd)
@@ -669,6 +671,12 @@ CMD_FUNC(reputationunperm)
client->name);
}
+int reputation_connect_extinfo(Client *client, NameValuePrioList **list)
+{
+ add_fmt_nvplist(list, 0, "reputation", "%d", GetReputation(client));
+ return 0;
+}
+
int count_reputation_records(void)
{
int i;
diff --git a/src/modules/stats.c b/src/modules/stats.c
@@ -488,9 +488,15 @@ int stats_allow(Client *client, char *para)
{
ConfigItem_allow *allows;
for (allows = conf_allow; allows; allows = allows->next)
- sendnumeric(client, RPL_STATSILINE, allows->ip, allows->hostname, allows->maxperip,
- allows->class->name, allows->server ? allows->server
- : defserv, allows->port ? allows->port : 6667);
+ {
+ sendnumeric(client, RPL_STATSILINE,
+ allows->ip, allows->hostname,
+ allows->maxperip,
+ allows->global_maxperip,
+ allows->class->name,
+ allows->server ? allows->server : defserv,
+ allows->port ? allows->port : 6667);
+ }
return 0;
}
@@ -866,12 +872,11 @@ int stats_set(Client *client, char *para)
if (LINK_BINDIP)
sendtxtnumeric(client, "link::bind-ip: %s", LINK_BINDIP);
sendtxtnumeric(client, "anti-flood::connect-flood: %d per %s", THROTTLING_COUNT, pretty_time_val(THROTTLING_PERIOD));
- sendtxtnumeric(client, "anti-flood::unknown-flood-bantime: %s", pretty_time_val(UNKNOWN_FLOOD_BANTIME));
- sendtxtnumeric(client, "anti-flood::unknown-flood-amount: %ldKB", UNKNOWN_FLOOD_AMOUNT);
+ sendtxtnumeric(client, "anti-flood::handshake-data-flood::amount: %ld bytes", iConf.handshake_data_flood_amount);
+ sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-action: %s", banact_valtostring(iConf.handshake_data_flood_ban_action));
+ sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-time: %s", pretty_time_val(iConf.handshake_data_flood_ban_time));
if (AWAY_PERIOD)
- {
sendtxtnumeric(client, "anti-flood::away-flood: %d per %s", AWAY_COUNT, pretty_time_val(AWAY_PERIOD));
- }
sendtxtnumeric(client, "anti-flood::nick-flood: %d per %s", NICK_COUNT, pretty_time_val(NICK_PERIOD));
sendtxtnumeric(client, "handshake-timeout: %s", pretty_time_val(iConf.handshake_timeout));
sendtxtnumeric(client, "sasl-timeout: %s", pretty_time_val(iConf.sasl_timeout));
diff --git a/src/modules/svsmode.c b/src/modules/svsmode.c
@@ -504,7 +504,7 @@ void do_svsmode(Client *client, MessageTag *recv_mtags, int parc, char *parv[],
only if the old flags (setflags) are different than the newly-
set ones */
if (setflags != target->umodes)
- RunHook3(HOOKTYPE_UMODE_CHANGE, client, setflags, target->umodes);
+ RunHook3(HOOKTYPE_UMODE_CHANGE, target, setflags, target->umodes);
if (show_change)
{
diff --git a/src/modules/tkl.c b/src/modules/tkl.c
@@ -34,7 +34,7 @@ ModuleHeader MOD_HEADER
/* Forward declarations */
int tkl_config_test_spamfilter(ConfigFile *, ConfigEntry *, int, int *);
-int tkl_config_match_spamfilter(ConfigFile *, ConfigEntry *, int);
+int tkl_config_run_spamfilter(ConfigFile *, ConfigEntry *, int);
int tkl_config_test_ban(ConfigFile *, ConfigEntry *, int, int *);
int tkl_config_run_ban(ConfigFile *, ConfigEntry *, int);
int tkl_config_test_except(ConfigFile *, ConfigEntry *, int, int *);
@@ -95,6 +95,7 @@ TKL *_find_tkl_banexception(int type, char *usermask, char *hostmask, int softba
TKL *_find_tkl_nameban(int type, char *name, int hold);
TKL *_find_tkl_spamfilter(int type, char *match_string, BanAction action, unsigned short target);
int _find_tkl_exception(int ban_type, Client *client);
+static void add_default_exempts(void);
/* Externals (only for us :D) */
extern int MODVAR spamf_ugly_vchanoverride;
@@ -122,27 +123,27 @@ struct TKLTypeTable
*/
TKLTypeTable tkl_types[] = {
/* <config name> <letter> <TKL_xxx type> <logging name> <tkl option?> <exempt option?> */
- { "gline", 'G', TKL_KILL | TKL_GLOBAL, "G-Line", 1, 1 },
- { "kline", 'k', TKL_KILL, "K-Line", 1, 1 },
- { "gzline", 'Z', TKL_ZAP | TKL_GLOBAL, "Global Z-Line", 1, 1 },
- { "zline", 'z', TKL_ZAP, "Z-Line", 1, 1 },
- { "spamfilter", 'F', TKL_SPAMF | TKL_GLOBAL, "Spamfilter", 1, 1 },
- { "qline", 'Q', TKL_NAME | TKL_GLOBAL, "Q-Line", 1, 1 },
- { "except", 'E', TKL_EXCEPTION | TKL_GLOBAL, "Exception", 1, 0 },
- { "shun", 's', TKL_SHUN | TKL_GLOBAL, "Shun", 1, 1 },
- { "local-qline", 'q', TKL_NAME, "Local Q-Line", 1, 0 },
- { "local-spamfilter", 'e', TKL_EXCEPTION, "Local Exception", 1, 0 },
- { "local-exception", 'f', TKL_SPAMF, "Local Spamfilter", 1, 0 },
- { "blacklist", 'b', TKL_BLACKLIST, "Blacklist", 0, 1 },
- { "connect-flood", 'c', TKL_CONNECT_FLOOD, "Connect flood", 0, 1 },
- { "maxperip", 'm', TKL_MAXPERIP, "Max-per-IP", 0, 1 },
- { "unknown-data-flood", 'd', TKL_UNKNOWN_DATA_FLOOD, "Unknown data flood", 0, 1 },
- { "antirandom", 'r', TKL_ANTIRANDOM, "Antirandom", 0, 1 },
- { "antimixedutf8", '8', TKL_ANTIMIXEDUTF8, "Antimixedutf8", 0, 1 },
- { "ban-version", 'v', TKL_BAN_VERSION, "Ban Version", 0, 1 },
- { NULL, '\0', 0, NULL, 0, 0 },
+ { "gline", 'G', TKL_KILL | TKL_GLOBAL, "G-Line", 1, 1 },
+ { "kline", 'k', TKL_KILL, "K-Line", 1, 1 },
+ { "gzline", 'Z', TKL_ZAP | TKL_GLOBAL, "Global Z-Line", 1, 1 },
+ { "zline", 'z', TKL_ZAP, "Z-Line", 1, 1 },
+ { "spamfilter", 'F', TKL_SPAMF | TKL_GLOBAL, "Spamfilter", 1, 1 },
+ { "qline", 'Q', TKL_NAME | TKL_GLOBAL, "Q-Line", 1, 1 },
+ { "except", 'E', TKL_EXCEPTION | TKL_GLOBAL, "Exception", 1, 0 },
+ { "shun", 's', TKL_SHUN | TKL_GLOBAL, "Shun", 1, 1 },
+ { "local-qline", 'q', TKL_NAME, "Local Q-Line", 1, 0 },
+ { "local-spamfilter", 'e', TKL_EXCEPTION, "Local Exception", 1, 0 },
+ { "local-exception", 'f', TKL_SPAMF, "Local Spamfilter", 1, 0 },
+ { "blacklist", 'b', TKL_BLACKLIST, "Blacklist", 0, 1 },
+ { "connect-flood", 'c', TKL_CONNECT_FLOOD, "Connect flood", 0, 1 },
+ { "maxperip", 'm', TKL_MAXPERIP, "Max-per-IP", 0, 1 },
+ { "handshake-data-flood", 'd', TKL_HANDSHAKE_DATA_FLOOD, "Handshake data flood", 0, 1 },
+ { "antirandom", 'r', TKL_ANTIRANDOM, "Antirandom", 0, 1 },
+ { "antimixedutf8", '8', TKL_ANTIMIXEDUTF8, "Antimixedutf8", 0, 1 },
+ { "ban-version", 'v', TKL_BAN_VERSION, "Ban Version", 0, 1 },
+ { NULL, '\0', 0, NULL, 0, 0 },
};
-#define ALL_VALID_EXCEPTION_TYPES "kline, gline, zline, gzline, spamfilter, shun, qline, blacklist, connect-flood, unknown-data-flood, antirandom, antimixedutf8, ban-version"
+#define ALL_VALID_EXCEPTION_TYPES "kline, gline, zline, gzline, spamfilter, shun, qline, blacklist, connect-flood, handshake-data-flood, antirandom, antimixedutf8, ban-version"
int max_stats_matches = 1000;
@@ -192,7 +193,7 @@ MOD_TEST()
MOD_INIT()
{
MARK_AS_OFFICIAL_MODULE(modinfo);
- HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_match_spamfilter);
+ HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_spamfilter);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_ban);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_except);
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkl_config_run_set);
@@ -205,6 +206,7 @@ MOD_INIT()
CommandAdd(modinfo->handle, "SPAMFILTER", cmd_spamfilter, 7, CMD_OPER);
CommandAdd(modinfo->handle, "ELINE", cmd_eline, 4, CMD_OPER);
CommandAdd(modinfo->handle, "TKL", _cmd_tkl, MAXPARA, CMD_OPER|CMD_SERVER);
+ add_default_exempts();
MARK_AS_OFFICIAL_MODULE(modinfo);
return MOD_SUCCESS;
}
@@ -437,7 +439,7 @@ int tkl_config_test_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type, int *e
}
/** Process a spamfilter { } block in the configuration file */
-int tkl_config_match_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
+int tkl_config_run_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
{
ConfigEntry *cep;
ConfigEntry *cepp;
@@ -491,7 +493,7 @@ int tkl_config_match_spamfilter(ConfigFile *cf, ConfigEntry *ce, int type)
target,
action,
m,
- me.name,
+ "-config-",
0,
TStime(),
bantime,
@@ -1525,14 +1527,14 @@ void eline_syntax(Client *client)
sendnotice(client, "F: Spamfilter");
sendnotice(client, "b: Blacklist checking");
sendnotice(client, "c: Connect flood (bypass set::anti-flood::connect-flood))");
- sendnotice(client, "d: Unknown data flood (no ZLINE on too much data before registration)");
+ sendnotice(client, "d: Handshake data flood (no ZLINE on too much data before registration)");
sendnotice(client, "m: Bypass allow::maxperip restriction");
sendnotice(client, "r: Bypass antirandom module");
sendnotice(client, "8: Bypass antimixedutf8 module");
sendnotice(client, "v: Bypass ban version { } blocks");
sendnotice(client, "Examples:");
- sendnotice(client, "/ELINE *@unrealircd.org kGf 0 This user is exempt");
- sendnotice(client, "/ELINE ~S:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef kGf 0 Trusted user with this certificate fingerprint");
+ sendnotice(client, "/ELINE *@unrealircd.org kGF 0 This user is exempt");
+ sendnotice(client, "/ELINE ~S:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef kGF 0 Trusted user with this certificate fingerprint");
sendnotice(client, "-");
sendnotice(client, "To get a list of all current ELINEs, type: /STATS except");
}
@@ -2637,6 +2639,18 @@ void _tkl_del_line(TKL *tkl)
free_tkl(tkl);
}
+/** Add some default ban exceptions - for localhost */
+static void add_default_exempts(void)
+{
+ /* The exempted ban types are only ones that will affect other connections as well,
+ * such as gline, and not policy decissions such as maxperip exempt or bypass qlines.
+ * Currently the list is: gline, kline, gzline, zline, shun, blacklist,
+ * connect-flood, handshake-data-flood.
+ */
+ tkl_add_banexception(TKL_EXCEPTION, "*", "127.*", "localhost is always exempt",
+ "-default-", 0, TStime(), 0, "GkZzsbcd", TKL_FLAG_CONFIG);
+}
+
/*
* tkl_check_local_remove_shun:
* removes shun from currently connected users affected by tmp.
@@ -4673,6 +4687,12 @@ int _match_spamfilter(Client *client, char *str_in, int target, char *destinatio
if (!client->user || ValidatePermissionsForPath("immune:server-ban:spamfilter",client,NULL,NULL,NULL) || IsULine(client))
return 0;
+ /* Client exempt from spamfilter checking?
+ * Let's check that early: going through elines is likely faster than running the regex(es).
+ */
+ if (find_tkl_exception(TKL_SPAMF, client))
+ return 0;
+
for (tkl = tklines[tkl_hash('F')]; tkl; tkl = tkl->next)
{
if (!(tkl->ptr.spamfilter->target & target))
diff --git a/src/modules/tkldb.c b/src/modules/tkldb.c
@@ -27,9 +27,16 @@ ModuleHeader MOD_HEADER = {
"unrealircd-5",
};
-#define TKL_DB_MAGIC 0x10101010
-#define TKL_DB_VERSION 4999
-#define TKL_DB_SAVE_EVERY 299
+#define TKLDB_MAGIC 0x10101010
+/* Database version */
+#define TKLDB_VERSION 4999
+/* Save tkls to file every <this> seconds */
+#define TKLDB_SAVE_EVERY 300
+/* The very first save after boot, apply this delta, this
+ * so we don't coincide with other (potentially) expensive
+ * I/O events like saving channeldb.
+ */
+#define TKLDB_SAVE_EVERY_DELTA +15
#ifdef DEBUGMODE
#define BENCHMARK
@@ -96,13 +103,13 @@ int write_tkline(FILE *fd, const char *tmpfname, TKL *tkl);
int read_tkldb(void);
/* Globals variables */
-const uint32_t tkl_db_version = TKL_DB_VERSION;
+const uint32_t tkldb_version = TKLDB_VERSION;
struct cfgstruct {
char *database;
};
static struct cfgstruct cfg;
-static int tkls_loaded = 0;
+static long tkldb_next_event = 0;
MOD_TEST()
{
@@ -115,11 +122,11 @@ MOD_INIT()
{
MARK_AS_OFFICIAL_MODULE(modinfo);
- LoadPersistentInt(modinfo, tkls_loaded);
+ LoadPersistentLong(modinfo, tkldb_next_event);
setcfg();
- if (!tkls_loaded)
+ if (!tkldb_next_event)
{
/* If this is the first time that our module is loaded, then
* read the TKL DB and add all *-Lines.
@@ -133,7 +140,7 @@ MOD_INIT()
else
config_warn("[tkldb] Failed to rename database from %s to %s: %s", cfg.database, fname, strerror(errno));
}
- tkls_loaded = 1;
+ tkldb_next_event = TStime() + TKLDB_SAVE_EVERY + TKLDB_SAVE_EVERY_DELTA;
}
HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, tkldb_configrun);
return MOD_SUCCESS;
@@ -141,7 +148,7 @@ MOD_INIT()
MOD_LOAD()
{
- EventAdd(modinfo->handle, "tkldb_write_tkldb", write_tkldb_evt, NULL, TKL_DB_SAVE_EVERY*1000, 0);
+ EventAdd(modinfo->handle, "tkldb_write_tkldb", write_tkldb_evt, NULL, 1000, 0);
if (ModuleGetError(modinfo->handle) != MODERR_NOERROR)
{
config_error("A critical error occurred when loading module %s: %s", MOD_HEADER.name, ModuleGetErrorStr(modinfo->handle));
@@ -154,7 +161,7 @@ MOD_UNLOAD()
{
write_tkldb();
freecfg();
- SavePersistentInt(modinfo, tkls_loaded);
+ SavePersistentLong(modinfo, tkldb_next_event);
return MOD_SUCCESS;
}
@@ -228,6 +235,9 @@ int tkldb_configrun(ConfigFile *cf, ConfigEntry *ce, int type)
EVENT(write_tkldb_evt)
{
+ if (tkldb_next_event > TStime())
+ return;
+ tkldb_next_event = TStime() + TKLDB_SAVE_EVERY;
write_tkldb();
}
@@ -245,7 +255,7 @@ int write_tkldb(void)
#endif
// Write to a tempfile first, then rename it if everything succeeded
- snprintf(tmpfname, sizeof(tmpfname), "%s.tmp", cfg.database);
+ snprintf(tmpfname, sizeof(tmpfname), "%s.%x.tmp", cfg.database, getrandom32());
fd = fopen(tmpfname, "wb");
if (!fd)
{
@@ -253,8 +263,8 @@ int write_tkldb(void)
return 0;
}
- W_SAFE(write_int32(fd, TKL_DB_MAGIC));
- W_SAFE(write_data(fd, &tkl_db_version, sizeof(tkl_db_version)));
+ W_SAFE(write_int32(fd, TKLDB_MAGIC));
+ W_SAFE(write_data(fd, &tkldb_version, sizeof(tkldb_version)));
// Count the *-Lines
tklcount = 0;
@@ -432,7 +442,7 @@ int read_tkldb(void)
/* The database starts with a "magic value" - unless it's some old version or corrupt */
R_SAFE(read_data(fd, &magic, sizeof(magic)));
- if (magic != TKL_DB_MAGIC)
+ if (magic != TKLDB_MAGIC)
{
config_warn("[tkldb] Database '%s' uses an old and unsupported format OR is corrupt", cfg.database);
config_status("If you are upgrading from UnrealIRCd 4 (or 5.0.0-alpha1) then we suggest you to "
@@ -450,10 +460,10 @@ int read_tkldb(void)
fclose(fd);
return 0;
}
- if (version > tkl_db_version)
+ if (version > tkldb_version)
{
config_warn("[tkldb] Database '%s' has version %lu while we only support %lu. Did you just downgrade UnrealIRCd? Sorry this is not suported",
- cfg.database, (unsigned long)tkl_db_version, (unsigned long)version);
+ cfg.database, (unsigned long)tkldb_version, (unsigned long)version);
fclose(fd);
return 0;
}
diff --git a/src/modules/websocket.c b/src/modules/websocket.c
@@ -6,7 +6,6 @@
*/
#include "unrealircd.h"
-#include <limits.h>
#define WEBSOCKET_VERSION "1.1.0"
diff --git a/src/numeric.c b/src/numeric.c
@@ -244,7 +244,7 @@ static char *replies[] = {
#endif
/* 213 RPL_STATSCLINE */ "%c %s * %s %d %d %s",
/* 214 RPL_STATSOLDNLINE */ "%c %s * %s %d %d %s",
-/* 215 RPL_STATSILINE */ "I %s * %s %d %s %s %d",
+/* 215 RPL_STATSILINE */ "I %s %s %d %d %s %s %d",
/* 216 RPL_STATSKLINE */ "%s %s %s",
/* 217 RPL_STATSQLINE */ "%c %s %ld %ld %s :%s",
/* 218 RPL_STATSYLINE */ "Y %s %d %d %d %d %d",
diff --git a/src/parse.c b/src/parse.c
@@ -35,6 +35,7 @@ static void remove_unknown(Client *, char *);
static void parse2(Client *client, Client **fromptr, MessageTag *mtags, char *ch);
static void parse_addlag(Client *client, int cmdbytes);
static int client_lagged_up(Client *client);
+static void ban_handshake_data_flooder(Client *client);
/** Put a packet in the client receive queue and process the data (if
* the 'fake lag' rules permit doing so).
@@ -60,14 +61,13 @@ int process_packet(Client *client, char *readbuf, int length, int killsafely)
return 0;
/* flood from unknown connection */
- if (IsUnknown(client) && (DBufLength(&client->local->recvQ) > UNKNOWN_FLOOD_AMOUNT*1024))
+ if (IsUnknown(client) && (DBufLength(&client->local->recvQ) > iConf.handshake_data_flood_amount))
{
- sendto_snomask(SNO_FLOOD, "Flood from unknown connection %s detected",
- client->local->sockhost);
+ sendto_snomask(SNO_FLOOD, "Handshake data flood from %s detected", client->local->sockhost);
if (!killsafely)
- ban_flooder(client);
+ ban_handshake_data_flooder(client);
else
- dead_socket(client, "Flood from unknown connection");
+ dead_socket(client, "Handshake data flood detected");
return 0;
}
@@ -105,7 +105,7 @@ void parse_client_queued(Client *client)
return; /* we delay processing of data until identd has replied */
if (!IsUser(client) && !IsServer(client) && (iConf.handshake_delay > 0) &&
- (TStime() - client->local->firsttime < iConf.handshake_delay))
+ !IsNoHandshakeDelay(client) && (TStime() - client->local->firsttime < iConf.handshake_delay))
{
return; /* we delay processing of data until set::handshake-delay is reached */
}
@@ -193,11 +193,10 @@ void parse(Client *cptr, char *buffer, int length)
if (IsDeadSocket(cptr))
return;
- if ((cptr->local->receiveK >= UNKNOWN_FLOOD_AMOUNT) && IsUnknown(cptr))
+ if ((cptr->local->receiveK >= iConf.handshake_data_flood_amount/1024) && IsUnknown(cptr))
{
- sendto_snomask(SNO_FLOOD, "Flood from unknown connection %s detected",
- cptr->local->sockhost);
- ban_flooder(cptr);
+ sendto_snomask(SNO_FLOOD, "Handshake data flood from %s detected", cptr->local->sockhost);
+ ban_handshake_data_flooder(cptr);
return;
}
@@ -533,20 +532,20 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, char *ch)
* Note that "lots" in terms of IRC is a few KB's, since more is rather unusual.
* @param client The client.
*/
-void ban_flooder(Client *client)
+static void ban_handshake_data_flooder(Client *client)
{
- if (find_tkl_exception(TKL_UNKNOWN_DATA_FLOOD, client))
+ if (find_tkl_exception(TKL_HANDSHAKE_DATA_FLOOD, client))
{
/* If the user is exempt we will still KILL the client, since it is
* clearly misbehaving. We just won't ZLINE the host, so it won't
* affect any other connections from the same IP address.
*/
- exit_client(client, NULL, "Flood from unknown connection");
+ exit_client(client, NULL, "Handshake data flood detected");
}
else
{
/* place_host_ban also takes care of removing any other clients with same host/ip */
- place_host_ban(client, BAN_ACT_ZLINE, "Flood from unknown connection", UNKNOWN_FLOOD_BANTIME);
+ place_host_ban(client, iConf.handshake_data_flood_ban_action, "Handshake data flood detected", iConf.handshake_data_flood_ban_time);
}
}
diff --git a/src/send.c b/src/send.c
@@ -1069,21 +1069,16 @@ void vsendto_prefix_one(Client *to, Client *from, MessageTag *mtags, const char
void sendto_connectnotice(Client *newuser, int disconnect, char *comment)
{
Client *acptr;
- char connect[512], secure[256];
+ char connect[512];
if (!disconnect)
{
RunHook(HOOKTYPE_LOCAL_CONNECT, newuser);
- *secure = '\0';
- if (IsSecure(newuser))
- snprintf(secure, sizeof(secure), " [secure %s]", tls_get_cipher(newuser->local->ssl));
-
ircsnprintf(connect, sizeof(connect),
- "*** Client connecting: %s (%s@%s) [%s] {%s}%s", newuser->name,
+ "*** Client connecting: %s (%s@%s) [%s] %s", newuser->name,
newuser->user->username, newuser->user->realhost, newuser->ip,
- newuser->local->class ? newuser->local->class->name : "0",
- secure);
+ get_connect_extinfo(newuser));
}
else
{
@@ -1101,18 +1096,14 @@ void sendto_connectnotice(Client *newuser, int disconnect, char *comment)
void sendto_fconnectnotice(Client *newuser, int disconnect, char *comment)
{
Client *acptr;
- char connect[512], secure[256];
+ char connect[512];
if (!disconnect)
{
- *secure = '\0';
- if (IsSecureConnect(newuser))
- strcpy(secure, " [secure]"); /* will we ever expand this? */
-
ircsnprintf(connect, sizeof(connect),
- "*** Client connecting: %s (%s@%s) [%s] {0}%s", newuser->name,
+ "*** Client connecting: %s (%s@%s) [%s] %s", newuser->name,
newuser->user->username, newuser->user->realhost, newuser->ip ? newuser->ip : "0",
- secure);
+ get_connect_extinfo(newuser));
}
else
{
diff --git a/src/socket.c b/src/socket.c
@@ -703,10 +703,7 @@ void set_ipv6_opts(int fd)
}
/** This sets the *OS* socket buffers.
- * Note that setting these high is not always a good idea.
- * For example for regular users we keep the receive buffer tight
- * so we detect a high receive queue (Excess Flood) properly.
- * See include/fdlist.h for more information
+ * This shouldn't be needed anymore, but I've left the function here.
*/
void set_socket_buffers(int fd, int rcvbuf, int sndbuf)
{
@@ -726,17 +723,24 @@ void set_sock_opts(int fd, Client *client, int ipv6)
if (ipv6)
set_ipv6_opts(fd);
+
#ifdef SO_REUSEADDR
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt)) < 0)
report_error("setsockopt(SO_REUSEADDR) %s:%s", client);
#endif
+
#if defined(SO_USELOOPBACK) && !defined(_WIN32)
opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK, (void *)&opt, sizeof(opt)) < 0)
report_error("setsockopt(SO_USELOOPBACK) %s:%s", client);
#endif
- set_socket_buffers(fd, USER_SOCKET_RECEIVE_BUFFER, USER_SOCKET_SEND_BUFFER);
+
+ /* Previously we also called set_socket_buffers() to set some
+ * specific buffer limits. This is no longer needed on modern OS's.
+ * Setting it explicitly actually slows things down.
+ */
+
/* Set to non blocking: */
#if !defined(_WIN32)
if ((opt = fcntl(fd, F_GETFL, 0)) == -1)
@@ -1105,8 +1109,10 @@ void read_packet(int fd, int revents, void *data)
for (h = Hooks[HOOKTYPE_RAWPACKET_IN]; h; h = h->next)
{
processdata = (*(h->func.intfunc))(client, readbuf, &length);
+ if (processdata == 0)
+ break; /* if hook tells to ignore the data, then break now */
if (processdata < 0)
- return;
+ return; /* if hook tells client is dead, return now */
}
if (processdata && !process_packet(client, readbuf, length, 0))
diff --git a/src/support.c b/src/support.c
@@ -1293,3 +1293,17 @@ int get_terminal_width(void)
return w.ws_col;
#endif
}
+
+/** Like strftime() but easier. */
+char *unreal_strftime(char *str)
+{
+ time_t t;
+ struct tm *tmp;
+ static char buf[512];
+
+ t = time(NULL);
+ tmp = localtime(&t);
+ if (!tmp || !strftime(buf, sizeof(buf), str, tmp))
+ return str;
+ return buf;
+}
diff --git a/src/user.c b/src/user.c
@@ -872,3 +872,50 @@ int user_allowed_by_security_group_name(Client *client, char *secgroupname)
return 0; /* security group not found: no match */
return user_allowed_by_security_group(client, s);
}
+
+/** Return extended information about user for the "Client connecting" line.
+ * @returns A string such as "[secure] [reputation: 5]", never returns NULL.
+ */
+char *get_connect_extinfo(Client *client)
+{
+ static char retbuf[512];
+ char tmp[512];
+ NameValuePrioList *list = NULL, *e;
+
+ /* From modules... */
+ RunHook2(HOOKTYPE_CONNECT_EXTINFO, client, &list);
+
+ /* And some built-in: */
+
+ /* "class": this should be first */
+ if (MyUser(client) && client->local->class)
+ add_nvplist(&list, -100000, "class", client->local->class->name);
+
+ /* "secure": SSL/TLS */
+ if (MyUser(client) && IsSecure(client))
+ add_nvplist(&list, -1000, "secure", tls_get_cipher(client->local->ssl));
+ else if (!MyUser(client) && IsSecureConnect(client))
+ add_nvplist(&list, -1000, "secure", NULL);
+
+ /* services account? */
+ if (IsLoggedIn(client))
+ add_nvplist(&list, -500, "account", client->user->svid);
+
+ *retbuf = '\0';
+ for (e = list; e; e = e->next)
+ {
+ if (e->value)
+ snprintf(tmp, sizeof(tmp), "[%s: %s] ", e->name, e->value);
+ else
+ snprintf(tmp, sizeof(tmp), "[%s] ", e->name);
+ strlcat(retbuf, tmp, sizeof(retbuf));
+ }
+ /* Cut off last space (unless empty string) */
+ if (*buf)
+ buf[strlen(buf)-1] = '\0';
+
+ /* Free the list, as it was only used to build retbuf */
+ free_nvplist(list);
+
+ return retbuf;
+}
diff --git a/src/version.c.SH b/src/version.c.SH
@@ -4,7 +4,7 @@ echo "Extracting src/version.c..."
#id=`grep '$Id: Changes,v' ../Changes`
#id=`echo $id |sed 's/.* Changes\,v \(.*\) .* Exp .*/\1/'`
-id="5.0.8"
+id="5.0.9"
echo "$id"
if test -r version.c
diff --git a/src/windows/UnrealIRCd.exe.manifest b/src/windows/UnrealIRCd.exe.manifest
@@ -3,7 +3,7 @@
<assemblyIdentity
processorArchitecture="amd64"
name="UnrealIRCd.UnrealIRCd.5"
- version="5.0.8.0"
+ version="5.0.9.0"
type="win32"
/>
<description>Internet Relay Chat Daemon</description>
diff --git a/src/windows/gui.c b/src/windows/gui.c
@@ -1034,6 +1034,7 @@ void win_log(FORMAT_STRING(const char *format), ...)
va_start(ap, format);
ircvsnprintf(buf, sizeof(buf), format, ap);
+ stripcrlf(buf);
if (!IsService)
{
@@ -1043,6 +1044,7 @@ void win_log(FORMAT_STRING(const char *format), ...)
char *tbuf = safe_alloc(strlen(errors) + strlen(buf) + 1);
strcpy(tbuf, errors);
strcat(tbuf, buf);
+ safe_free(errors);
errors = tbuf;
}
else
diff --git a/src/windows/unrealinst.iss b/src/windows/unrealinst.iss
@@ -6,7 +6,7 @@
[Setup]
AppName=UnrealIRCd 5
-AppVerName=UnrealIRCd 5.0.8
+AppVerName=UnrealIRCd 5.0.9
AppPublisher=UnrealIRCd Team
AppPublisherURL=https://www.unrealircd.org
AppSupportURL=https://www.unrealircd.org
diff --git a/src/windows/unrealsvc.c b/src/windows/unrealsvc.c
@@ -1,6 +1,7 @@
/************************************************************************
- * IRC - Internet Relay Chat, windows/unreal.c
+ * IRC - Internet Relay Chat, windows/unrealsvc.c
* Copyright (C) 2002 Dominick Meglio (codemastr)
+ * Copyright (C) 2006-2021 Bram Matthys (Syzop)
*
* 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
@@ -25,7 +26,7 @@ UCHANGESERVICECONFIG2 uChangeServiceConfig2;
#define IRCD_SERVICE_CONTROL_REHASH 128
void show_usage() {
- fprintf(stderr, "unreal start|stop|rehash|restart|install|uninstall|config <option> <value>");
+ fprintf(stderr, "unrealsvc start|stop|rehash|restart|install|uninstall|config <option> <value>");
fprintf(stderr, "\nValid config options:\nstartup auto|manual\n");
fprintf(stderr, "crashrestart delay\n");
}
diff --git a/unrealircd.in b/unrealircd.in
@@ -286,6 +286,8 @@ elif [ "$1" = "hot-patch" -o "$1" = "cold-patch" ] ; then
else
echo "Patch applied successfully. You must now restart your IRC server."
fi
+elif [ "$1" = "upgrade" ] ; then
+ @BINDIR@/unrealircd-upgrade-script $*
elif [ "$1" = "genlinkblock" ] ; then
@BINDIR@/unrealircd -L
else
@@ -298,15 +300,17 @@ else
echo "unrealircd start Start the IRC Server"
echo "unrealircd stop Stop (kill) the IRC Server"
echo "unrealircd rehash Reload the configuration file"
- echo "unrealircd reloadtls Reload the SSL/TLS certificate and settings"
+ echo "unrealircd reloadtls Reload the SSL/TLS certificates"
echo "unrealircd restart Restart the IRC Server (stop+start)"
+ echo "unrealircd upgrade Upgrade UnrealIRCd to the latest version"
+ echo "unrealircd upgrade-conf Upgrade the configuration file from UnrealIRCd"
+ echo " 3.2.x/4.x to 5.x format"
echo "unrealircd mkpasswd Hash a password"
echo "unrealircd version Display the UnrealIRCd version"
echo "unrealircd module Install and uninstall 3rd party modules"
echo "unrealircd croncheck For use in crontab: this checks if the server"
echo " is running. If not, the server is started."
+ echo "unrealircd genlinkblock Generate link { } block for the other side."
echo "unrealircd gencloak Display 3 random cloak keys"
echo "unrealircd spkifp Display SPKI Fingerprint"
- echo "unrealircd upgrade-conf Upgrade the configuration file from UnrealIRCd"
- echo " 3.2.x/4.x to 5.x format"
fi
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |