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:
Willy Tarreau 2012-05-11 16:16:40 +02:00
parent 1539a01645
commit 59b9479667
12 changed files with 127 additions and 63 deletions

View File

@ -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);

View File

@ -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 */

View File

@ -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 */
/*

View File

@ -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 */
/*

View File

@ -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 */

View File

@ -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 */

View File

@ -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:

View File

@ -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:

View File

@ -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);

View File

@ -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 ||

View File

@ -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)))

View File

@ -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.