For the most part, yes except the portions that make the header presence
optional (the HDR_MISSING case). Those were added as it came into the
code base to handle a use case I was working on. I've added some
comments inline since I won't have time to poke around myself for a
while yet.


For convenience, here's a link to the original code

https://github.com/roadrunner2/mod-proxy-protocol/blob/master/mod_proxy_protocol.c


On 1/16/2017 10:14 AM, Jim Jagielski wrote:
> Let me take a look... afaict, this is a copy of what
> was donated, which has been working for numerous people.
> But that doesn't mean it can't have bugs ;)
>
>> On Jan 16, 2017, at 7:20 AM, Ruediger Pluem <rpl...@apache.org> wrote:
>>
>> Anyone?

Apologies for missing the original reply

>> Regards
>>
>> Rüdiger
>>
>> On 01/10/2017 12:39 PM, Ruediger Pluem wrote:
>>>
>>> On 12/30/2016 03:20 PM, drugg...@apache.org wrote:
>>>> 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
>>>>
>>>> ==============================================================================
>>>> --- httpd/httpd/trunk/modules/metadata/mod_remoteip.c (original)
>>>> +++ httpd/httpd/trunk/modules/metadata/mod_remoteip.c Fri Dec 30 14:20:48 
>>>> 2016
>>>> @@ -427,6 +730,464 @@ static int remoteip_modify_request(reque
>>>>     return OK;
>>>> }
>>>>
>>>> +static int remoteip_is_server_port(apr_port_t port)
>>>> +{
>>>> +    ap_listen_rec *lr;
>>>> +
>>>> +    for (lr = ap_listeners; lr; lr = lr->next) {
>>>> +        if (lr->bind_addr && lr->bind_addr->port == port) {
>>>> +            return 1;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Human readable format:
>>>> + * PROXY {TCP4|TCP6|UNKNOWN} <client-ip-addr> <dest-ip-addr> 
>>>> <client-port> <dest-port><CR><LF>
>>>> + */
>>>> +static remoteip_parse_status_t remoteip_process_v1_header(conn_rec *c,
>>>> +                                                          
>>>> remoteip_conn_config_t *conn_conf,
>>>> +                                                          proxy_header 
>>>> *hdr, apr_size_t len,
>>>> +                                                          apr_size_t 
>>>> *hdr_len)
>>>> +{
>>>> +    char *end, *word, *host, *valid_addr_chars, *saveptr;
>>>> +    char buf[sizeof(hdr->v1.line)];
>>>> +    apr_port_t port;
>>>> +    apr_status_t ret;
>>>> +    apr_int32_t family;
>>>> +
>>>> +#define GET_NEXT_WORD(field) \
>>>> +    word = apr_strtok(NULL, " ", &saveptr); \
>>>> +    if (!word) { \
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03497) \
>>>> +                      "RemoteIPProxyProtocol: no " field " found in 
>>>> header '%s'", \
>>>> +                      hdr->v1.line); \
>>>> +        return HDR_ERROR; \
>>>> +    }
>>>> +
>>>> +    end = memchr(hdr->v1.line, '\r', len - 1);
>>>> +    if (!end || end[1] != '\n') {
>>>> +        return HDR_NEED_MORE; /* partial or invalid header */
>>>> +    }
>>>> +
>>>> +    *end = '\0';
>>>> +    *hdr_len = end + 2 - hdr->v1.line; /* skip header + CRLF */
>>>> +
>>>> +    /* parse in separate buffer so have the original for error messages */
>>>> +    strcpy(buf, hdr->v1.line);
>>>> +
>>>> +    apr_strtok(buf, " ", &saveptr);
>>>> +
>>>> +    /* parse family */
>>>> +    GET_NEXT_WORD("family")
>>>> +    if (strcmp(word, "UNKNOWN") == 0) {
>>>> +        conn_conf->client_addr = c->client_addr;
>>>> +        conn_conf->client_ip = c->client_ip;
>>>> +        return HDR_DONE;
>>>> +    }
>>>> +    else if (strcmp(word, "TCP4") == 0) {
>>>> +        family = APR_INET;
>>>> +        valid_addr_chars = "0123456789.";
>>>> +    }
>>>> +    else if (strcmp(word, "TCP6") == 0) {
>>>> +#if APR_HAVE_IPV6
>>>> +        family = APR_INET6;
>>>> +        valid_addr_chars = "0123456789abcdefABCDEF:";
>>>> +#else
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03498)
>>>> +                      "RemoteIPProxyProtocol: Unable to parse v6 address 
>>>> - APR is not compiled with IPv6 support",
>>>> +                      word, hdr->v1.line);
>>>> +        return HDR_ERROR;
>>>> +#endif
>>>> +    }
>>>> +    else {
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03499)
>>>> +                      "RemoteIPProxyProtocol: unknown family '%s' in 
>>>> header '%s'",
>>>> +                      word, hdr->v1.line);
>>>> +        return HDR_ERROR;
>>>> +    }
>>>> +
>>>> +    /* parse client-addr */
>>>> +    GET_NEXT_WORD("client-address")
>>>> +
>>>> +    if (strspn(word, valid_addr_chars) != strlen(word)) {
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03500)
>>>> +                      "RemoteIPProxyProtocol: invalid client-address '%s' 
>>>> found in "
>>>> +                      "header '%s'", word, hdr->v1.line);
>>>> +        return HDR_ERROR;
>>>> +    }
>>>> +
>>>> +    host = word;
>>>> +
>>>> +    /* parse dest-addr */
>>>> +    GET_NEXT_WORD("destination-address")
>>>> +
>>>> +    /* parse client-port */
>>>> +    GET_NEXT_WORD("client-port")
>>>> +    if (sscanf(word, "%hu", &port) != 1) {
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03501)
>>>> +                      "RemoteIPProxyProtocol: error parsing port '%s' in 
>>>> header '%s'",
>>>> +                      word, hdr->v1.line);
>>>> +        return HDR_ERROR;
>>>> +    }
>>>> +
>>>> +    /* parse dest-port */
>>>> +    /* GET_NEXT_WORD("destination-port") - no-op since we don't care 
>>>> about it */
>>>> +
>>>> +    /* create a socketaddr from the info */
>>>> +    ret = apr_sockaddr_info_get(&conn_conf->client_addr, host, family, 
>>>> port, 0,
>>>> +                                c->pool);
>>>> +    if (ret != APR_SUCCESS) {
>>>> +        conn_conf->client_addr = NULL;
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, APLOGNO(03502)
>>>> +                      "RemoteIPProxyProtocol: error converting family 
>>>> '%d', host '%s',"
>>>> +                      " and port '%hu' to sockaddr; header was '%s'",
>>>> +                      family, host, port, hdr->v1.line);
>>>> +        return HDR_ERROR;
>>>> +    }
>>>> +
>>>> +    conn_conf->client_ip = apr_pstrdup(c->pool, host);
>>>> +
>>>> +    return HDR_DONE;
>>>> +}
>>>> +
>>>> +/** Add our filter to the connection if it is requested
>>>> + */
>>>> +static int remoteip_hook_pre_connection(conn_rec *c, void *csd)
>>>> +{
>>>> +    remoteip_config_t *conf;
>>>> +    remoteip_conn_config_t *conn_conf;
>>>> +    int optional;
>>>> +
>>>> +    conf = ap_get_module_config(ap_server_conf->module_config,
>>>> +                                &remoteip_module);
>>>> +
>>>> +    /* Used twice - do the check only once */
>>>> +    optional = remoteip_addr_in_list(conf->proxy_protocol_optional, 
>>>> c->local_addr);
>>>> +
>>>> +    /* check if we're enabled for this connection */
>>>> +    if ((!remoteip_addr_in_list(conf->proxy_protocol_enabled, 
>>>> c->local_addr)
>>>> +          && !optional )
>>>> +        || remoteip_addr_in_list(conf->proxy_protocol_disabled, 
>>>> c->local_addr)) {
>>>> +        return DECLINED;
>>>> +    }
>>>> +
>>>> +    /* mod_proxy creates outgoing connections - we don't want those */
>>>> +    if (!remoteip_is_server_port(c->local_addr->port)) {
>>>> +        return DECLINED;
>>>> +    }
>>> Why is the c->local_addr->port set to a port we are listening on in case of 
>>> proxy connections?

This is from the original code, but wouldn't this be the local port on
the outbound connection (some high number)? The remoteip_is_server_port
should therefore fail this check.


>>>
>>>> +
>>>> +    /* add our filter */
>>>> +    if (!ap_add_input_filter(remoteip_filter_name, NULL, NULL, c)) {
>>>> +        /* XXX: Shouldn't this WARN in log? */
>>>> +        return DECLINED;
>>>> +    }
>>>> +
>>>> +    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03503)
>>>> +                  "RemoteIPProxyProtocol: enabled on connection to 
>>>> %s:%hu",
>>>> +                  c->local_ip, c->local_addr->port);
>>>> +
>>>> +    /* this holds the resolved proxy info for this connection */
>>>> +    conn_conf = apr_pcalloc(c->pool, sizeof(*conn_conf));
>>>> +
>>>> +    /* Propagate the optional flag so the connection handler knows not to
>>>> +       abort if the header is mising. NOTE: This means we must check after
>>>> +       we read the request that the header was NOT optional, too.
>>>> +    */
>>>> +    conn_conf->proxy_protocol_optional = optional;
>>>> +
>>>> +    ap_set_module_config(c->conn_config, &remoteip_module, conn_conf);
>>>> +
>>>> +    return OK;
>>>> +}
>>>> +
>>>> +/* Binary format:
>>>> + * <sig><cmd><proto><addr-len><addr>
>>>> + * sig = \x0D \x0A \x0D \x0A \x00 \x0D \x0A \x51 \x55 \x49 \x54 \x0A
>>>> + * cmd = <4-bits-version><4-bits-command>
>>>> + * 4-bits-version = \x02
>>>> + * 4-bits-command = {\x00|\x01}  (\x00 = LOCAL: discard con info; \x01 = 
>>>> PROXY)
>>>> + * proto = <4-bits-family><4-bits-protocol>
>>>> + * 4-bits-family = {\x00|\x01|\x02|\x03}  (AF_UNSPEC, AF_INET, AF_INET6, 
>>>> AF_UNIX)
>>>> + * 4-bits-protocol = {\x00|\x01|\x02}  (UNSPEC, STREAM, DGRAM)
>>>> + */
>>>> +static remoteip_parse_status_t remoteip_process_v2_header(conn_rec *c,
>>>> +                                              remoteip_conn_config_t 
>>>> *conn_conf,
>>>> +                                              proxy_header *hdr)
>>>> +{
>>>> +    apr_status_t ret;
>>>> +
>>>> +    switch (hdr->v2.ver_cmd & 0xF) {
>>>> +        case 0x01: /* PROXY command */
>>>> +            switch (hdr->v2.fam) {
>>>> +                case 0x11:  /* TCPv4 */
>>>> +                    ret = apr_sockaddr_info_get(&conn_conf->client_addr, 
>>>> NULL,
>>>> +                                                APR_INET,
>>>> +                                                
>>>> ntohs(hdr->v2.addr.ip4.src_port),
>>>> +                                                0, c->pool);
>>>> +                    if (ret != APR_SUCCESS) {
>>>> +                        conn_conf->client_addr = NULL;
>>>> +                        ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, 
>>>> APLOGNO(03504)
>>>> +                                      "RemoteIPPProxyProtocol: error 
>>>> creating sockaddr");
>>>> +                        return HDR_ERROR;
>>>> +                    }
>>>> +
>>>> +                    conn_conf->client_addr->sa.sin.sin_addr.s_addr =
>>>> +                            hdr->v2.addr.ip4.src_addr;
>>>> +                    break;
>>>> +
>>>> +                case 0x21:  /* TCPv6 */
>>>> +#if APR_HAVE_IPV6
>>>> +                    ret = apr_sockaddr_info_get(&conn_conf->client_addr, 
>>>> NULL,
>>>> +                                                APR_INET6,
>>>> +                                                
>>>> ntohs(hdr->v2.addr.ip6.src_port),
>>>> +                                                0, c->pool);
>>>> +                    if (ret != APR_SUCCESS) {
>>>> +                        conn_conf->client_addr = NULL;
>>>> +                        ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, 
>>>> APLOGNO(03505)
>>>> +                                      "RemoteIPProxyProtocol: error 
>>>> creating sockaddr");
>>>> +                        return HDR_ERROR;
>>>> +                    }
>>>> +                    
>>>> memcpy(&conn_conf->client_addr->sa.sin6.sin6_addr.s6_addr,
>>>> +                           hdr->v2.addr.ip6.src_addr, 16);
>>>> +                    break;
>>>> +#else
>>>> +                    ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, 
>>>> APLOGNO(03506)
>>>> +                                  "RemoteIPProxyProtocol: APR is not 
>>>> compiled with IPv6 support");
>>>> +                    return HDR_ERROR;
>>>> +#endif
>>>> +                default:
>>>> +                    /* unsupported protocol, keep local connection 
>>>> address */
>>>> +                    return HDR_DONE;
>>>> +            }
>>>> +            break;  /* we got a sockaddr now */
>>>> +
>>>> +        case 0x00: /* LOCAL command */
>>>> +            /* keep local connection address for LOCAL */
>>>> +            return HDR_DONE;
>>>> +
>>>> +        default:
>>>> +            /* not a supported command */
>>>> +            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03507)
>>>> +                          "RemoteIPProxyProtocol: unsupported command 
>>>> %.2hx",
>>>> +                          hdr->v2.ver_cmd);
>>>> +            return HDR_ERROR;
>>>> +    }
>>>> +
>>>> +    /* got address - compute the client_ip from it */
>>>> +    ret = apr_sockaddr_ip_get(&conn_conf->client_ip, 
>>>> conn_conf->client_addr);
>>>> +    if (ret != APR_SUCCESS) {
>>>> +        conn_conf->client_addr = NULL;
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, APLOGNO(03508)
>>>> +                      "RemoteIPProxyProtocol: error converting address to 
>>>> string");
>>>> +        return HDR_ERROR;
>>>> +    }
>>>> +
>>>> +    return HDR_DONE;
>>>> +}
>>>> +
>>>> +/** Determine if this is a v1 or v2 PROXY header.
>>>> + */
>>>> +static int remoteip_determine_version(conn_rec *c, const char *ptr)
>>>> +{
>>>> +    proxy_header *hdr = (proxy_header *) ptr;
>>>> +
>>>> +    /* assert len >= 14 */
>>>> +
>>>> +    if (memcmp(&hdr->v2, v2sig, sizeof(v2sig)) == 0 &&
>>>> +        (hdr->v2.ver_cmd & 0xF0) == 0x20) {
>>>> +        return 2;
>>>> +    }
>>>> +    else if (memcmp(hdr->v1.line, "PROXY ", 6) == 0) {
>>>> +        return 1;
>>>> +    }
>>>> +    else {
>>>> +        return -1;
>>>> +    }
>>>> +}
>>>> +
>>>> +/* Capture the first bytes on the protocol and parse the proxy protocol 
>>>> header.
>>>> + * Removes itself when the header is complete.
>>>> + */
>>>> +static apr_status_t remoteip_input_filter(ap_filter_t *f,
>>>> +                                    apr_bucket_brigade *bb_out,
>>>> +                                    ap_input_mode_t mode,
>>>> +                                    apr_read_type_e block,
>>>> +                                    apr_off_t readbytes)
>>>> +{
>>>> +    apr_status_t ret;
>>>> +    remoteip_filter_context *ctx = f->ctx;
>>>> +    remoteip_conn_config_t *conn_conf;
>>>> +    apr_bucket *b;
>>>> +    remoteip_parse_status_t psts;
>>>> +    const char *ptr;
>>>> +    apr_size_t len;
>>>> +
>>>> +    if (f->c->aborted) {
>>>> +        return APR_ECONNABORTED;
>>>> +    }
>>>> +
>>>> +    /* allocate/retrieve the context that holds our header */
>>>> +    if (!ctx) {
>>>> +        ctx = f->ctx = apr_palloc(f->c->pool, sizeof(*ctx));
>>>> +        ctx->rcvd = 0;
>>>> +        ctx->need = MIN_HDR_LEN;
>>>> +        ctx->version = 0;
>>>> +        ctx->mode = AP_MODE_READBYTES;
>>>> +        ctx->bb = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
>>>> +        ctx->done = 0;
>>>> +    }
>>>> +
>>>> +    if (ctx->done) {
>>>> +        /* Note: because we're a connection filter we can't remove 
>>>> ourselves
>>>> +         * when we're done, so we have to stay in the chain and just go 
>>>> into
>>>> +         * passthrough mode.
>>>> +         */
>>>> +        return ap_get_brigade(f->next, bb_out, mode, block, readbytes);
>>>> +    }
>>>> +
>>>> +    conn_conf = ap_get_module_config(f->c->conn_config, &remoteip_module);
>>>> +
>>>> +    /* try to read a header's worth of data */
>>>> +    while (!ctx->done) {
>>>> +        if (APR_BRIGADE_EMPTY(ctx->bb)) {
>>>> +            ret = ap_get_brigade(f->next, ctx->bb, ctx->mode, block,
>>>> +                                 ctx->need - ctx->rcvd);
>>>> +            if (ret != APR_SUCCESS) {
>>>> +                return ret;
>>>> +            }
>>>> +        }
>>>> +        if (APR_BRIGADE_EMPTY(ctx->bb)) {
>>> What about the case of an non blocking read where the upstream filter 
>>> returns an empty brigade
>>> and APR_SUCCESS. This is equal to returning EAGAIN.

Also from the original code

>>>> +            return APR_EOF;
>>>> +        }
>>>> +
>>>> +        while (!ctx->done && !APR_BRIGADE_EMPTY(ctx->bb)) {
>>>> +            b = APR_BRIGADE_FIRST(ctx->bb);
>>>> +
>>>> +            ret = apr_bucket_read(b, &ptr, &len, block);
>>>> +            if (APR_STATUS_IS_EAGAIN(ret) && block == APR_NONBLOCK_READ) {
>>>> +                return APR_SUCCESS;
>>>> +            }
>>>> +            if (ret != APR_SUCCESS) {
>>>> +                return ret;
>>>> +            }
>>>> +
>>>> +            memcpy(ctx->header + ctx->rcvd, ptr, len);
>>>> +            ctx->rcvd += len;
>>>> +
>>>> +            /* Remove instead of delete - we may put this bucket
>>>> +               back into bb_out if the header was optional and we
>>>> +               pass down the chain */
>>>> +            APR_BUCKET_REMOVE(b);

Note: In the original code this was apr_bucket_delete.

>>>> +            psts = HDR_NEED_MORE;
>>>> +
>>>> +            if (ctx->version == 0) {
>>>> +                /* reading initial chunk */
>>>> +                if (ctx->rcvd >= MIN_HDR_LEN) {
>>>> +                    ctx->version = remoteip_determine_version(f->c, 
>>>> ctx->header);
>>>> +                    if (ctx->version < 0) {
>>>> +                        psts = HDR_MISSING;
>>>> +                    }
>>>> +                    else if (ctx->version == 1) {
>>>> +                        ctx->mode = AP_MODE_GETLINE;
>>>> +                        ctx->need = sizeof(proxy_v1);
>>>> +                    }
>>>> +                    else if (ctx->version == 2) {
>>>> +                        ctx->need = MIN_V2_HDR_LEN;
>>>> +                    }
>>>> +                }
>>>> +            }
>>>> +            else if (ctx->version == 1) {
>>>> +                psts = remoteip_process_v1_header(f->c, conn_conf,
>>>> +                                            (proxy_header *) ctx->header,
>>>> +                                            ctx->rcvd, &ctx->need);
>>>> +            }
>>>> +            else if (ctx->version == 2) {
>>>> +                if (ctx->rcvd >= MIN_V2_HDR_LEN) {
>>>> +                    ctx->need = MIN_V2_HDR_LEN +
>>>> +                                ntohs(((proxy_header *) 
>>>> ctx->header)->v2.len);
>>>> +                }
>>>> +                if (ctx->rcvd >= ctx->need) {
>>>> +                    psts = remoteip_process_v2_header(f->c, conn_conf,
>>>> +                                                (proxy_header *) 
>>>> ctx->header);
>>>> +                }
>>>> +            }
>>>> +            else {
>>>> +                ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, 
>>>> APLOGNO(03509)
>>>> +                              "RemoteIPProxyProtocol: internal error: 
>>>> unknown version "
>>>> +                              "%d", ctx->version);
>>>> +                f->c->aborted = 1;
>>>> +                apr_bucket_delete(b);
>>>> +                apr_brigade_destroy(ctx->bb);
>>>> +                return APR_ECONNABORTED;
>>>> +            }
>>>> +
>>>> +            switch (psts) {
>>>> +                case HDR_MISSING:
>>>> +                    if (conn_conf->proxy_protocol_optional) {
>>>> +                        /* Same as DONE, but don't delete the bucket. 
>>>> Rather, put it
>>>> +                           back into the brigade and move the request 
>>>> along the stack */
>>>> +                        ctx->done = 1;
>>>> +                        APR_BRIGADE_INSERT_HEAD(bb_out, b);
>>> See below. We need to restore all buckets. What if the original read was 
>>> speculative?
>>>
>>>> +                        return ap_pass_brigade(f->next, ctx->bb);
>>> Why using ap_pass_brigade on f->next? We are an input filter and f->next is 
>>> our upstream input filter.

This is probably my own misunderstanding... what would be the preferred
way to move this down the stack, then?

>>>
>>>> +                    }
>>>> +                    else {
>>>> +                        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, 
>>>> APLOGNO(03510)
>>>> +                                     "RemoteIPProxyProtocol: no valid 
>>>> PROXY header found");
>>>> +                        /* fall through to error case */
>>>> +                    }
>>>> +                case HDR_ERROR:
>>>> +                    f->c->aborted = 1;
>>>> +                    apr_bucket_delete(b);
>>>> +                    apr_brigade_destroy(ctx->bb);
>>>> +                    return APR_ECONNABORTED;
>>>> +
>>>> +                case HDR_DONE:
>>>> +                    apr_bucket_delete(b);
>>>> +                    ctx->done = 1;
>>>> +                    break;
>>>> +
>>>> +                case HDR_NEED_MORE:
>>>> +                    /* It is safe to delete this bucket if we get here 
>>>> since we know
>>>> +                       that we are definitely processing a header (we've 
>>>> read enough to 
>>>> +                       know if the signatures exist on the line) */ 
>>> No. We might not even received MIN_HDR_LEN data so far and thus did not 
>>> check for the signature
>>> so far. We need to safe all the buckets that we might need to restore in a 
>>> separate bucket brigade,
>>> that we need to be set aside before doing the next ap_get_brigade to avoid 
>>> killing transient buckets.

This is a good point. As a side note, in the original code, this delete
didn't exist on this line, but was done earlier (noted above).

Editorially, while I was testing a patch I was writing to do this same
work with mod_ssl down stack, I was consistently getting only 11 bytes
read and I would have expected that same thing to be an issue here
(since MIN_HDR_LEN is 16)... but never actually observed that. I'm sure
that's because ap_get_brigade on the first round through is called
requesting MIN_HDR_LEN bytes (as assigned to ctx->need). Would
ap_get_brigade ever turn less than what was requested?

>>>> +                    apr_bucket_delete(b);
>>>> +                    break;
>>>> +            }
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /* we only get here when done == 1 */
>>>> +    if (psts == HDR_DONE) {
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03511)
>>>> +                      "RemoteIPProxyProtocol: received valid PROXY 
>>>> header: %s:%hu",
>>>> +                      conn_conf->client_ip, conn_conf->client_addr->port);
>>>> +    }
>>>> +    else {
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03512)
>>>> +                      "RemoteIPProxyProtocol: PROXY header was missing");
>>>> +    }
>>>> +
>>>> +    if (ctx->rcvd > ctx->need || !APR_BRIGADE_EMPTY(ctx->bb)) {
>>>> +        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(03513)
>>>> +                      "RemoteIPProxyProtocol: internal error: have data 
>>>> left over; "
>>>> +                      " need=%lu, rcvd=%lu, brigade-empty=%d", ctx->need,
>>>> +                      ctx->rcvd, APR_BRIGADE_EMPTY(ctx->bb));
>>>> +        f->c->aborted = 1;
>>>> +        apr_brigade_destroy(ctx->bb);
>>>> +        return APR_ECONNABORTED;
>>>> +    }
>>>> +
>>>> +    /* clean up */
>>>> +    apr_brigade_destroy(ctx->bb);
>>>> +    ctx->bb = NULL;
>>>> +
>>>> +    /* now do the real read for the upper layer */
>>>> +    return ap_get_brigade(f->next, bb_out, mode, block, readbytes);
>>>> +}
>>>> +
>>>> static const command_rec remoteip_cmds[] =
>>>> {
>>>>     AP_INIT_TAKE1("RemoteIPHeader", header_name_set, NULL, RSRC_CONF,
>>> Regards
>>>
>>> Rüdiger
>>>

-- 
Daniel Ruggeri

Reply via email to