From 129f8f1aed883408755c4faaa4b846dd09eaedc0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 16 Dec 2011 21:35:50 +0100 Subject: MEDIUM: http: replace get_ip_from_hdr2() with http_get_hdr() The new function does not return IP addresses but header values instead, so that the caller is free to make what it want of them. The conversion is not quite clean yet, as the previous test which considered that address 0.0.0.0 meant "no address" is still used. A different IP parsing function should be used to take this into account. --- include/proto/proto_http.h | 5 ++- src/backend.c | 32 +++++++++++++-------- src/proto_http.c | 67 +++++++++++++++++++++++++++----------------- 3 files changed, 64 insertions(+), 40 deletions(-) diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h index 4cb4f0b..f5dcbce 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 5e88f62..5dbdec3 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 10a4bdd..da785bb 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; + + 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(get_ip_from_hdr2(&txn->req, arg_p->data.str.str, arg_p->data.str.len, &txn->hdr_idx, -1)); + data->ip.s_addr = htonl(inetaddr_host_lim(vptr, vptr + vlen)); return data->ip.s_addr != 0; } -- 1.7.2.3