Skip to content

v2.5.0

Latest

Choose a tag to compare

@chrj chrj released this 01 Sep 10:28
· 3 commits to main since this release
204dbbd

Security

Upgrade if you take AUTH from the public internet, or if you run behind a
proxy.

  • Server.MaxAuthAttempts closes a connection whose AUTH commands keep
    failing.
    RFC 4954 section 6 asks for such a limit. PLAIN and LOGIN
    both carry a password, and one connection took as many guesses as the client
    cared to send.

    Only a refusal from the Authenticate hooks counts, and a successful AUTH
    sets the count back to zero.

    This changes behavior. The default is 5, so a client that fails five
    times now gets a 421 reply and a closed connection, where it could go on
    before. Set the field to -1 for the behavior of earlier versions.

  • Server.TrustedProxies holds the addresses that may restate the identity
    of the client
    , with a PROXY protocol header or an XCLIENT command. Both
    write Peer.Addr, which the greylist, the RBL check, the rate limit and the
    SPF check all read, so a client that reached either one took the identity of
    any client it named.

    The server reads the address of the connection, and never Peer.Addr: a
    header that arrived already wrote that one, so a client could otherwise name
    a trusted address and then act on it.

    This changes behavior. An empty list trusts the addresses that the public
    internet does not reach: the loopback addresses, the private ranges of RFC
    1918 and RFC 4193, and the link-local addresses. A proxy that reaches the
    server from any other address, such as a load balancer with a public one,
    has to be named:

    srv.TrustedProxies = []netip.Prefix{
        netip.MustParsePrefix("203.0.113.7/32"),
    }

    The list replaces the default rule rather than adding to it, so a server
    that names its proxies and still takes connections over the loopback
    interface names that range too.

Added

  • middleware.AuthRateLimit limits the failed authentication attempts of one
    address
    , across the connections of that address. Server.MaxAuthAttempts
    bounds a single connection alone. A client that opens a new connection for
    every guess gets around that limit.

    A failed attempt takes a token, and a successful one takes none, so a client
    that always sends the right password never spends the bucket of its address.
    An address with no tokens left gets a 454 reply.

Fixed

  • middleware.Greylist holds the three parts of a triple apart. The key
    put the address of the client, the sender and the recipient in one string
    with a | between them, and RFC 5321 gives | to the local part of an
    address, so two triples could meet on one entry. The second of them read the
    entry of the first, and it passed a delay that it never waited.

  • One AUTH command can succeed in a session, and every AUTH command
    after it gets a 503 reply. RFC 4954 section 4 asks for that. The server
    took every one of them, so a client could take a second identity on a
    session whose earlier commands ran under the first.

    This changes behavior. A client that sends AUTH twice gets a 503 for
    the second one, where the server authenticated it again before.

  • Server.Shutdown closes the connection that the listener gave, and not
    the one that the session holds. STARTTLS puts a TLS connection in the place
    of that one, on the goroutine of the session. Shutdown read the same field
    from the goroutine of its caller, and nothing ordered the two.

The changelog carries
the whole text of each entry.