/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. */ #include "ap_config.h" #include "ap_mmn.h" #include "httpd.h" #include "http_config.h" #include "http_connection.h" #include "http_protocol.h" #include "http_log.h" #include "apr_strings.h" #define APR_WANT_BYTEFUNC #include "apr_want.h" #include "apr_network_io.h" module AP_MODULE_DECLARE_DATA remoteip_module; typedef struct { const char *remoteip_header; } remoteip_config_t; static void *create_remoteip_server_config(apr_pool_t *p, server_rec *s) { remoteip_config_t *config = apr_palloc(p, sizeof *config); config->remoteip_header = NULL; return config; } static void *merge_remoteip_server_config(apr_pool_t *p, void *globalv, void *serverv) { remoteip_config_t *global = (remoteip_config_t *) globalv; remoteip_config_t *server = (remoteip_config_t *) serverv; remoteip_config_t *config; config = (remoteip_config_t *) apr_palloc(p, sizeof(*config)); if (server->remoteip_header) config->remoteip_header = server->remoteip_header; else config->remoteip_header = global->remoteip_header; return config; } static const char *remoteip_header_set(cmd_parms *cmd, void *dummy, const char *arg) { remoteip_config_t *config = ap_get_module_config(cmd->server->module_config, &remoteip_module); config->remoteip_header = apr_pstrdup(cmd->pool, arg); return NULL; } static int modify_connection(request_rec *r) { conn_rec *c = r->connection; remoteip_config_t *config = ap_get_module_config(r->server->module_config, &remoteip_module); char *remote; if (!config->remoteip_header) return OK; remote = (char*)apr_table_get(r->headers_in, config->remoteip_header); if (!remote) return OK; /* Decode remote_addr - sucks; apr_sockaddr_vars_set isn't 'public' */ if (inet_pton(AF_INET, remote, &c->remote_addr->sa.sin.sin_addr) > 0) { apr_sockaddr_vars_set(c->remote_addr, APR_INET, 0); } #if APR_HAVE_IPV6 else if (inet_pton(AF_INET6, remote, &c->remote_addr->sa.sin6.sin6_addr) > 0) { apr_sockaddr_vars_set(c->remote_addr, APR_INET6, 0); } #endif else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, apr_get_netos_error(), r, "Header %s value of %s doesn't appear to be a client IP", config->remoteip_header, remote); return OK; } /* Set remote_ip string */ remote = apr_pstrdup(c->pool, remote); c->remote_ip = remote; /* Unset remote_host string DNS lookups */ c->remote_host = NULL; c->remote_logname = NULL; ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, "Using header %s value %s as client's IP", config->remoteip_header, remote); return OK; } static const command_rec remoteip_cmds[] = { AP_INIT_TAKE1("RemoteIPHeader", remoteip_header_set, NULL, RSRC_CONF, "Define the request-header to identify the remote IP."), { NULL } }; static void register_hooks(apr_pool_t *p) { ap_hook_post_read_request(modify_connection, NULL, NULL, APR_HOOK_FIRST); } module AP_MODULE_DECLARE_DATA remoteip_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ create_remoteip_server_config, /* create per-server config structure */ merge_remoteip_server_config, /* merge per-server config structures */ remoteip_cmds, /* command apr_table_t */ register_hooks /* register hooks */ };