From 59b947966738f2769cd572a21650cbad0b9d58d6 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 11 May 2012 16:16:40 +0200 Subject: [PATCH] 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. --- include/proto/proto_tcp.h | 2 ++ include/proto/proto_uxst.h | 2 ++ include/proto/sock_raw.h | 45 ------------------------------- include/proto/stream_interface.h | 34 +++++++++++++++++++++++ include/types/protocols.h | 4 +-- src/backend.c | 8 +++--- src/dumpstats.c | 6 ++--- src/frontend.c | 6 ++--- src/log.c | 4 +-- src/proto_http.c | 2 +- src/proto_tcp.c | 46 +++++++++++++++++++++++++++++--- src/proto_uxst.c | 31 +++++++++++++++++++++ 12 files changed, 127 insertions(+), 63 deletions(-) diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h index 947699bb4..374c7fdb2 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 b412f0ad4..9422ea7c2 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 7a618872f..a17db4dca 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 cbe828257..5446786be 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 4112b08c8..bda492268 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 95b395324..928d63e25 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 832534e84..43cc275ae 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 a72f6b8bb..d2a9e70bf 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 9fa1b8285..74af1c680 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 4a3de8fdf..6cc9c9fbe 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 29aa32355..5d5ede682 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 ace1e448f..082599201 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. -- 2.47.3