From 6b953c0e2aceae66f261ee0bdcea14918e23efa7 Mon Sep 17 00:00:00 2001 From: JihoJung Date: Wed, 6 Sep 2023 10:58:03 +0900 Subject: [PATCH 1/5] Add 3 features 1) http-request options set-proxy-v2-header set-proxy-v2-tlv-header 2) server option set-proxy-v2-tlv --- include/haproxy/action-t.h | 4 + include/haproxy/server-t.h | 3 + src/connection.c | 32 ++++ src/http_act.c | 304 +++++++++++++++++++++++++++++++++++++ src/server.c | 94 ++++++++++++ 5 files changed, 437 insertions(+) diff --git a/include/haproxy/action-t.h b/include/haproxy/action-t.h index 7fafd612a4a6..760b7d673edd 100644 --- a/include/haproxy/action-t.h +++ b/include/haproxy/action-t.h @@ -89,6 +89,10 @@ enum act_name { /* http request actions. */ ACT_HTTP_REQ_TARPIT, + /* http request for ppv2, joyent */ + ACT_HTTP_SET_PPV2_HDR, + ACT_HTTP_SET_PPV2_TLV_HDR, + /* tcp actions */ ACT_TCP_EXPECT_PX, ACT_TCP_EXPECT_CIP, diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index 03f6899a9bf1..435073dcf4bd 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -164,6 +164,7 @@ enum srv_initaddr { #define SRV_PP_V2_AUTHORITY 0x0080 /* proxy protocol version 2 with authority */ #define SRV_PP_V2_CRC32C 0x0100 /* proxy protocol version 2 with crc32c */ #define SRV_PP_V2_UNIQUE_ID 0x0200 /* proxy protocol version 2 with unique ID */ +#define SRV_PP_V2_SET_TLV 0x0400 /* proxy protocol version 2 with TLV, joyent */ /* function which act on servers need to return various errors */ #define SRV_STATUS_OK 0 /* everything is OK. */ @@ -445,6 +446,8 @@ struct server { struct sockaddr_storage addr; /* the address to connect to, doesn't include the port */ struct sockaddr_storage socks4_addr; /* the address of the SOCKS4 Proxy, including the port */ + struct list tlv_list; /* server's PPV2 TLVs, joyent */ + EXTRA_COUNTERS(extra_counters); }; diff --git a/src/connection.c b/src/connection.c index 5f7226aaeca6..efc53c7f4268 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1912,6 +1912,18 @@ static int make_tlv(char *dest, int dest_len, char type, uint16_t length, const return length + sizeof(*tlv); } +/* put tlv data into buffer, joyent */ +static int put_tlv(char *dest, int dest_len, struct conn_tlv_list *tlv) +{ + size_t length = TLV_HEADER_SIZE + tlv->len; + + if (!dest || length > dest_len) + return 0; + + memcpy(dest, tlv, length); + return length; +} + /* Note: is explicitly allowed to be NULL */ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm) { @@ -2043,6 +2055,26 @@ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct } } + /* copy server TLVs, joyent */ + if (strm && (srv->pp_opts & SRV_PP_V2_SET_TLV)) { + struct conn_tlv_list *node; + + list_for_each_entry(node, &srv->tlv_list, list) { + /* append TLVs from config */ + ret += put_tlv(&buf[ret], (buf_len - ret), node); + } + } + + /* copy TLVs from remote's, joyent */ + if (strm && remote) { + struct conn_tlv_list *node; + + list_for_each_entry(node, &remote->tlv_list, list) { + /* append remote TLVs */ + ret += put_tlv(&buf[ret], (buf_len - ret), node); + } + } + #ifdef USE_OPENSSL if (srv->pp_opts & SRV_PP_V2_SSL) { struct tlv_ssl *tlv; diff --git a/src/http_act.c b/src/http_act.c index d168cf5e034c..5a1a6f2fadc2 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include /* Release memory allocated by most of HTTP actions. Concretly, it releases @@ -1554,6 +1556,305 @@ static enum act_parse_ret parse_http_set_header(const char **args, int *orig_arg return ACT_RET_PRS_OK; } +/* joyent */ +static int generate_ppv2_tlv_header(struct list *tlv_lists, char *buf, int max_len) { + struct conn_tlv_list *node; + int len = 0, tlv_val_len; + +// leading code: 0xff= +// tail semicolon +#define CODE_LEN 6 + + list_for_each_entry(node, tlv_lists, list) { + tlv_val_len = node->len; + if (max_len <= (len+tlv_val_len+CODE_LEN)) { + break; + } + + len += snprintf(&buf[len], max_len-len, "0x%02x=", node->type); + len += a2base64((char*)node->value, tlv_val_len, &buf[len], max_len-len); + buf[len++] = ';'; + } + + return len; +} + +static enum act_return http_action_set_ppv2_tlv_header(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp); + struct htx *htx = htxbuf(&msg->chn->buf); + enum act_return ret = ACT_RET_CONT; + struct server *srv = px->srv; + struct connection *conn = objt_conn(strm_orig(s)); + struct http_hdr_ctx ctx; + struct ist n, v; + + int max_len=1024, len=0; + char val[max_len]; + + val[0] = '\0'; + + // req only + if (srv == NULL || rule->from == ACT_F_HTTP_RES) { + return ret; + } + + if (srv != NULL) { + len += generate_ppv2_tlv_header(&srv->tlv_list, &val[len], max_len - len); + } + + if (conn != NULL) { + len += generate_ppv2_tlv_header(&conn->tlv_list, &val[len], max_len - len); + } + + if (len < 1) { + return ret; + } + else if (max_len < len) { + val[max_len-1] = '\0'; + } + else { + val[len] = '\0'; + } + + n = rule->arg.http.str; + v = ist(val); + + /* remove all occurrences of the header */ + ctx.blk = NULL; + while (http_find_header(htx, n, &ctx, 1)) + http_remove_header(htx, &ctx); + + /* Now add header */ + if (!http_add_header(htx, n, v)) + goto fail_rewrite; + +leave: + return ret; + +fail_rewrite: + _HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites); + if (s->flags & SF_BE_ASSIGNED) + _HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites); + if (sess->listener && sess->listener->counters) + _HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites); + if (objt_server(s->target)) + _HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites); + + if (!(msg->flags & HTTP_MSGF_SOFT_RW)) { + ret = ACT_RET_ERR; + if (!(s->flags & SF_ERR_MASK)) + s->flags |= SF_ERR_PRXCOND; + } + goto leave; +} + +static int generate_ppv2_header(char *buf, int buf_len, const struct sockaddr_storage *src, const struct sockaddr_storage *dst) +{ + int ret = 0; + char * protocol; + char src_str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + char dst_str[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + in_port_t src_port; + in_port_t dst_port; + + if ( !src + || !dst + || (src->ss_family != AF_INET && src->ss_family != AF_INET6) + || (dst->ss_family != AF_INET && dst->ss_family != AF_INET6)) { + + return ret; + } + + /* IPv4 for both src and dst */ + if (src->ss_family == AF_INET && dst->ss_family == AF_INET) { + protocol = "TCP4"; + if (!inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, src_str, sizeof(src_str))) + return 0; + src_port = ((struct sockaddr_in *)src)->sin_port; + if (!inet_ntop(AF_INET, &((struct sockaddr_in *)dst)->sin_addr, dst_str, sizeof(dst_str))) + return 0; + dst_port = ((struct sockaddr_in *)dst)->sin_port; + } + /* IPv6 for at least one of src and dst */ + else { + struct in6_addr tmp; + + protocol = "TCP6"; + + if (src->ss_family == AF_INET) { + /* Convert src to IPv6 */ + v4tov6(&tmp, &((struct sockaddr_in *)src)->sin_addr); + src_port = ((struct sockaddr_in *)src)->sin_port; + } + else { + tmp = ((struct sockaddr_in6 *)src)->sin6_addr; + src_port = ((struct sockaddr_in6 *)src)->sin6_port; + } + + if (!inet_ntop(AF_INET6, &tmp, src_str, sizeof(src_str))) + return 0; + + if (dst->ss_family == AF_INET) { + /* Convert dst to IPv6 */ + v4tov6(&tmp, &((struct sockaddr_in *)dst)->sin_addr); + dst_port = ((struct sockaddr_in *)dst)->sin_port; + } + else { + tmp = ((struct sockaddr_in6 *)dst)->sin6_addr; + dst_port = ((struct sockaddr_in6 *)dst)->sin6_port; + } + + if (!inet_ntop(AF_INET6, &tmp, dst_str, sizeof(dst_str))) + return 0; + } + + ret = snprintf(buf, buf_len, "address-type=%s;source-address=%s:%u;destination-address=%s:%u;", + protocol, src_str, ntohs(src_port), dst_str, ntohs(dst_port)); + + if (ret >= buf_len) + return 0; + + return ret; +} + +static enum act_return http_action_set_ppv2_header(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp); + struct htx *htx = htxbuf(&msg->chn->buf); + enum act_return ret = ACT_RET_CONT; + struct connection *conn = objt_conn(strm_orig(s)); + struct http_hdr_ctx ctx; + struct ist n, v; + + const struct sockaddr_storage *src = NULL; + const struct sockaddr_storage *dst = NULL; + + int max_len=1024, len=0; + char val[max_len]; + + val[0] = '\0'; + + // req only + if (rule->from == ACT_F_HTTP_RES) { + return ret; + } + + if (s) { + src = sc_src(s->scf); + dst = sc_dst(s->scf); + } + else if (conn && conn_get_src(conn) && conn_get_dst(conn)) { + src = conn_src(conn); + dst = conn_dst(conn); + } + + if (src && dst) + len = generate_ppv2_header(val, max_len, src, dst); + else + len = generate_ppv2_header(val, max_len, NULL, NULL); + + if (len < 1) { + return ret; + } + else if (max_len < len) { + val[max_len-1] = '\0'; + } + else { + val[len] = '\0'; + } + + n = rule->arg.http.str; + v = ist(val); + + /* remove all occurrences of the header */ + ctx.blk = NULL; + while (http_find_header(htx, n, &ctx, 1)) + http_remove_header(htx, &ctx); + + /* Now add header */ + if (!http_add_header(htx, n, v)) + goto fail_rewrite; + +leave: + return ret; + +fail_rewrite: + _HA_ATOMIC_INC(&sess->fe->fe_counters.failed_rewrites); + if (s->flags & SF_BE_ASSIGNED) + _HA_ATOMIC_INC(&s->be->be_counters.failed_rewrites); + if (sess->listener && sess->listener->counters) + _HA_ATOMIC_INC(&sess->listener->counters->failed_rewrites); + if (objt_server(s->target)) + _HA_ATOMIC_INC(&__objt_server(s->target)->counters.failed_rewrites); + + if (!(msg->flags & HTTP_MSGF_SOFT_RW)) { + ret = ACT_RET_ERR; + if (!(s->flags & SF_ERR_MASK)) + s->flags |= SF_ERR_PRXCOND; + } + goto leave; +} + +static enum act_parse_ret parse_http_set_ppv2_header(const char **args, int *orig_arg, struct proxy *px, + struct act_rule *rule, char **err) +{ + int cur_arg; + const char *p; + + /* set-proxy-v2-header */ + if (args[*orig_arg-1][13] == 'h') { + rule->action = ACT_HTTP_SET_PPV2_HDR; + rule->action_ptr = http_action_set_ppv2_header; + rule->release_ptr = release_http_action; + } + /* set-proxy-v2-tlv-header */ + else { + rule->action = ACT_HTTP_SET_PPV2_TLV_HDR; + rule->action_ptr = http_action_set_ppv2_tlv_header; + rule->release_ptr = release_http_action; + } + + LIST_INIT(&rule->arg.http.fmt); + + cur_arg = *orig_arg; + if (!*args[cur_arg]) { + memprintf(err, "expects exactly 1 arguments"); + return ACT_RET_PRS_ERR; + } + + rule->arg.http.str = ist(strdup(args[cur_arg])); + + free(px->conf.lfs_file); + px->conf.lfs_file = strdup(px->conf.args.file); + px->conf.lfs_line = px->conf.args.line; + + (*orig_arg) ++; + + /* some characters are totally forbidden in header names and + * may happen by accident when writing configs, causing strange + * failures in field. Better catch these ones early, nobody will + * miss them. In particular, a colon at the end (or anywhere + * after the first char) or a space/cr anywhere due to misplaced + * quotes are hard to spot. + */ + for (p = istptr(rule->arg.http.str); p < istend(rule->arg.http.str); p++) { + if (HTTP_IS_TOKEN(*p)) + continue; + if (p == istptr(rule->arg.http.str) && *p == ':') + continue; + /* we only report this as-is but it will not cause an error */ + memprintf(err, "header name '%s' contains forbidden character '%c'", istptr(rule->arg.http.str), *p); + break; + } + + return ACT_RET_PRS_OK; +} +/* joyent */ + + /* This function executes a replace-header or replace-value actions. It * builds a string in the trash from the specified format string. It finds * the action to be performed in <.action>, previously filled by function @@ -2450,6 +2751,9 @@ static struct action_kw_list http_req_actions = { { "track-sc", parse_http_track_sc, KWF_MATCH_PREFIX }, { "set-timeout", parse_http_set_timeout, 0 }, { "wait-for-body", parse_http_wait_for_body, 0 }, + { "set-proxy-v2-header", parse_http_set_ppv2_header, 0 }, /* joyent */ + { "set-proxy-v2-tlv-header", parse_http_set_ppv2_header, 0 }, /* joyent */ + { NULL, NULL } } }; diff --git a/src/server.c b/src/server.c index 3673340d155a..89c73799eef4 100644 --- a/src/server.c +++ b/src/server.c @@ -49,6 +49,9 @@ #include #include +#define TLV_DELIM ";" +#define TLV_VALUE_DELIM "=" + static void srv_update_status(struct server *s, int type, int cause); static int srv_apply_lastaddr(struct server *srv, int *err_code); @@ -1304,6 +1307,81 @@ static int srv_parse_send_proxy_v2(char **args, int *cur_arg, return srv_enable_pp_flags(newsrv, SRV_PP_V2); } +static struct conn_tlv_list* parse_tlv_kv(char* str, char *delim) +{ + char *key = NULL; + char *val = NULL; + uint16_t l; + struct conn_tlv_list *cur_node; + + key = strtok_r(str, delim, &val); + val = strtok_r(NULL, delim, &val); + l = (uint16_t)strlen(val); + + cur_node = (struct conn_tlv_list*)malloc(sizeof(struct conn_tlv_list) + l + 1); + if (cur_node == NULL) { + return NULL; + } + + LIST_INIT(&cur_node->list); + + cur_node->type = (uint8_t)strtol(key, NULL, 0); + strncpy((char*)cur_node->value, val, l); + cur_node->value[l] = '\0'; + cur_node->len = l; + + return cur_node; +} + +/* parse TLVs in config file */ +/* 0xe0=this-is-tlv-value;0x30=tlv-123456; */ +static int parse_tlv(struct server *newsrv, char* value, char *delim) +{ + struct conn_tlv_list *node; + char *ret_ptr = NULL; + char *next_ptr = NULL; + int cnt=0; + + ret_ptr = strtok_r(value, delim, &next_ptr); + + while(ret_ptr) { + node = parse_tlv_kv(ret_ptr, TLV_VALUE_DELIM); + if (node != NULL) { + LIST_APPEND(&newsrv->tlv_list, &node->list); + cnt ++; + } + + ret_ptr = strtok_r(NULL, delim, &next_ptr); + } + + return cnt; +} + +/* Parse the "set-proxy-v2-tlv" server keyword, joyent */ +static int srv_parse_set_proxy_v2_tlv(char **args, int *cur_arg, + struct proxy *curproxy, struct server *newsrv, char **err) +{ + char *errmsg=NULL, *value; + + value = args[*cur_arg + 1]; + if (!*value) { + memprintf(err, "'%s' expects \n", args[*cur_arg]); + goto err; + } + + *cur_arg += 1; + parse_tlv(newsrv, value, TLV_DELIM); + + srv_enable_pp_flags(newsrv, SRV_PP_V2); + srv_enable_pp_flags(newsrv, SRV_PP_V2_SET_TLV); + + return 0; + + err: + free(errmsg); + return ERR_ALERT | ERR_FATAL; +} + /* Parse the "slowstart" server keyword */ static int srv_parse_slowstart(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err) @@ -1914,6 +1992,7 @@ static struct srv_kw_list srv_kws = { "ALL", { }, { { "resolvers", srv_parse_resolvers, 1, 1, 0 }, /* Configure the resolver to use for name resolution */ { "send-proxy", srv_parse_send_proxy, 0, 1, 1 }, /* Enforce use of PROXY V1 protocol */ { "send-proxy-v2", srv_parse_send_proxy_v2, 0, 1, 1 }, /* Enforce use of PROXY V2 protocol */ + { "set-proxy-v2-tlv", srv_parse_set_proxy_v2_tlv, 0, 0, 1 }, /* Set TLV of PROXY V2 protocol, joyent */ { "shard", srv_parse_shard, 1, 1, 1 }, /* Server shard (only in peers protocol context) */ { "slowstart", srv_parse_slowstart, 1, 1, 1 }, /* Set the warm-up timer for a previously failed server */ { "source", srv_parse_source, -1, 1, 1 }, /* Set the source address to be used to connect to the server */ @@ -2428,6 +2507,7 @@ struct server *new_server(struct proxy *proxy) LIST_APPEND(&servers_list, &srv->global_list); LIST_INIT(&srv->srv_rec_item); LIST_INIT(&srv->ip_rec_item); + LIST_INIT(&srv->tlv_list); MT_LIST_INIT(&srv->prev_deleted); event_hdl_sub_list_init(&srv->e_subs); srv->rid = 0; /* rid defaults to 0 */ @@ -2485,6 +2565,18 @@ void srv_free_params(struct server *srv) xprt_get(XPRT_SSL)->destroy_srv(srv); } +/* free tlvs belongs to svr, joyent */ +void srv_free_tlv_nodes(struct server *srv) +{ + struct conn_tlv_list *node, *back; + + list_for_each_entry_safe(node, back, &srv->tlv_list, list) { + LIST_DEL_INIT(&node->list); + free(node); + } +} + + /* Deallocate a server and its member. must be allocated. For * dynamic servers, its refcount is decremented first. The free operations are * conducted only if the refcount is nul. @@ -2525,6 +2617,8 @@ struct server *srv_drop(struct server *srv) LIST_DELETE(&srv->global_list); event_hdl_sub_list_destroy(&srv->e_subs); + srv_free_tlv_nodes(srv); + EXTRA_COUNTERS_FREE(srv->extra_counters); ha_free(&srv); From 49c99e7ee3736fd553d7e20e0ea0bb7204e1c65f Mon Sep 17 00:00:00 2001 From: Fred Rossi Date: Wed, 13 Sep 2023 10:03:31 -0400 Subject: [PATCH 2/5] Fix segfault when parsing TLVs * Make parsing safer * Allow non-ending ; TLV values i.e 0xe0=this-is-tlv-value;0x30=tlv-123456 * Allow max length TLV values of 2048 Enough to accomodate vpcid (max length 1024) --- src/server.c | 77 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/src/server.c b/src/server.c index 89c73799eef4..c946299a0993 100644 --- a/src/server.c +++ b/src/server.c @@ -49,8 +49,9 @@ #include #include -#define TLV_DELIM ";" +#define TLV_DELIM ";\n" #define TLV_VALUE_DELIM "=" +#define TLV_VALUE_LEN 2048 static void srv_update_status(struct server *s, int type, int cause); @@ -1307,27 +1308,41 @@ static int srv_parse_send_proxy_v2(char **args, int *cur_arg, return srv_enable_pp_flags(newsrv, SRV_PP_V2); } -static struct conn_tlv_list* parse_tlv_kv(char* str, char *delim) +static struct conn_tlv_list* parse_tlv_kv(char* str) { - char *key = NULL; - char *val = NULL; - uint16_t l; - struct conn_tlv_list *cur_node; + struct conn_tlv_list *cur_node; + char *key = NULL; + char *val = NULL; + char *saveptr_int = NULL; + uint16_t l; - key = strtok_r(str, delim, &val); - val = strtok_r(NULL, delim, &val); - l = (uint16_t)strlen(val); + key = strtok_r(str, TLV_VALUE_DELIM, &saveptr_int); + if (key == NULL) { + ha_warning("'%s' ignoring TLV, invalid key.\n", str); + return NULL; + } - cur_node = (struct conn_tlv_list*)malloc(sizeof(struct conn_tlv_list) + l + 1); - if (cur_node == NULL) { - return NULL; - } + val = strtok_r(NULL, TLV_VALUE_DELIM, &saveptr_int); + if (val == NULL) { + ha_warning("'%s' ignoring TLV, invalid value.\n", str); + return NULL; + } + + l = (uint16_t)strlen(val); + if (l > TLV_VALUE_LEN) { + ha_warning("'%s' ignoring TLV, invalid length.\n", str); + return NULL; + } + + cur_node = (struct conn_tlv_list*)malloc(sizeof(struct conn_tlv_list) + l + 1); + if (cur_node == NULL) + return NULL; LIST_INIT(&cur_node->list); - - cur_node->type = (uint8_t)strtol(key, NULL, 0); - strncpy((char*)cur_node->value, val, l); - cur_node->value[l] = '\0'; + + cur_node->type = (uint8_t)strtol(key, NULL, 0); + strncpy((char*)cur_node->value, val, l); + cur_node->value[l] = '\0'; cur_node->len = l; return cur_node; @@ -1335,24 +1350,22 @@ static struct conn_tlv_list* parse_tlv_kv(char* str, char *delim) /* parse TLVs in config file */ /* 0xe0=this-is-tlv-value;0x30=tlv-123456; */ -static int parse_tlv(struct server *newsrv, char* value, char *delim) +static int parse_tlv(struct server *newsrv, char* value) { - struct conn_tlv_list *node; - char *ret_ptr = NULL; - char *next_ptr = NULL; + struct conn_tlv_list *node; + char *ret_ptr = NULL; + char *saveptr_ext = NULL; int cnt=0; - ret_ptr = strtok_r(value, delim, &next_ptr); - - while(ret_ptr) { - node = parse_tlv_kv(ret_ptr, TLV_VALUE_DELIM); + ret_ptr = strtok_r(value, TLV_DELIM, &saveptr_ext); + while(ret_ptr) { + node = parse_tlv_kv(ret_ptr); if (node != NULL) { LIST_APPEND(&newsrv->tlv_list, &node->list); cnt ++; } - - ret_ptr = strtok_r(NULL, delim, &next_ptr); - } + ret_ptr = strtok_r(NULL, TLV_DELIM, &saveptr_ext); + } return cnt; } @@ -1370,7 +1383,7 @@ static int srv_parse_set_proxy_v2_tlv(char **args, int *cur_arg, } *cur_arg += 1; - parse_tlv(newsrv, value, TLV_DELIM); + parse_tlv(newsrv, value); srv_enable_pp_flags(newsrv, SRV_PP_V2); srv_enable_pp_flags(newsrv, SRV_PP_V2_SET_TLV); @@ -2566,10 +2579,10 @@ void srv_free_params(struct server *srv) } /* free tlvs belongs to svr, joyent */ -void srv_free_tlv_nodes(struct server *srv) +void srv_free_tlv_nodes(struct server *srv) { - struct conn_tlv_list *node, *back; - + struct conn_tlv_list *node, *back; + list_for_each_entry_safe(node, back, &srv->tlv_list, list) { LIST_DEL_INIT(&node->list); free(node); From b04ee0697aa0e226ab17ee344a4549b262a043ba Mon Sep 17 00:00:00 2001 From: Fred Rossi Date: Tue, 19 Sep 2023 14:53:47 -0400 Subject: [PATCH 3/5] Fix put_tlb() incorrect proxy header length * Causes the server to drop connections with a CO_ER_PRX_BAD_HDR error message in conn_recv_proxy() Replaced put_tlv() by haproxy make_tlv() * (minor) Add unlikely branch predict macro --- src/connection.c | 16 ++-------------- src/server.c | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/connection.c b/src/connection.c index efc53c7f4268..fa1d6b68b26d 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1912,18 +1912,6 @@ static int make_tlv(char *dest, int dest_len, char type, uint16_t length, const return length + sizeof(*tlv); } -/* put tlv data into buffer, joyent */ -static int put_tlv(char *dest, int dest_len, struct conn_tlv_list *tlv) -{ - size_t length = TLV_HEADER_SIZE + tlv->len; - - if (!dest || length > dest_len) - return 0; - - memcpy(dest, tlv, length); - return length; -} - /* Note: is explicitly allowed to be NULL */ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connection *remote, struct stream *strm) { @@ -2061,7 +2049,7 @@ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct list_for_each_entry(node, &srv->tlv_list, list) { /* append TLVs from config */ - ret += put_tlv(&buf[ret], (buf_len - ret), node); + ret += make_tlv(&buf[ret], (buf_len - ret), node->type, node->len, node); } } @@ -2071,7 +2059,7 @@ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct list_for_each_entry(node, &remote->tlv_list, list) { /* append remote TLVs */ - ret += put_tlv(&buf[ret], (buf_len - ret), node); + ret += make_tlv(&buf[ret], (buf_len - ret), node->type, node->len, node); } } diff --git a/src/server.c b/src/server.c index c946299a0993..b53194fc23d1 100644 --- a/src/server.c +++ b/src/server.c @@ -1335,7 +1335,7 @@ static struct conn_tlv_list* parse_tlv_kv(char* str) } cur_node = (struct conn_tlv_list*)malloc(sizeof(struct conn_tlv_list) + l + 1); - if (cur_node == NULL) + if (unlikely(!cur_node)) return NULL; LIST_INIT(&cur_node->list); From 3282ae4718e13d5259c6062ba5eb6cded4bb46ac Mon Sep 17 00:00:00 2001 From: Fred Rossi Date: Wed, 25 Oct 2023 12:22:56 -0400 Subject: [PATCH 4/5] Fix copy TLV value in proxy line and generate header action --- src/connection.c | 4 ++-- src/http_act.c | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/connection.c b/src/connection.c index fa1d6b68b26d..368e688a35a5 100644 --- a/src/connection.c +++ b/src/connection.c @@ -2049,7 +2049,7 @@ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct list_for_each_entry(node, &srv->tlv_list, list) { /* append TLVs from config */ - ret += make_tlv(&buf[ret], (buf_len - ret), node->type, node->len, node); + ret += make_tlv(&buf[ret], (buf_len - ret), node->type, node->len, node->value); } } @@ -2059,7 +2059,7 @@ static int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct list_for_each_entry(node, &remote->tlv_list, list) { /* append remote TLVs */ - ret += make_tlv(&buf[ret], (buf_len - ret), node->type, node->len, node); + ret += make_tlv(&buf[ret], (buf_len - ret), node->type, node->len, node->value); } } diff --git a/src/http_act.c b/src/http_act.c index 5a1a6f2fadc2..1e2a66eeaf82 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -1570,10 +1570,12 @@ static int generate_ppv2_tlv_header(struct list *tlv_lists, char *buf, int max_l if (max_len <= (len+tlv_val_len+CODE_LEN)) { break; } - len += snprintf(&buf[len], max_len-len, "0x%02x=", node->type); - len += a2base64((char*)node->value, tlv_val_len, &buf[len], max_len-len); - buf[len++] = ';'; + strncpy(&buf[len], (char*)node->value, tlv_val_len); + len += tlv_val_len; + if (node->list.n != tlv_lists) { + buf[len++] = ';'; + } } return len; @@ -1596,7 +1598,7 @@ static enum act_return http_action_set_ppv2_tlv_header(struct act_rule *rule, st val[0] = '\0'; // req only - if (srv == NULL || rule->from == ACT_F_HTTP_RES) { + if (rule->from == ACT_F_HTTP_RES) { return ret; } @@ -1610,10 +1612,10 @@ static enum act_return http_action_set_ppv2_tlv_header(struct act_rule *rule, st if (len < 1) { return ret; - } + } else if (max_len < len) { val[max_len-1] = '\0'; - } + } else { val[len] = '\0'; } @@ -1710,7 +1712,7 @@ static int generate_ppv2_header(char *buf, int buf_len, const struct sockaddr_st return 0; } - ret = snprintf(buf, buf_len, "address-type=%s;source-address=%s:%u;destination-address=%s:%u;", + ret = snprintf(buf, buf_len, "address-type=%s;source-address=%s:%u;destination-address=%s:%u;", protocol, src_str, ntohs(src_port), dst_str, ntohs(dst_port)); if (ret >= buf_len) @@ -1758,10 +1760,10 @@ static enum act_return http_action_set_ppv2_header(struct act_rule *rule, struct if (len < 1) { return ret; - } + } else if (max_len < len) { val[max_len-1] = '\0'; - } + } else { val[len] = '\0'; } From 5220217730bf22801bad2369cca1b99356fd55a1 Mon Sep 17 00:00:00 2001 From: Fred Rossi Date: Wed, 25 Oct 2023 14:48:56 -0400 Subject: [PATCH 5/5] Use pp2 max allocation limit for TLV value --- src/server.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/server.c b/src/server.c index b53194fc23d1..096f6a850ff7 100644 --- a/src/server.c +++ b/src/server.c @@ -51,7 +51,6 @@ #define TLV_DELIM ";\n" #define TLV_VALUE_DELIM "=" -#define TLV_VALUE_LEN 2048 static void srv_update_status(struct server *s, int type, int cause); @@ -1317,19 +1316,19 @@ static struct conn_tlv_list* parse_tlv_kv(char* str) uint16_t l; key = strtok_r(str, TLV_VALUE_DELIM, &saveptr_int); - if (key == NULL) { + if (unlikely(key == NULL)) { ha_warning("'%s' ignoring TLV, invalid key.\n", str); return NULL; } val = strtok_r(NULL, TLV_VALUE_DELIM, &saveptr_int); - if (val == NULL) { + if (unlikely(val == NULL)) { ha_warning("'%s' ignoring TLV, invalid value.\n", str); return NULL; } l = (uint16_t)strlen(val); - if (l > TLV_VALUE_LEN) { + if (unlikely(l > HA_PP2_MAX_ALLOC)) { ha_warning("'%s' ignoring TLV, invalid length.\n", str); return NULL; }