diff --git a/include/proto/client.h b/include/proto/client.h index 3065b616d2..6540d096fb 100644 --- a/include/proto/client.h +++ b/include/proto/client.h @@ -2,7 +2,7 @@ include/proto/client.h This file contains client-side definitions. - Copyright (C) 2000-2006 Willy Tarreau - w@1wt.eu + Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -24,7 +24,9 @@ #include #include +#include +void get_frt_addr(struct session *s); int event_accept(int fd); diff --git a/include/types/session.h b/include/types/session.h index 1011c9a023..7ef138f105 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -47,7 +47,7 @@ #define SN_CONN_CLOSED 0x00000010 /* "Connection: close" was present or added */ #define SN_MONITOR 0x00000020 /* this session comes from a monitoring system */ #define SN_SELF_GEN 0x00000040 /* the proxy generates data for the client (eg: stats) */ -/* unused: 0x00000080 */ +#define SN_FRT_ADDR_SET 0x00000080 /* set if the frontend address has been filled */ /* session termination conditions, bits values 0x100 to 0x700 (0-7 shift 8) */ #define SN_ERR_NONE 0x00000000 @@ -92,6 +92,7 @@ struct session { struct buffer *req; /* request buffer */ struct buffer *rep; /* response buffer */ struct sockaddr_storage cli_addr; /* the client address */ + struct sockaddr_storage frt_addr; /* the frontend address reached by the client if SN_FRT_ADDR_SET is set */ struct sockaddr_in srv_addr; /* the address to connect to */ struct server *srv; /* the server being used */ struct pendconn *pend_pos; /* if not NULL, points to the position in the pending queue */ diff --git a/src/backend.c b/src/backend.c index bb5705008b..69e79d408d 100644 --- a/src/backend.c +++ b/src/backend.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -235,13 +236,15 @@ int assign_server_address(struct session *s) /* if this server remaps proxied ports, we'll use * the port the client connected to with an offset. */ if (s->srv->state & SRV_MAPPORTS) { - struct sockaddr_in sockname; - socklen_t namelen = sizeof(sockname); - - if (!(s->fe->options & PR_O_TRANSP) || - get_original_dst(s->cli_fd, (struct sockaddr_in *)&sockname, &namelen) == -1) - getsockname(s->cli_fd, (struct sockaddr *)&sockname, &namelen); - s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + ntohs(sockname.sin_port)); + if (!(s->fe->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET)) + get_frt_addr(s); + if (s->frt_addr.ss_family == AF_INET) { + s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + + ntohs(((struct sockaddr_in *)&s->frt_addr)->sin_port)); + } else { + s->srv_addr.sin_port = htons(ntohs(s->srv_addr.sin_port) + + ntohs(((struct sockaddr_in6 *)&s->frt_addr)->sin6_port)); + } } } else if (*(int *)&s->be->dispatch_addr.sin_addr) { diff --git a/src/client.c b/src/client.c index 650db1fd7f..2754b91f72 100644 --- a/src/client.c +++ b/src/client.c @@ -43,6 +43,17 @@ #include +/* 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->frt_addr); + + if (get_original_dst(s->cli_fd, (struct sockaddr_in *)&s->frt_addr, &namelen) == -1) + getsockname(s->cli_fd, (struct sockaddr *)&s->frt_addr, &namelen); + s->flags |= SN_FRT_ADDR_SET; +} /* * FIXME: This should move to the STREAM_SOCK code then split into TCP and HTTP. @@ -263,14 +274,6 @@ int event_accept(int fd) { if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP) && (p->logfac1 >= 0 || p->logfac2 >= 0)) { - struct sockaddr_storage sockname; - socklen_t namelen = sizeof(sockname); - - if (addr.ss_family != AF_INET || - !(s->fe->options & PR_O_TRANSP) || - get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1) - getsockname(cfd, (struct sockaddr *)&sockname, &namelen); - if (p->to_log) { /* we have the client ip */ if (s->logs.logwait & LW_CLIP) @@ -279,38 +282,43 @@ int event_accept(int fd) { } else if (s->cli_addr.ss_family == AF_INET) { char pn[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN]; - if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sockname)->sin_addr, + + if (!(s->flags & SN_FRT_ADDR_SET)) + get_frt_addr(s); + + if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->frt_addr)->sin_addr, sn, sizeof(sn)) && inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr, pn, sizeof(pn))) { send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n", pn, ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port), - sn, ntohs(((struct sockaddr_in *)&sockname)->sin_port), + sn, ntohs(((struct sockaddr_in *)&s->frt_addr)->sin_port), p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP"); } } else { char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN]; - if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sockname)->sin6_addr, + + if (!(s->flags & SN_FRT_ADDR_SET)) + get_frt_addr(s); + + if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->frt_addr)->sin6_addr, sn, sizeof(sn)) && inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&s->cli_addr)->sin6_addr, pn, sizeof(pn))) { send_log(p, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n", pn, ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port), - sn, ntohs(((struct sockaddr_in6 *)&sockname)->sin6_port), + sn, ntohs(((struct sockaddr_in6 *)&s->frt_addr)->sin6_port), p->id, (p->mode == PR_MODE_HTTP) ? "HTTP" : "TCP"); } } } if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) { - struct sockaddr_in sockname; - socklen_t namelen = sizeof(sockname); int len; - if (addr.ss_family != AF_INET || - !(s->fe->options & PR_O_TRANSP) || - get_original_dst(cfd, (struct sockaddr_in *)&sockname, &namelen) == -1) - getsockname(cfd, (struct sockaddr *)&sockname, &namelen); + + if (!(s->flags & SN_FRT_ADDR_SET)) + get_frt_addr(s); if (s->cli_addr.ss_family == AF_INET) { char pn[INET_ADDRSTRLEN];