Skip to content

Commit 9b86c3a

Browse files
committed
improve support for proxy protocol
* Add support for parsing tlv headers * Add support for parsing network id from common cloud providers. Note, currently only GCP is fully supported as I couldn't test the flow on AWS, Azure but it should be easy to add this support in the future. * Fix bug that we didn't account for the tlv when checking the header length * Fix bug that tlv would have been stored as extra data inside the address union Change-Id: Idb68144f34bfa302c478de54eea631e6f80883f9 Signed-off-by: Roy Babayov <[email protected]>
1 parent b37fb73 commit 9b86c3a

File tree

6 files changed

+383
-133
lines changed

6 files changed

+383
-133
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ endif (USE_GSS)
7979

8080
option(USE_MONITORING "Enable monitoring stack" ON)
8181

82+
option(PROXY_PROTOCOL_PARSE_COMMON_NETWORK_ID "Enable parsing of common network id from haproxy TLV" OFF)
83+
8284
option(USE_RPC_RDMA "platform supports RDMA" OFF)
8385
if (USE_RPC_RDMA)
8486
find_package(RDMA REQUIRED)
@@ -263,6 +265,7 @@ message(STATUS "USE_GSS = ${USE_GSS}")
263265
message(STATUS "USE_PROFILE = ${USE_PROFILE}")
264266
message(STATUS "USE_LTTNG_NTIRPC = ${USE_LTTNG_NTIRPC}")
265267
message(STATUS "USE_MONITORING = ${USE_MONITORING}")
268+
message(STATUS "PROXY_PROTOCOL_PARSE_COMMON_NETWORK_ID = ${PROXY_PROTOCOL_PARSE_COMMON_NETWORK_ID}")
266269

267270
#force command line options to be stored in cache
268271
set(_MSPAC_SUPPORT ${_MSPAC_SUPPORT}

src/haproxy.h renamed to ntirpc/rpc/haproxy.h

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,16 @@
2323
* https://github.com/haproxy/haproxy.git
2424
*
2525
* Specifically, parts of this file: include/haproxy/connection-t.h
26+
*
27+
* NOTE: the definitions in this file are based on the haproxy spec in
28+
* https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
2629
*/
2730

31+
#include "config.h"
32+
33+
#ifndef _NTIRPC_RPC_HAPROXY_H
34+
#define _NTIRPC_RPC_HAPROXY_H
35+
2836
/* proxy protocol v2 definitions */
2937
#define PP2_SIGNATURE "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
3038
#define PP2_SIG_UINT32 0x0d0a0d0a
@@ -42,7 +50,7 @@
4250
#define PP2_VERSION_MASK 0xF0
4351

4452
#define PP2_VERSION2_CMD_LOCAL (PP2_CMD_LOCAL | PP2_VERSION)
45-
#define PP2_VERSIOB2_CMD_PROXY (PP2_CMD_PROXY | PP2_VERSION)
53+
#define PP2_VERSION2_CMD_PROXY (PP2_CMD_PROXY | PP2_VERSION)
4654

4755
/* fam byte */
4856
#define PP2_TRANS_UNSPEC 0x00
@@ -82,6 +90,17 @@
8290
#define PP2_SUBTYPE_SSL_KEY_ALG 0x25
8391
#define PP2_TYPE_NETNS 0x30
8492

93+
#define PP2_TYPE_UNSET 0x00
94+
95+
/* Define custom PP2_TYPE by common cloud provides */
96+
/* https://cloud.google.com/vpc/docs/about-vpc-hosted-services#proxy-protocol */
97+
#define PP2_TYPE_GCP 0xE0
98+
#define PP2_TYPE_GCP_EXPECTED_LENGTH 8
99+
/* https://docs.aws.amazon.com/elasticloadbalancing/latest/network/edit-target-group-attributes.html#proxy-protocol */
100+
#define PP2_TYPE_AWS 0xEA
101+
/* https://learn.microsoft.com/en-us/azure/private-link/private-link-service-overview#getting-connection-information-using-tcp-proxy-v2 */
102+
#define PP2_TYPE_AZURE 0xEE
103+
85104
#define PP2_CLIENT_SSL 0x01
86105
#define PP2_CLIENT_CERT_CONN 0x02
87106
#define PP2_CLIENT_CERT_SESS 0x04
@@ -97,29 +116,38 @@ struct proxy_header_part {
97116
uint16_t len; /* number of following bytes part of the header */
98117
};
99118

100-
union proxy_addr {
101-
struct { /* for TCP/UDP over IPv4, len = 12 */
102-
uint32_t src_addr;
103-
uint32_t dst_addr;
104-
uint16_t src_port;
105-
uint16_t dst_port;
106-
} ip4;
107-
struct { /* for TCP/UDP over IPv6, len = 36 */
108-
uint8_t src_addr[16];
109-
uint8_t dst_addr[16];
110-
uint16_t src_port;
111-
uint16_t dst_port;
112-
} ip6;
113-
struct { /* for AF_UNIX sockets, len = 216 */
114-
uint8_t src_addr[108];
115-
uint8_t dst_addr[108];
116-
} unx;
119+
struct proxy_header_addr_ip4_part { /* for TCP/UDP over IPv4, len = 12 */
120+
uint32_t src_addr;
121+
uint32_t dst_addr;
122+
uint16_t src_port;
123+
uint16_t dst_port;
124+
};
125+
_Static_assert(
126+
sizeof(struct proxy_header_addr_ip4_part) == PP2_ADDR_LEN_INET,
127+
"proxy_header_addr_ip4_part size is not equal to PP2_ADDR_LEN_INET");
128+
129+
struct proxy_header_addr_ip6_part { /* for TCP/UDP over IPv6, len = 36 */
130+
uint8_t src_addr[16];
131+
uint8_t dst_addr[16];
132+
uint16_t src_port;
133+
uint16_t dst_port;
134+
};
135+
_Static_assert(
136+
sizeof(struct proxy_header_addr_ip6_part) == PP2_ADDR_LEN_INET6,
137+
"proxy_header_addr_ip6_part size is not equal to PP2_ADDR_LEN_INET6");
138+
139+
typedef uint8_t proxy_protocol_tlv_type;
140+
typedef uint16_t proxy_protocol_tlv_length;
141+
struct proxy_protocol_tlv_header {
142+
proxy_protocol_tlv_type type;
143+
proxy_protocol_tlv_length length;
144+
/* value is stored in big-endian as received from socket */
145+
void *value;
117146
};
118147

119-
struct proxy_hdr_v2 {
120-
uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
121-
struct proxy_header_part header_part;
122-
union proxy_addr addr;
148+
struct proxy_protocol_tlv_headers {
149+
uint16_t tlv_count;
150+
struct proxy_protocol_tlv_header *tlvs;
123151
};
124152

125-
enum xprt_stat recv_haproxy_header(SVCXPRT *xprt);
153+
#endif /* _NTIRPC_RPC_HAPROXY_H */

ntirpc/rpc/svc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ struct svc_xprt {
294294
struct rpc_address xp_local; /* local address, length, port */
295295
struct rpc_address xp_remote; /* remote address, length, port */
296296
struct rpc_address xp_proxy; /* proxy address, length, port */
297+
struct proxy_protocol_tlv_headers proxy_protocol_tlv_headers;
298+
/* Network id parsed from proxy protocol.
299+
* Populated only when PARSE_COMMON_NETWORK_ID flag is on
300+
*/
301+
struct network_id xp_remote_network_id;
297302

298303
#if defined(HAVE_BLKIN)
299304
/* blkin tracing */

ntirpc/rpc/types.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
#include <sys/types.h>
4949
#include <inttypes.h>
5050

51+
#include "haproxy.h"
52+
5153
#if defined(_WIN32)
5254

5355
#define __BEGIN_DECLS
@@ -259,6 +261,23 @@ struct rpc_address {
259261
struct sockaddr_storage ss; /* address buffer */
260262
};
261263

264+
/*
265+
* The network id struct is used in combination with the client address
266+
* to identify the unique client.
267+
* Using proxy protocol, it's possible for clients from multiple networks to connect
268+
* to the server, although they have the same IP address.
269+
* This means that the client IP is not enough to identify the client and the network id
270+
* is needed as well.
271+
*/
272+
struct network_id {
273+
/* based on proxy protocol TLV header type values */
274+
uint32_t source;
275+
union {
276+
uint64_t gcp_psc_connection_id;
277+
/* TODO: add support for more common cloud providers */
278+
};
279+
};
280+
262281
/*
263282
* The format of the addres and options arguments of the XTI t_bind call.
264283
* Only provided for compatibility, it should not be used.

src/rpc_dplx_internal.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <rpc/svc.h>
3434
#include <rpc/xdr_ioq.h>
3535
#include <rpc/pool_queue.h>
36+
#include <rpc/haproxy.h>
3637

3738
/* Svc event strategy */
3839
enum svc_event_type {
@@ -126,6 +127,12 @@ rpc_dplx_rec_init(struct rpc_dplx_rec *rec)
126127
(void)clock_gettime(CLOCK_MONOTONIC_FAST, &(rec->recv.ts));
127128

128129
rec->xprt.xp_refcnt = 1;
130+
131+
// Init TLV headers, network id values in case they are not set later on
132+
rec->xprt.proxy_protocol_tlv_headers.tlv_count = 0;
133+
rec->xprt.proxy_protocol_tlv_headers.tlvs = NULL;
134+
rec->xprt.xp_remote_network_id.source = PP2_TYPE_UNSET;
135+
rec->xprt.xp_remote_network_id.gcp_psc_connection_id = 0;
129136
}
130137

131138
static inline void
@@ -135,6 +142,14 @@ rpc_dplx_rec_destroy(struct rpc_dplx_rec *rec)
135142
mutex_destroy(&rec->xprt.xp_lock);
136143
mutex_destroy(&rec->writeq.qmutex);
137144

145+
if (rec->xprt.proxy_protocol_tlv_headers.tlv_count > 0) {
146+
for (uint16_t i = 0; i < rec->xprt.proxy_protocol_tlv_headers.tlv_count; i++)
147+
free(rec->xprt.proxy_protocol_tlv_headers.tlvs[i].value);
148+
free(rec->xprt.proxy_protocol_tlv_headers.tlvs);
149+
rec->xprt.proxy_protocol_tlv_headers.tlvs = NULL;
150+
rec->xprt.proxy_protocol_tlv_headers.tlv_count = 0;
151+
}
152+
138153
#if defined(HAVE_BLKIN)
139154
if (rec->xprt.blkin.svc_name)
140155
mem_free(rec->xprt.blkin.svc_name, 2*INET6_ADDRSTRLEN);

0 commit comments

Comments
 (0)