MEDIUM: stream_sock: add a get_src and get_dst callback and remove SN_FRT_ADDR_SET

These callbacks are used to retrieve the source and destination address
of a socket. The address flags are not hold on the stream interface and
not on the session anymore. The addresses are collected when needed.

This still needs to be improved to store the IP and port separately so
that it is not needed to perform a getsockname() when only the IP address
is desired for outgoing traffic.
This commit is contained in:
Willy Tarreau 2012-04-07 18:03:52 +02:00
parent 5e19a2866f
commit 9b061e3320
11 changed files with 80 additions and 53 deletions

View File

@ -25,7 +25,6 @@
#include <common/config.h> #include <common/config.h>
#include <types/session.h> #include <types/session.h>
void get_frt_addr(struct session *s);
int frontend_accept(struct session *s); int frontend_accept(struct session *s);
int frontend_decode_proxy_request(struct session *s, struct buffer *req, int an_bit); 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); int make_proxy_line(char *buf, int buf_len, struct sockaddr_storage *src, struct sockaddr_storage *dst);

View File

@ -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 */ #endif /* _PROTO_STREAM_SOCK_H */
/* /*

View File

@ -50,7 +50,7 @@
#define SN_FORCE_PRST 0x00000010 /* force persistence here, even if server is down */ #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_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_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_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_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) */ #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_IGNORE_PRST 0x00080000 /* ignore persistence */
#define SN_BE_TRACK_SC1 0x00100000 /* backend tracks stick-counter 1 */ #define SN_BE_TRACK_SC1 0x00100000 /* backend tracks stick-counter 1 */
#define SN_BE_TRACK_SC2 0x00200000 /* backend tracks stick-counter 2 */ #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. /* Termination sequence tracing.
* *

View File

@ -133,6 +133,8 @@ struct stream_interface {
void (*chk_snd)(struct stream_interface *);/* chk_snd function */ void (*chk_snd)(struct stream_interface *);/* chk_snd function */
int (*connect)(struct stream_interface *); /* connect function if any */ int (*connect)(struct stream_interface *); /* connect function if any */
void (*release)(struct stream_interface *); /* handler to call after the last close() */ 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 members below are the "remote" part, as seen from the buffer side */
struct target target; /* the target to connect to (server, proxy, applet, ...) */ struct target target; /* the target to connect to (server, proxy, applet, ...) */

View File

@ -688,8 +688,8 @@ int assign_server_address(struct session *s)
* the client asked, which is handy for remapping ports * the client asked, which is handy for remapping ports
* locally on multiple addresses at once. * locally on multiple addresses at once.
*/ */
if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET)) if (!(s->be->options & PR_O_TRANSP))
get_frt_addr(s); stream_sock_get_to_addr(s->req->prod);
if (s->req->prod->addr.to.ss_family == AF_INET) { 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; ((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) { if (target_srv(&s->target)->state & SRV_MAPPORTS) {
int base_port; int base_port;
if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET)) if (!(s->be->options & PR_O_TRANSP))
get_frt_addr(s); stream_sock_get_to_addr(s->req->prod);
/* First, retrieve the port from the incoming connection */ /* First, retrieve the port from the incoming connection */
base_port = get_host_port(&s->req->prod->addr.to); 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) { else if (s->be->options & PR_O_TRANSP) {
/* in transparent mode, use the original dest addr if no dispatch specified */ /* in transparent mode, use the original dest addr if no dispatch specified */
if (!(s->flags & SN_FRT_ADDR_SET)) stream_sock_get_to_addr(s->req->prod);
get_frt_addr(s);
if (s->req->prod->addr.to.ss_family == AF_INET || s->req->prod->addr.to.ss_family == AF_INET6) { 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))); 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); stream_sock_prepare_interface(s->req->cons);
s->req->cons->connect = tcp_connect_server; 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 */ /* the target was only on the session, assign it to the SI now */
copy_target(&s->req->cons->target, &s->target); 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; s->req->cons->send_proxy_ofs = 0;
if (s->target.type == TARG_TYPE_SERVER && (s->target.ptr.s->state & SRV_SEND_PROXY)) { 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 */ s->req->cons->send_proxy_ofs = 1; /* must compute size */
if (!(s->flags & SN_FRT_ADDR_SET)) stream_sock_get_to_addr(s->req->prod);
get_frt_addr(s);
} }
assign_tproxy_address(s); assign_tproxy_address(s);

View File

@ -44,20 +44,6 @@
#include <proto/stream_sock.h> #include <proto/stream_sock.h>
#include <proto/task.h> #include <proto/task.h>
/* 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 /* 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 * 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 * 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 { else {
char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN]; char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
if (!(s->flags & SN_FRT_ADDR_SET)) stream_sock_get_from_addr(s->req->prod);
get_frt_addr(s); stream_sock_get_to_addr(s->req->prod);
switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) { switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) {
case AF_INET: case AF_INET:
@ -178,8 +164,7 @@ int frontend_accept(struct session *s)
char pn[INET6_ADDRSTRLEN]; char pn[INET6_ADDRSTRLEN];
int len = 0; int len = 0;
if (!(s->flags & SN_FRT_ADDR_SET)) stream_sock_get_from_addr(s->req->prod);
get_frt_addr(s);
switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) { switch (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn))) {
case AF_INET: 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_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_addr.s_addr = htonl(dst3);
((struct sockaddr_in *)&s->si[0].addr.to)->sin_port = htons(dport); ((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) { else if (!memcmp(line, "TCP6 ", 5) != 0) {
u32 sport, dport; 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; ((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)); 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); ((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 { else {
goto fail; goto fail;

View File

@ -33,6 +33,7 @@
#include <proto/frontend.h> #include <proto/frontend.h>
#include <proto/log.h> #include <proto/log.h>
#include <proto/stream_interface.h> #include <proto/stream_interface.h>
#include <proto/stream_sock.h>
const char *log_facilities[NB_LOG_FACILITIES] = { const char *log_facilities[NB_LOG_FACILITIES] = {
"kern", "user", "mail", "daemon", "kern", "user", "mail", "daemon",
@ -858,7 +859,7 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_FRONTENDIP: // %Fi 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, ret = lf_ip(tmplog, (struct sockaddr *)&s->req->prod->addr.to,
dst + maxsize - tmplog, tmp); dst + maxsize - tmplog, tmp);
if (ret == NULL) if (ret == NULL)
@ -868,7 +869,7 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
break; break;
case LOG_FMT_FRONTENDPORT: // %Fp 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) { if (s->req->prod->addr.to.ss_family == AF_UNIX) {
ret = ltoa_o(s->listener->luid, ret = ltoa_o(s->listener->luid,
tmplog, dst + maxsize - tmplog); tmplog, dst + maxsize - tmplog);

View File

@ -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_type = SI_ET_NONE;
s->si[0].err_loc = NULL; s->si[0].err_loc = NULL;
s->si[0].connect = NULL; s->si[0].connect = NULL;
s->si[0].get_src = NULL;
s->si[0].get_dst = NULL;
clear_target(&s->si[0].target); clear_target(&s->si[0].target);
s->si[0].exp = TICK_ETERNITY; s->si[0].exp = TICK_ETERNITY;
s->si[0].flags = SI_FL_NONE; 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_type = SI_ET_NONE;
s->si[1].err_loc = NULL; s->si[1].err_loc = NULL;
s->si[1].connect = tcp_connect_server; 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); set_target_proxy(&s->si[1].target, s->be);
s->si[1].exp = TICK_ETERNITY; s->si[1].exp = TICK_ETERNITY;
s->si[1].flags = SI_FL_NONE; s->si[1].flags = SI_FL_NONE;

View File

@ -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 /* Add an X-Original-To header unless the destination IP is
* in the 'except' network range. * in the 'except' network range.
*/ */
if (!(s->flags & SN_FRT_ADDR_SET)) stream_sock_get_to_addr(s->req->prod);
get_frt_addr(s);
if (s->req->prod->addr.to.ss_family == AF_INET && if (s->req->prod->addr.to.ss_family == AF_INET &&
((!s->fe->except_mask_to.s_addr || ((!s->fe->except_mask_to.s_addr ||

View File

@ -403,6 +403,7 @@ int tcp_connect_server(struct stream_interface *si)
if (global.tune.server_rcvbuf) if (global.tune.server_rcvbuf)
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(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) && if ((connect(fd, (struct sockaddr *)&si->addr.to, get_addr_len(&si->addr.to)) == -1) &&
(errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) { (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
@ -438,13 +439,8 @@ int tcp_connect_server(struct stream_interface *si)
} }
/* needs src ip/port for logging */ /* needs src ip/port for logging */
if (si->flags & SI_FL_SRC_ADDR) { if (si->flags & SI_FL_SRC_ADDR)
socklen_t addrlen = sizeof(si->addr.from); stream_sock_get_from_addr(si);
if (getsockname(fd, (struct sockaddr *)&si->addr.from, &addrlen) == -1) {
Warning("Cannot get source address for logging.\n");
}
si->flags |= SI_FL_FROM_SET;
}
fdtab[fd].owner = si; fdtab[fd].owner = si;
fdtab[fd].state = FD_STCONN; /* connection in progress */ 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, acl_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir,
struct acl_expr *expr, struct acl_test *test) struct acl_expr *expr, struct acl_test *test)
{ {
if (!(l4->flags & SN_FRT_ADDR_SET)) stream_sock_get_to_addr(&l4->si[0]);
get_frt_addr(l4);
switch (l4->si[0].addr.to.ss_family) { switch (l4->si[0].addr.to.ss_family) {
case AF_INET: case AF_INET:
@ -1344,8 +1339,7 @@ static int
pattern_fetch_dst(struct proxy *px, struct session *l4, void *l7, int dir, 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) const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
{ {
if (!(l4->flags & SN_FRT_ADDR_SET)) stream_sock_get_to_addr(&l4->si[0]);
get_frt_addr(l4);
if (l4->si[0].addr.to.ss_family != AF_INET) if (l4->si[0].addr.to.ss_family != AF_INET)
return 0; return 0;
@ -1359,8 +1353,7 @@ static int
pattern_fetch_dst6(struct proxy *px, struct session *l4, void *l7, int dir, 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) const struct pattern_arg *arg_p, int arg_i, union pattern_data *data)
{ {
if (!(l4->flags & SN_FRT_ADDR_SET)) stream_sock_get_to_addr(&l4->si[0]);
get_frt_addr(l4);
if (l4->si[0].addr.to.ss_family != AF_INET6) if (l4->si[0].addr.to.ss_family != AF_INET6)
return 0; return 0;
@ -1374,8 +1367,7 @@ static int
acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
struct acl_expr *expr, struct acl_test *test) struct acl_expr *expr, struct acl_test *test)
{ {
if (!(l4->flags & SN_FRT_ADDR_SET)) stream_sock_get_to_addr(&l4->si[0]);
get_frt_addr(l4);
if (!(temp_pattern.data.integer = get_host_port(&l4->si[0].addr.to))) if (!(temp_pattern.data.integer = get_host_port(&l4->si[0].addr.to)))
return 0; return 0;
@ -1388,8 +1380,7 @@ static int
pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, pattern_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir,
const struct pattern_arg *arg, int i, union pattern_data *data) const struct pattern_arg *arg, int i, union pattern_data *data)
{ {
if (!(l4->flags & SN_FRT_ADDR_SET)) stream_sock_get_to_addr(&l4->si[0]);
get_frt_addr(l4);
if (!(data->integer = get_host_port(&l4->si[0].addr.to))) if (!(data->integer = get_host_port(&l4->si[0].addr.to)))
return 0; return 0;

View File

@ -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].err_loc = NULL;
s->si[0].connect = NULL; s->si[0].connect = NULL;
s->si[0].release = NULL; s->si[0].release = NULL;
s->si[0].get_src = getpeername;
s->si[0].get_dst = getsockname;
clear_target(&s->si[0].target); clear_target(&s->si[0].target);
s->si[0].exp = TICK_ETERNITY; s->si[0].exp = TICK_ETERNITY;
s->si[0].flags = SI_FL_NONE; 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].err_loc = NULL;
s->si[1].connect = NULL; s->si[1].connect = NULL;
s->si[1].release = NULL; s->si[1].release = NULL;
s->si[1].get_src = NULL;
s->si[1].get_dst = NULL;
clear_target(&s->si[1].target); clear_target(&s->si[1].target);
s->si[1].shutr = stream_int_shutr; s->si[1].shutr = stream_int_shutr;
s->si[1].shutw = stream_int_shutw; s->si[1].shutw = stream_int_shutw;