diff --git a/include/proto/frontend.h b/include/proto/frontend.h index 6a686229f..a80f9bd64 100644 --- a/include/proto/frontend.h +++ b/include/proto/frontend.h @@ -25,7 +25,6 @@ #include #include -void get_frt_addr(struct session *s); int frontend_accept(struct session *s); int frontend_decode_proxy_request(struct session *s, struct buffer *req, int an_bit); int make_proxy_line(char *buf, int buf_len, struct sockaddr_storage *src, struct sockaddr_storage *dst); diff --git a/include/proto/stream_sock.h b/include/proto/stream_sock.h index e5d4f517a..9e1bc3f1a 100644 --- a/include/proto/stream_sock.h +++ b/include/proto/stream_sock.h @@ -58,6 +58,50 @@ static inline int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *sa } +/* + * Retrieves the original destination address for the stream interface. On the + * client side, if the original destination address was translated, the original + * address is retrieved. + */ +static inline void stream_sock_get_to_addr(struct stream_interface *si) +{ + socklen_t namelen; + + if (si->flags & SI_FL_TO_SET) + return; + + namelen = sizeof(si->addr.to); + +#if defined(TPROXY) && defined(SO_ORIGINAL_DST) + if (getsockopt(si->fd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr *)&si->addr.to, &namelen) != -1) { + si->flags |= SI_FL_TO_SET; + return; + } +#endif + if (si->get_dst && + si->get_dst(si->fd, (struct sockaddr *)&si->addr.to, &namelen) != -1) + si->flags |= SI_FL_TO_SET; + return; +} + +/* + * Retrieves the source address for the stream interface. + */ +static inline void stream_sock_get_from_addr(struct stream_interface *si) +{ + socklen_t namelen; + + if (si->flags & SI_FL_FROM_SET) + return; + + namelen = sizeof(si->addr.to); + if (si->get_src && + si->get_src(si->fd, (struct sockaddr *)&si->addr.from, &namelen) != -1) + si->flags |= SI_FL_FROM_SET; + return; +} + + #endif /* _PROTO_STREAM_SOCK_H */ /* diff --git a/include/types/session.h b/include/types/session.h index 7539c0cd8..f1b745102 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -50,7 +50,7 @@ #define SN_FORCE_PRST 0x00000010 /* force persistence here, even if server is down */ #define SN_MONITOR 0x00000020 /* this session comes from a monitoring system */ #define SN_CURR_SESS 0x00000040 /* a connection is currently being counted on the server */ -#define SN_FRT_ADDR_SET 0x00000080 /* set if the frontend address has been filled */ +/* unused: 0x00000080 */ #define SN_REDISP 0x00000100 /* set if this session was redispatched from one server to another */ #define SN_CONN_TAR 0x00000200 /* set if this session is turning around before reconnecting */ #define SN_REDIRECTABLE 0x00000400 /* set if this session is redirectable (GET or HEAD) */ @@ -84,7 +84,6 @@ #define SN_IGNORE_PRST 0x00080000 /* ignore persistence */ #define SN_BE_TRACK_SC1 0x00100000 /* backend tracks stick-counter 1 */ #define SN_BE_TRACK_SC2 0x00200000 /* backend tracks stick-counter 2 */ -#define SN_BCK_ADDR_SET 0x00400000 /* set if the backend address has been filled */ /* Termination sequence tracing. * diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index dae36efdb..271abc75c 100644 --- a/include/types/stream_interface.h +++ b/include/types/stream_interface.h @@ -133,6 +133,8 @@ struct stream_interface { void (*chk_snd)(struct stream_interface *);/* chk_snd function */ int (*connect)(struct stream_interface *); /* connect function if any */ void (*release)(struct stream_interface *); /* handler to call after the last close() */ + int (*get_src)(int, struct sockaddr *, socklen_t *); /* syscall used to retrieve src addr */ + int (*get_dst)(int, struct sockaddr *, socklen_t *); /* syscall used to retrieve dst addr */ /* struct members below are the "remote" part, as seen from the buffer side */ struct target target; /* the target to connect to (server, proxy, applet, ...) */ diff --git a/src/backend.c b/src/backend.c index f6e2d731b..57acbe77f 100644 --- a/src/backend.c +++ b/src/backend.c @@ -688,8 +688,8 @@ int assign_server_address(struct session *s) * the client asked, which is handy for remapping ports * locally on multiple addresses at once. */ - if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET)) - get_frt_addr(s); + if (!(s->be->options & PR_O_TRANSP)) + stream_sock_get_to_addr(s->req->prod); if (s->req->prod->addr.to.ss_family == AF_INET) { ((struct sockaddr_in *)&s->req->cons->addr.to)->sin_addr = ((struct sockaddr_in *)&s->req->prod->addr.to)->sin_addr; @@ -703,8 +703,8 @@ int assign_server_address(struct session *s) if (target_srv(&s->target)->state & SRV_MAPPORTS) { int base_port; - if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET)) - get_frt_addr(s); + if (!(s->be->options & PR_O_TRANSP)) + stream_sock_get_to_addr(s->req->prod); /* First, retrieve the port from the incoming connection */ base_port = get_host_port(&s->req->prod->addr.to); @@ -720,8 +720,7 @@ int assign_server_address(struct session *s) } else if (s->be->options & PR_O_TRANSP) { /* in transparent mode, use the original dest addr if no dispatch specified */ - if (!(s->flags & SN_FRT_ADDR_SET)) - get_frt_addr(s); + stream_sock_get_to_addr(s->req->prod); if (s->req->prod->addr.to.ss_family == AF_INET || s->req->prod->addr.to.ss_family == AF_INET6) { memcpy(&s->req->cons->addr.to, &s->req->prod->addr.to, MIN(sizeof(s->req->cons->addr.to), sizeof(s->req->prod->addr.to))); @@ -973,6 +972,8 @@ int connect_server(struct session *s) */ stream_sock_prepare_interface(s->req->cons); s->req->cons->connect = tcp_connect_server; + s->req->cons->get_src = getsockname; + s->req->cons->get_dst = getpeername; /* the target was only on the session, assign it to the SI now */ copy_target(&s->req->cons->target, &s->target); @@ -980,8 +981,7 @@ int connect_server(struct session *s) s->req->cons->send_proxy_ofs = 0; if (s->target.type == TARG_TYPE_SERVER && (s->target.ptr.s->state & SRV_SEND_PROXY)) { s->req->cons->send_proxy_ofs = 1; /* must compute size */ - if (!(s->flags & SN_FRT_ADDR_SET)) - get_frt_addr(s); + stream_sock_get_to_addr(s->req->prod); } assign_tproxy_address(s); diff --git a/src/frontend.c b/src/frontend.c index 35c3ef338..12f55ad2b 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -44,20 +44,6 @@ #include #include - -/* Retrieves the original destination address used by the client, and sets the - * SN_FRT_ADDR_SET flag. - */ -void get_frt_addr(struct session *s) -{ - socklen_t namelen = sizeof(s->si[0].addr.to); - - if (get_original_dst(s->si[0].fd, (struct sockaddr_in *)&s->si[0].addr.to, &namelen) == -1) - getsockname(s->si[0].fd, (struct sockaddr *)&s->si[0].addr.to, &namelen); - s->si[0].flags |= SI_FL_TO_SET; - s->flags |= SN_FRT_ADDR_SET; -} - /* Finish a session accept() for a proxy (TCP or HTTP). It returns a negative * value in case of a critical failure which must cause the listener to be * disabled, a positive value in case of success, or zero if it is a success @@ -152,8 +138,8 @@ int frontend_accept(struct session *s) else { char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN]; - if (!(s->flags & SN_FRT_ADDR_SET)) - get_frt_addr(s); + stream_sock_get_from_addr(s->req->prod); + stream_sock_get_to_addr(s->req->prod); switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) { case AF_INET: @@ -178,8 +164,7 @@ int frontend_accept(struct session *s) char pn[INET6_ADDRSTRLEN]; int len = 0; - if (!(s->flags & SN_FRT_ADDR_SET)) - get_frt_addr(s); + stream_sock_get_from_addr(s->req->prod); switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) { case AF_INET: @@ -334,8 +319,7 @@ int frontend_decode_proxy_request(struct session *s, struct buffer *req, int an_ ((struct sockaddr_in *)&s->si[0].addr.to)->sin_family = AF_INET; ((struct sockaddr_in *)&s->si[0].addr.to)->sin_addr.s_addr = htonl(dst3); ((struct sockaddr_in *)&s->si[0].addr.to)->sin_port = htons(dport); - s->flags |= SN_FRT_ADDR_SET; - + s->si[0].flags |= SI_FL_FROM_SET | SI_FL_TO_SET; } else if (!memcmp(line, "TCP6 ", 5) != 0) { u32 sport, dport; @@ -396,7 +380,7 @@ int frontend_decode_proxy_request(struct session *s, struct buffer *req, int an_ ((struct sockaddr_in6 *)&s->si[0].addr.to)->sin6_family = AF_INET6; memcpy(&((struct sockaddr_in6 *)&s->si[0].addr.to)->sin6_addr, &dst3, sizeof(struct in6_addr)); ((struct sockaddr_in6 *)&s->si[0].addr.to)->sin6_port = htons(dport); - s->flags |= SN_FRT_ADDR_SET; + s->si[0].flags |= SI_FL_FROM_SET | SI_FL_TO_SET; } else { goto fail; diff --git a/src/log.c b/src/log.c index 00d0e711a..a0493dc9f 100644 --- a/src/log.c +++ b/src/log.c @@ -33,6 +33,7 @@ #include #include #include +#include const char *log_facilities[NB_LOG_FACILITIES] = { "kern", "user", "mail", "daemon", @@ -858,7 +859,7 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis break; case LOG_FMT_FRONTENDIP: // %Fi - get_frt_addr(s); + stream_sock_get_to_addr(s->req->prod); ret = lf_ip(tmplog, (struct sockaddr *)&s->req->prod->addr.to, dst + maxsize - tmplog, tmp); if (ret == NULL) @@ -868,7 +869,7 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis break; case LOG_FMT_FRONTENDPORT: // %Fp - get_frt_addr(s); + stream_sock_get_to_addr(s->req->prod); if (s->req->prod->addr.to.ss_family == AF_UNIX) { ret = ltoa_o(s->listener->luid, tmplog, dst + maxsize - tmplog); diff --git a/src/peers.c b/src/peers.c index 250e17fe9..6c25dcd49 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1156,6 +1156,8 @@ static struct session *peer_session_create(struct peer *peer, struct peer_sessio s->si[0].err_type = SI_ET_NONE; s->si[0].err_loc = NULL; s->si[0].connect = NULL; + s->si[0].get_src = NULL; + s->si[0].get_dst = NULL; clear_target(&s->si[0].target); s->si[0].exp = TICK_ETERNITY; s->si[0].flags = SI_FL_NONE; @@ -1173,6 +1175,8 @@ static struct session *peer_session_create(struct peer *peer, struct peer_sessio s->si[1].err_type = SI_ET_NONE; s->si[1].err_loc = NULL; s->si[1].connect = tcp_connect_server; + s->si[1].get_src = getsockname; + s->si[1].get_dst = getpeername; set_target_proxy(&s->si[1].target, s->be); s->si[1].exp = TICK_ETERNITY; s->si[1].flags = SI_FL_NONE; diff --git a/src/proto_http.c b/src/proto_http.c index dd2f0d07d..3c3bd1ce2 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3380,8 +3380,7 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit) /* Add an X-Original-To header unless the destination IP is * in the 'except' network range. */ - if (!(s->flags & SN_FRT_ADDR_SET)) - get_frt_addr(s); + stream_sock_get_to_addr(s->req->prod); if (s->req->prod->addr.to.ss_family == AF_INET && ((!s->fe->except_mask_to.s_addr || diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 7b0158641..8966ad3c1 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -403,6 +403,7 @@ int tcp_connect_server(struct stream_interface *si) if (global.tune.server_rcvbuf) setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf)); + si->flags &= ~SI_FL_FROM_SET; if ((connect(fd, (struct sockaddr *)&si->addr.to, get_addr_len(&si->addr.to)) == -1) && (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) { @@ -438,13 +439,8 @@ int tcp_connect_server(struct stream_interface *si) } /* needs src ip/port for logging */ - if (si->flags & SI_FL_SRC_ADDR) { - socklen_t addrlen = sizeof(si->addr.from); - if (getsockname(fd, (struct sockaddr *)&si->addr.from, &addrlen) == -1) { - Warning("Cannot get source address for logging.\n"); - } - si->flags |= SI_FL_FROM_SET; - } + if (si->flags & SI_FL_SRC_ADDR) + stream_sock_get_from_addr(si); fdtab[fd].owner = si; fdtab[fd].state = FD_STCONN; /* connection in progress */ @@ -1318,8 +1314,7 @@ static int acl_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir, struct acl_expr *expr, struct acl_test *test) { - if (!(l4->flags & SN_FRT_ADDR_SET)) - get_frt_addr(l4); + stream_sock_get_to_addr(&l4->si[0]); switch (l4->si[0].addr.to.ss_family) { case AF_INET: @@ -1344,8 +1339,7 @@ static int pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir, const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { - if (!(l4->flags & SN_FRT_ADDR_SET)) - get_frt_addr(l4); + stream_sock_get_to_addr(&l4->si[0]); if (l4->si[0].addr.to.ss_family != AF_INET) return 0; @@ -1359,8 +1353,7 @@ static int pattern_fetch_dst6(struct proxy *px, struct session *l4, void *l7, int dir, const struct pattern_arg *arg_p, int arg_i, union pattern_data *data) { - if (!(l4->flags & SN_FRT_ADDR_SET)) - get_frt_addr(l4); + stream_sock_get_to_addr(&l4->si[0]); if (l4->si[0].addr.to.ss_family != AF_INET6) return 0; @@ -1374,8 +1367,7 @@ static int acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, struct acl_expr *expr, struct acl_test *test) { - if (!(l4->flags & SN_FRT_ADDR_SET)) - get_frt_addr(l4); + stream_sock_get_to_addr(&l4->si[0]); if (!(temp_pattern.data.integer = get_host_port(&l4->si[0].addr.to))) return 0; @@ -1388,8 +1380,7 @@ static int pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, const struct pattern_arg *arg, int i, union pattern_data *data) { - if (!(l4->flags & SN_FRT_ADDR_SET)) - get_frt_addr(l4); + stream_sock_get_to_addr(&l4->si[0]); if (!(data->integer = get_host_port(&l4->si[0].addr.to))) return 0; diff --git a/src/session.c b/src/session.c index b90b25465..e814903aa 100644 --- a/src/session.c +++ b/src/session.c @@ -169,6 +169,8 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) s->si[0].err_loc = NULL; s->si[0].connect = NULL; s->si[0].release = NULL; + s->si[0].get_src = getpeername; + s->si[0].get_dst = getsockname; clear_target(&s->si[0].target); s->si[0].exp = TICK_ETERNITY; s->si[0].flags = SI_FL_NONE; @@ -193,6 +195,8 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) s->si[1].err_loc = NULL; s->si[1].connect = NULL; s->si[1].release = NULL; + s->si[1].get_src = NULL; + s->si[1].get_dst = NULL; clear_target(&s->si[1].target); s->si[1].shutr = stream_int_shutr; s->si[1].shutw = stream_int_shutw;