/* * Copyright (C) 2001,2004 Igor Sysoev, http://sysoev.ru/en/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * / /* MODULE-DEFINITION-START Name: realip_module ConfigStart ConfigEnd MODULE-DEFINITION-END */ #include "httpd.h" #include "http_config.h" #define MOD_REALIP_VER "mod_realip/2.0" #define REALIP_ON 1 #define REALIP_OFF 2 #define REALIP_XFWD 4 typedef struct { int realip; array_header *hosts; } server_conf; module realip_module; static void set_real_remote_ip(request_rec *r, server_conf *conf) { int i, found; char *x_real_ip, *token, *last_ip; const char *x_fwd_for; struct in_addr *addr, raddr; if (conf->hosts->nelts) { found = 0; addr = (struct in_addr *) conf->hosts->elts; raddr = r->connection->remote_addr.sin_addr; for (i = 0; i < conf->hosts->nelts; i++) { if (addr[i].s_addr == raddr.s_addr) { found = 1; break; } } if (!found) { return; } } if (conf->realip & REALIP_XFWD) { if (x_fwd_for = ap_table_get(r->headers_in, "X-Forwarded-For")) { while (*x_fwd_for && (token = ap_get_token(r->pool, &x_fwd_for, 0))) { /* ap_get_token() bug */ if (*x_fwd_for == ',' || *x_fwd_for == ';') x_fwd_for++; last_ip = token; } r->connection->remote_ip = last_ip; } } else { if (x_real_ip = (char *)ap_table_get(r->headers_in, "X-Real-IP")) { r->connection->remote_ip = x_real_ip; } } r->connection->remote_addr.sin_addr.s_addr = ap_inet_addr(r->connection->remote_ip); } static int realip_postread(request_rec *r) { server_conf *conf; conf = (server_conf *) ap_get_module_config(r->server->module_config, &realip_module); if (conf->realip & REALIP_OFF) { return DECLINED; } if (conf->realip & REALIP_ON || conf->hosts->nelts) { set_real_remote_ip(r, conf); } return DECLINED; } static void *realip_config(pool *p, server_rec *s) { server_conf *conf; conf = ap_palloc(p, sizeof(server_conf)); conf->realip = 0; conf->hosts = ap_make_array(p, 3, sizeof(struct in_addr)); return (void *)conf; } static void *realip_merge(pool *p, void *base, void *new) { server_conf *parent = (server_conf *) base; server_conf *child = (server_conf *) new; server_conf *merged; merged = ap_pcalloc(p, sizeof(server_conf)); merged->realip = child->realip ? child->realip : parent->realip; merged->hosts = child->hosts->nelts ? child->hosts : parent->hosts; return (void *)merged; } static const char *set_realip(cmd_parms *cmd, void *dummy, char *host) { struct hostent *h; struct in_addr *addr; server_conf *conf; conf = (server_conf *) ap_get_module_config(cmd->server->module_config, &realip_module); if (strcmp(host, "on") == 0) { conf->realip |= REALIP_ON; return NULL; } if (strcmp(host, "off") == 0) { conf->realip |= REALIP_OFF; return NULL; } if (strcmp(host, "xfwd") == 0) { conf->realip |= REALIP_XFWD; return NULL; } addr = ap_push_array(conf->hosts); if ((addr->s_addr = ap_inet_addr(host)) == INADDR_NONE) { if ((h = ap_pgethostbyname(cmd->pool, host)) != NULL && h->h_addr_list[0] != NULL) { *addr = *(struct in_addr *)(h->h_addr_list[0]); } else { return ap_psprintf(cmd->pool, "Can not resolve host %s", host); } } return NULL; } static const command_rec realip_cmds[] = { {"RealIP", set_realip, NULL, RSRC_CONF, ITERATE, "set hosts that can override a real remote ip"}, {NULL} }; module realip_module = { STANDARD_MODULE_STUFF, NULL, /* module initializer */ NULL, /* per-directory config creator */ NULL, /* dir config merger */ realip_config, /* server config creator */ realip_merge, /* server config merger */ realip_cmds, /* command table */ NULL, /* [9] list of handlers */ NULL, /* [2] filename-to-URI translation */ NULL, /* [5] check/validate user_id */ NULL, /* [6] check user_id is valid *here* */ NULL, /* [4] check access by host address */ NULL, /* [7] MIME type checker/setter */ NULL, /* [8] fixups */ NULL, /* [10] logger */ NULL, /* [3] header parser */ NULL, /* process initializer */ NULL, /* process exit/cleanup */ realip_postread, /* [1] post read_request handling */ };