|
Packit |
90a5c9 |
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
90a5c9 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
90a5c9 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
90a5c9 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
90a5c9 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
90a5c9 |
* the License. You may obtain a copy of the License at
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
90a5c9 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
90a5c9 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
90a5c9 |
* See the License for the specific language governing permissions and
|
|
Packit |
90a5c9 |
* limitations under the License.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Portions of the input filter code for PROXY protocol support is
|
|
Packit |
90a5c9 |
* Copyright 2014 Cloudzilla Inc.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "ap_config.h"
|
|
Packit |
90a5c9 |
#include "ap_mmn.h"
|
|
Packit |
90a5c9 |
#include "ap_listen.h"
|
|
Packit |
90a5c9 |
#include "httpd.h"
|
|
Packit |
90a5c9 |
#include "http_config.h"
|
|
Packit |
90a5c9 |
#include "http_connection.h"
|
|
Packit |
90a5c9 |
#include "http_protocol.h"
|
|
Packit |
90a5c9 |
#include "http_log.h"
|
|
Packit |
90a5c9 |
#include "http_main.h"
|
|
Packit |
90a5c9 |
#include "apr_strings.h"
|
|
Packit |
90a5c9 |
#include "apr_lib.h"
|
|
Packit |
90a5c9 |
#define APR_WANT_BYTEFUNC
|
|
Packit |
90a5c9 |
#include "apr_want.h"
|
|
Packit |
90a5c9 |
#include "apr_network_io.h"
|
|
Packit |
90a5c9 |
#include "apr_version.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
module AP_MODULE_DECLARE_DATA remoteip_module;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
/** A proxy IP mask to match */
|
|
Packit |
90a5c9 |
apr_ipsubnet_t *ip;
|
|
Packit |
90a5c9 |
/** Flagged if internal, otherwise an external trusted proxy */
|
|
Packit |
90a5c9 |
void *internal;
|
|
Packit |
90a5c9 |
} remoteip_proxymatch_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct remoteip_addr_info {
|
|
Packit |
90a5c9 |
struct remoteip_addr_info *next;
|
|
Packit |
90a5c9 |
apr_sockaddr_t *addr;
|
|
Packit |
90a5c9 |
server_rec *source;
|
|
Packit |
90a5c9 |
} remoteip_addr_info;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
/** The header to retrieve a proxy-via IP list */
|
|
Packit |
90a5c9 |
const char *header_name;
|
|
Packit |
90a5c9 |
/** A header to record the proxied IP's
|
|
Packit |
90a5c9 |
* (removed as the physical connection and
|
|
Packit |
90a5c9 |
* from the proxy-via IP header value list)
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
const char *proxies_header_name;
|
|
Packit |
90a5c9 |
/** A list of trusted proxies, ideally configured
|
|
Packit |
90a5c9 |
* with the most commonly encountered listed first
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_array_header_t *proxymatch_ip;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
remoteip_addr_info *proxy_protocol_enabled;
|
|
Packit |
90a5c9 |
remoteip_addr_info *proxy_protocol_disabled;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_array_header_t *disabled_subnets;
|
|
Packit |
90a5c9 |
apr_pool_t *pool;
|
|
Packit |
90a5c9 |
} remoteip_config_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
apr_sockaddr_t *useragent_addr;
|
|
Packit |
90a5c9 |
char *useragent_ip;
|
|
Packit |
90a5c9 |
/** The list of proxy IP's ignored as remote IP's */
|
|
Packit |
90a5c9 |
const char *proxy_ips;
|
|
Packit |
90a5c9 |
/** The remaining list of untrusted proxied remote IP's */
|
|
Packit |
90a5c9 |
const char *proxied_remote;
|
|
Packit |
90a5c9 |
} remoteip_req_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* For PROXY protocol processing */
|
|
Packit |
90a5c9 |
static ap_filter_rec_t *remoteip_filter;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
char line[108];
|
|
Packit |
90a5c9 |
} proxy_v1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef union {
|
|
Packit |
90a5c9 |
struct { /* for TCP/UDP over IPv4, len = 12 */
|
|
Packit |
90a5c9 |
apr_uint32_t src_addr;
|
|
Packit |
90a5c9 |
apr_uint32_t dst_addr;
|
|
Packit |
90a5c9 |
apr_uint16_t src_port;
|
|
Packit |
90a5c9 |
apr_uint16_t dst_port;
|
|
Packit |
90a5c9 |
} ip4;
|
|
Packit |
90a5c9 |
struct { /* for TCP/UDP over IPv6, len = 36 */
|
|
Packit |
90a5c9 |
apr_byte_t src_addr[16];
|
|
Packit |
90a5c9 |
apr_byte_t dst_addr[16];
|
|
Packit |
90a5c9 |
apr_uint16_t src_port;
|
|
Packit |
90a5c9 |
apr_uint16_t dst_port;
|
|
Packit |
90a5c9 |
} ip6;
|
|
Packit |
90a5c9 |
struct { /* for AF_UNIX sockets, len = 216 */
|
|
Packit |
90a5c9 |
apr_byte_t src_addr[108];
|
|
Packit |
90a5c9 |
apr_byte_t dst_addr[108];
|
|
Packit |
90a5c9 |
} unx;
|
|
Packit |
90a5c9 |
} proxy_v2_addr;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
apr_byte_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
|
|
Packit |
90a5c9 |
apr_byte_t ver_cmd; /* protocol version and command */
|
|
Packit |
90a5c9 |
apr_byte_t fam; /* protocol family and address */
|
|
Packit |
90a5c9 |
apr_uint16_t len; /* number of following bytes part of the header */
|
|
Packit |
90a5c9 |
proxy_v2_addr addr;
|
|
Packit |
90a5c9 |
} proxy_v2;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef union {
|
|
Packit |
90a5c9 |
proxy_v1 v1;
|
|
Packit |
90a5c9 |
proxy_v2 v2;
|
|
Packit |
90a5c9 |
} proxy_header;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
|
|
Packit |
90a5c9 |
#define MIN_V1_HDR_LEN 15
|
|
Packit |
90a5c9 |
#define MIN_V2_HDR_LEN 16
|
|
Packit |
90a5c9 |
#define MIN_HDR_LEN MIN_V1_HDR_LEN
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* XXX: Unsure if this is needed if v6 support is not available on
|
|
Packit |
90a5c9 |
this platform */
|
|
Packit |
90a5c9 |
#ifndef INET6_ADDRSTRLEN
|
|
Packit |
90a5c9 |
#define INET6_ADDRSTRLEN 46
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
char header[sizeof(proxy_header)];
|
|
Packit |
90a5c9 |
apr_size_t rcvd;
|
|
Packit |
90a5c9 |
apr_size_t need;
|
|
Packit |
90a5c9 |
int version;
|
|
Packit |
90a5c9 |
ap_input_mode_t mode;
|
|
Packit |
90a5c9 |
apr_bucket_brigade *bb;
|
|
Packit |
90a5c9 |
int done;
|
|
Packit |
90a5c9 |
} remoteip_filter_context;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/** Holds the resolved proxy info for this connection and any additional
|
|
Packit |
90a5c9 |
configurable parameters
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
/** The parsed client address in native format */
|
|
Packit |
90a5c9 |
apr_sockaddr_t *client_addr;
|
|
Packit |
90a5c9 |
/** Character representation of the client */
|
|
Packit |
90a5c9 |
char *client_ip;
|
|
Packit |
90a5c9 |
} remoteip_conn_config_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef enum { HDR_DONE, HDR_ERROR, HDR_NEED_MORE } remoteip_parse_status_t;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *create_remoteip_server_config(apr_pool_t *p, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
remoteip_config_t *config = apr_pcalloc(p, sizeof(*config));
|
|
Packit |
90a5c9 |
config->disabled_subnets = apr_array_make(p, 1, sizeof(apr_ipsubnet_t *));
|
|
Packit |
90a5c9 |
/* config->header_name = NULL;
|
|
Packit |
90a5c9 |
* config->proxies_header_name = NULL;
|
|
Packit |
90a5c9 |
* config->proxy_protocol_enabled = NULL;
|
|
Packit |
90a5c9 |
* config->proxy_protocol_disabled = NULL;
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
config->pool = p;
|
|
Packit |
90a5c9 |
return config;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *merge_remoteip_server_config(apr_pool_t *p, void *globalv,
|
|
Packit |
90a5c9 |
void *serverv)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
remoteip_config_t *global = (remoteip_config_t *) globalv;
|
|
Packit |
90a5c9 |
remoteip_config_t *server = (remoteip_config_t *) serverv;
|
|
Packit |
90a5c9 |
remoteip_config_t *config;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
config = (remoteip_config_t *) apr_palloc(p, sizeof(*config));
|
|
Packit |
90a5c9 |
config->header_name = server->header_name
|
|
Packit |
90a5c9 |
? server->header_name
|
|
Packit |
90a5c9 |
: global->header_name;
|
|
Packit |
90a5c9 |
config->proxies_header_name = server->proxies_header_name
|
|
Packit |
90a5c9 |
? server->proxies_header_name
|
|
Packit |
90a5c9 |
: global->proxies_header_name;
|
|
Packit |
90a5c9 |
config->proxymatch_ip = server->proxymatch_ip
|
|
Packit |
90a5c9 |
? server->proxymatch_ip
|
|
Packit |
90a5c9 |
: global->proxymatch_ip;
|
|
Packit |
90a5c9 |
return config;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *header_name_set(cmd_parms *cmd, void *dummy,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
remoteip_config_t *config = ap_get_module_config(cmd->server->module_config,
|
|
Packit |
90a5c9 |
&remoteip_module);
|
|
Packit |
90a5c9 |
config->header_name = arg;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *proxies_header_name_set(cmd_parms *cmd, void *dummy,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
remoteip_config_t *config = ap_get_module_config(cmd->server->module_config,
|
|
Packit |
90a5c9 |
&remoteip_module);
|
|
Packit |
90a5c9 |
config->proxies_header_name = arg;
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Would be quite nice if APR exported this */
|
|
Packit |
90a5c9 |
/* apr:network_io/unix/sockaddr.c */
|
|
Packit |
90a5c9 |
static int looks_like_ip(const char *ipstr)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (ap_strchr_c(ipstr, ':')) {
|
|
Packit |
90a5c9 |
/* definitely not a hostname; assume it is intended to be an IPv6 address */
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* simple IPv4 address string check */
|
|
Packit |
90a5c9 |
while ((*ipstr == '.') || apr_isdigit(*ipstr))
|
|
Packit |
90a5c9 |
ipstr++;
|
|
Packit |
90a5c9 |
return (*ipstr == '\0');
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *proxies_set(cmd_parms *cmd, void *cfg,
|
|
Packit |
90a5c9 |
const char *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
remoteip_config_t *config = ap_get_module_config(cmd->server->module_config,
|
|
Packit |
90a5c9 |
&remoteip_module);
|
|
Packit |
90a5c9 |
remoteip_proxymatch_t *match;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
char *ip = apr_pstrdup(cmd->temp_pool, arg);
|
|
Packit |
90a5c9 |
char *s = ap_strchr(ip, '/');
|
|
Packit |
90a5c9 |
if (s) {
|
|
Packit |
90a5c9 |
*s++ = '\0';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!config->proxymatch_ip) {
|
|
Packit |
90a5c9 |
config->proxymatch_ip = apr_array_make(cmd->pool, 1, sizeof(*match));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
match = (remoteip_proxymatch_t *) apr_array_push(config->proxymatch_ip);
|
|
Packit |
90a5c9 |
match->internal = cmd->info;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (looks_like_ip(ip)) {
|
|
Packit |
90a5c9 |
/* Note s may be null, that's fine (explicit host) */
|
|
Packit |
90a5c9 |
rv = apr_ipsubnet_create(&match->ip, ip, s, cmd->pool);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_sockaddr_t *temp_sa;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (s) {
|
|
Packit |
90a5c9 |
return apr_pstrcat(cmd->pool, "RemoteIP: Error parsing IP ", arg,
|
|
Packit |
90a5c9 |
" the subnet /", s, " is invalid for ",
|
|
Packit |
90a5c9 |
cmd->cmd->name, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_sockaddr_info_get(&temp_sa, ip, APR_UNSPEC, 0,
|
|
Packit |
90a5c9 |
APR_IPV4_ADDR_OK, cmd->temp_pool);
|
|
Packit |
90a5c9 |
while (rv == APR_SUCCESS)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_sockaddr_ip_get(&ip, temp_sa);
|
|
Packit |
90a5c9 |
rv = apr_ipsubnet_create(&match->ip, ip, NULL, cmd->pool);
|
|
Packit |
90a5c9 |
if (!(temp_sa = temp_sa->next)) {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
match = (remoteip_proxymatch_t *)
|
|
Packit |
90a5c9 |
apr_array_push(config->proxymatch_ip);
|
|
Packit |
90a5c9 |
match->internal = cmd->info;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return apr_psprintf(cmd->pool,
|
|
Packit |
90a5c9 |
"RemoteIP: Error parsing IP %s (%pm error) for %s",
|
|
Packit |
90a5c9 |
arg, &rv, cmd->cmd->name);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *proxylist_read(cmd_parms *cmd, void *cfg,
|
|
Packit |
90a5c9 |
const char *filename)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char lbuf[MAX_STRING_LEN];
|
|
Packit |
90a5c9 |
char *arg;
|
|
Packit |
90a5c9 |
const char *args;
|
|
Packit |
90a5c9 |
const char *errmsg;
|
|
Packit |
90a5c9 |
ap_configfile_t *cfp;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
filename = ap_server_root_relative(cmd->temp_pool, filename);
|
|
Packit |
90a5c9 |
rv = ap_pcfg_openfile(&cfp, cmd->temp_pool, filename);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return apr_psprintf(cmd->pool, "%s: Could not open file %s: %pm",
|
|
Packit |
90a5c9 |
cmd->cmd->name, filename, &rv;;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (!(ap_cfg_getline(lbuf, MAX_STRING_LEN, cfp))) {
|
|
Packit |
90a5c9 |
args = lbuf;
|
|
Packit |
90a5c9 |
while (*(arg = ap_getword_conf(cmd->temp_pool, &args)) != '\0') {
|
|
Packit |
90a5c9 |
if (*arg == '#') {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
errmsg = proxies_set(cmd, cfg, arg);
|
|
Packit |
90a5c9 |
if (errmsg) {
|
|
Packit |
90a5c9 |
ap_cfg_closefile(cfp);
|
|
Packit |
90a5c9 |
errmsg = apr_psprintf(cmd->pool, "%s at line %d of %s",
|
|
Packit |
90a5c9 |
errmsg, cfp->line_number, filename);
|
|
Packit |
90a5c9 |
return errmsg;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_cfg_closefile(cfp);
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/** Similar to apr_sockaddr_equal, except that it compares ports too. */
|
|
Packit |
90a5c9 |
static int remoteip_sockaddr_equal(apr_sockaddr_t *addr1, apr_sockaddr_t *addr2)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return (addr1->port == addr2->port && apr_sockaddr_equal(addr1, addr2));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#if !APR_VERSION_AT_LEAST(1,5,0)
|
|
Packit |
90a5c9 |
#define apr_sockaddr_is_wildcard sockaddr_is_wildcard
|
|
Packit |
90a5c9 |
/* XXX: temp build fix from apr 1.5.x */
|
|
Packit |
90a5c9 |
static int sockaddr_is_wildcard(const apr_sockaddr_t *addr)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
static const char inaddr_any[
|
|
Packit |
90a5c9 |
#if APR_HAVE_IPV6
|
|
Packit |
90a5c9 |
sizeof(struct in6_addr)
|
|
Packit |
90a5c9 |
#else
|
|
Packit |
90a5c9 |
sizeof(struct in_addr)
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
] = {0};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (addr->ipaddr_ptr /* IP address initialized */
|
|
Packit |
90a5c9 |
&& addr->ipaddr_len <= sizeof inaddr_any) { /* else bug elsewhere? */
|
|
Packit |
90a5c9 |
if (!memcmp(inaddr_any, addr->ipaddr_ptr, addr->ipaddr_len)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
#if APR_HAVE_IPV6
|
|
Packit |
90a5c9 |
if (addr->family == AF_INET6
|
|
Packit |
90a5c9 |
&& IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr)) {
|
|
Packit |
90a5c9 |
struct in_addr *v4 = (struct in_addr *)&((apr_uint32_t *)addr->ipaddr_ptr)[3];
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!memcmp(inaddr_any, v4, sizeof *v4)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/** Similar to remoteip_sockaddr_equal, except that it handles wildcard addresses
|
|
Packit |
90a5c9 |
* and ports too.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static int remoteip_sockaddr_compat(apr_sockaddr_t *addr1, apr_sockaddr_t *addr2)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* test exact address equality */
|
|
Packit |
90a5c9 |
if (apr_sockaddr_equal(addr1, addr2) &&
|
|
Packit |
90a5c9 |
(addr1->port == addr2->port || addr1->port == 0 || addr2->port == 0)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* test address wildcards */
|
|
Packit |
90a5c9 |
if (apr_sockaddr_is_wildcard(addr1) &&
|
|
Packit |
90a5c9 |
(addr1->port == 0 || addr1->port == addr2->port)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (apr_sockaddr_is_wildcard(addr2) &&
|
|
Packit |
90a5c9 |
(addr2->port == 0 || addr2->port == addr1->port)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int remoteip_addr_in_list(remoteip_addr_info *list, apr_sockaddr_t *addr)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
for (; list; list = list->next) {
|
|
Packit |
90a5c9 |
if (remoteip_sockaddr_compat(list->addr, addr)) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void remoteip_warn_enable_conflict(remoteip_addr_info *prev, server_rec *new, int flag)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char buf[INET6_ADDRSTRLEN];
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_sockaddr_ip_getbuf(buf, sizeof(buf), prev->addr);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, new, APLOGNO(03491)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: previous setting for %s:%hu from virtual "
|
|
Packit |
90a5c9 |
"host {%s:%hu in %s} is being overriden by virtual host "
|
|
Packit |
90a5c9 |
"{%s:%hu in %s}; new setting is '%s'",
|
|
Packit |
90a5c9 |
buf, prev->addr->port, prev->source->server_hostname,
|
|
Packit |
90a5c9 |
prev->source->addrs->host_port, prev->source->defn_name,
|
|
Packit |
90a5c9 |
new->server_hostname, new->addrs->host_port, new->defn_name,
|
|
Packit |
90a5c9 |
flag ? "On" : "Off");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *remoteip_enable_proxy_protocol(cmd_parms *cmd, void *config,
|
|
Packit |
90a5c9 |
int flag)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
remoteip_config_t *conf;
|
|
Packit |
90a5c9 |
server_addr_rec *addr;
|
|
Packit |
90a5c9 |
remoteip_addr_info **add;
|
|
Packit |
90a5c9 |
remoteip_addr_info **rem;
|
|
Packit |
90a5c9 |
remoteip_addr_info *list;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conf = ap_get_module_config(ap_server_conf->module_config,
|
|
Packit |
90a5c9 |
&remoteip_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (flag) {
|
|
Packit |
90a5c9 |
add = &conf->proxy_protocol_enabled;
|
|
Packit |
90a5c9 |
rem = &conf->proxy_protocol_disabled;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
add = &conf->proxy_protocol_disabled;
|
|
Packit |
90a5c9 |
rem = &conf->proxy_protocol_enabled;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (addr = cmd->server->addrs; addr; addr = addr->next) {
|
|
Packit |
90a5c9 |
/* remove address from opposite list */
|
|
Packit |
90a5c9 |
if (*rem) {
|
|
Packit |
90a5c9 |
if (remoteip_sockaddr_equal((*rem)->addr, addr->host_addr)) {
|
|
Packit |
90a5c9 |
remoteip_warn_enable_conflict(*rem, cmd->server, flag);
|
|
Packit |
90a5c9 |
*rem = (*rem)->next;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
for (list = *rem; list->next; list = list->next) {
|
|
Packit |
90a5c9 |
if (remoteip_sockaddr_equal(list->next->addr, addr->host_addr)) {
|
|
Packit |
90a5c9 |
remoteip_warn_enable_conflict(list->next, cmd->server, flag);
|
|
Packit |
90a5c9 |
list->next = list->next->next;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* add address to desired list */
|
|
Packit |
90a5c9 |
if (!remoteip_addr_in_list(*add, addr->host_addr)) {
|
|
Packit |
90a5c9 |
remoteip_addr_info *info = apr_palloc(conf->pool, sizeof(*info));
|
|
Packit |
90a5c9 |
info->addr = addr->host_addr;
|
|
Packit |
90a5c9 |
info->source = cmd->server;
|
|
Packit |
90a5c9 |
info->next = *add;
|
|
Packit |
90a5c9 |
*add = info;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *remoteip_disable_networks(cmd_parms *cmd, void *d,
|
|
Packit |
90a5c9 |
int argc, char *const argv[])
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
apr_pool_t *ptemp = cmd->temp_pool;
|
|
Packit |
90a5c9 |
apr_pool_t *p = cmd->pool;
|
|
Packit |
90a5c9 |
remoteip_config_t *conf = ap_get_module_config(ap_server_conf->module_config,
|
|
Packit |
90a5c9 |
&remoteip_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (argc == 0)
|
|
Packit |
90a5c9 |
return apr_pstrcat(p, cmd->cmd->name, " requires an argument", NULL);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (i=0; i
|
|
Packit |
90a5c9 |
char *addr = apr_pstrdup(ptemp, argv[i]);
|
|
Packit |
90a5c9 |
char *mask;
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
apr_ipsubnet_t **ip = apr_pcalloc(p, sizeof(apr_ipsubnet_t *));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((mask = ap_strchr(addr, '/')))
|
|
Packit |
90a5c9 |
*mask++ = '\0';
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_ipsubnet_create(ip, addr, mask, p);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_STATUS_IS_EINVAL(rv)) {
|
|
Packit |
90a5c9 |
/* looked nothing like an IP address */
|
|
Packit |
90a5c9 |
return apr_psprintf(p, "ip address '%s' appears to be invalid", addr);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return apr_psprintf(p, "ip address '%s' appears to be invalid: %pm",
|
|
Packit |
90a5c9 |
addr, &rv;;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
*(apr_ipsubnet_t**)apr_array_push(conf->disabled_subnets) = *ip;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int remoteip_hook_post_config(apr_pool_t *pconf, apr_pool_t *plog,
|
|
Packit |
90a5c9 |
apr_pool_t *ptemp, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
remoteip_config_t *conf;
|
|
Packit |
90a5c9 |
remoteip_addr_info *info;
|
|
Packit |
90a5c9 |
char buf[INET6_ADDRSTRLEN];
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conf = ap_get_module_config(ap_server_conf->module_config,
|
|
Packit |
90a5c9 |
&remoteip_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (info = conf->proxy_protocol_enabled; info; info = info->next) {
|
|
Packit |
90a5c9 |
apr_sockaddr_ip_getbuf(buf, sizeof(buf), info->addr);
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(03492)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: enabled on %s:%hu", buf, info->addr->port);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
for (info = conf->proxy_protocol_disabled; info; info = info->next) {
|
|
Packit |
90a5c9 |
apr_sockaddr_ip_getbuf(buf, sizeof(buf), info->addr);
|
|
Packit |
90a5c9 |
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(03494)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: disabled on %s:%hu", buf, info->addr->port);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int remoteip_modify_request(request_rec *r)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
conn_rec *c = r->connection;
|
|
Packit |
90a5c9 |
remoteip_config_t *config = (remoteip_config_t *)
|
|
Packit |
90a5c9 |
ap_get_module_config(r->server->module_config, &remoteip_module);
|
|
Packit |
90a5c9 |
remoteip_conn_config_t *conn_config = (remoteip_conn_config_t *)
|
|
Packit |
90a5c9 |
ap_get_module_config(r->connection->conn_config, &remoteip_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
remoteip_req_t *req = NULL;
|
|
Packit |
90a5c9 |
apr_sockaddr_t *temp_sa;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
char *remote;
|
|
Packit |
90a5c9 |
char *proxy_ips = NULL;
|
|
Packit |
90a5c9 |
char *parse_remote;
|
|
Packit |
90a5c9 |
char *eos;
|
|
Packit |
90a5c9 |
unsigned char *addrbyte;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* If no RemoteIPInternalProxy, RemoteIPInternalProxyList, RemoteIPTrustedProxy
|
|
Packit |
90a5c9 |
or RemoteIPTrustedProxyList directive is configured,
|
|
Packit |
90a5c9 |
all proxies will be considered as external trusted proxies.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
void *internal = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* No header defined or results from our input filter */
|
|
Packit |
90a5c9 |
if (!config->header_name && !conn_config) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Easy parsing case - just position the data we already have from PROXY
|
|
Packit |
90a5c9 |
protocol handling allowing it to take precedence and return
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (conn_config) {
|
|
Packit |
90a5c9 |
if (!conn_config->client_addr) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03496)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol data is missing, but required! Aborting request.");
|
|
Packit |
90a5c9 |
return HTTP_BAD_REQUEST;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
r->useragent_addr = conn_config->client_addr;
|
|
Packit |
90a5c9 |
r->useragent_ip = conn_config->client_ip;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
|
Packit |
90a5c9 |
"Using %s as client's IP from PROXY protocol", r->useragent_ip);
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (config->proxymatch_ip) {
|
|
Packit |
90a5c9 |
/* This indicates that a RemoteIPInternalProxy, RemoteIPInternalProxyList, RemoteIPTrustedProxy
|
|
Packit |
90a5c9 |
or RemoteIPTrustedProxyList directive is configured.
|
|
Packit |
90a5c9 |
In this case, default to internal proxy.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
internal = (void *) 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
remote = (char *) apr_table_get(r->headers_in, config->header_name);
|
|
Packit |
90a5c9 |
if (!remote) {
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
remote = apr_pstrdup(r->pool, remote);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
temp_sa = r->useragent_addr ? r->useragent_addr : c->client_addr;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (remote) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* verify user agent IP against the trusted proxy list
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (config->proxymatch_ip) {
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
remoteip_proxymatch_t *match;
|
|
Packit |
90a5c9 |
match = (remoteip_proxymatch_t *)config->proxymatch_ip->elts;
|
|
Packit |
90a5c9 |
for (i = 0; i < config->proxymatch_ip->nelts; ++i) {
|
|
Packit |
90a5c9 |
if (apr_ipsubnet_test(match[i].ip, temp_sa)) {
|
|
Packit |
90a5c9 |
if (internal) {
|
|
Packit |
90a5c9 |
/* Allow an internal proxy to present an external proxy,
|
|
Packit |
90a5c9 |
but do not allow an external proxy to present an internal proxy.
|
|
Packit |
90a5c9 |
In this case, the presented internal proxy will be considered external.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
internal = match[i].internal;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (i && i >= config->proxymatch_ip->nelts) {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if ((parse_remote = strrchr(remote, ',')) == NULL) {
|
|
Packit |
90a5c9 |
parse_remote = remote;
|
|
Packit |
90a5c9 |
remote = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
*(parse_remote++) = '\0';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (*parse_remote == ' ') {
|
|
Packit |
90a5c9 |
++parse_remote;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
eos = parse_remote + strlen(parse_remote) - 1;
|
|
Packit |
90a5c9 |
while (eos >= parse_remote && *eos == ' ') {
|
|
Packit |
90a5c9 |
*(eos--) = '\0';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (eos < parse_remote) {
|
|
Packit |
90a5c9 |
if (remote) {
|
|
Packit |
90a5c9 |
*(remote + strlen(remote)) = ',';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
remote = parse_remote;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* We map as IPv4 rather than IPv6 for equivalent host names
|
|
Packit |
90a5c9 |
* or IPV4OVERIPV6
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
rv = apr_sockaddr_info_get(&temp_sa, parse_remote,
|
|
Packit |
90a5c9 |
APR_UNSPEC, temp_sa->port,
|
|
Packit |
90a5c9 |
APR_IPV4_ADDR_OK, r->pool);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(01568)
|
|
Packit |
90a5c9 |
"RemoteIP: Header %s value of %s cannot be parsed "
|
|
Packit |
90a5c9 |
"as a client IP",
|
|
Packit |
90a5c9 |
config->header_name, parse_remote);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (remote) {
|
|
Packit |
90a5c9 |
*(remote + strlen(remote)) = ',';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
remote = parse_remote;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
addrbyte = (unsigned char *) &temp_sa->sa.sin.sin_addr;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* For intranet (Internal proxies) ignore all restrictions below */
|
|
Packit |
90a5c9 |
if (!internal
|
|
Packit |
90a5c9 |
&& ((temp_sa->family == APR_INET
|
|
Packit |
90a5c9 |
/* For internet (non-Internal proxies) deny all
|
|
Packit |
90a5c9 |
* RFC3330 designated local/private subnets:
|
|
Packit |
90a5c9 |
* 10.0.0.0/8 169.254.0.0/16 192.168.0.0/16
|
|
Packit |
90a5c9 |
* 127.0.0.0/8 172.16.0.0/12
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
&& (addrbyte[0] == 10
|
|
Packit |
90a5c9 |
|| addrbyte[0] == 127
|
|
Packit |
90a5c9 |
|| (addrbyte[0] == 169 && addrbyte[1] == 254)
|
|
Packit |
90a5c9 |
|| (addrbyte[0] == 172 && (addrbyte[1] & 0xf0) == 16)
|
|
Packit |
90a5c9 |
|| (addrbyte[0] == 192 && addrbyte[1] == 168)))
|
|
Packit |
90a5c9 |
#if APR_HAVE_IPV6
|
|
Packit |
90a5c9 |
|| (temp_sa->family == APR_INET6
|
|
Packit |
90a5c9 |
/* For internet (non-Internal proxies) we translated
|
|
Packit |
90a5c9 |
* IPv4-over-IPv6-mapped addresses as IPv4, above.
|
|
Packit |
90a5c9 |
* Accept only Global Unicast 2000::/3 defined by RFC4291
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
&& ((temp_sa->sa.sin6.sin6_addr.s6_addr[0] & 0xe0) != 0x20))
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
)) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(01569)
|
|
Packit |
90a5c9 |
"RemoteIP: Header %s value of %s appears to be "
|
|
Packit |
90a5c9 |
"a private IP or nonsensical. Ignored",
|
|
Packit |
90a5c9 |
config->header_name, parse_remote);
|
|
Packit |
90a5c9 |
if (remote) {
|
|
Packit |
90a5c9 |
*(remote + strlen(remote)) = ',';
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
remote = parse_remote;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* save away our results */
|
|
Packit |
90a5c9 |
if (!req) {
|
|
Packit |
90a5c9 |
req = (remoteip_req_t *) apr_palloc(r->pool, sizeof(remoteip_req_t));
|
|
Packit |
90a5c9 |
req->useragent_ip = r->useragent_ip;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Set useragent_ip string */
|
|
Packit |
90a5c9 |
if (!internal) {
|
|
Packit |
90a5c9 |
if (proxy_ips) {
|
|
Packit |
90a5c9 |
proxy_ips = apr_pstrcat(r->pool, proxy_ips, ", ",
|
|
Packit |
90a5c9 |
req->useragent_ip, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
proxy_ips = req->useragent_ip;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
req->useragent_addr = temp_sa;
|
|
Packit |
90a5c9 |
apr_sockaddr_ip_get(&req->useragent_ip, req->useragent_addr);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Nothing happened? */
|
|
Packit |
90a5c9 |
if (!req) {
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Port is not known so set it to zero; otherwise it can be misleading */
|
|
Packit |
90a5c9 |
req->useragent_addr->port = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
req->proxied_remote = remote;
|
|
Packit |
90a5c9 |
req->proxy_ips = proxy_ips;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (req->proxied_remote) {
|
|
Packit |
90a5c9 |
apr_table_setn(r->headers_in, config->header_name,
|
|
Packit |
90a5c9 |
req->proxied_remote);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
apr_table_unset(r->headers_in, config->header_name);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (req->proxy_ips) {
|
|
Packit |
90a5c9 |
apr_table_setn(r->notes, "remoteip-proxy-ip-list", req->proxy_ips);
|
|
Packit |
90a5c9 |
if (config->proxies_header_name) {
|
|
Packit |
90a5c9 |
apr_table_setn(r->headers_in, config->proxies_header_name,
|
|
Packit |
90a5c9 |
req->proxy_ips);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
r->useragent_addr = req->useragent_addr;
|
|
Packit |
90a5c9 |
r->useragent_ip = req->useragent_ip;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
|
Packit |
90a5c9 |
req->proxy_ips
|
|
Packit |
90a5c9 |
? "Using %s as client's IP by proxies %s"
|
|
Packit |
90a5c9 |
: "Using %s as client's IP by internal proxies%s",
|
|
Packit |
90a5c9 |
req->useragent_ip,
|
|
Packit |
90a5c9 |
(req->proxy_ips ? req->proxy_ips : ""));
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int remoteip_is_server_port(apr_port_t port)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
ap_listen_rec *lr;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
for (lr = ap_listeners; lr; lr = lr->next) {
|
|
Packit |
90a5c9 |
if (lr->bind_addr && lr->bind_addr->port == port) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* Human readable format:
|
|
Packit |
90a5c9 |
* PROXY {TCP4|TCP6|UNKNOWN} <client-ip-addr> <dest-ip-addr> <client-port> <dest-port><CR><LF>
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static remoteip_parse_status_t remoteip_process_v1_header(conn_rec *c,
|
|
Packit |
90a5c9 |
remoteip_conn_config_t *conn_conf,
|
|
Packit |
90a5c9 |
proxy_header *hdr, apr_size_t len,
|
|
Packit |
90a5c9 |
apr_size_t *hdr_len)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *end, *word, *host, *valid_addr_chars, *saveptr;
|
|
Packit |
90a5c9 |
char buf[sizeof(hdr->v1.line)];
|
|
Packit |
90a5c9 |
apr_port_t port;
|
|
Packit |
90a5c9 |
apr_status_t ret;
|
|
Packit |
90a5c9 |
apr_int32_t family;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define GET_NEXT_WORD(field) \
|
|
Packit |
90a5c9 |
word = apr_strtok(NULL, " ", &saveptr); \
|
|
Packit |
90a5c9 |
if (!word) { \
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03497) \
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: no " field " found in header '%s'", \
|
|
Packit |
90a5c9 |
hdr->v1.line); \
|
|
Packit |
90a5c9 |
return HDR_ERROR; \
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
end = memchr(hdr->v1.line, '\r', len - 1);
|
|
Packit |
90a5c9 |
if (!end || end[1] != '\n') {
|
|
Packit |
90a5c9 |
return HDR_NEED_MORE; /* partial or invalid header */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
*end = '\0';
|
|
Packit |
90a5c9 |
*hdr_len = end + 2 - hdr->v1.line; /* skip header + CRLF */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* parse in separate buffer so have the original for error messages */
|
|
Packit |
90a5c9 |
strcpy(buf, hdr->v1.line);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_strtok(buf, " ", &saveptr);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* parse family */
|
|
Packit |
90a5c9 |
GET_NEXT_WORD("family")
|
|
Packit |
90a5c9 |
if (strcmp(word, "UNKNOWN") == 0) {
|
|
Packit |
90a5c9 |
conn_conf->client_addr = c->client_addr;
|
|
Packit |
90a5c9 |
conn_conf->client_ip = c->client_ip;
|
|
Packit |
90a5c9 |
return HDR_DONE;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (strcmp(word, "TCP4") == 0) {
|
|
Packit |
90a5c9 |
family = APR_INET;
|
|
Packit |
90a5c9 |
valid_addr_chars = "0123456789.";
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (strcmp(word, "TCP6") == 0) {
|
|
Packit |
90a5c9 |
#if APR_HAVE_IPV6
|
|
Packit |
90a5c9 |
family = APR_INET6;
|
|
Packit |
90a5c9 |
valid_addr_chars = "0123456789abcdefABCDEF:";
|
|
Packit |
90a5c9 |
#else
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03498)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: Unable to parse v6 address - APR is not compiled with IPv6 support");
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03499)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: unknown family '%s' in header '%s'",
|
|
Packit |
90a5c9 |
word, hdr->v1.line);
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* parse client-addr */
|
|
Packit |
90a5c9 |
GET_NEXT_WORD("client-address")
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (strspn(word, valid_addr_chars) != strlen(word)) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03500)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: invalid client-address '%s' found in "
|
|
Packit |
90a5c9 |
"header '%s'", word, hdr->v1.line);
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
host = word;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* parse dest-addr */
|
|
Packit |
90a5c9 |
GET_NEXT_WORD("destination-address")
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* parse client-port */
|
|
Packit |
90a5c9 |
GET_NEXT_WORD("client-port")
|
|
Packit |
90a5c9 |
if (sscanf(word, "%hu", &port) != 1) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03501)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: error parsing port '%s' in header '%s'",
|
|
Packit |
90a5c9 |
word, hdr->v1.line);
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* parse dest-port */
|
|
Packit |
90a5c9 |
/* GET_NEXT_WORD("destination-port") - no-op since we don't care about it */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* create a socketaddr from the info */
|
|
Packit |
90a5c9 |
ret = apr_sockaddr_info_get(&conn_conf->client_addr, host, family, port, 0,
|
|
Packit |
90a5c9 |
c->pool);
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
conn_conf->client_addr = NULL;
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, APLOGNO(03502)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: error converting family '%d', host '%s',"
|
|
Packit |
90a5c9 |
" and port '%hu' to sockaddr; header was '%s'",
|
|
Packit |
90a5c9 |
family, host, port, hdr->v1.line);
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conn_conf->client_ip = apr_pstrdup(c->pool, host);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return HDR_DONE;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/** Add our filter to the connection if it is requested
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static int remoteip_hook_pre_connection(conn_rec *c, void *csd)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
remoteip_config_t *conf;
|
|
Packit |
90a5c9 |
remoteip_conn_config_t *conn_conf;
|
|
Packit |
90a5c9 |
int i;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Establish master config in slave connections, so that request processing
|
|
Packit |
90a5c9 |
* finds it. */
|
|
Packit |
90a5c9 |
if (c->master != NULL) {
|
|
Packit |
90a5c9 |
conn_conf = ap_get_module_config(c->master->conn_config, &remoteip_module);
|
|
Packit |
90a5c9 |
if (conn_conf) {
|
|
Packit |
90a5c9 |
ap_set_module_config(c->conn_config, &remoteip_module, conn_conf);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conf = ap_get_module_config(ap_server_conf->module_config,
|
|
Packit |
90a5c9 |
&remoteip_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* check if we're enabled for this connection */
|
|
Packit |
90a5c9 |
if (!remoteip_addr_in_list(conf->proxy_protocol_enabled, c->local_addr)
|
|
Packit |
90a5c9 |
|| remoteip_addr_in_list(conf->proxy_protocol_disabled, c->local_addr)) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* We are enabled for this IP/port, but check that we aren't
|
|
Packit |
90a5c9 |
explicitly disabled */
|
|
Packit |
90a5c9 |
for (i = 0; i < conf->disabled_subnets->nelts; i++) {
|
|
Packit |
90a5c9 |
apr_ipsubnet_t *ip = ((apr_ipsubnet_t**)conf->disabled_subnets->elts)[i];
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (ip && apr_ipsubnet_test(ip, c->client_addr))
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* mod_proxy creates outgoing connections - we don't want those */
|
|
Packit |
90a5c9 |
if (!remoteip_is_server_port(c->local_addr->port)) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* add our filter */
|
|
Packit |
90a5c9 |
if (!ap_add_input_filter_handle(remoteip_filter, NULL, NULL, c)) {
|
|
Packit |
90a5c9 |
/* XXX: Shouldn't this WARN in log? */
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(03503)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: enabled on connection to %s:%hu",
|
|
Packit |
90a5c9 |
c->local_ip, c->local_addr->port);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* this holds the resolved proxy info for this connection */
|
|
Packit |
90a5c9 |
conn_conf = apr_pcalloc(c->pool, sizeof(*conn_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_set_module_config(c->conn_config, &remoteip_module, conn_conf);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Binary format:
|
|
Packit |
90a5c9 |
* <sig><cmd><proto><addr-len><addr>
|
|
Packit |
90a5c9 |
* sig = \x0D \x0A \x0D \x0A \x00 \x0D \x0A \x51 \x55 \x49 \x54 \x0A
|
|
Packit |
90a5c9 |
* cmd = <4-bits-version><4-bits-command>
|
|
Packit |
90a5c9 |
* 4-bits-version = \x02
|
|
Packit |
90a5c9 |
* 4-bits-command = {\x00|\x01} (\x00 = LOCAL: discard con info; \x01 = PROXY)
|
|
Packit |
90a5c9 |
* proto = <4-bits-family><4-bits-protocol>
|
|
Packit |
90a5c9 |
* 4-bits-family = {\x00|\x01|\x02|\x03} (AF_UNSPEC, AF_INET, AF_INET6, AF_UNIX)
|
|
Packit |
90a5c9 |
* 4-bits-protocol = {\x00|\x01|\x02} (UNSPEC, STREAM, DGRAM)
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static remoteip_parse_status_t remoteip_process_v2_header(conn_rec *c,
|
|
Packit |
90a5c9 |
remoteip_conn_config_t *conn_conf,
|
|
Packit |
90a5c9 |
proxy_header *hdr)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t ret;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
switch (hdr->v2.ver_cmd & 0xF) {
|
|
Packit |
90a5c9 |
case 0x01: /* PROXY command */
|
|
Packit |
90a5c9 |
switch (hdr->v2.fam) {
|
|
Packit |
90a5c9 |
case 0x11: /* TCPv4 */
|
|
Packit |
90a5c9 |
ret = apr_sockaddr_info_get(&conn_conf->client_addr, NULL,
|
|
Packit |
90a5c9 |
APR_INET,
|
|
Packit |
90a5c9 |
ntohs(hdr->v2.addr.ip4.src_port),
|
|
Packit |
90a5c9 |
0, c->pool);
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
conn_conf->client_addr = NULL;
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, APLOGNO(03504)
|
|
Packit |
90a5c9 |
"RemoteIPPProxyProtocol: error creating sockaddr");
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conn_conf->client_addr->sa.sin.sin_addr.s_addr =
|
|
Packit |
90a5c9 |
hdr->v2.addr.ip4.src_addr;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
case 0x21: /* TCPv6 */
|
|
Packit |
90a5c9 |
#if APR_HAVE_IPV6
|
|
Packit |
90a5c9 |
ret = apr_sockaddr_info_get(&conn_conf->client_addr, NULL,
|
|
Packit |
90a5c9 |
APR_INET6,
|
|
Packit |
90a5c9 |
ntohs(hdr->v2.addr.ip6.src_port),
|
|
Packit |
90a5c9 |
0, c->pool);
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
conn_conf->client_addr = NULL;
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, APLOGNO(03505)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: error creating sockaddr");
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
memcpy(&conn_conf->client_addr->sa.sin6.sin6_addr.s6_addr,
|
|
Packit |
90a5c9 |
hdr->v2.addr.ip6.src_addr, 16);
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
#else
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03506)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: APR is not compiled with IPv6 support");
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
#endif
|
|
Packit |
90a5c9 |
default:
|
|
Packit |
df9dbe |
/* unsupported protocol */
|
|
Packit |
df9dbe |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(10183)
|
|
Packit |
df9dbe |
"RemoteIPProxyProtocol: unsupported protocol %.2hx",
|
|
Packit |
df9dbe |
(unsigned short)hdr->v2.fam);
|
|
Packit |
df9dbe |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
break; /* we got a sockaddr now */
|
|
Packit |
90a5c9 |
default:
|
|
Packit |
90a5c9 |
/* not a supported command */
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03507)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: unsupported command %.2hx",
|
|
Packit |
90a5c9 |
(unsigned short)hdr->v2.ver_cmd);
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* got address - compute the client_ip from it */
|
|
Packit |
90a5c9 |
ret = apr_sockaddr_ip_get(&conn_conf->client_ip, conn_conf->client_addr);
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
conn_conf->client_addr = NULL;
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, c, APLOGNO(03508)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: error converting address to string");
|
|
Packit |
90a5c9 |
return HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return HDR_DONE;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/** Return length for a v2 protocol header. */
|
|
Packit |
90a5c9 |
static apr_size_t remoteip_get_v2_len(proxy_header *hdr)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return ntohs(hdr->v2.len);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/** Determine if this is a v1 or v2 PROXY header.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static int remoteip_determine_version(conn_rec *c, const char *ptr)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
proxy_header *hdr = (proxy_header *) ptr;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* assert len >= 14 */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (memcmp(&hdr->v2, v2sig, sizeof(v2sig)) == 0 &&
|
|
Packit |
90a5c9 |
(hdr->v2.ver_cmd & 0xF0) == 0x20) {
|
|
Packit |
90a5c9 |
return 2;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (memcmp(hdr->v1.line, "PROXY ", 6) == 0) {
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
return -1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Capture the first bytes on the protocol and parse the PROXY protocol header.
|
|
Packit |
90a5c9 |
* Removes itself when the header is complete.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t remoteip_input_filter(ap_filter_t *f,
|
|
Packit |
90a5c9 |
apr_bucket_brigade *bb_out,
|
|
Packit |
90a5c9 |
ap_input_mode_t mode,
|
|
Packit |
90a5c9 |
apr_read_type_e block,
|
|
Packit |
90a5c9 |
apr_off_t readbytes)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_status_t ret;
|
|
Packit |
90a5c9 |
remoteip_filter_context *ctx = f->ctx;
|
|
Packit |
90a5c9 |
remoteip_conn_config_t *conn_conf;
|
|
Packit |
90a5c9 |
apr_bucket *b;
|
|
Packit |
90a5c9 |
remoteip_parse_status_t psts = HDR_NEED_MORE;
|
|
Packit |
90a5c9 |
const char *ptr;
|
|
Packit |
90a5c9 |
apr_size_t len;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (f->c->aborted) {
|
|
Packit |
90a5c9 |
return APR_ECONNABORTED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* allocate/retrieve the context that holds our header */
|
|
Packit |
90a5c9 |
if (!ctx) {
|
|
Packit |
90a5c9 |
ctx = f->ctx = apr_palloc(f->c->pool, sizeof(*ctx));
|
|
Packit |
90a5c9 |
ctx->rcvd = 0;
|
|
Packit |
90a5c9 |
ctx->need = MIN_HDR_LEN;
|
|
Packit |
90a5c9 |
ctx->version = 0;
|
|
Packit |
90a5c9 |
ctx->mode = AP_MODE_READBYTES;
|
|
Packit |
90a5c9 |
ctx->bb = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
|
|
Packit |
90a5c9 |
ctx->done = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (ctx->done) {
|
|
Packit |
90a5c9 |
/* Note: because we're a connection filter we can't remove ourselves
|
|
Packit |
90a5c9 |
* when we're done, so we have to stay in the chain and just go into
|
|
Packit |
90a5c9 |
* passthrough mode.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
return ap_get_brigade(f->next, bb_out, mode, block, readbytes);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conn_conf = ap_get_module_config(f->c->conn_config, &remoteip_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* try to read a header's worth of data */
|
|
Packit |
90a5c9 |
while (!ctx->done) {
|
|
Packit |
90a5c9 |
if (APR_BRIGADE_EMPTY(ctx->bb)) {
|
|
Packit |
df9dbe |
apr_off_t got, want = ctx->need - ctx->rcvd;
|
|
Packit |
df9dbe |
|
|
Packit |
df9dbe |
ret = ap_get_brigade(f->next, ctx->bb, ctx->mode, block, want);
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
df9dbe |
ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, f->c, APLOGNO(10184)
|
|
Packit |
df9dbe |
"failed reading input");
|
|
Packit |
90a5c9 |
return ret;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
df9dbe |
|
|
Packit |
df9dbe |
ret = apr_brigade_length(ctx->bb, 1, &got;;
|
|
Packit |
df9dbe |
if (ret || got > want) {
|
|
Packit |
df9dbe |
ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, f->c, APLOGNO(10185)
|
|
Packit |
df9dbe |
"RemoteIPProxyProtocol header too long, "
|
|
Packit |
df9dbe |
"got %" APR_OFF_T_FMT " expected %" APR_OFF_T_FMT,
|
|
Packit |
df9dbe |
got, want);
|
|
Packit |
df9dbe |
f->c->aborted = 1;
|
|
Packit |
df9dbe |
return APR_ECONNABORTED;
|
|
Packit |
df9dbe |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_BRIGADE_EMPTY(ctx->bb)) {
|
|
Packit |
90a5c9 |
return block == APR_NONBLOCK_READ ? APR_SUCCESS : APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (!ctx->done && !APR_BRIGADE_EMPTY(ctx->bb)) {
|
|
Packit |
90a5c9 |
b = APR_BRIGADE_FIRST(ctx->bb);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ret = apr_bucket_read(b, &ptr, &len, block);
|
|
Packit |
90a5c9 |
if (APR_STATUS_IS_EAGAIN(ret) && block == APR_NONBLOCK_READ) {
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return ret;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
memcpy(ctx->header + ctx->rcvd, ptr, len);
|
|
Packit |
90a5c9 |
ctx->rcvd += len;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_bucket_delete(b);
|
|
Packit |
90a5c9 |
psts = HDR_NEED_MORE;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (ctx->version == 0) {
|
|
Packit |
90a5c9 |
/* reading initial chunk */
|
|
Packit |
90a5c9 |
if (ctx->rcvd >= MIN_HDR_LEN) {
|
|
Packit |
90a5c9 |
ctx->version = remoteip_determine_version(f->c, ctx->header);
|
|
Packit |
90a5c9 |
if (ctx->version < 0) {
|
|
Packit |
90a5c9 |
psts = HDR_ERROR;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (ctx->version == 1) {
|
|
Packit |
90a5c9 |
ctx->mode = AP_MODE_GETLINE;
|
|
Packit |
90a5c9 |
ctx->need = sizeof(proxy_v1);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (ctx->version == 2) {
|
|
Packit |
90a5c9 |
ctx->need = MIN_V2_HDR_LEN;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (ctx->version == 1) {
|
|
Packit |
90a5c9 |
psts = remoteip_process_v1_header(f->c, conn_conf,
|
|
Packit |
90a5c9 |
(proxy_header *) ctx->header,
|
|
Packit |
90a5c9 |
ctx->rcvd, &ctx->need);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (ctx->version == 2) {
|
|
Packit |
90a5c9 |
if (ctx->rcvd >= MIN_V2_HDR_LEN) {
|
|
Packit |
90a5c9 |
ctx->need = MIN_V2_HDR_LEN +
|
|
Packit |
90a5c9 |
remoteip_get_v2_len((proxy_header *) ctx->header);
|
|
Packit |
df9dbe |
if (ctx->need > sizeof(proxy_v2)) {
|
|
Packit |
df9dbe |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(10186)
|
|
Packit |
df9dbe |
"RemoteIPProxyProtocol protocol header length too long");
|
|
Packit |
df9dbe |
f->c->aborted = 1;
|
|
Packit |
df9dbe |
apr_brigade_destroy(ctx->bb);
|
|
Packit |
df9dbe |
return APR_ECONNABORTED;
|
|
Packit |
df9dbe |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (ctx->rcvd >= ctx->need) {
|
|
Packit |
90a5c9 |
psts = remoteip_process_v2_header(f->c, conn_conf,
|
|
Packit |
90a5c9 |
(proxy_header *) ctx->header);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(03509)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: internal error: unknown version "
|
|
Packit |
90a5c9 |
"%d", ctx->version);
|
|
Packit |
90a5c9 |
f->c->aborted = 1;
|
|
Packit |
90a5c9 |
apr_brigade_destroy(ctx->bb);
|
|
Packit |
90a5c9 |
return APR_ECONNABORTED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
switch (psts) {
|
|
Packit |
90a5c9 |
case HDR_ERROR:
|
|
Packit |
90a5c9 |
f->c->aborted = 1;
|
|
Packit |
90a5c9 |
apr_brigade_destroy(ctx->bb);
|
|
Packit |
90a5c9 |
return APR_ECONNABORTED;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
case HDR_DONE:
|
|
Packit |
90a5c9 |
ctx->done = 1;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
case HDR_NEED_MORE:
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* we only get here when done == 1 */
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03511)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: received valid PROXY header: %s:%hu",
|
|
Packit |
90a5c9 |
conn_conf->client_ip, conn_conf->client_addr->port);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (ctx->rcvd > ctx->need || !APR_BRIGADE_EMPTY(ctx->bb)) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(03513)
|
|
Packit |
90a5c9 |
"RemoteIPProxyProtocol: internal error: have data left over; "
|
|
Packit |
90a5c9 |
" need=%" APR_SIZE_T_FMT ", rcvd=%" APR_SIZE_T_FMT
|
|
Packit |
90a5c9 |
", brigade-empty=%d", ctx->need, ctx->rcvd,
|
|
Packit |
90a5c9 |
APR_BRIGADE_EMPTY(ctx->bb));
|
|
Packit |
90a5c9 |
f->c->aborted = 1;
|
|
Packit |
90a5c9 |
apr_brigade_destroy(ctx->bb);
|
|
Packit |
90a5c9 |
return APR_ECONNABORTED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* clean up */
|
|
Packit |
90a5c9 |
apr_brigade_destroy(ctx->bb);
|
|
Packit |
90a5c9 |
ctx->bb = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* now do the real read for the upper layer */
|
|
Packit |
90a5c9 |
return ap_get_brigade(f->next, bb_out, mode, block, readbytes);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const command_rec remoteip_cmds[] =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("RemoteIPHeader", header_name_set, NULL, RSRC_CONF,
|
|
Packit |
90a5c9 |
"Specifies a request header to trust as the client IP, "
|
|
Packit |
90a5c9 |
"e.g. X-Forwarded-For"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("RemoteIPProxiesHeader", proxies_header_name_set,
|
|
Packit |
90a5c9 |
NULL, RSRC_CONF,
|
|
Packit |
90a5c9 |
"Specifies a request header to record proxy IP's, "
|
|
Packit |
90a5c9 |
"e.g. X-Forwarded-By; if not given then do not record"),
|
|
Packit |
90a5c9 |
AP_INIT_ITERATE("RemoteIPTrustedProxy", proxies_set, 0, RSRC_CONF,
|
|
Packit |
90a5c9 |
"Specifies one or more proxies which are trusted "
|
|
Packit |
90a5c9 |
"to present IP headers"),
|
|
Packit |
90a5c9 |
AP_INIT_ITERATE("RemoteIPInternalProxy", proxies_set, (void*)1, RSRC_CONF,
|
|
Packit |
90a5c9 |
"Specifies one or more internal (transparent) proxies "
|
|
Packit |
90a5c9 |
"which are trusted to present IP headers"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("RemoteIPTrustedProxyList", proxylist_read, 0,
|
|
Packit |
90a5c9 |
RSRC_CONF | EXEC_ON_READ,
|
|
Packit |
90a5c9 |
"The filename to read the list of trusted proxies, "
|
|
Packit |
90a5c9 |
"see the RemoteIPTrustedProxy directive"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("RemoteIPInternalProxyList", proxylist_read, (void*)1,
|
|
Packit |
90a5c9 |
RSRC_CONF | EXEC_ON_READ,
|
|
Packit |
90a5c9 |
"The filename to read the list of internal proxies, "
|
|
Packit |
90a5c9 |
"see the RemoteIPInternalProxy directive"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("RemoteIPProxyProtocol", remoteip_enable_proxy_protocol, NULL,
|
|
Packit |
90a5c9 |
RSRC_CONF, "Enable PROXY protocol handling ('on', 'off')"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE_ARGV("RemoteIPProxyProtocolExceptions",
|
|
Packit |
90a5c9 |
remoteip_disable_networks, NULL, RSRC_CONF, "Disable PROXY "
|
|
Packit |
90a5c9 |
"protocol handling for this list of networks in CIDR format"),
|
|
Packit |
90a5c9 |
{ NULL }
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void register_hooks(apr_pool_t *p)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* mod_ssl is CONNECTION + 5, so we want something higher (earlier);
|
|
Packit |
90a5c9 |
* mod_reqtimeout is CONNECTION + 8, so we want something lower (later) */
|
|
Packit |
90a5c9 |
remoteip_filter =
|
|
Packit |
90a5c9 |
ap_register_input_filter("REMOTEIP_INPUT", remoteip_input_filter, NULL,
|
|
Packit |
90a5c9 |
AP_FTYPE_CONNECTION + 7);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_hook_post_config(remoteip_hook_post_config, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
ap_hook_pre_connection(remoteip_hook_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
ap_hook_post_read_request(remoteip_modify_request, NULL, NULL, APR_HOOK_FIRST);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
AP_DECLARE_MODULE(remoteip) = {
|
|
Packit |
90a5c9 |
STANDARD20_MODULE_STUFF,
|
|
Packit |
90a5c9 |
NULL, /* create per-directory config structure */
|
|
Packit |
90a5c9 |
NULL, /* merge per-directory config structures */
|
|
Packit |
90a5c9 |
create_remoteip_server_config, /* create per-server config structure */
|
|
Packit |
90a5c9 |
merge_remoteip_server_config, /* merge per-server config structures */
|
|
Packit |
90a5c9 |
remoteip_cmds, /* command apr_table_t */
|
|
Packit |
90a5c9 |
register_hooks /* register hooks */
|
|
Packit |
90a5c9 |
};
|