I'm not sure if my mail client mangled the message or my email provider
did, but I couldn't read this except from lists.a.o so my reply may
appear as a new thread in your email client if it's following thread IDs.


Christophe JAILLET wrote:
> First of all, http://blog.haproxy.com/haproxy/proxy-protocol/ list 
> another module implementation for Apache:
> https://github.com/ggrandes/apache24-modules/blob/master/mod_myfixip.c
>
> If anyone wants to give it a look.
>
>
>
> Anyway, a few minor comments below.
>
> CJ
>
>
> Le 30/12/2016 à 15:20, drugg...@apache.org a écrit :
>> Author: druggeri
>> Date: Fri Dec 30 14:20:48 2016
>> New Revision: 1776575
>>
>> URL:http://svn.apache.org/viewvc?rev=1776575&view=rev
>> Log:
>> Merge new PROXY protocol code into mod_remoteip
>>
>> Modified:
>>      httpd/httpd/trunk/docs/log-message-tags/next-number
>>      httpd/httpd/trunk/docs/manual/mod/mod_remoteip.xml
>>      httpd/httpd/trunk/modules/metadata/mod_remoteip.c
>>
>> Modified: httpd/httpd/trunk/docs/log-message-tags/next-number
>> URL:http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/log-message-tags/next-number?rev=1776575&r1=1776574&r2=1776575&view=diff
>> ==============================================================================
>> --- httpd/httpd/trunk/docs/log-message-tags/next-number (original)
>> +++ httpd/httpd/trunk/docs/log-message-tags/next-number Fri Dec 30 14:20:48 
>> 2016
>> @@ -1 +1 @@
>> -3491
>> +3514
>>
>> Modified: httpd/httpd/trunk/docs/manual/mod/mod_remoteip.xml
>> URL:http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_remoteip.xml?rev=1776575&r1=1776574&r2=1776575&view=diff
>> ==============================================================================
>> --- httpd/httpd/trunk/docs/manual/mod/mod_remoteip.xml (original)
>> +++ httpd/httpd/trunk/docs/manual/mod/mod_remoteip.xml Fri Dec 30 14:20:48 
>> 2016
>> @@ -42,6 +42,12 @@ via the request headers.
>>       with the useragent IP address reported in the request header configured
>>       with the <directive module="mod_remoteip">RemoteIPHeader</directive> 
>> directive.</p>
>>   
>> +    <p>Additionally, this module implements the server side of
>> +    HAProxy's
>> +    <a href="http://blog.haproxy.com/haproxy/proxy-protocol/";>Proxy 
>> Protocol</a> when
>> +    using the <directive 
>> module="mod_remoteip">RemoteIPProxyProtocolEnable</directive>
>> +    directive.</p>
>> +
>>       <p>Once replaced as instructed, this overridden useragent IP address is
>>       then used for the <module>mod_authz_host</module>
>>       <directive module="mod_authz_core" name="Require">Require 
>> ip</directive>
>> @@ -59,6 +65,7 @@ via the request headers.
>>   <seealso><module>mod_authz_host</module></seealso>
>>   <seealso><module>mod_status</module></seealso>
>>   <seealso><module>mod_log_config</module></seealso>
>> +<seealso><a 
>> href="http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt";>Proxy 
>> Protocol Spec</a></seealso>
>>   
>>   <section id="processing"><title>Remote IP Processing</title>
>>   
>> @@ -214,6 +221,70 @@ RemoteIPProxiesHeader X-Forwarded-By
>>   </usage>
>>   </directivesynopsis>
>>   
>> +<directivesynopsis>
>> +<name>RemoteIPProxyProtocol</name>
> s/RemoteIPProxyProtocol/RemoteIPProxyProtocolEnable/

Right - this was addressed in a subsequent commit after discussing the
name. It's now RemoteIPProxyProtocol


>
>> +<description>Enable, optionally enable or disable the proxy protocol 
>> handling</description>
>> +<syntax>ProxyProtocol On|Optional|Off</syntax>
>> +<contextlist><context>server config</context><context>virtual host</context>
>> +</contextlist>
> Compatibility note missing.

Added - thanks!


>
>> ....
>>
>> Modified: httpd/httpd/trunk/modules/metadata/mod_remoteip.c
>> URL:http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/metadata/mod_remoteip.c?rev=1776575&r1=1776574&r2=1776575&view=diff
>> ==============================================================================
>> --- httpd/httpd/trunk/modules/metadata/mod_remoteip.c (original)
>> +++ httpd/httpd/trunk/modules/metadata/mod_remoteip.c Fri Dec 30 14:20:48 
>> 2016
>> @@ -12,15 +12,20 @@
>>    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>>    * See the License for the specific language governing permissions and
>>    * limitations under the License.
>> + *
>> + * The majority of the input filter code for PROXY protocol support is
>> + * Copyright 2014 Cloudzilla Inc.
>>    */
>>   
>>   #include "ap_config.h"
>>   #include "ap_mmn.h"
>> +#include "ap_listen.h"
>>   #include "httpd.h"
>>   #include "http_config.h"
>>   #include "http_connection.h"
>>   #include "http_protocol.h"
>>   #include "http_log.h"
>> +#include "http_main.h"
>>   #include "apr_strings.h"
>>   #include "apr_lib.h"
>>   #define APR_WANT_BYTEFUNC
>> @@ -36,6 +41,12 @@ typedef struct {
>>       void  *internal;
>>   } remoteip_proxymatch_t;
>>   
>> +typedef struct remoteip_addr_info {
>> +    struct remoteip_addr_info *next;
>> +    apr_sockaddr_t *addr;
>> +    server_rec *source;
>> +} remoteip_addr_info;
>> +
>>   typedef struct {
>>       /** The header to retrieve a proxy-via IP list */
>>       const char *header_name;
>> @@ -48,6 +59,17 @@ typedef struct {
>>        *  with the most commonly encountered listed first
>>        */
>>       apr_array_header_t *proxymatch_ip;
>> +
>> +    remoteip_addr_info *proxy_protocol_enabled;
>> +    remoteip_addr_info *proxy_protocol_optional;
>> +    remoteip_addr_info *proxy_protocol_disabled;
>> +
>> +    /** A flag indicating whether or not proxyprotocol
>> +     * is optoinal for this specific server
>> +     */
>> +    int pp_optional;
>> +
>> +    apr_pool_t *pool;
> Do we really need to keep the config pool here? if badly used", wouldn't 
> it generate a kind of leak?

See response below to your follow up question


>
>>   } remoteip_config_t;
>>   
>>   typedef struct {
>> @@ -59,12 +81,92 @@ typedef struct {
>>       const char *proxied_remote;
>>   } remoteip_req_t;
>>   
>> +/* For PROXY protocol processing */
>> +static const char *remoteip_filter_name = "REMOTEIP_INPUT";
>> +
>> +typedef struct {
>> +    char line[108];
>> +} proxy_v1;
>> +
>> +typedef union {
>> +    struct {        /* for TCP/UDP over IPv4, len = 12 */
>> +        uint32_t src_addr;
>> +        uint32_t dst_addr;
>> +        uint16_t src_port;
>> +        uint16_t dst_port;
>> +    } ip4;
>> +    struct {        /* for TCP/UDP over IPv6, len = 36 */
>> +         uint8_t  src_addr[16];
>> +         uint8_t  dst_addr[16];
>> +         uint16_t src_port;
>> +         uint16_t dst_port;
>> +    } ip6;
>> +    struct {        /* for AF_UNIX sockets, len = 216 */
>> +         uint8_t src_addr[108];
>> +         uint8_t dst_addr[108];
>> +    } unx;
>> +} proxy_v2_addr;
>> +
>> +typedef struct {
>> +    uint8_t  sig[12];  /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
>> +    uint8_t  ver_cmd;  /* protocol version and command */
>> +    uint8_t  fam;      /* protocol family and address */
>> +    uint16_t len;     /* number of following bytes part of the header */
>> +    proxy_v2_addr addr;
>> +} proxy_v2;
>> +
>> +typedef union {
>> +        proxy_v1 v1;
>> +        proxy_v2 v2;
>> +} proxy_header;
>> +
>> +static const char v2sig[12] = 
>> "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
>> +#define MIN_V1_HDR_LEN 15
>> +#define MIN_V2_HDR_LEN 16
>> +#define MIN_HDR_LEN MIN_V1_HDR_LEN
>> +
>> +/* XXX: Unsure if this is needed if v6 support is not available on
>> +   this platform */
>> +#ifndef INET6_ADDRSTRLEN
>> +#define INET6_ADDRSTRLEN 46
>> +#endif
>> +
>> +typedef struct {
>> +    char header[sizeof(proxy_header)];
>> +    apr_size_t rcvd;
>> +    apr_size_t need;
>> +    int version;
>> +    ap_input_mode_t mode;
>> +    apr_bucket_brigade *bb;
>> +    int done;
>> +} remoteip_filter_context;
>> +
>> +/** Holds the resolved proxy info for this connection and any addition
>> +  configurable parameters
>> +*/
>> +typedef struct {
>> +    /** The parsed client address in native format */
>> +    apr_sockaddr_t *client_addr;
>> +    /** Character representation of the client */
>> +    char *client_ip;
>> +    /** Flag indicating that the PROXY header may be omitted on this
>> +      connection (do not abort if it is missing). */
>> +    int proxy_protocol_optional;
>> +} remoteip_conn_config_t;
>> +
>> +typedef enum { HDR_DONE, HDR_ERROR, HDR_MISSING, HDR_NEED_MORE } 
>> remoteip_parse_status_t;
>> +
>>   static void *create_remoteip_server_config(apr_pool_t *p, server_rec *s)
>>   {
>>       remoteip_config_t *config = apr_pcalloc(p, sizeof *config);
>>       /* config->header_name = NULL;
>>        * config->proxies_header_name = NULL;
>>        */
>> +    config->proxy_protocol_enabled = NULL;
>> +    config->proxy_protocol_optional = NULL;
>> +    config->proxy_protocol_disabled = NULL;
>> +    config->pp_optional = 0;
> Useless init because of apr_pcalloc. Should be consistent with 
> header_name and proxies_header_name. All commented or all NULL/0 
> assigned or dropped completely.

NP - moved to comments in latest commit


>
>> +    config->pool = p;
>>       return config;
>>   }
>>   
>> @@ -85,6 +187,9 @@ static void *merge_remoteip_server_confi
>>       config->proxymatch_ip = server->proxymatch_ip
>>                             ? server->proxymatch_ip
>>                             : global->proxymatch_ip;
>> +    config->pp_optional = server->pp_optional
>> +                          ? server->pp_optional
>> +                          : global->pp_optional;
>>       return config;
>>   }
>>   
>> @@ -215,13 +320,184 @@ static const char *proxylist_read(cmd_pa
>>       return NULL;
>>   }
>>   
>> +/** Similar apr_sockaddr_equal, except that it compares ports too. */
>> +static int remoteip_sockaddr_equal(apr_sockaddr_t *addr1, apr_sockaddr_t 
>> *addr2)
>> +{
>> +    return (addr1->port == addr2->port && apr_sockaddr_equal(addr1, addr2));
>> +}
>> +
>> +/** Similar remoteip_sockaddr_equal, except that it handles wildcard 
>> addresses
>> + *  and ports too.
>> + */
>> +static int remoteip_sockaddr_compat(apr_sockaddr_t *addr1, apr_sockaddr_t 
>> *addr2)
>> +{
>> +    /* test exact address equality */
>> +    if (apr_sockaddr_equal(addr1, addr2) &&
>> +        (addr1->port == addr2->port || addr1->port == 0 || addr2->port == 
>> 0)) {
>> +        return 1;
>> +    }
>> +
>> +    /* test address wildcards */
>> +    if (apr_sockaddr_is_wildcard(addr1) &&
>> +        (addr1->port == 0 || addr1->port == addr2->port)) {
>> +        return 1;
>> +    }
>> +
>> +    if (apr_sockaddr_is_wildcard(addr2) &&
>> +        (addr2->port == 0 || addr2->port == addr1->port)) {
>> +        return 1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int remoteip_addr_in_list(remoteip_addr_info *list, apr_sockaddr_t 
>> *addr)
>> +{
>> +    for (; list; list = list->next) {
>> +        if (remoteip_sockaddr_compat(list->addr, addr)) {
>> +            return 1;
>> +        }
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void remoteip_warn_enable_conflict(remoteip_addr_info *prev, 
>> server_rec *new, const char* arg)
>> +{
>> +    char buf[INET6_ADDRSTRLEN];
>> +
>> +    apr_sockaddr_ip_getbuf(buf, sizeof(buf), prev->addr);
>> +
>> +    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, new, APLOGNO(03491)
>> +                 "RemoteIPProxyProtocolEnable: previous setting for %s:%hu 
>> from virtual "
>> +                 "host {%s:%hu in %s} is being overriden by virtual host "
>> +                 "{%s:%hu in %s}; new setting is '%s'",
>> +                 buf, prev->addr->port, prev->source->server_hostname,
>> +                 prev->source->addrs->host_port, prev->source->defn_name,
>> +                 new->server_hostname, new->addrs->host_port, 
>> new->defn_name,
>> +                 arg);
>> +}
>> +
>> +static const char *remoteip_enable_proxy_protocol(cmd_parms *cmd, void 
>> *config,
>> +                                                  const char *arg)
>> +{
>> +    remoteip_config_t *global_conf;
>> +    remoteip_config_t *server_conf;
>> +    server_addr_rec *addr;
>> +    remoteip_addr_info **add;
>> +    int list_len = 2;
>> +    remoteip_addr_info **rem_list[list_len];
>> +    remoteip_addr_info *list;
>> +    int i;
>> +
>> +    global_conf = ap_get_module_config(ap_server_conf->module_config,
>> +                                &remoteip_module);
>> +    server_conf = ap_get_module_config(cmd->server->module_config,
>> +                                &remoteip_module);
>> +
>> +    if (strcasecmp(arg, "On") == 0) {
>> +        add = &global_conf->proxy_protocol_enabled;
>> +        rem_list[0] = &global_conf->proxy_protocol_optional;
>> +        rem_list[1] = &global_conf->proxy_protocol_disabled;
>> +    }
>> +    else if (strcasecmp(arg, "Optional") == 0) {
>> +        add = &global_conf->proxy_protocol_optional;
>> +        rem_list[0] = &global_conf->proxy_protocol_enabled;
>> +        rem_list[1] = &global_conf->proxy_protocol_disabled;
>> +        server_conf->pp_optional = 1;
>> +    }
>> +    else if (strcasecmp(arg, "Off") == 0 ) {
>> +        add = &global_conf->proxy_protocol_disabled;
>> +        rem_list[0] = &global_conf->proxy_protocol_enabled;
>> +        rem_list[1] = &global_conf->proxy_protocol_optional;
>> +    }
>> +    else {
>> +        return apr_pstrcat(cmd->pool, "Unrecognized option for 
>> ProxyProtocolEnable `%s'", arg, NULL);
> s/ProxyProtocolEnable/RemoteIPProxyProtocolEnable/
> or cmd->cmd->name to be safe.
I like that even better - updated to the safest case

>
>> +    }
>> +
>> +    for (addr = cmd->server->addrs; addr; addr = addr->next) {
>> +        /* remove address from other lists */
>> +        for (i = 0; i < list_len ; i++) {
>> +            remoteip_addr_info **rem = rem_list[i];
>> +            if (*rem) {
>> +                if (remoteip_sockaddr_equal((*rem)->addr, addr->host_addr)) 
>> {
>> +                    remoteip_warn_enable_conflict(*rem, cmd->server, arg);
>> +                    *rem = (*rem)->next;
>> +                }
>> +                else {
>> +                    for (list = *rem; list->next; list = list->next) {
>> +                        if (remoteip_sockaddr_equal(list->next->addr, 
>> addr->host_addr)) {
>> +                            remoteip_warn_enable_conflict(list->next, 
>> cmd->server, arg);
>> +                            list->next = list->next->next;
>> +                            break;
>> +                        }
>> +                    }
>> +                }
>> +            }
>> +        }
>> +
>> +        /* add address to desired list */
>> +        if (!remoteip_addr_in_list(*add, addr->host_addr)) {
>> +            remoteip_addr_info *info = apr_palloc(global_conf->pool, 
>> sizeof(*info));
> Could cmd->pool be used here, instead?

This came from the original authors of the code, but I think it's
correct. This is the only place remoteip_config_t->pool is allocated
into. A collection of all enabled, disabled and optional
remoteip_addr_info structs is kept and examined pre-connection to
determine if the filter should be inserted for the connection. Since the
server is not known pre-connection, this must be stored in the global
server. The lifetime of cmd->pool would prevent using it here.


>
>> . . . 
>>   static const command_rec remoteip_cmds[] =
>>   {
>>       AP_INIT_TAKE1("RemoteIPHeader", header_name_set, NULL, RSRC_CONF,
>> @@ -450,11 +1211,21 @@ static const command_rec remoteip_cmds[]
>>                     RSRC_CONF | EXEC_ON_READ,
>>                     "The filename to read the list of internal proxies, "
>>                     "see the RemoteIPInternalProxy directive"),
>> +    AP_INIT_TAKE1("RemoteIPProxyProtocolEnable", 
>> remoteip_enable_proxy_protocol, NULL,
>> +                  RSRC_CONF, "Enable proxy-protocol handling (`on', 
>> `off')"),
> `optional' is missing

Fixed - thanks!


>
>>       { NULL }
>>   };
>>   
>>   static void register_hooks(apr_pool_t *p)
>>   {
>> +    /* mod_ssl is CONNECTION + 5, so we want something higher (earlier);
>> +     * mod_reqtimeout is CONNECTION + 8, so we want something lower (later) 
>> */
>> +    ap_register_input_filter(remoteip_filter_name, remoteip_input_filter, 
>> NULL,
>> +                             AP_FTYPE_CONNECTION + 7);
>> +
>> +    ap_hook_pre_config(remoteip_hook_pre_config, NULL, NULL, 
>> APR_HOOK_MIDDLE);
>> +    ap_hook_post_config(remoteip_hook_post_config, NULL, NULL, 
>> APR_HOOK_MIDDLE);
>> +    ap_hook_pre_connection(remoteip_hook_pre_connection, NULL, NULL, 
>> APR_HOOK_MIDDLE);
>>       ap_hook_post_read_request(remoteip_modify_request, NULL, NULL, 
>> APR_HOOK_FIRST);
>>   }
>>   

-- 
Daniel Ruggeri

Reply via email to