mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 07:07:04 +02:00
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.
This commit is contained in:
parent
1539a01645
commit
59b9479667
@ -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);
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include <types/task.h>
|
||||
|
||||
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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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=<NONE> (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=<NONE> (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:
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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 ||
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <proto/session.h>
|
||||
#include <proto/sock_raw.h>
|
||||
#include <proto/stick_table.h>
|
||||
#include <proto/stream_interface.h>
|
||||
#include <proto/task.h>
|
||||
#include <proto/buffers.h>
|
||||
|
||||
@ -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 <fd>, with <dir> 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
|
||||
* <sa> for <salen> 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 <fd>, with <dir>
|
||||
* 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 <sa> for <salen> 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 <err> if the message is at most <errlen> 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)))
|
||||
|
@ -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 <fd>, with <dir> 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
|
||||
* <sa> for <salen> 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 <fd>, with <dir>
|
||||
* 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 <sa> for <salen> 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 <path>. The socket must not be used
|
||||
* anymore. It practises best effort, and no error is returned.
|
||||
|
Loading…
Reference in New Issue
Block a user