3737DECLARE_POOL (pool_head_connection , "connection" , sizeof (struct connection ));
3838DECLARE_POOL (pool_head_conn_hash_node , "conn_hash_node" , sizeof (struct conn_hash_node ));
3939DECLARE_POOL (pool_head_sockaddr , "sockaddr" , sizeof (struct sockaddr_storage ));
40- DECLARE_POOL (pool_head_authority , "authority" , HA_PP2_AUTHORITY_MAX );
40+ DECLARE_POOL (pool_head_pp_tlv_128 , "pp_tlv_128" , sizeof (struct conn_tlv_list ) + HA_PP2_TLV_VALUE_128 );
41+ DECLARE_POOL (pool_head_pp_tlv_256 , "pp_tlv_256" , sizeof (struct conn_tlv_list ) + HA_PP2_TLV_VALUE_256 );
4142
4243struct idle_conns idle_conns [MAX_THREADS ] = { };
4344struct xprt_ops * registered_xprt [XPRT_ENTRIES ] = { NULL , };
@@ -52,6 +53,22 @@ struct mux_stopping_data mux_stopping_data[MAX_THREADS];
5253/* disables sending of proxy-protocol-v2's LOCAL command */
5354static int pp2_never_send_local ;
5455
56+ /* find the value of a received TLV for a given type */
57+ struct conn_tlv_list * conn_get_tlv (struct connection * conn , int type )
58+ {
59+ struct conn_tlv_list * tlv = NULL ;
60+
61+ if (!conn )
62+ return NULL ;
63+
64+ list_for_each_entry (tlv , & conn -> tlv_list , list ) {
65+ if (tlv -> type == type )
66+ return tlv ;
67+ }
68+
69+ return NULL ;
70+ }
71+
5572/* Remove <conn> idle connection from its attached tree (idle, safe or avail).
5673 * If also present in the secondary server idle list, conn is removed from it.
5774 *
@@ -447,11 +464,10 @@ void conn_init(struct connection *conn, void *target)
447464 LIST_INIT (& conn -> session_list );
448465 else
449466 LIST_INIT (& conn -> stopping_list );
467+ LIST_INIT (& conn -> tlv_list );
450468 conn -> subs = NULL ;
451469 conn -> src = NULL ;
452470 conn -> dst = NULL ;
453- conn -> proxy_authority = IST_NULL ;
454- conn -> proxy_unique_id = IST_NULL ;
455471 conn -> hash_node = NULL ;
456472 conn -> xprt = NULL ;
457473 conn -> reverse .target = NULL ;
@@ -531,6 +547,8 @@ struct connection *conn_new(void *target)
531547/* Releases a connection previously allocated by conn_new() */
532548void conn_free (struct connection * conn )
533549{
550+ struct conn_tlv_list * tlv , * tlv_back = NULL ;
551+
534552 if (conn_is_back (conn ))
535553 conn_backend_deinit (conn );
536554
@@ -545,11 +563,16 @@ void conn_free(struct connection *conn)
545563 sockaddr_free (& conn -> src );
546564 sockaddr_free (& conn -> dst );
547565
548- pool_free (pool_head_authority , istptr (conn -> proxy_authority ));
549- conn -> proxy_authority = IST_NULL ;
550-
551- pool_free (pool_head_uniqueid , istptr (conn -> proxy_unique_id ));
552- conn -> proxy_unique_id = IST_NULL ;
566+ /* Free all previously allocated TLVs */
567+ list_for_each_entry_safe (tlv , tlv_back , & conn -> tlv_list , list ) {
568+ LIST_DELETE (& tlv -> list );
569+ if (tlv -> len > HA_PP2_TLV_VALUE_256 )
570+ free (tlv );
571+ else if (tlv -> len < HA_PP2_TLV_VALUE_128 )
572+ pool_free (pool_head_pp_tlv_128 , tlv );
573+ else
574+ pool_free (pool_head_pp_tlv_256 , tlv );
575+ }
553576
554577 ha_free (& conn -> reverse .name .area );
555578
@@ -1080,8 +1103,10 @@ int conn_recv_proxy(struct connection *conn, int flag)
10801103
10811104 /* TLV parsing */
10821105 while (tlv_offset < total_v2_len ) {
1083- struct tlv * tlv_packet ;
10841106 struct ist tlv ;
1107+ struct tlv * tlv_packet = NULL ;
1108+ struct conn_tlv_list * new_tlv = NULL ;
1109+ size_t data_len = 0 ;
10851110
10861111 /* Verify that we have at least TLV_HEADER_SIZE bytes left */
10871112 if (tlv_offset + TLV_HEADER_SIZE > total_v2_len )
@@ -1095,6 +1120,7 @@ int conn_recv_proxy(struct connection *conn, int flag)
10951120 if (tlv_offset > total_v2_len )
10961121 goto bad_header ;
10971122
1123+ /* Prepare known TLV types */
10981124 switch (tlv_packet -> type ) {
10991125 case PP2_TYPE_CRC32C : {
11001126 uint32_t n_crc32c ;
@@ -1121,36 +1147,49 @@ int conn_recv_proxy(struct connection *conn, int flag)
11211147 }
11221148#endif
11231149 case PP2_TYPE_AUTHORITY : {
1150+ /* For now, keep the length restriction by HAProxy */
11241151 if (istlen (tlv ) > HA_PP2_AUTHORITY_MAX )
11251152 goto bad_header ;
1126- conn -> proxy_authority = ist2 (pool_alloc (pool_head_authority ), 0 );
1127- if (!isttest (conn -> proxy_authority ))
1128- goto fail ;
1129- if (istcpy (& conn -> proxy_authority , tlv , HA_PP2_AUTHORITY_MAX ) < 0 ) {
1130- /* This is impossible, because we verified that the TLV value fits. */
1131- my_unreachable ();
1132- goto fail ;
1133- }
1153+
11341154 break ;
11351155 }
11361156 case PP2_TYPE_UNIQUE_ID : {
11371157 if (istlen (tlv ) > UNIQUEID_LEN )
11381158 goto bad_header ;
1139- conn -> proxy_unique_id = ist2 (pool_alloc (pool_head_uniqueid ), 0 );
1140- if (!isttest (conn -> proxy_unique_id ))
1141- goto fail ;
1142- if (istcpy (& conn -> proxy_unique_id , tlv , UNIQUEID_LEN ) < 0 ) {
1143- /* This is impossible, because we verified that the TLV value fits. */
1144- my_unreachable ();
1145- goto fail ;
1146- }
11471159 break ;
11481160 }
11491161 default :
11501162 break ;
11511163 }
1164+
1165+ /* If we did not find a known TLV type that we can optimize for, we generically allocate it */
1166+ data_len = get_tlv_length (tlv_packet );
1167+
1168+ /* Prevent attackers from allocating too much memory */
1169+ if (unlikely (data_len > HA_PP2_MAX_ALLOC ))
1170+ goto fail ;
1171+
1172+ /* Alloc memory based on data_len */
1173+ if (data_len > HA_PP2_TLV_VALUE_256 )
1174+ new_tlv = malloc (get_tlv_length (tlv_packet ) + sizeof (struct conn_tlv_list ));
1175+ else if (data_len <= HA_PP2_TLV_VALUE_128 )
1176+ new_tlv = pool_alloc (pool_head_pp_tlv_128 );
1177+ else
1178+ new_tlv = pool_alloc (pool_head_pp_tlv_256 );
1179+
1180+ if (unlikely (!new_tlv ))
1181+ goto fail ;
1182+
1183+ new_tlv -> type = tlv_packet -> type ;
1184+
1185+ /* Save TLV to make it accessible via sample fetch */
1186+ memcpy (new_tlv -> value , tlv .ptr , data_len );
1187+ new_tlv -> len = data_len ;
1188+
1189+ LIST_APPEND (& conn -> tlv_list , & new_tlv -> list );
11521190 }
11531191
1192+
11541193 /* Verify that the PROXYv2 header ends at a TLV boundary.
11551194 * This is can not be true, because the TLV parsing already
11561195 * verifies that a TLV does not exceed the total length and
@@ -1969,10 +2008,12 @@ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct
19692008 }
19702009
19712010 if (srv -> pp_opts & SRV_PP_V2_AUTHORITY ) {
2011+ struct conn_tlv_list * tlv = conn_get_tlv (remote , PP2_TYPE_AUTHORITY );
2012+
19722013 value = NULL ;
1973- if (remote && isttest ( remote -> proxy_authority ) ) {
1974- value = istptr ( remote -> proxy_authority ) ;
1975- value_len = istlen ( remote -> proxy_authority ) ;
2014+ if (tlv ) {
2015+ value_len = tlv -> len ;
2016+ value = tlv -> value ;
19762017 }
19772018#ifdef USE_OPENSSL
19782019 else {
@@ -2220,7 +2261,8 @@ int smp_fetch_fc_rcvd_proxy(const struct arg *args, struct sample *smp, const ch
22202261/* fetch the authority TLV from a PROXY protocol header */
22212262int smp_fetch_fc_pp_authority (const struct arg * args , struct sample * smp , const char * kw , void * private )
22222263{
2223- struct connection * conn ;
2264+ struct connection * conn = NULL ;
2265+ struct conn_tlv_list * conn_tlv ;
22242266
22252267 conn = objt_conn (smp -> sess -> origin );
22262268 if (!conn )
@@ -2231,21 +2273,29 @@ int smp_fetch_fc_pp_authority(const struct arg *args, struct sample *smp, const
22312273 return 0 ;
22322274 }
22332275
2234- if (!isttest (conn -> proxy_authority ))
2235- return 0 ;
2276+ conn_tlv = smp -> ctx .p ? smp -> ctx .p : LIST_ELEM (conn -> tlv_list .n , struct conn_tlv_list * , list );
2277+ list_for_each_entry_from (conn_tlv , & conn -> tlv_list , list ) {
2278+ if (conn_tlv -> type == PP2_TYPE_AUTHORITY ) {
2279+ smp -> flags |= SMP_F_NOT_LAST ;
2280+ smp -> data .type = SMP_T_STR ;
2281+ smp -> data .u .str .area = conn_tlv -> value ;
2282+ smp -> data .u .str .data = conn_tlv -> len ;
2283+ smp -> ctx .p = conn_tlv ;
22362284
2237- smp -> flags = 0 ;
2238- smp -> data .type = SMP_T_STR ;
2239- smp -> data .u .str .area = istptr (conn -> proxy_authority );
2240- smp -> data .u .str .data = istlen (conn -> proxy_authority );
2285+ return 1 ;
2286+ }
2287+ }
22412288
2242- return 1 ;
2289+ smp -> flags &= ~SMP_F_NOT_LAST ;
2290+
2291+ return 0 ;
22432292}
22442293
22452294/* fetch the unique ID TLV from a PROXY protocol header */
22462295int smp_fetch_fc_pp_unique_id (const struct arg * args , struct sample * smp , const char * kw , void * private )
22472296{
2248- struct connection * conn ;
2297+ struct connection * conn = NULL ;
2298+ struct conn_tlv_list * conn_tlv ;
22492299
22502300 conn = objt_conn (smp -> sess -> origin );
22512301 if (!conn )
@@ -2256,15 +2306,22 @@ int smp_fetch_fc_pp_unique_id(const struct arg *args, struct sample *smp, const
22562306 return 0 ;
22572307 }
22582308
2259- if (!isttest (conn -> proxy_unique_id ))
2260- return 0 ;
2309+ conn_tlv = smp -> ctx .p ? smp -> ctx .p : LIST_ELEM (conn -> tlv_list .n , struct conn_tlv_list * , list );
2310+ list_for_each_entry_from (conn_tlv , & conn -> tlv_list , list ) {
2311+ if (conn_tlv -> type == PP2_TYPE_UNIQUE_ID ) {
2312+ smp -> flags |= SMP_F_NOT_LAST ;
2313+ smp -> data .type = SMP_T_STR ;
2314+ smp -> data .u .str .area = conn_tlv -> value ;
2315+ smp -> data .u .str .data = conn_tlv -> len ;
2316+ smp -> ctx .p = conn_tlv ;
22612317
2262- smp -> flags = 0 ;
2263- smp -> data .type = SMP_T_STR ;
2264- smp -> data .u .str .area = istptr (conn -> proxy_unique_id );
2265- smp -> data .u .str .data = istlen (conn -> proxy_unique_id );
2318+ return 1 ;
2319+ }
2320+ }
22662321
2267- return 1 ;
2322+ smp -> flags &= ~SMP_F_NOT_LAST ;
2323+
2324+ return 0 ;
22682325}
22692326
22702327/* fetch the error code of a connection */
0 commit comments