mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-17 11:06:54 +00:00
[MEDIUM] backend: move the transparent proxy address selection to backend
The transparent proxy address selection was set in the TCP connect function which is not the most appropriate place since this function has limited access to the amount of parameters which could produce a source address. Instead, now we determine the source address in backend.c:connect_server(), right after calling assign_server_address() and we assign this address in the session and pass it to the TCP connect function. This cannot be performed in assign_server_address() itself because in some cases (transparent mode, dispatch mode or http_proxy mode), we assign the address somewhere else. This change will open the ability to bind to addresses extracted from many other criteria (eg: from a header).
This commit is contained in:
parent
07a5490881
commit
b1d67749db
@ -1,23 +1,23 @@
|
||||
/*
|
||||
include/proto/proto_tcp.h
|
||||
This file contains TCP socket protocol definitions.
|
||||
|
||||
Copyright (C) 2000-2008 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
|
||||
License as published by the Free Software Foundation, version 2.1
|
||||
exclusively.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
* include/proto/proto_tcp.h
|
||||
* This file contains TCP socket protocol definitions.
|
||||
*
|
||||
* Copyright (C) 2000-2010 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
|
||||
* License as published by the Free Software Foundation, version 2.1
|
||||
* exclusively.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _PROTO_PROTO_TCP_H
|
||||
#define _PROTO_PROTO_TCP_H
|
||||
@ -33,7 +33,7 @@ void tcpv6_add_listener(struct listener *listener);
|
||||
int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen);
|
||||
int tcpv4_connect_server(struct stream_interface *si,
|
||||
struct proxy *be, struct server *srv,
|
||||
struct sockaddr *srv_addr, struct sockaddr *cli_addr);
|
||||
struct sockaddr *srv_addr, struct sockaddr *from_addr);
|
||||
int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit);
|
||||
int acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
|
||||
struct acl_expr *expr, struct acl_test *test);
|
||||
|
@ -170,6 +170,7 @@ struct session {
|
||||
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 sockaddr_in from_addr; /* the address to spoof when connecting to the server (transparent mode) */
|
||||
struct server *srv; /* the server the session will be running or has been running on */
|
||||
struct server *srv_conn; /* session already has a slot on a server and is not in queue */
|
||||
struct server *prev_srv; /* the server the was running on, after a redispatch, otherwise NULL */
|
||||
|
@ -820,6 +820,45 @@ int assign_server_and_queue(struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
/* If an explicit source binding is specified on the server and/or backend, and
|
||||
* this source makes use of the transparent proxy, then it is extracted now and
|
||||
* assigned to the session's from_addr entry.
|
||||
*/
|
||||
static void assign_tproxy_address(struct session *s)
|
||||
{
|
||||
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
|
||||
if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
|
||||
switch (s->srv->state & SRV_TPROXY_MASK) {
|
||||
case SRV_TPROXY_ADDR:
|
||||
s->from_addr = *(struct sockaddr_in *)&s->srv->tproxy_addr;
|
||||
break;
|
||||
case SRV_TPROXY_CLI:
|
||||
case SRV_TPROXY_CIP:
|
||||
/* FIXME: what can we do if the client connects in IPv6 ? */
|
||||
s->from_addr = *(struct sockaddr_in *)&s->cli_addr;
|
||||
break;
|
||||
default:
|
||||
s->from_addr = *(struct sockaddr_in *)0;
|
||||
}
|
||||
}
|
||||
else if (s->be->options & PR_O_BIND_SRC) {
|
||||
switch (s->be->options & PR_O_TPXY_MASK) {
|
||||
case PR_O_TPXY_ADDR:
|
||||
s->from_addr = *(struct sockaddr_in *)&s->be->tproxy_addr;
|
||||
break;
|
||||
case PR_O_TPXY_CLI:
|
||||
case PR_O_TPXY_CIP:
|
||||
/* FIXME: what can we do if the client connects in IPv6 ? */
|
||||
s->from_addr = *(struct sockaddr_in *)&s->cli_addr;
|
||||
break;
|
||||
default:
|
||||
s->from_addr = *(struct sockaddr_in *)0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function initiates a connection to the server assigned to this session
|
||||
* (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
|
||||
@ -845,9 +884,11 @@ int connect_server(struct session *s)
|
||||
if (!s->req->cons->connect)
|
||||
return SN_ERR_INTERNAL;
|
||||
|
||||
assign_tproxy_address(s);
|
||||
|
||||
err = s->req->cons->connect(s->req->cons, s->be, s->srv,
|
||||
(struct sockaddr *)&s->srv_addr,
|
||||
(struct sockaddr *)&s->cli_addr);
|
||||
(struct sockaddr *)&s->from_addr);
|
||||
|
||||
if (err != SN_ERR_NONE)
|
||||
return err;
|
||||
|
@ -180,7 +180,11 @@ int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct socka
|
||||
|
||||
/*
|
||||
* This function initiates a connection to the server assigned to this session
|
||||
* (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
|
||||
* (s->srv, s->srv_addr). It will assign a server if none is assigned yet. A
|
||||
* source address may be pointed to by <from_addr>. Note that this is only used
|
||||
* in case of transparent proxying. Normal source bind addresses are still
|
||||
* determined locally (due to the possible need of a source port).
|
||||
*
|
||||
* It can return one of :
|
||||
* - SN_ERR_NONE if everything's OK
|
||||
* - SN_ERR_SRVTO if there are no more servers
|
||||
@ -192,7 +196,7 @@ int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct socka
|
||||
*/
|
||||
int tcpv4_connect_server(struct stream_interface *si,
|
||||
struct proxy *be, struct server *srv,
|
||||
struct sockaddr *srv_addr, struct sockaddr *cli_addr)
|
||||
struct sockaddr *srv_addr, struct sockaddr *from_addr)
|
||||
{
|
||||
int fd;
|
||||
|
||||
@ -242,27 +246,18 @@ int tcpv4_connect_server(struct stream_interface *si,
|
||||
* - proxy-specific next
|
||||
*/
|
||||
if (srv != NULL && srv->state & SRV_BIND_SRC) {
|
||||
struct sockaddr_in *remote = NULL;
|
||||
int ret, flags = 0;
|
||||
|
||||
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
|
||||
switch (srv->state & SRV_TPROXY_MASK) {
|
||||
case SRV_TPROXY_ADDR:
|
||||
remote = (struct sockaddr_in *)&srv->tproxy_addr;
|
||||
flags = 3;
|
||||
break;
|
||||
case SRV_TPROXY_CLI:
|
||||
if (cli_addr)
|
||||
flags |= 2;
|
||||
/* fall through */
|
||||
flags = 3;
|
||||
break;
|
||||
case SRV_TPROXY_CIP:
|
||||
/* FIXME: what can we do if the client connects in IPv6 ? */
|
||||
if (cli_addr)
|
||||
flags |= 1;
|
||||
remote = (struct sockaddr_in *)cli_addr;
|
||||
flags = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_BINDTODEVICE
|
||||
/* Note: this might fail if not CAP_NET_RAW */
|
||||
if (srv->iface_name)
|
||||
@ -294,11 +289,11 @@ int tcpv4_connect_server(struct stream_interface *si,
|
||||
fdinfo[fd].port_range = srv->sport_range;
|
||||
src.sin_port = htons(fdinfo[fd].local_port);
|
||||
|
||||
ret = tcpv4_bind_socket(fd, flags, &src, remote);
|
||||
ret = tcpv4_bind_socket(fd, flags, &src, (struct sockaddr_in *)from_addr);
|
||||
} while (ret != 0); /* binding NOK */
|
||||
}
|
||||
else {
|
||||
ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, remote);
|
||||
ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, (struct sockaddr_in *)from_addr);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
@ -323,33 +318,24 @@ int tcpv4_connect_server(struct stream_interface *si,
|
||||
}
|
||||
}
|
||||
else if (be->options & PR_O_BIND_SRC) {
|
||||
struct sockaddr_in *remote = NULL;
|
||||
int ret, flags = 0;
|
||||
|
||||
#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
|
||||
switch (be->options & PR_O_TPXY_MASK) {
|
||||
case PR_O_TPXY_ADDR:
|
||||
remote = (struct sockaddr_in *)&be->tproxy_addr;
|
||||
flags = 3;
|
||||
break;
|
||||
case PR_O_TPXY_CLI:
|
||||
if (cli_addr)
|
||||
flags |= 2;
|
||||
/* fall through */
|
||||
flags = 3;
|
||||
break;
|
||||
case PR_O_TPXY_CIP:
|
||||
/* FIXME: what can we do if the client connects in IPv6 ? */
|
||||
if (cli_addr)
|
||||
flags |= 1;
|
||||
remote = (struct sockaddr_in *)cli_addr;
|
||||
flags = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SO_BINDTODEVICE
|
||||
/* Note: this might fail if not CAP_NET_RAW */
|
||||
if (be->iface_name)
|
||||
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, be->iface_name, be->iface_len + 1);
|
||||
#endif
|
||||
ret = tcpv4_bind_socket(fd, flags, &be->source_addr, remote);
|
||||
ret = tcpv4_bind_socket(fd, flags, &be->source_addr, (struct sockaddr_in *)from_addr);
|
||||
if (ret) {
|
||||
close(fd);
|
||||
if (ret == 1) {
|
||||
|
Loading…
Reference in New Issue
Block a user