From 7c60ab28cb14c473b9069e27c297280e1043f17e Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 25 Oct 2024 18:03:05 +0200 Subject: [PATCH] [ADD] Proper stanza limits --- CHANGELOG.md | 6 +++--- etc/man/man1/parsee-config.1 | 7 ++++++- src/MatrixEventHandler.c | 5 ++--- src/Parsee/Config.c | 2 +- src/StanzaBuilder.c | 8 ++++++-- src/XMPP/Component.c | 25 +++++++++++++++++++++---- src/XMPP/MUC.c | 8 ++++---- src/XMPP/Stanza.c | 4 ++-- src/XMPPCommand/Manager.c | 6 +++--- src/XMPPThread/PEPs/Avatar.c | 2 +- src/XMPPThread/PEPs/VCard.c | 2 +- src/XMPPThread/PresenceSub.c | 2 +- src/XMPPThread/Stanzas/IQ.c | 12 ++++++------ src/XMPPThread/Stanzas/Message.c | 4 ++-- src/XMPPThread/Stanzas/Presence.c | 2 +- src/include/StanzaBuilder.h | 2 +- src/include/XMPP.h | 5 +++-- tools/config.c | 11 ++++++++++- 18 files changed, 74 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aaf0a9..cee509e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ commit done between releases. *There is currently no beta releases of Parsee* ## Alpha -### v0.2.0[star-of-hope] +### v0.2.0[star-of-hope] <8/11/2024?> Fixes some media metadata things, replaces the build system, tries out avatar support some more and speeds up Parsee a tad bit. @@ -25,8 +25,8 @@ the MUC. - Start adding basic documentation to Parsee, through the wiki page. - Add MUC whitelists for plumbing, alongside a `whitelist` tool -- Add (yet unused) parameter for setting the max stanza size -allowed. +- Add parameter for setting the max stanza size allowed, with +the default being the XMPP minimum of 10000 bytes. - Allows experimental MbedTLS through a specific Cytoplasm patch (though still unstable AND slow). - Does basic work towards NetBSD support diff --git a/etc/man/man1/parsee-config.1 b/etc/man/man1/parsee-config.1 index cb6e999..a297075 100644 --- a/etc/man/man1/parsee-config.1 +++ b/etc/man/man1/parsee-config.1 @@ -1,6 +1,6 @@ ." The last field is the codename, by the way. ." ALL MANPAGES FOR PARSEE ARE UNDER PUBLIC DOMAIN -.TH parsee-config 1 "Parsee Utility" "tomboyish-bridges-adventure" +.TH parsee-config 1 "Parsee Utility" "star-of-hope" .SH NAME parsee-config - generate a basic configuration file @@ -13,6 +13,7 @@ parsee-config .B [-J JABBER_HOST] .B [-p JABBER_PORT] .B [-d DATABASE] +.B [-M MAX_STANZA] .B [-S DATABASE size] .SH DESCRIPTION @@ -54,6 +55,10 @@ For example, if you except Parsee users to be on .I SHARED_SECRET is a shared secret known by Parsee and the XMPP component to authenticate. .TP +.BR -M MAX_STANZA +.I MAX_STANZA +is the maximum stanza size accepted by the XMPP host. If it is less than 10000 bytes, then it shall be set to that limit(the standardised value). +.TP .BR -m MEDIA_URL .I MEDIA_URL is an optional field used by Parsee as an address that points to Matrix diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index bae2f3e..234001b 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -487,7 +487,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) SetStanzaEdit(builder, origin_id); SetStanzaXParsee(builder, event); - WriteoutStanza(builder, jabber); + WriteoutStanza(builder, jabber, data->config->max_stanza_size); DestroyStanzaBuilder(builder); if (direct) @@ -542,8 +542,7 @@ ParseeEventHandler(ParseeData *data, HashMap *event) return; } else if (StrEquals(event_type, "m.room.message") || - StrEquals(event_type, "m.sticker")) /* TODO: Actual sticker - * support here... */ + StrEquals(event_type, "m.sticker")) { ParseeMessageHandler(data, event); Free(parsee); diff --git a/src/Parsee/Config.c b/src/Parsee/Config.c index c5c23ec..5361d2a 100644 --- a/src/Parsee/Config.c +++ b/src/Parsee/Config.c @@ -66,7 +66,7 @@ ParseeConfigLoad(char *conf) if (!config->max_stanza_size) { /* Standard XMPP "minimum" maximum */ - config->max_stanza_size = 10 KB; + config->max_stanza_size = 10000; } CopyToStr(media_base, "media_base"); diff --git a/src/StanzaBuilder.c b/src/StanzaBuilder.c index 96f22e3..f03c3b6 100644 --- a/src/StanzaBuilder.c +++ b/src/StanzaBuilder.c @@ -228,16 +228,20 @@ ExportStanza(StanzaBuilder *builder) } void -WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber) +WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber, size_t max) { XMLElement *elem; if (!builder || !jabber) { return; } + if (!max) + { + max = 10000; /* XMPP recommended limit */ + } elem = ExportStanza(builder); - XMPPSendStanza(jabber, elem); + XMPPSendStanza(jabber, elem, max); XMLFreeElement(elem); } diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index 0722460..4440ff0 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -214,17 +214,34 @@ XMPPEndCompStream(XMPPComponent *comp) Free(comp); } void -XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza) +XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza, size_t max) { + size_t len; + char *c = NULL; + Stream *stringWriter; if (!comp || !stanza) { return; } + stringWriter = StrStreamWriter(&c); + XMLEncode(stringWriter, stanza); + StreamFlush(stringWriter); + StreamClose(stringWriter); + if (c && max && (len = strlen(c)) > max) + { + Log(LOG_WARNING, + "Unexceptedly large stanza received (len=%d max=%d).", + (int) len, (int) max + ); + Free(c); + return; + } + + pthread_mutex_lock(&comp->write_lock); - /* TODO: Find a way to negociate to the server about stanza size - * (beyond the 10KB limit that is REQUIRED by XMPP standards) */ - XMLEncode(comp->stream, stanza); + StreamPrintf(comp->stream, c); StreamFlush(comp->stream); pthread_mutex_unlock(&comp->write_lock); + Free(c); } diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index f97f664..7064698 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -33,7 +33,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) { XMLElement *identity; - XMPPSendStanza(jabber, iq_query); + XMPPSendStanza(jabber, iq_query, 10000); XMLFreeElement(iq_query); /* Except an IQ reply. 10 seconds of timeout is pretty @@ -153,7 +153,7 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) } XMLAddChild(stanza, x); } - XMPPSendStanza(jabber, stanza); + XMPPSendStanza(jabber, stanza, 10000); XMLFreeElement(stanza); Free(identifier); @@ -201,7 +201,7 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool XMLAddChild(presence, x); } - XMPPSendStanza(comp, presence); + XMPPSendStanza(comp, presence, 10000); XMLFreeElement(presence); Free(from); @@ -248,7 +248,7 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) XMPPAnnotatePresence(presence); - XMPPSendStanza(comp, presence); + XMPPSendStanza(comp, presence, 10000); XMLFreeElement(presence); Free(from); diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 310b2d1..451c16f 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -66,7 +66,7 @@ XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) } - XMPPSendStanza(comp, message); + XMPPSendStanza(comp, message, 10000); XMLFreeElement(message); Free(from); @@ -264,7 +264,7 @@ XMPPSendDisco(ParseeData *data, char *from, char *to) XMLAddChild(iq, query); } - XMPPSendStanza(jabber, iq); + XMPPSendStanza(jabber, iq, 10000); XMLFreeElement(iq); ret = ParseeAwaitStanza(identifier, 1.25 SECONDS); diff --git a/src/XMPPCommand/Manager.c b/src/XMPPCommand/Manager.c index f5714b9..bd38579 100644 --- a/src/XMPPCommand/Manager.c +++ b/src/XMPPCommand/Manager.c @@ -274,7 +274,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) x = XMPPFormifyCommand(m, cmd, from); XMLAddChild(command_xml, x); - XMPPSendStanza(jabber, iq); + XMPPSendStanza(jabber, iq, data->config->max_stanza_size); XMLFreeElement(iq); goto end; @@ -302,7 +302,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, NULL); XMLAddChild(iq, command_xml); - XMPPSendStanza(jabber, iq); + XMPPSendStanza(jabber, iq, data->config->max_stanza_size); XMLFreeElement(iq); InvalidateSession(m, session_id); @@ -342,7 +342,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMPPExecuteCommand(m, cmd, from, command_xml, x_form); XMLAddChild(iq, command_xml); - XMPPSendStanza(jabber, iq); + XMPPSendStanza(jabber, iq, data->config->max_stanza_size); XMLFreeElement(iq); InvalidateSession(m, session_given); diff --git a/src/XMPPThread/PEPs/Avatar.c b/src/XMPPThread/PEPs/Avatar.c index e2ea636..c42d260 100644 --- a/src/XMPPThread/PEPs/Avatar.c +++ b/src/XMPPThread/PEPs/Avatar.c @@ -72,7 +72,7 @@ PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) char *url = HashMapGet(item->attrs, "url"); XMLElement *request = CreateAvatarRequest(from, to, id); - XMPPSendStanza(jabber, request); + XMPPSendStanza(jabber, request, args->config->max_stanza_size); XMLFreeElement(request); (void) url; /* TODO */ diff --git a/src/XMPPThread/PEPs/VCard.c b/src/XMPPThread/PEPs/VCard.c index 0ca65be..086e248 100644 --- a/src/XMPPThread/PEPs/VCard.c +++ b/src/XMPPThread/PEPs/VCard.c @@ -113,7 +113,7 @@ PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item) } } - XMPPSendStanza(jabber, reply); + XMPPSendStanza(jabber, reply, data->config->max_stanza_size); XMLFreeElement(reply); (void) item; } diff --git a/src/XMPPThread/PresenceSub.c b/src/XMPPThread/PresenceSub.c index 13ee9d5..dc30400 100644 --- a/src/XMPPThread/PresenceSub.c +++ b/src/XMPPThread/PresenceSub.c @@ -131,7 +131,7 @@ ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *stanza) /* TODO: Should we store IDs somewhere? */ XMLAddAttr(sub, "id", (storm_id = StrRandom(16))); - XMPPSendStanza(jabber, sub); + XMPPSendStanza(jabber, sub, data->config->max_stanza_size); XMLFreeElement(sub); Free(storm_id); end: diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 1cf6de2..d185e4c 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -175,7 +175,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) } XMLAddChild(iq_reply, query); - XMPPSendStanza(jabber, iq_reply); + XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); (void) args; @@ -412,7 +412,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMPPShoveCommandList(thr->info->m, to, q); XMLAddChild(iq_reply, q); } - XMPPSendStanza(jabber, iq_reply); + XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); } else if (XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp")) @@ -450,7 +450,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - XMPPSendStanza(jabber, iqVCard); + XMPPSendStanza(jabber, iqVCard, args->config->max_stanza_size); XMLFreeElement(iqVCard); Free(to_matrix); Free(name); @@ -477,7 +477,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(iqVCard, vCard); } - XMPPSendStanza(jabber, iqVCard); + XMPPSendStanza(jabber, iqVCard, args->config->max_stanza_size); XMLFreeElement(iqVCard); Free(to_matrix); Free(name); @@ -531,7 +531,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(reply, ps); } - XMPPSendStanza(jabber, reply); + XMPPSendStanza(jabber, reply, args->config->max_stanza_size); XMLFreeElement(reply); Free(to_matrix); @@ -569,7 +569,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) XMLAddChild(query, version); XMLAddChild(iq_reply, query); - XMPPSendStanza(jabber, iq_reply); + XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); } else diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index cd606dc..69342ca 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -370,13 +370,13 @@ end_error: ps = CreatePubsubRequest( parsee, decode_from, "urn:xmpp:avatar:metadata" ); - XMPPSendStanza(jabber, ps); + XMPPSendStanza(jabber, ps, args->config->max_stanza_size); XMLFreeElement(ps); ps = CreatePubsubRequest( parsee, trim, "urn:xmpp:avatar:metadata" ); - XMPPSendStanza(jabber, ps); + XMPPSendStanza(jabber, ps, args->config->max_stanza_size); XMLFreeElement(ps); if (args->verbosity >= PARSEE_VERBOSE_TIMINGS) { diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 12c06cd..4a66f94 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -381,7 +381,7 @@ end_item: from, HashMapGet(stanza->attrs, "from") ); - XMPPSendStanza(jabber, vcard_request); + XMPPSendStanza(jabber, vcard_request, args->config->max_stanza_size); XMLFreeElement(vcard_request); Free(from); } diff --git a/src/include/StanzaBuilder.h b/src/include/StanzaBuilder.h index e434e43..18b56bb 100644 --- a/src/include/StanzaBuilder.h +++ b/src/include/StanzaBuilder.h @@ -16,7 +16,7 @@ extern StanzaBuilder * SetStanzaID(StanzaBuilder *builder, char *id); extern StanzaBuilder * SetStanzaXParsee(StanzaBuilder *builder, HashMap *e); extern StanzaBuilder * AddStanzaElem(StanzaBuilder *builder, XMLElement *item); extern XMLElement * ExportStanza(StanzaBuilder *builder); -extern void WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber); +extern void WriteoutStanza(StanzaBuilder *builder, XMPPComponent *jabber, size_t max); extern void DestroyStanzaBuilder(StanzaBuilder *builder); #endif diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 27cecd0..b2c5293 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -30,11 +30,12 @@ extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); /** Writes an XML stanza through a component, while making sure any locking - * work is done. + * work is done. If {max} is non-zero, then this function will not send + * stanzas beyond {max} bytes. * ----------------------- * Modifies: {comp}, the XMPP stream * See-Also: XMPPInitialiseCompStream, XMPPAuthenticateCompStream, XMPP-core RFC */ -extern void XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza); +extern void XMPPSendStanza(XMPPComponent *comp, XMLElement *stanza, size_t max); /* Makes a user join/leave a MUC */ extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int secs, bool ret); diff --git a/tools/config.c b/tools/config.c index 3881eb1..b949c14 100644 --- a/tools/config.c +++ b/tools/config.c @@ -23,11 +23,12 @@ Main(Array *args, HashMap *env) int flag, code = EXIT_FAILURE; int port = 5347; size_t lmdb_size = 0; + size_t max_stanza = 10000; listen = "localhost"; ArgParseStateInit(&state); - while ((flag = ArgParse(&state, args, "H:J:s:d:p:m:l:S:")) != -1) + while ((flag = ArgParse(&state, args, "H:J:s:d:p:m:l:S:M:")) != -1) { switch (flag) { @@ -56,6 +57,12 @@ Main(Array *args, HashMap *env) case 'S': lmdb_size = strtol(state.optArg, NULL, 10) * 1024 * 1024; break; + case 'M': + max_stanza = strtol(state.optArg, NULL, 10); + if (max_stanza < 10000) + { + max_stanza = 10000; + } } } @@ -71,6 +78,7 @@ Main(Array *args, HashMap *env) "-l [Host/IP to listen as] " "-p [XMPP component port=5347] " "-J [parsee.xmppserver.ex]", + "-M [max stanza size>=10000]", "-S [LMDB size]", ArrayGet(args, 0) ); @@ -109,6 +117,7 @@ Main(Array *args, HashMap *env) JsonSet(json, JsonValueString(jabber), 1, "component_host"); JsonSet(json, JsonValueInteger(port), 1, "component_port"); + JsonSet(json, JsonValueInteger(max_stanza), 1, "max_stanza_size"); JsonSet(json, JsonValueString(jcp), 1, "shared_secret");