From: Willy Tarreau Date: Fri, 11 May 2012 14:16:40 +0000 (+0200) Subject: BUG/MEDIUM: stream_interface: restore get_src/get_dst X-Git-Tag: v1.5-dev10~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=59b947966738f2769cd572a21650cbad0b9d58d6;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: stream_interface: restore get_src/get_dst Commit e164e7a removed get_src/get_dst setting in the stream interfaces but forgot to set it in proto_tcp. Get the feature back because we need it for logging, transparent mode, ACLs etc... We now rely on the stream interface direction to know what syscall to use. One benefit of doing it this way is that we don't use getsockopt() anymore on outgoing stream interfaces nor on UNIX sockets. --- diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h index 947699bb42..374c7fdb20 100644 --- a/include/proto/proto_tcp.h +++ b/include/proto/proto_tcp.h @@ -31,6 +31,8 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so void tcpv4_add_listener(struct listener *listener); void tcpv6_add_listener(struct listener *listener); int tcp_connect_server(struct stream_interface *si); +int tcp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir); +int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir); int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit); int tcp_inspect_response(struct session *s, struct buffer *rep, int an_bit); int tcp_exec_req_rules(struct session *s); diff --git a/include/proto/proto_uxst.h b/include/proto/proto_uxst.h index b412f0ad49..9422ea7c2b 100644 --- a/include/proto/proto_uxst.h +++ b/include/proto/proto_uxst.h @@ -27,6 +27,8 @@ #include void uxst_add_listener(struct listener *listener); +int uxst_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir); +int uxst_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir); #endif /* _PROTO_PROTO_UXST_H */ diff --git a/include/proto/sock_raw.h b/include/proto/sock_raw.h index 7a618872f5..a17db4dca7 100644 --- a/include/proto/sock_raw.h +++ b/include/proto/sock_raw.h @@ -56,51 +56,6 @@ static inline int get_original_dst(int fd, struct sockaddr_in *sa, socklen_t *sa #endif } - -/* - * 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->proto->get_dst && - si->proto->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->proto->get_src && - si->proto->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/proto/stream_interface.h b/include/proto/stream_interface.h index cbe8282573..5446786beb 100644 --- a/include/proto/stream_interface.h +++ b/include/proto/stream_interface.h @@ -109,6 +109,40 @@ static inline void stream_interface_prepare(struct stream_interface *si, const s memcpy(&si->sock, ops, sizeof(si->sock)); } + +/* Retrieves the source address for the stream interface. */ +static inline void si_get_from_addr(struct stream_interface *si) +{ + if (si->flags & SI_FL_FROM_SET) + return; + + if (!si->proto || !si->proto->get_src) + return; + + if (si->proto->get_src(si->fd, (struct sockaddr *)&si->addr.from, + sizeof(si->addr.from), + si->target.type != TARG_TYPE_CLIENT) == -1) + return; + si->flags |= SI_FL_FROM_SET; +} + +/* Retrieves the original destination address for the stream interface. */ +static inline void si_get_to_addr(struct stream_interface *si) +{ + if (si->flags & SI_FL_TO_SET) + return; + + if (!si->proto || !si->proto->get_dst) + return; + + if (si->proto->get_dst(si->fd, (struct sockaddr *)&si->addr.to, + sizeof(si->addr.to), + si->target.type != TARG_TYPE_CLIENT) == -1) + return; + si->flags |= SI_FL_TO_SET; +} + + #endif /* _PROTO_STREAM_INTERFACE_H */ /* diff --git a/include/types/protocols.h b/include/types/protocols.h index 4112b08c88..bda4922684 100644 --- a/include/types/protocols.h +++ b/include/types/protocols.h @@ -157,8 +157,8 @@ struct protocol { int (*enable_all)(struct protocol *proto); /* enable all bound listeners */ int (*disable_all)(struct protocol *proto); /* disable all bound listeners */ int (*connect)(struct stream_interface *); /* connect function if any */ - 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 */ + int (*get_src)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve src addr */ + int (*get_dst)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve dst addr */ struct list listeners; /* list of listeners using this protocol */ int nb_listeners; /* number of listeners */ diff --git a/src/backend.c b/src/backend.c index 95b395324d..928d63e253 100644 --- a/src/backend.c +++ b/src/backend.c @@ -693,7 +693,7 @@ int assign_server_address(struct session *s) * locally on multiple addresses at once. */ if (!(s->be->options & PR_O_TRANSP)) - stream_sock_get_to_addr(s->req->prod); + si_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; @@ -708,7 +708,7 @@ int assign_server_address(struct session *s) int base_port; if (!(s->be->options & PR_O_TRANSP)) - stream_sock_get_to_addr(s->req->prod); + si_get_to_addr(s->req->prod); /* First, retrieve the port from the incoming connection */ base_port = get_host_port(&s->req->prod->addr.to); @@ -724,7 +724,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 */ - stream_sock_get_to_addr(s->req->prod); + si_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))); @@ -983,7 +983,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 */ - stream_sock_get_to_addr(s->req->prod); + si_get_to_addr(s->req->prod); } /* set the correct protocol on the output stream interface */ diff --git a/src/dumpstats.c b/src/dumpstats.c index 832534e846..43cc275ae8 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -3256,7 +3256,7 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si) sess->listener ? sess->listener->name ? sess->listener->name : "?" : "?", sess->listener ? sess->listener->luid : 0); - stream_sock_get_to_addr(&sess->si[0]); + si_get_to_addr(&sess->si[0]); switch (addr_to_str(&sess->si[0].addr.to, pn, sizeof(pn))) { case AF_INET: case AF_INET6: @@ -3280,7 +3280,7 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si) else chunk_printf(&msg, " backend= (id=-1 mode=-)"); - stream_sock_get_from_addr(&sess->si[1]); + si_get_from_addr(&sess->si[1]); switch (addr_to_str(&sess->si[1].addr.from, pn, sizeof(pn))) { case AF_INET: case AF_INET6: @@ -3304,7 +3304,7 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si) else chunk_printf(&msg, " server= (id=-1)"); - stream_sock_get_to_addr(&sess->si[1]); + si_get_to_addr(&sess->si[1]); switch (addr_to_str(&sess->si[1].addr.to, pn, sizeof(pn))) { case AF_INET: case AF_INET6: diff --git a/src/frontend.c b/src/frontend.c index a72f6b8bbf..d2a9e70bf5 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -139,8 +139,8 @@ int frontend_accept(struct session *s) else { char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN]; - stream_sock_get_from_addr(s->req->prod); - stream_sock_get_to_addr(s->req->prod); + si_get_from_addr(s->req->prod); + si_get_to_addr(s->req->prod); switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) { case AF_INET: @@ -165,7 +165,7 @@ int frontend_accept(struct session *s) char pn[INET6_ADDRSTRLEN]; int len = 0; - stream_sock_get_from_addr(s->req->prod); + si_get_from_addr(s->req->prod); switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) { case AF_INET: diff --git a/src/log.c b/src/log.c index 9fa1b82858..74af1c6804 100644 --- a/src/log.c +++ b/src/log.c @@ -859,7 +859,7 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis break; case LOG_FMT_FRONTENDIP: // %Fi - stream_sock_get_to_addr(s->req->prod); + si_get_to_addr(s->req->prod); ret = lf_ip(tmplog, (struct sockaddr *)&s->req->prod->addr.to, dst + maxsize - tmplog, tmp); if (ret == NULL) @@ -869,7 +869,7 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis break; case LOG_FMT_FRONTENDPORT: // %Fp - stream_sock_get_to_addr(s->req->prod); + si_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/proto_http.c b/src/proto_http.c index 4a3de8fdf2..6cc9c9fbe9 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3335,7 +3335,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. */ - stream_sock_get_to_addr(s->req->prod); + si_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 29aa323554..5d5ede6820 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,8 @@ static struct protocol proto_tcpv4 = { .bind_all = tcp_bind_listeners, .unbind_all = unbind_all_listeners, .enable_all = enable_all_listeners, + .get_src = tcp_get_src, + .get_dst = tcp_get_dst, .listeners = LIST_HEAD_INIT(proto_tcpv4.listeners), .nb_listeners = 0, }; @@ -94,6 +97,8 @@ static struct protocol proto_tcpv6 = { .bind_all = tcp_bind_listeners, .unbind_all = unbind_all_listeners, .enable_all = enable_all_listeners, + .get_src = tcp_get_src, + .get_dst = tcp_get_dst, .listeners = LIST_HEAD_INIT(proto_tcpv6.listeners), .nb_listeners = 0, }; @@ -439,7 +444,7 @@ int tcp_connect_server(struct stream_interface *si) /* needs src ip/port for logging */ if (si->flags & SI_FL_SRC_ADDR) - stream_sock_get_from_addr(si); + si_get_from_addr(si); fdtab[fd].owner = si; fdtab[fd].state = FD_STCONN; /* connection in progress */ @@ -463,6 +468,41 @@ int tcp_connect_server(struct stream_interface *si) } +/* + * Retrieves the source address for the socket , with indicating + * if we're a listener (=0) or an initiator (!=0). It returns 0 in case of + * success, -1 in case of error. The socket's source address is stored in + * for bytes. + */ +int tcp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir) +{ + if (dir) + return getsockname(fd, sa, &salen); + else + return getpeername(fd, sa, &salen); +} + + +/* + * Retrieves the original destination address for the socket , with + * indicating if we're a listener (=0) or an initiator (!=0). In the case of a + * listener, if the original destination address was translated, the original + * address is retrieved. It returns 0 in case of success, -1 in case of error. + * The socket's source address is stored in for bytes. + */ +int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) +{ + if (dir) + return getpeername(fd, sa, &salen); +#if defined(TPROXY) && defined(SO_ORIGINAL_DST) + else if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, &salen) == 0) + return 0; +#endif + else + return getsockname(fd, sa, &salen); +} + + /* This function tries to bind a TCPv4/v6 listener. It may return a warning or * an error message in if the message is at most bytes long * (including '\0'). The return value is composed from ERR_ABORT, ERR_WARN, @@ -1417,7 +1457,7 @@ static int smp_fetch_dst(struct proxy *px, struct session *l4, void *l7, unsigned int opt, const struct arg *args, struct sample *smp) { - stream_sock_get_to_addr(&l4->si[0]); + si_get_to_addr(&l4->si[0]); switch (l4->si[0].addr.to.ss_family) { case AF_INET: @@ -1441,7 +1481,7 @@ static int smp_fetch_dport(struct proxy *px, struct session *l4, void *l7, unsigned int opt, const struct arg *args, struct sample *smp) { - stream_sock_get_to_addr(&l4->si[0]); + si_get_to_addr(&l4->si[0]); smp->type = SMP_T_UINT; if (!(smp->data.uint = get_host_port(&l4->si[0].addr.to))) diff --git a/src/proto_uxst.c b/src/proto_uxst.c index ace1e448f5..0825992017 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -61,6 +61,8 @@ static struct protocol proto_unix = { .unbind_all = uxst_unbind_listeners, .enable_all = enable_all_listeners, .disable_all = disable_all_listeners, + .get_src = uxst_get_src, + .get_dst = uxst_get_dst, .listeners = LIST_HEAD_INIT(proto_unix.listeners), .nb_listeners = 0, }; @@ -69,6 +71,35 @@ static struct protocol proto_unix = { * 1) low-level socket functions ********************************/ +/* + * Retrieves the source address for the socket , with indicating + * if we're a listener (=0) or an initiator (!=0). It returns 0 in case of + * success, -1 in case of error. The socket's source address is stored in + * for bytes. + */ +int uxst_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir) +{ + if (dir) + return getsockname(fd, sa, &salen); + else + return getpeername(fd, sa, &salen); +} + + +/* + * Retrieves the original destination address for the socket , with + * indicating if we're a listener (=0) or an initiator (!=0). It returns 0 in + * case of success, -1 in case of error. The socket's source address is stored + * in for bytes. + */ +int uxst_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) +{ + if (dir) + return getpeername(fd, sa, &salen); + else + return getsockname(fd, sa, &salen); +} + /* Tries to destroy the UNIX stream socket . The socket must not be used * anymore. It practises best effort, and no error is returned.