Re: [PATCH] MEDIUM: proxy_protocol: Send IPv4 addresses when possible

2018-07-20 Thread Lukas Tribus
Hello,


On Wed, 18 Jul 2018 at 14:30, Willy Tarreau  wrote:
>
> Hi Tim,
>
> On Wed, Jul 18, 2018 at 01:48:01PM +0200, Tim Düsterhus wrote:
> > This would solve the issue for my use case and should not break anything
> > (a few UNKNOWNs will become TCP6 then).
>
> OK.
>
> > I can rework the patch, if technical changes look good to you. There's a
> > ton of memcpy in there to not destroy the data structures needed for the
> > actual communication: make_proxy_line() now always operates on a copy of
> > `struct connection remote`.
>
> I don't see why a copy could be needed, given that you should never have
> to modify anything in the source. Or maybe it's because it was more
> convenient to store the remapped addresses ? In this case I think that
> it's still cleaner to have two local struct sockaddr_storage that you
> can use for the operations. Another option, which I *thought* we had but
> am probably wrong on this, was to first check the source+destination
> address classes before deciding what to emit. (or maybe it's done in the
> PPv2 format) :
>
>  if (src_is_v4 && dst_is_v4)
>   /* emit_v4(src, dst) */
>  else if (src_is_v6 && dst_is_v6)
>   /* emit_v6(src, dst) */
>  else if (src_is_v6 && dst_is_v4)
>   /* emit_v6(src, 4to6(dst)) */
>  else if (src_is_v4 && dst_is_v6)
>   /* emit_v6(4to6(src), dst) */
>  else
>   /* emit_unknown()*/
>
> So in practice you always need only one temporary sockaddr_storage for
> a conversion.
>
> I'm personally fine with something roughly like this. Lukas, I'm interested
> in your opinion on this one, as I *think* it addresses the issues without
> introducing new ones.

However if I read the pseudo-code correctly, we will still transform a
v4 src to v6 src, when the destination is v6? I don't like
transforming the address family at all - but I realize the proxy
protocol needs a single AF for both source and destination, which
means we need to compromise and the proposed solution is the best
compromise as far as I can see.

Agreed.

cheers,
lukas



Re: [PATCH] MEDIUM: proxy_protocol: Send IPv4 addresses when possible

2018-07-18 Thread Tim Düsterhus
Willy,

Am 18.07.2018 um 14:30 schrieb Willy Tarreau:
>> I can rework the patch, if technical changes look good to you. There's a
>> ton of memcpy in there to not destroy the data structures needed for the
>> actual communication: make_proxy_line() now always operates on a copy of
>> `struct connection remote`.
> 
> I don't see why a copy could be needed, given that you should never have
> to modify anything in the source. Or maybe it's because it was more
> convenient to store the remapped addresses ? In this case I think that

Yes it is more convenient. In my current patch I just converted once in
connection.c and thus did not need to make any large logic changes in
make_proxy_line_v[12]: Keep the patch as small as possible.

> it's still cleaner to have two local struct sockaddr_storage that you
> can use for the operations. Another option, which I *thought* we had but
> am probably wrong on this, was to first check the source+destination

Yes, you do this, but you specifically check whether `src->ss_family ==
dst->ss_family`, not for every possible combination.

> address classes before deciding what to emit. (or maybe it's done in the
> PPv2 format) :
> 
>  if (src_is_v4 && dst_is_v4)
>   /* emit_v4(src, dst) */
>  else if (src_is_v6 && dst_is_v6)
>   /* emit_v6(src, dst) */
>  else if (src_is_v6 && dst_is_v4)
>   /* emit_v6(src, 4to6(dst)) */
>  else if (src_is_v4 && dst_is_v6)
>   /* emit_v6(4to6(src), dst) */
>  else
>   /* emit_unknown()*/
> 
> So in practice you always need only one temporary sockaddr_storage for
> a conversion.

Correct. Reason I did the copy (as mentioned above) is, that I did not
want to touch the actual logic.

> I'm personally fine with something roughly like this. Lukas, I'm interested
> in your opinion on this one, as I *think* it addresses the issues without
> introducing new ones. We could even think about backporting this.
> 

Best regards
Tim Düsterhus



Re: [PATCH] MEDIUM: proxy_protocol: Send IPv4 addresses when possible

2018-07-18 Thread Willy Tarreau
Hi Tim,

On Wed, Jul 18, 2018 at 01:48:01PM +0200, Tim Düsterhus wrote:
> This would solve the issue for my use case and should not break anything
> (a few UNKNOWNs will become TCP6 then).

OK.

> I can rework the patch, if technical changes look good to you. There's a
> ton of memcpy in there to not destroy the data structures needed for the
> actual communication: make_proxy_line() now always operates on a copy of
> `struct connection remote`.

I don't see why a copy could be needed, given that you should never have
to modify anything in the source. Or maybe it's because it was more
convenient to store the remapped addresses ? In this case I think that
it's still cleaner to have two local struct sockaddr_storage that you
can use for the operations. Another option, which I *thought* we had but
am probably wrong on this, was to first check the source+destination
address classes before deciding what to emit. (or maybe it's done in the
PPv2 format) :

 if (src_is_v4 && dst_is_v4)
  /* emit_v4(src, dst) */
 else if (src_is_v6 && dst_is_v6)
  /* emit_v6(src, dst) */
 else if (src_is_v6 && dst_is_v4)
  /* emit_v6(src, 4to6(dst)) */
 else if (src_is_v4 && dst_is_v6)
  /* emit_v6(4to6(src), dst) */
 else
  /* emit_unknown()*/

So in practice you always need only one temporary sockaddr_storage for
a conversion.

I'm personally fine with something roughly like this. Lukas, I'm interested
in your opinion on this one, as I *think* it addresses the issues without
introducing new ones. We could even think about backporting this.

> I could not find a better solution and already thought hard about the
> current version.

I have some vague memories about this area a long time ago, and believe
me, when I have memories of some code parts it's likely that I got a
headache on it :-)

Thanks!
Willy



Re: [PATCH] MEDIUM: proxy_protocol: Send IPv4 addresses when possible

2018-07-18 Thread Tim Düsterhus
Willy,

Am 18.07.2018 um 04:25 schrieb Willy Tarreau:
> What I would suggest would be to only "upgrade" the addresses to IPv6
> if either side already is on IPv6, but never downgrade from IPv6 to
> IPv4 since v6-mapped v4 addresses can exist on both sides for a valid
> reason.
> 

This would solve the issue for my use case and should not break anything
(a few UNKNOWNs will become TCP6 then).

I can rework the patch, if technical changes look good to you. There's a
ton of memcpy in there to not destroy the data structures needed for the
actual communication: make_proxy_line() now always operates on a copy of
`struct connection remote`.

I could not find a better solution and already thought hard about the
current version.

Best regards
Tim Düsterhus



Re: [PATCH] MEDIUM: proxy_protocol: Send IPv4 addresses when possible

2018-07-17 Thread Willy Tarreau
Hi!

On Tue, Jul 17, 2018 at 01:39:38PM +0200, Lukas Tribus wrote:
> Hello Tim,
> 
> 
> On Fri, 29 Jun 2018 at 21:00, Tim Duesterhus  wrote:
> >
> > This patch changes the sending side of proxy protocol to convert IP
> > addresses to IPv4 when possible (and converts them IPv6 otherwise).
> >
> > Previously the code failed to properly provide information under
> > certain circumstances:
> >
> > 1. haproxy is being accessed using IPv4, http-request set-src sets
> >a IPv6 address.
> > 2. haproxy is being accessed using IPv6, http-request set-src sets
> >a IPv4 address.
> > 3. haproxy listens on `::` with v4v6 and is accessed using IPv4:
> >It would send a TCP6 line, instead of a proper TCP4 line, because
> >the IP addresses are representing as a mapped IPv4 address internally.
> >
> > Once correctness of this patch has been verified it should be evaluated
> > whether it should be backported, as (1) and (2) are bugs. (3) is an
> > enhancement.
> 
> Thanks for this, just a comment about nr 3:
> 
> A backend may rely on v4-mapped addresses for various reason, consider
> a backend that to simplify its handling of IP addresses only handles
> IPv6 and expects IPv4 addresses to be mapped.
> Also consider that to send native v4 addresses the admin only has to
> make a small adjustment in the bind configuration.
> 
> So since this would be a breaking change, and that the admin can
> easily reconfigure the bind line any time, I would advise against this
> and vote for maintaining the current behavior (where the bind
> configuration controls this behavior).

I must say I'm a bit reluctant about this change for the same reasons.
What I would suggest would be to only "upgrade" the addresses to IPv6
if either side already is on IPv6, but never downgrade from IPv6 to
IPv4 since v6-mapped v4 addresses can exist on both sides for a valid
reason.

I don't know what ppv2 does in this situation where source and destination
are in different classes, because initially it was not expected to happen
and this became possible after we introduced set-src :-/

Also I suspect we can have similar issues with unix domain sockets. Let's
say we have a listener on /var/haproxy-sockets/foo which accepts a
connection on which we do a set-src. I don't really know what happens
in this case if we want to send a PP header. Maybe we'd need to improve
the PP spec to be able to mention only one side when the other one is
unknown, though that would obviously not solve the case Tim tried to
address above.

Cheers,
Willy



Re: [PATCH] MEDIUM: proxy_protocol: Send IPv4 addresses when possible

2018-07-17 Thread Lukas Tribus
Hello Tim,


On Fri, 29 Jun 2018 at 21:00, Tim Duesterhus  wrote:
>
> This patch changes the sending side of proxy protocol to convert IP
> addresses to IPv4 when possible (and converts them IPv6 otherwise).
>
> Previously the code failed to properly provide information under
> certain circumstances:
>
> 1. haproxy is being accessed using IPv4, http-request set-src sets
>a IPv6 address.
> 2. haproxy is being accessed using IPv6, http-request set-src sets
>a IPv4 address.
> 3. haproxy listens on `::` with v4v6 and is accessed using IPv4:
>It would send a TCP6 line, instead of a proper TCP4 line, because
>the IP addresses are representing as a mapped IPv4 address internally.
>
> Once correctness of this patch has been verified it should be evaluated
> whether it should be backported, as (1) and (2) are bugs. (3) is an
> enhancement.

Thanks for this, just a comment about nr 3:

A backend may rely on v4-mapped addresses for various reason, consider
a backend that to simplify its handling of IP addresses only handles
IPv6 and expects IPv4 addresses to be mapped.
Also consider that to send native v4 addresses the admin only has to
make a small adjustment in the bind configuration.

So since this would be a breaking change, and that the admin can
easily reconfigure the bind line any time, I would advise against this
and vote for maintaining the current behavior (where the bind
configuration controls this behavior).

I assume the X-Forwarded-For header behaves similar in this regard.



cheers,
lukas



Re: [PATCH] MEDIUM: proxy_protocol: Send IPv4 addresses when possible

2018-07-17 Thread Tim Düsterhus
Willy,

Am 29.06.2018 um 20:59 schrieb Tim Duesterhus:
> This patch changes the sending side of proxy protocol to convert IP
> addresses to IPv4 when possible (and converts them IPv6 otherwise).
> 
> Previously the code failed to properly provide information under
> certain circumstances:
> 
> 1. haproxy is being accessed using IPv4, http-request set-src sets
>a IPv6 address.
> 2. haproxy is being accessed using IPv6, http-request set-src sets
>a IPv4 address.
> 3. haproxy listens on `::` with v4v6 and is accessed using IPv4:
>It would send a TCP6 line, instead of a proper TCP4 line, because
>the IP addresses are representing as a mapped IPv4 address internally.
> 
> Once correctness of this patch has been verified it should be evaluated
> whether it should be backported, as (1) and (2) are bugs. (3) is an
> enhancement.

based on the overall lack of responses I assume that you are busy. I
just want to make sure that this patch / bug report did not slip through
the cracks. A short acknowledgement that you received it would be great,
if you are currently unable to take a deeper look at it.

Best regards
Tim Düsterhus



[PATCH] MEDIUM: proxy_protocol: Send IPv4 addresses when possible

2018-06-29 Thread Tim Duesterhus
This patch changes the sending side of proxy protocol to convert IP
addresses to IPv4 when possible (and converts them IPv6 otherwise).

Previously the code failed to properly provide information under
certain circumstances:

1. haproxy is being accessed using IPv4, http-request set-src sets
   a IPv6 address.
2. haproxy is being accessed using IPv6, http-request set-src sets
   a IPv4 address.
3. haproxy listens on `::` with v4v6 and is accessed using IPv4:
   It would send a TCP6 line, instead of a proper TCP4 line, because
   the IP addresses are representing as a mapped IPv4 address internally.

Once correctness of this patch has been verified it should be evaluated
whether it should be backported, as (1) and (2) are bugs. (3) is an
enhancement.
---
 include/common/standard.h  |  6 ++
 include/proto/connection.h |  2 +-
 src/connection.c   | 29 -
 src/standard.c | 21 +
 4 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/include/common/standard.h b/include/common/standard.h
index 6542759d..eb92b22b 100644
--- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -1047,6 +1047,12 @@ extern void v4tov6(struct in6_addr *sin6_addr, struct 
in_addr *sin_addr);
  */
 extern int v6tov4(struct in_addr *sin_addr, struct in6_addr *sin6_addr);
 
+/* Calls v4tov6 on the addr in v4. Copies v4 to v6 v6 already is of type 
AF_INET6 */
+extern void sockaddr_v4tov6(struct sockaddr_storage *v6, struct 
sockaddr_storage *v4);
+
+/* Calls v6tov4 on the addr in v6. Copies v6 to v4 if conversion fails or v6 
already is of type AF_INET */
+extern int sockaddr_v6tov4(struct sockaddr_storage *v4, struct 
sockaddr_storage *v6);
+
 /* compare two struct sockaddr_storage and return:
  *  0 (true)  if the addr is the same in both
  *  1 (false) if the addr is not the same in both
diff --git a/include/proto/connection.h b/include/proto/connection.h
index 8566736f..4e19756b 100644
--- a/include/proto/connection.h
+++ b/include/proto/connection.h
@@ -46,7 +46,7 @@ void conn_fd_handler(int fd);
 /* receive a PROXY protocol header over a connection */
 int conn_recv_proxy(struct connection *conn, int flag);
 int make_proxy_line(char *buf, int buf_len, struct server *srv, struct 
connection *remote);
-int make_proxy_line_v1(char *buf, int buf_len, struct sockaddr_storage *src, 
struct sockaddr_storage *dst);
+int make_proxy_line_v1(char *buf, int buf_len, struct connection *remote);
 int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct 
connection *remote);
 
 /* receive a NetScaler Client IP insertion header over a connection */
diff --git a/src/connection.c b/src/connection.c
index 1ea96ae3..e8e48d69 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -888,14 +888,24 @@ int make_proxy_line(char *buf, int buf_len, struct server 
*srv, struct connectio
 {
int ret = 0;
 
+   struct connection tmp;
+   if (remote) {
+   memcpy(&tmp, remote, sizeof(tmp));
+
+   if (!sockaddr_v6tov4(&tmp.addr.from, &remote->addr.from) || 
!sockaddr_v6tov4(&tmp.addr.to, &remote->addr.to)) {
+   sockaddr_v4tov6(&tmp.addr.from, &remote->addr.from);
+   sockaddr_v4tov6(&tmp.addr.to, &remote->addr.to);
+   }
+
+   remote = &tmp;
+   }
+
+
if (srv && (srv->pp_opts & SRV_PP_V2)) {
ret = make_proxy_line_v2(buf, buf_len, srv, remote);
}
else {
-   if (remote)
-   ret = make_proxy_line_v1(buf, buf_len, 
&remote->addr.from, &remote->addr.to);
-   else
-   ret = make_proxy_line_v1(buf, buf_len, NULL, NULL);
+   ret = make_proxy_line_v1(buf, buf_len, remote);
}
 
return ret;
@@ -908,10 +918,19 @@ int make_proxy_line(char *buf, int buf_len, struct server 
*srv, struct connectio
  * TCP6 and "UNKNOWN" formats. If any of  or  is null, UNKNOWN is
  * emitted as well.
  */
-int make_proxy_line_v1(char *buf, int buf_len, struct sockaddr_storage *src, 
struct sockaddr_storage *dst)
+int make_proxy_line_v1(char *buf, int buf_len, struct connection *remote)
 {
int ret = 0;
 
+   struct sockaddr_storage null_addr = { .ss_family = 0 };
+   struct sockaddr_storage *src = &null_addr;
+   struct sockaddr_storage *dst = &null_addr;
+
+   if (remote) {
+   src = &remote->addr.from;
+   dst = &remote->addr.to;
+   }
+
if (src && dst && src->ss_family == dst->ss_family && src->ss_family == 
AF_INET) {
ret = snprintf(buf + ret, buf_len - ret, "PROXY TCP4 ");
if (ret >= buf_len)
diff --git a/src/standard.c b/src/standard.c
index ebe043f1..51fd2cc4 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -2693,6 +2693,27 @@ int v6tov4(struct in_addr *sin_addr, struct in6_addr 
*sin6_addr)
return 0;
 }
 
+void sockaddr_v4tov6(struct sockaddr_stora