diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 36fd327d4b9..89ac680efd5 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -270,6 +270,18 @@ + + 3.9999 + - + Reserved for protocol greasing. libpq may use this version, which + is higher than any minor version the project ever expects to use, to + test that servers and middleware properly implement protocol version + negotiation. Servers must not add special-case + logic for this version; they should simply compare it to their latest + supported version (which will always be smaller) and downgrade via a + NegotiateProtocolVersion message. + + 3.1 - @@ -353,6 +365,17 @@ otherwise continue the connection. + + + _pq_.test_protocol_negotiation + Reserved for protocol greasing. libpq may send this extension to + test that servers and middleware properly implement protocol extension + negotiation. Servers must not add special-case + logic for this parameter; they should simply send the list of all + unsupported options (including this one) via a NegotiateProtocolVersion + message. + + diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h index 1bbe5b9ee45..a29c9c94d79 100644 --- a/src/include/libpq/pqcomm.h +++ b/src/include/libpq/pqcomm.h @@ -104,6 +104,16 @@ is_unixsock_path(const char *path) */ #define PG_PROTOCOL_RESERVED_31 PG_PROTOCOL(3,1) +/* + * PG_PROTOCOL_GREASE is an intentionally unsupported protocol version used + * for "greasing" (the practice of sending valid, but extraneous or otherwise + * unusual, messages to keep peer implementations honest). This helps ensure + * that servers properly implement protocol version negotiation. Version 3.9999 + * was chosen since it is safely within the valid range, it is representable + * via PQfullProtocolVersion, and it is unlikely to ever be needed in practice. + */ +#define PG_PROTOCOL_GREASE PG_PROTOCOL(3,9999) + /* * A client can send a cancel-current-operation request to the postmaster. * This is uglier than sending it directly to the client's backend, but it diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 103428033ef..90bbb2eba1f 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -1451,7 +1451,19 @@ pqGetNegotiateProtocolVersion3(PGconn *conn) if (pqGetInt(&num, 4, conn) != 0) goto eof; - /* Check the protocol version */ + /* + * Check the protocol version. + * + * PG_PROTOCOL_GREASE is intentionally unsupported and reserved. It's + * higher than any real version, so check for that first, to get the most + * specific error message. Then check the upper and lower bounds. + */ + if (their_version == PG_PROTOCOL_GREASE) + { + libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested \"grease\" protocol version 3.9999"); + goto failure; + } + if (their_version > conn->pversion) { libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to a higher-numbered version");