diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 4cb4f0b25..f5dcbce30 100644 --- a/include/proto/proto_http.h +++ b/include/proto/proto_http.h @@ -97,8 +97,9 @@ void http_return_srv_error(struct session *s, struct stream_interface *si); void http_capture_bad_message(struct error_snapshot *es, struct session *s, struct buffer *buf, struct http_msg *msg, int state, struct proxy *other_end); -unsigned int get_ip_from_hdr2(struct http_msg *msg, const char *hname, int hlen, - struct hdr_idx *idx, int occ); +unsigned int http_get_hdr(struct http_msg *msg, const char *hname, int hlen, + struct hdr_idx *idx, int occ, + struct hdr_ctx *ctx, char **vptr, int *vlen); void http_init_txn(struct session *s); void http_end_txn(struct session *s); diff --git a/src/backend.c b/src/backend.c index 5e88f62c9..5dbdec37a 100644 --- a/src/backend.c +++ b/src/backend.c @@ -881,15 +881,19 @@ static void assign_tproxy_address(struct session *s) break; case SRV_TPROXY_DYN: if (srv->bind_hdr_occ) { + char *vptr; + int vlen; + /* bind to the IP in a header */ ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_family = AF_INET; ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_port = 0; - ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = - htonl(get_ip_from_hdr2(&s->txn.req, - srv->bind_hdr_name, - srv->bind_hdr_len, - &s->txn.hdr_idx, - srv->bind_hdr_occ)); + ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = 0; + + if (http_get_hdr(&s->txn.req, srv->bind_hdr_name, srv->bind_hdr_len, + &s->txn.hdr_idx, srv->bind_hdr_occ, NULL, &vptr, &vlen)) { + ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = + htonl(inetaddr_host_lim(vptr, vptr + vlen)); + } } break; default: @@ -908,15 +912,19 @@ static void assign_tproxy_address(struct session *s) break; case PR_O_TPXY_DYN: if (s->be->bind_hdr_occ) { + char *vptr; + int vlen; + /* bind to the IP in a header */ ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_family = AF_INET; ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_port = 0; - ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = - htonl(get_ip_from_hdr2(&s->txn.req, - s->be->bind_hdr_name, - s->be->bind_hdr_len, - &s->txn.hdr_idx, - s->be->bind_hdr_occ)); + ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = 0; + + if (http_get_hdr(&s->txn.req, s->be->bind_hdr_name, s->be->bind_hdr_len, + &s->txn.hdr_idx, s->be->bind_hdr_occ, NULL, &vptr, &vlen)) { + ((struct sockaddr_in *)&s->req->cons->addr.from)->sin_addr.s_addr = + htonl(inetaddr_host_lim(vptr, vptr + vlen)); + } } break; default: diff --git a/src/proto_http.c b/src/proto_http.c index 10a4bddb7..da785bb48 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -7483,45 +7483,53 @@ void http_capture_bad_message(struct error_snapshot *es, struct session *s, es->ev_id = error_snapshot_id++; } -/* return the IP address pointed to by occurrence of header in - * HTTP message indexed in . If is strictly positive, the - * occurrence number corresponding to this value is returned. If is - * strictly negative, the occurrence number before the end corresponding to - * this value is returned. If is null, any value is returned, so it is - * not recommended to use it that way. Negative occurrences are limited to - * a small value because it is required to keep them in memory while scanning. - * IP address 0.0.0.0 is returned if no match is found. +/* Return in and the pointer and length of occurrence of + * header whose name is of length . If is null, lookup is + * performed over the whole headers. Otherwise it must contain a valid header + * context, initialised with ctx->idx=0 for the first lookup in a series. If + * is positive or null, occurrence #occ from the beginning (or last ctx) + * is returned. Occ #0 and #1 are equivalent. If is negative (and no less + * than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is + * -1. + * The return value is 0 if nothing was found, or non-zero otherwise. */ -unsigned int get_ip_from_hdr2(struct http_msg *msg, const char *hname, int hlen, struct hdr_idx *idx, int occ) +unsigned int http_get_hdr(struct http_msg *msg, const char *hname, int hlen, + struct hdr_idx *idx, int occ, + struct hdr_ctx *ctx, char **vptr, int *vlen) { - struct hdr_ctx ctx; - unsigned int hdr_hist[MAX_HDR_HISTORY]; + struct hdr_ctx local_ctx; + char *ptr_hist[MAX_HDR_HISTORY]; + int len_hist[MAX_HDR_HISTORY]; unsigned int hist_ptr; - int found = 0; + int found; + + if (!ctx) { + local_ctx.idx = 0; + ctx = &local_ctx; + } - ctx.idx = 0; if (occ >= 0) { - while (http_find_header2(hname, hlen, msg->sol, idx, &ctx)) { + /* search from the beginning */ + while (http_find_header2(hname, hlen, msg->sol, idx, ctx)) { occ--; if (occ <= 0) { - found = 1; - break; + *vptr = ctx->line + ctx->val; + *vlen = ctx->vlen; + return 1; } } - if (!found) - return 0; - return inetaddr_host_lim(ctx.line+ctx.val, ctx.line+ctx.val+ctx.vlen); + return 0; } /* negative occurrence, we scan all the list then walk back */ if (-occ > MAX_HDR_HISTORY) return 0; - hist_ptr = 0; - hdr_hist[hist_ptr] = 0; - while (http_find_header2(hname, hlen, msg->sol, idx, &ctx)) { - hdr_hist[hist_ptr++] = inetaddr_host_lim(ctx.line+ctx.val, ctx.line+ctx.val+ctx.vlen); - if (hist_ptr >= MAX_HDR_HISTORY) + found = hist_ptr = 0; + while (http_find_header2(hname, hlen, msg->sol, idx, ctx)) { + ptr_hist[hist_ptr] = ctx->line + ctx->val; + len_hist[hist_ptr] = ctx->vlen; + if (++hist_ptr >= MAX_HDR_HISTORY) hist_ptr = 0; found++; } @@ -7533,7 +7541,9 @@ unsigned int get_ip_from_hdr2(struct http_msg *msg, const char *hname, int hlen, hist_ptr += occ; if (hist_ptr >= MAX_HDR_HISTORY) hist_ptr -= MAX_HDR_HISTORY; - return hdr_hist[hist_ptr]; + *vptr = ptr_hist[hist_ptr]; + *vlen = len_hist[hist_ptr]; + return 1; } /* @@ -8489,8 +8499,13 @@ pattern_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, int dir, const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { struct http_txn *txn = l7; + const char *vptr; + int vlen; - data->ip.s_addr = htonl(get_ip_from_hdr2(&txn->req, arg_p->data.str.str, arg_p->data.str.len, &txn->hdr_idx, -1)); + if (!http_get_hdr(&txn->req, arg_p->data.str.str, arg_p->data.str.len, &txn->hdr_idx, -1, NULL, &vptr, &vlen)) + return 0; + + data->ip.s_addr = htonl(inetaddr_host_lim(vptr, vptr + vlen)); return data->ip.s_addr != 0; }