diff --git a/doc/RELEASE-NOTES.md b/doc/RELEASE-NOTES.md index 805a7554c..dd5e11588 100644 --- a/doc/RELEASE-NOTES.md +++ b/doc/RELEASE-NOTES.md @@ -107,6 +107,22 @@ in progress and may not be a stable version. * The [`require module` block](https://www.unrealircd.org/docs/Require_module_block) was only checked of one side of the link, thus partially not working. +### Developers and protocol: +* Server to server lines can now be 16384 bytes in size when + `PROTOCTL BIGLINES` is set. This will allow us to do things more + efficiently and possibly raise some other limits in the future. + This 16k is the size of the complete line, including sender, + message tags, content and \r\n. Also, in server-to-server traffic + we now allow 30 parameters (MAXPARA*2). + The original input size limits for non-servers remain the same: the + complete line can be 4k+512, with the non-mtag portion limit set + at 512 bytes (including \r\n), and MAXPARA is still 15 as well. +* To receive BIGLINES in a command, you need to `CommandAdd()` with + flags `CMD_BIGLINES`, without it you still get regular 512 max. + This is so, because a lot of the code does not expect longer than + 512 bytes lines or in parameters, so we can gradually change that + (where needed). + UnrealIRCd 6.1.0 ----------------- This is UnrealIRCd 6.1.0 stable. It is the direct successor to 6.0.7, there diff --git a/include/channel.h b/include/channel.h index f229290aa..083cfd2e1 100644 --- a/include/channel.h +++ b/include/channel.h @@ -33,8 +33,6 @@ * before Dreamforge aren't safe with more than six. -Donwulff */ #include "msg.h" -#define MAXMODEPARAMS (MAXPARA-3) /* Maximum modes processed */ -#define RESYNCMODES 12 /* Max modes per MODE in resync */ -#define MODEPARAMS 6 /* Max modes from user */ +#define MAXMODEPARAMS (MAXPARA_USER-3) /* Maximum modes processed */ #endif diff --git a/include/msg.h b/include/msg.h index dcae50970..3537fbf38 100644 --- a/include/msg.h +++ b/include/msg.h @@ -167,6 +167,7 @@ #define MSG_MLOCK "MLOCK" -#define MAXPARA 15 +#define MAXPARA 30 +#define MAXPARA_USER 15 #endif diff --git a/include/struct.h b/include/struct.h index 8a2edddce..a27fb1cbb 100644 --- a/include/struct.h +++ b/include/struct.h @@ -183,8 +183,9 @@ typedef OperPermission (*OperClassEntryEvalCallback)(OperClassACLEntryVar* varia #define LINKLEN 32 #define BUFSIZE 512 /* WARNING: *DONT* CHANGE THIS!!!! */ #define MAXTAGSIZE 8192 /**< Maximum length of message tags (4K user + 4K server) */ -#define MAXLINELENGTH (MAXTAGSIZE+BUFSIZE) /**< Maximum length of a line on IRC: 4k client tags + 4k server tags + 512 bytes (IRCv3) */ -#define READBUFSIZE MAXLINELENGTH /* for the read buffer */ +#define MAXLINELENGTH_USER (MAXTAGSIZE+BUFSIZE) /**< Maximum length of a line on IRC (for non-servers): 4k client tags + 4k server tags + 512 bytes (IRCv3) */ +#define MAXLINELENGTH 16384 /**< Maximum length of a line on IRC: from servers is 16k */ +#define READBUFSIZE MAXLINELENGTH /**< for the read buffer */ #define MAXRECIPIENTS 20 #define MAXSILELENGTH NICKLEN+USERLEN+HOSTLEN+10 #define IDLEN 12 @@ -449,6 +450,7 @@ typedef enum ClientStatus { #define PROTO_SJSBY 0x000020 /* SJOIN setby information (TS and nick) */ #define PROTO_MTAGS 0x000040 /* Support message tags and big buffers */ #define PROTO_NEXTBANS 0x000080 /* Server supports named extended bans */ +#define PROTO_BIGLINES 0x000100 /* BIGLINES support */ /* For client capabilities: */ #define CAP_INVERT 1L @@ -614,6 +616,7 @@ typedef enum ClientStatus { #define SupportCLK(x) (CHECKSERVERPROTO(x, PROTO_CLK)) #define SupportMTAGS(x) (CHECKSERVERPROTO(x, PROTO_MTAGS)) #define SupportNEXTBANS(x) (CHECKSERVERPROTO(x, PROTO_NEXTBANS)) +#define SupportBIGLINES(x) (CHECKSERVERPROTO(x, PROTO_BIGLINES)) #define SetVL(x) ((x)->local->proto |= PROTO_VL) #define SetSJSBY(x) ((x)->local->proto |= PROTO_SJSBY) @@ -621,6 +624,7 @@ typedef enum ClientStatus { #define SetCLK(x) ((x)->local->proto |= PROTO_CLK) #define SetMTAGS(x) ((x)->local->proto |= PROTO_MTAGS) #define SetNEXTBANS(x) ((x)->local->proto |= PROTO_NEXTBANS) +#define SetBIGLINES(x) ((x)->local->proto |= PROTO_BIGLINES) /* Dcc deny types (see src/s_extra.c) */ #define DCCDENY_HARD 0 @@ -917,6 +921,8 @@ struct SWhois { #define CMD_OPER 0x0200 /** Command is for control channel only (unrealircd.ctl socket) */ #define CMD_CONTROL 0x0400 +/** Command is able to receive BIG lines */ +#define CMD_BIGLINES 0x0800 /** Command function - used by all command handlers. * This is used in the code like
CMD_FUNC(cmd_yourcmd)as a function definition. diff --git a/src/modules/protoctl.c b/src/modules/protoctl.c index b4d48c4b8..3767f8c6b 100644 --- a/src/modules/protoctl.c +++ b/src/modules/protoctl.c @@ -122,6 +122,10 @@ CMD_FUNC(cmd_protoctl) { SetNEXTBANS(client); } + else if (!strcmp(name, "BIGLINES")) + { + SetBIGLINES(client); + } else if (!strcmp(name, "NICKCHARS") && value) { if (!IsServer(client) && !IsEAuth(client) && !IsHandshake(client)) diff --git a/src/parse.c b/src/parse.c index 321093077..e08279ffd 100644 --- a/src/parse.c +++ b/src/parse.c @@ -251,12 +251,13 @@ void parse(Client *cptr, char *buffer, int length) * the message has a sender, eg :xyz PRIVMSG .. * @param mtags Message tags received for this message. * @param mtags_bytes The length of all message tags. - * @param ch The incoming line received (buffer), excluding message tags. + * @param line The incoming line received (buffer), excluding message tags. */ -static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_bytes, char *ch) +static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_bytes, char *line) { Client *from = cptr; char *s; + char *ch = line; int len, i, numeric = 0, paramcount; #ifdef DEBUGMODE time_t then, ticks; @@ -267,14 +268,14 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_ *fromptr = cptr; /* The default, unless a source is specified (and permitted) */ - /* The remaining part should never be more than 510 bytes - * (that is 512 minus CR LF, as specified in RFC1459 section 2.3). + /* In client-to-server traffic, the remaining part should + * never be more than 510 bytes (that is 512 minus CR LF, + * as specified in RFC1459 section 2.3). * If it is too long, then we cut it off here. + * Note that there is a second check later for the IsServer() case. */ - if (strlen(ch) > 510) - { + if (!IsServer(cptr) && (strlen(ch) > 510)) ch[510] = '\0'; - } para[0] = (char *)DEADBEEF_ADDR; /* helps us catch bugs :) */ @@ -355,6 +356,20 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_ s = strchr(ch, ' '); /* s -> End of the command code */ len = (s) ? (s - ch) : 0; + /* An early "guard": check for oversized command name + * (not parameters, the actual command name being 512+ chars), + * just in case... especially for BIGLINES. + */ + if (len > 512) + { + ch[510] = '\0'; + sendto_one(from, NULL, ":%s %d %s %s :Unknown command", + me.name, ERR_UNKNOWNCOMMAND, + from->name, ch); + ircstats.is_unco++; + return; + } + if (len == 3 && isdigit(*ch) && isdigit(*(ch + 1)) && isdigit(*(ch + 2))) { /* Numeric (eg: 311) */ @@ -462,11 +477,26 @@ static void parse2(Client *cptr, Client **fromptr, MessageTag *mtags, int mtags_ ** (about same effect as ":" has...) --msa */ + /* The high MAXPARA is only for servers, so readjust here for clients... */ + if (!IsServer(from) && (paramcount > MAXPARA_USER)) + paramcount = MAXPARA_USER; + /* Note initially true: s==NULL || *(s-1) == '\0' !! */ i = 0; if (s) { + if (IsServer(cptr) && (!cmptr || !(cmptr->flags & CMD_BIGLINES))) + { + int slen = strlen(s); + if ((s-line)+slen > 510) + { + ch[510] = '\0'; /* same as check at beginning of this function */ + if (slen > 510) + s[510] = '\0'; /* just in case the earlier cut was like mid-sender instead of in parameters */ + } + } + /* if (paramcount > MAXPARA) paramcount = MAXPARA; diff --git a/src/send.c b/src/send.c index ff303298f..54d6dcff8 100644 --- a/src/send.c +++ b/src/send.c @@ -253,11 +253,33 @@ static int sendbufto_one_prepare_line(Client *to, char *msg) len = strlen(p); if (!len || (p[len - 1] != '\n')) { - if (len > 510) - len = 510; - p[len++] = '\r'; - p[len++] = '\n'; - p[len] = '\0'; + if (!IsServer(to) || !SupportBIGLINES(to->direction)) + { + /* Normal case */ + if (len > 510) + len = 510; + p[len++] = '\r'; + p[len++] = '\n'; + p[len] = '\0'; + } else { + /* BIGLINES case: + * - first 'if' is about the total line length, + * this is basically an optimized strlen(msg) + * - the 'else' applies to non-mtags part, + * like in the 'Normal case' from above. + */ + if ((p - msg) + len > MAXLINELENGTH-3) + { + len = MAXLINELENGTH-3; + msg[len++] = '\r'; + msg[len++] = '\n'; + msg[len] = '\0'; + } else { + p[len++] = '\r'; + p[len++] = '\n'; + p[len] = '\0'; + } + } } /* Return length, that is: diff --git a/src/serv.c b/src/serv.c index 757ffcda6..153c51223 100644 --- a/src/serv.c +++ b/src/serv.c @@ -264,7 +264,7 @@ void send_proto(Client *client, ConfigItem_link *aconf) me.id, (long long)TStime()); /* Third line */ - sendto_one(client, NULL, "PROTOCTL NICKCHARS=%s CHANNELCHARS=%s", + sendto_one(client, NULL, "PROTOCTL NICKCHARS=%s CHANNELCHARS=%s BIGLINES", charsys_get_current_languages(), allowed_channelchars_valtostr(iConf.allowed_channelchars)); }