Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] V2.1.1: support HAProxy PROXY protocol V1 on MySQL frontends #2971

Closed

Conversation

noahwilliamsson
Copy link

This adds basic support for the HAProxy PROXY protocol V1 on MySQL frontend
client connections. This allows the true client IP to be seen in the output
of SHOW FULL PROCESSLIST in ProxySQL's admin frontend when the ProxySQL
servers sit behind a load balancer such as HAProxy or AWS classic ELBs with
the PROXY protocol feature enabled.

I believe this should resolve #2497 (Support for proxy_protocol for proxysql behind aws load balancer).

The patch adds a Proxy_Protocol class which handles:

  • parsing of PROXY protocol headers (only the V1 header supported for now)
  • matching client IPs against a list of configured network CIDRs

A new option, proxy_protocol_frontend_nets (list of network CIDRs), is
introduced to allow the PROXY protocol feature to be selectively turned on for
specific subnets where e.g. load balancers are running. This is similar to how
the PROXY protocol is implemented in MariaDB.

This variable can be set either in the config file or via the ProxySQL Admin
interface. Configuration file example:

mysql_variables=
{
    ...
    proxy_protocol_frontend_nets="10.42.0.0/28 127.10.0.0/16"
    ...
}

ProxySQL Admin interface example:

UPDATE global_variables
SET variable_value="192.168.42.0/24"
WHERE variable_name="mysql-proxy_protocol_frontend_nets";
LOAD MYSQL VARIABLES TO RUNTIME;

The network CIDRs are stored as a thread-local variable in the MySQL_Thread
class. It's only updated by MySQL_Thread::refresh_variables().

A new MySQL Data Stream state (DSS), STATE_PROXY_PROTOCOL, is introduced to
handle the initial parsing of the PROXY protocol header. Once this has
completed, the state is reset back to STATE_SERVER_HANDSHAKE.

The patch hooks into the MySQL_Thread's main loop where accept() is called
to handle incoming connections. Next, the actual parsing of the PROXY protocol
header is invoked from the MySQL_Data_Stream::read_pkts() method, which is
also called from MySQL_Thread's main loop (where incoming data is handled).

I've only tested this with a HAProxy configuration block like:

listen proxysql-with-proxy
    bind *:6030
    option tcp-check
    mode tcp
    timeout server 6h
    timeout client 6h
    balance roundrobin
    server proxysql-backend-1 127.0.0.1:6033 check send-proxy
listen proxysql-without-proxy
    bind *:6031
    option tcp-check
    mode tcp
    timeout server 6h
    timeout client 6h
    balance roundrobin
    server proxysql-backend-2 192.168.1.123:6033 check

NOTE: I took the liberty to reindent a block of code in MySQL_Thread.cpp
so please review with whitespace changes hidden.

@pondix
Copy link
Contributor

pondix commented Jul 20, 2020

Automated message: PR pending admin approval for build testing

@noahwilliamsson noahwilliamsson force-pushed the haproxy-proxy-protocol branch 2 times, most recently from 88c4619 to 612fb1b Compare July 20, 2020 16:24
This adds basic support for the HAProxy PROXY protocol V1 on MySQL frontend
client connections.  This allows the true client IP to be seen in the output
of `SHOW FULL PROCESSLIST` in ProxySQL's admin frontend when the ProxySQL
servers sit behind a load balancer such as HAProxy or AWS classic ELBs with
the PROXY protocol feature enabled.

I believe this should resolve sysown#2497 (Support for proxy_protocol for proxysql behind aws load balancer).

The patch adds a Proxy_Protocol class which handles:

- parsing of PROXY protocol headers (only the V1 header supported for now)
- matching client IPs against a list of configured network CIDRs

A new option, `proxy_protocol_frontend_nets` (list of network CIDRs), is
introduced to allow the PROXY protocol feature to be selectively turned on for
specific subnets where e.g. load balancers are running.  This is similar to how
the PROXY protocol is implemented in MariaDB.

This variable can be set either in the config file or via the ProxySQL Admin
interface.  Configuration file example:

    mysql_variables=
    {
        ...
        proxy_protocol_frontend_nets="10.42.0.0/28 127.10.0.0/16"
        ...
    }

ProxySQL Admin interface example:

    UPDATE global_variables
    SET variable_value="192.168.42.0/24"
    WHERE variable_name="mysql-proxy_protocol_frontend_nets";
    LOAD MYSQL VARIABLES TO RUNTIME;

The network CIDRs are stored as a thread-local variable in the MySQL_Thread
class.  It's only updated by MySQL_Thread::refresh_variables().

A new MySQL Data Stream state (DSS), `STATE_PROXY_PROTOCOL`, is introduced to
handle the initial parsing of the PROXY protocol header.  Once this has
completed, the state is reset back to `STATE_SERVER_HANDSHAKE`.

The patch hooks into the MySQL_Thread's main loop where `accept()` is called
to handle incoming connections.  Next, the actual parsing of the PROXY protocol
header is invoked from the `MySQL_Data_Stream::read_pkts()` method, which is
also called from MySQL_Thread's main loop (where incoming data is handled).

I've only tested this with a HAProxy configuration block like:

    listen proxysql-with-proxy
        bind *:6030
        option tcp-check
        mode tcp
        timeout server 6h
        timeout client 6h
        balance roundrobin
        server proxysql-backend-1 127.0.0.1:6033 check send-proxy
    listen proxysql-without-proxy
        bind *:6031
        option tcp-check
        mode tcp
        timeout server 6h
        timeout client 6h
        balance roundrobin
        server proxysql-backend-2 192.168.1.123:6033 check
@noahwilliamsson noahwilliamsson changed the base branch from v2.0.14 to v2.1.1 February 28, 2021 00:34
@noahwilliamsson noahwilliamsson changed the title WIP: Support HAProxy PROXY protocol V1 on MySQL frontends [RFC] V2.1.1: support HAProxy PROXY protocol V1 on MySQL frontends Feb 28, 2021
@noahwilliamsson
Copy link
Author

I assume v2.1 is where new development happens so I rebased the changes on top of v2.1.1.

@mirostauder
Copy link
Collaborator

Can one of the admins verify this patch?

@noahwilliamsson
Copy link
Author

Closing since this appears to have been implemented in #4600 and released with ProxySQL v2.7.0: https://github.com/sysown/proxysql/releases/tag/v2.7.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for proxy_protocol for proxysql behind aws load balancer
3 participants