From b39ad99ecdcba72038acc985c016d39da0d27e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Sch=C3=A4fer?= Date: Sun, 18 Aug 2024 12:29:13 +0200 Subject: [PATCH] parsers: add stream error XSO --- parsers/ChangeLog | 1 + parsers/src/lib.rs | 2 + parsers/src/stream_error.rs | 283 ++++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+) create mode 100644 parsers/src/stream_error.rs diff --git a/parsers/ChangeLog b/parsers/ChangeLog index 3e0cbc191563306270e5b424aee7277591f24440..8c667c32ef1aca8c4cb29611c5f2bf34d69e178d 100644 --- a/parsers/ChangeLog +++ b/parsers/ChangeLog @@ -29,6 +29,7 @@ XXXX-YY-ZZ RELEASER - Extensible SASL Profile (XEP-0388) - SASL Channel-Binding Type Capability (XEP-0440) - Stream Limits Advertisement (XEP-0478) + - RFC 6120 stream errors Version 0.21.0: 2024-07-25 Emmanuel Gil Peyrot diff --git a/parsers/src/lib.rs b/parsers/src/lib.rs index 2154cb660a2bb9b74b077757beff46a7779d49f3..dc19160ea5e1de8fc2da4142a8710f5f6e840047 100644 --- a/parsers/src/lib.rs +++ b/parsers/src/lib.rs @@ -59,6 +59,8 @@ pub mod starttls; /// RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core pub mod stream; /// RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core +pub mod stream_error; +/// RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core pub mod stream_features; /// RFC 6121: Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence diff --git a/parsers/src/stream_error.rs b/parsers/src/stream_error.rs new file mode 100644 index 0000000000000000000000000000000000000000..85ee13b4986fe283f08751b8d99a10ba68b16055 --- /dev/null +++ b/parsers/src/stream_error.rs @@ -0,0 +1,283 @@ +// Copyright (c) 2024 Jonas Schäfer +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +use minidom::Element; +use xso::{AsXml, FromXml}; + +use crate::ns; + +/// Enumeration of all stream error conditions as defined in [RFC 6120]. +/// +/// All variant documentation is directly quoted from [RFC 6120]. +/// +/// [RFC 6120]: https://datatracker.ietf.org/doc/html/rfc6120#section-4.9.3 +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::STREAM)] +pub enum DefinedCondition { + /// The entity has sent XML that cannot be processed. + /// + /// This error can be used instead of the more specific XML-related + /// errors, such as ``, ``, + /// ``, ``, and + /// ``. However, the more specific errors are + /// RECOMMENDED. + #[xml(name = "bad-format")] + BadFormat, + + /// The entity has sent a namespace prefix that is unsupported, or has + /// sent no namespace prefix on an element that needs such a prefix (see + /// [Section 11.2](https://datatracker.ietf.org/doc/html/rfc6120#section-11.2)). + #[xml(name = "bad-namespace-prefix")] + BadNamespacePrefix, + + /// The server either (1) is closing the existing stream for this entity + /// because a new stream has been initiated that conflicts with the + /// existing stream, or (2) is refusing a new stream for this entity + /// because allowing the new stream would conflict with an existing + /// stream (e.g., because the server allows only a certain number of + /// connections from the same IP address or allows only one server-to- + /// server stream for a given domain pair as a way of helping to ensure + /// in-order processing as described under + /// [Section 10.1](https://datatracker.ietf.org/doc/html/rfc6120#section-10.1)). + /// + /// If a client receives a `` stream error, during the resource + /// binding aspect of its reconnection attempt it MUST NOT blindly request + /// the resourcepart it used during the former session but instead MUST + /// choose a different resourcepart; details are provided under + /// [Section 7](https://datatracker.ietf.org/doc/html/rfc6120#section-7). + #[xml(name = "conflict")] + Conflict, + + /// One party is closing the stream because it has reason to believe that + /// the other party has permanently lost the ability to communicate over + /// the stream. The lack of ability to communicate can be discovered + /// using various methods, such as whitespace keepalives as specified + /// under + /// [Section 4.4](https://datatracker.ietf.org/doc/html/rfc6120#section-4.4), + /// XMPP-level pings as defined in + /// [XEP-0199](https://xmpp.org/extensions/xep-0199.html), and + /// XMPP Stream Management as defined in + /// [XEP-0198](https://xmpp.org/extensions/xep-0198.html). + /// + /// Interoperability Note: RFC 3920 specified that the + /// `` stream error is to be used if the peer has not + /// generated any traffic over the stream for some period of time. + /// That behavior is no longer recommended; instead, the error SHOULD be + /// used only if the connected client or peer server has not responded to + /// data sent over the stream. + #[xml(name = "connection-timeout")] + ConnectionTimeout, + + /// The value of the 'to' attribute provided in the initial stream header + /// corresponds to an FQDN that is no longer serviced by the receiving + /// entity. + #[xml(name = "host-gone")] + HostGone, + + /// The value of the 'to' attribute provided in the initial stream header + /// does not correspond to an FQDN that is serviced by the receiving + /// entity. + #[xml(name = "host-unknown")] + HostUnknown, + + /// A stanza sent between two servers lacks a 'to' or 'from' attribute, + /// the 'from' or 'to' attribute has no value, or the value violates the + /// rules for XMPP addresses + /// (see [RFC 6122](https://datatracker.ietf.org/doc/html/rfc6122)). + #[xml(name = "improper-addressing")] + ImproperAddressing, + + /// The server has experienced a misconfiguration or other internal error + /// that prevents it from servicing the stream. + #[xml(name = "internal-server-error")] + InternalServerError, + + /// The data provided in a 'from' attribute does not match an authorized + /// JID or validated domain as negotiated (1) between two servers using + /// SASL or Server Dialback, or (2) between a client and a server via + /// SASL authentication and resource binding. + #[xml(name = "invalid-from")] + InvalidFrom, + + /// The stream namespace name is something other than + /// `http://etherx.jabber.org/streams` (see + /// [Section 11.2](https://datatracker.ietf.org/doc/html/rfc6120#section-11.2)) + /// or the content namespace declared as the default namespace is not + /// supported (e.g., something other than `jabber:client` or + /// `jabber:server`). + #[xml(name = "invalid-namespace")] + InvalidNamespace, + + /// The entity has sent invalid XML over the stream to a server that + /// performs validation (see + /// [Section 11.4](https://datatracker.ietf.org/doc/html/rfc6120#section-11.4)). + #[xml(name = "invalid-xml")] + InvalidXml, + + /// The entity has attempted to send XML stanzas or other outbound data + /// before the stream has been authenticated, or otherwise is not + /// authorized to perform an action related to stream negotiation; the + /// receiving entity MUST NOT process the offending data before sending + /// the stream error. + #[xml(name = "not-authorized")] + NotAuthorized, + + /// The initiating entity has sent XML that violates the well-formedness + /// rules of [XML](https://www.w3.org/TR/REC-xml/) or + /// [XML-NAMES](https://www.w3.org/TR/REC-xml-names/). + #[xml(name = "not-well-formed")] + NotWellFormed, + + /// The entity has violated some local service policy (e.g., a stanza + /// exceeds a configured size limit); the server MAY choose to specify + /// the policy in the `` element or in an application-specific + /// condition element. + #[xml(name = "policy-violation")] + PolicyViolation, + + /// The server is unable to properly connect to a remote entity that is + /// needed for authentication or authorization (e.g., in certain + /// scenarios related to Server Dialback + /// [XEP-0220](https://xmpp.org/extensions/xep-0220.html)); this condition + /// is not to be used when the cause of the error is within the + /// administrative domain of the XMPP service provider, in which case the + /// `` condition is more appropriate. + #[xml(name = "remote-connection-failed")] + RemoteConnectionFailed, + + /// The server is closing the stream because it has new (typically + /// security-critical) features to offer, because the keys or + /// certificates used to establish a secure context for the stream have + /// expired or have been revoked during the life of the stream + /// ([Section 13.7.2.3](https://datatracker.ietf.org/doc/html/rfc6120#section-13.7.2.3)), + /// because the TLS sequence number has wrapped + /// ([Section 5.3.5](https://datatracker.ietf.org/doc/html/rfc6120#section-5.3.5)), + /// etc. The reset applies to the stream and to any security context + /// established for that stream (e.g., via TLS and SASL), which means that + /// encryption and authentication need to be negotiated again for the new + /// stream (e.g., TLS session resumption cannot be used). + #[xml(name = "reset")] + Reset, + + /// The server lacks the system resources necessary to service the stream. + #[xml(name = "resource-constraint")] + ResourceConstraint, + + /// The entity has attempted to send restricted XML features such as a + /// comment, processing instruction, DTD subset, or XML entity reference + /// (see + /// [Section 11.1](https://datatracker.ietf.org/doc/html/rfc6120#section-11.1)). + #[xml(name = "restricted-xml")] + RestrictedXml, + + /// The server will not provide service to the initiating entity but is + /// redirecting traffic to another host under the administrative control + /// of the same service provider. The XML character data of the + /// `` element returned by the server MUST specify the + /// alternate FQDN or IP address at which to connect, which MUST be a + /// valid domainpart or a domainpart plus port number (separated by the + /// ':' character in the form "domainpart:port"). If the domainpart is + /// the same as the source domain, derived domain, or resolved IPv4 or + /// IPv6 address to which the initiating entity originally connected + /// (differing only by the port number), then the initiating entity + /// SHOULD simply attempt to reconnect at that address. (The format of + /// an IPv6 address MUST follow + /// [IPv6-ADDR](https://datatracker.ietf.org/doc/html/rfc6120#ref-IPv6-ADDR), + /// which includes the enclosing the IPv6 address in square brackets + /// '[' and ']' as originally defined by + /// [URI](https://datatracker.ietf.org/doc/html/rfc6120#ref-URI). + /// ) Otherwise, the initiating entity MUST resolve the FQDN + /// specified in the `` element as described under + /// [Section 3.2](https://datatracker.ietf.org/doc/html/rfc6120#section-3.2). + /// + /// When negotiating a stream with the host to which it has been + /// redirected, the initiating entity MUST apply the same policies it + /// would have applied to the original connection attempt (e.g., a policy + /// requiring TLS), MUST specify the same 'to' address on the initial + /// stream header, and MUST verify the identity of the new host using the + /// same reference identifier(s) it would have used for the original + /// connection attempt (in accordance with + /// [TLS-CERTS](https://datatracker.ietf.org/doc/html/rfc6120#ref-TLS-CERTS)). + /// Even if the receiving entity returns a `` error + /// before the confidentiality and integrity of the stream have been + /// established (thus introducing the possibility of a denial-of-service + /// attack), the fact that the initiating entity needs to verify the + /// identity of the XMPP service based on the same reference identifiers + /// implies that the initiating entity will not connect to a malicious + /// entity. To reduce the possibility of a denial-of-service attack, (a) + /// the receiving entity SHOULD NOT close the stream with a + /// `` stream error until after the confidentiality and + /// integrity of the stream have been protected via TLS or an equivalent + /// security layer (such as the SASL GSSAPI mechanism), and (b) the + /// receiving entity MAY have a policy of following redirects only if it + /// has authenticated the receiving entity. In addition, the initiating + /// entity SHOULD abort the connection attempt after a certain number of + /// successive redirects (e.g., at least 2 but no more than 5). + #[xml(name = "see-other-host")] + SeeOtherHost(#[xml(text)] String), + + /// The server is being shut down and all active streams are being closed. + #[xml(name = "system-shutdown")] + SystemShutdown, + + /// The error condition is not one of those defined by the other + /// conditions in this list; this error condition SHOULD NOT be used + /// except in conjunction with an application-specific condition. + #[xml(name = "undefined-condition")] + UndefinedCondition, + + /// The initiating entity has encoded the stream in an encoding that is + /// not supported by the server (see + /// [Section 11.6](https://datatracker.ietf.org/doc/html/rfc6120#section-11.6)) + /// or has otherwise improperly encoded the stream (e.g., by violating the + /// rules of the + /// [UTF-8](https://datatracker.ietf.org/doc/html/rfc6120#ref-UTF-8) + /// encoding). + #[xml(name = "unsupported-encoding")] + UnsupportedEncoding, + + /// The receiving entity has advertised a mandatory-to-negotiate stream + /// feature that the initiating entity does not support, and has offered + /// no other mandatory-to-negotiate feature alongside the unsupported + /// feature. + #[xml(name = "unsupported-feature")] + UnsupportedFeature, + + /// The initiating entity has sent a first-level child of the stream that + /// is not supported by the server, either because the receiving entity + /// does not understand the namespace or because the receiving entity + /// does not understand the element name for the applicable namespace + /// (which might be the content namespace declared as the default + /// namespace). + #[xml(name = "unsupported-stanza-type")] + UnsupportedStanzaType, + + /// The 'version' attribute provided by the initiating entity in the + /// stream header specifies a version of XMPP that is not supported by + /// the server. + #[xml(name = "unsupported-version")] + UnsupportedVersion, +} + +/// Stream error as specified in RFC 6120. +#[derive(FromXml, AsXml, PartialEq, Debug, Clone)] +#[xml(namespace = ns::STREAM, name = "error")] +pub struct StreamError { + /// The enumerated error condition which triggered this stream error. + #[xml(child)] + pub condition: DefinedCondition, + + /// Optional error text. The first part is the optional `xml:lang` + /// language tag, the second part is the actual text content. + #[xml(extract(default, fields(attribute(name = "xml:lang", default, type_ = Option), text(type_ = String))))] + pub text: Option<(Option, String)>, + + /// Optional application-defined element which refines the specified + /// [`Self::condition`]. + // TODO: use n = 1 once we have it. + #[xml(element(n = ..))] + pub application_specific: Vec, +}