+ size_t ReadProxyTLV(StreamSocket* sock, size_t start_index, uint16_t buffer_length)
+ {
+ // A TLV must at least consist of a type (uint8_t) and a length (uint16_t).
+ if (buffer_length < PP2_TLV_LENGTH)
+ {
+ sock->SetError("Truncated HAProxy PROXY TLV type and/or length");
+ return 0;
+ }
+
+ // Check that the length can actually contain the TLV value.
+ std::string& recvq = GetRecvQ();
+ uint16_t length = ntohs(recvq[start_index + 1] | (recvq[start_index + 2] << 8));
+ if (buffer_length < PP2_TLV_LENGTH + length)
+ {
+ sock->SetError("Truncated HAProxy PROXY TLV value");
+ return 0;
+ }
+
+ // What type of TLV are we parsing?
+ switch (recvq[start_index])
+ {
+ case PP2_TYPE_SSL:
+ if (!ReadProxyTLVSSL(sock, start_index + PP2_TLV_LENGTH, length))
+ return 0;
+ break;
+ }
+
+ return PP2_TLV_LENGTH + length;
+ }
+
+ bool ReadProxyTLVSSL(StreamSocket* sock, size_t start_index, uint16_t buffer_length)
+ {
+ // A SSL TLV must at least consist of client info (uint8_t) and verification info (uint32_t).
+ if (buffer_length < PP2_TYPE_SSL_LENGTH)
+ {
+ sock->SetError("Truncated HAProxy PROXY SSL TLV");
+ return false;
+ }
+
+ // If the socket is not a user socket we don't have to do
+ // anything with this TLVs information.
+ if (sock->type != StreamSocket::SS_USER)
+ return true;
+
+ // If the sslinfo module is not loaded we can't
+ // do anything with this TLV.
+ if (!sslapi)
+ return true;
+
+ // If the client is not connecting via SSL the rest of this TLV is irrelevant.
+ std::string& recvq = GetRecvQ();
+ if ((recvq[start_index] & PP2_CLIENT_SSL) == 0)
+ return true;
+
+ // Create a fake ssl_cert for the user. Ideally we should use the user's
+ // SSL client certificate here but as of 2018-10-16 this is not forwarded
+ // by HAProxy.
+ ssl_cert* cert = new ssl_cert;
+ cert->error = "HAProxy does not forward client SSL certificates";
+ cert->invalid = true;
+ cert->revoked = true;
+ cert->trusted = false;
+ cert->unknownsigner = true;
+
+ // Extract the user for this socket and set their certificate.
+ LocalUser* luser = static_cast<UserIOHandler*>(sock)->user;
+ sslapi->SetCertificate(luser, cert);
+ return true;
+ }
+
+ int ReadData(std::string& destrecvq)
+ {
+ // Once connected we handle no special data.
+ std::string& recvq = GetRecvQ();
+ destrecvq.append(recvq);
+ recvq.clear();
+ return 1;
+ }
+
+ int ReadProxyAddress(StreamSocket* sock, std::string& destrecvq)