source: trunk/server/common/oursrc/httpdmods/mod_original_dst.c @ 2066

Last change on this file since 2066 was 1796, checked in by mitchb, 14 years ago
New mod_original_dst - makes Apache use original destination IP In a setup where requests have passed through a transparent proxy, or an iptables REDIRECT rule, the destination address of the traffic changes. The netfilter code provides an option (SO_ORIGINAL_DST) to find out the original destination address. In an Apache vhost that is IP-based instead of name-based, you may need the original address in order to match the vhost. This module causes Apache to always see the original, instead of the redirected, destination. Apache module written by Anders Kaseorg Method for obtaining the original address pointed out by Quentin Smith Trivial packaging updates for Scripts by Mitch Berger
File size: 2.8 KB
Line 
1/* mod_original_dst
2 * version 1.0, released 2011-03-25
3 * Anders Kaseorg <andersk@mit.edu>
4 *
5 * This replaces the address of incoming connections with the original
6 * destination, before any local masquerading (as given by
7 * SO_ORIGINAL_DST).
8 */
9
10#include <sys/types.h>
11#include <sys/socket.h>
12#include <limits.h>
13#include <netdb.h>
14#include <linux/netfilter_ipv4.h>
15
16#include "ap_config.h"
17#include "ap_listen.h"
18#include "http_config.h"
19#include "http_log.h"
20#include "httpd.h"
21#include "mpm.h"
22
23extern void apr_sockaddr_vars_set(apr_sockaddr_t *, int, apr_port_t);
24
25static apr_status_t original_dst_accept_func(void **accepted, ap_listen_rec *lr, apr_pool_t *ptrans)
26{
27    apr_status_t status = MPM_ACCEPT_FUNC(accepted, lr, ptrans);
28    if (status != APR_SUCCESS)
29        return status;
30
31    apr_socket_t *csd = *accepted;
32
33    apr_sockaddr_t *local_addr;
34    status = apr_socket_addr_get(&local_addr, APR_LOCAL, csd);
35    if (status != APR_SUCCESS) {
36        ap_log_perror(APLOG_MARK, APLOG_EMERG, status, ptrans,
37                      "original_dst_accept_func: apr_socket_addr_get failed");
38        apr_socket_close(csd);
39        return APR_EGENERAL;
40    }
41
42    int sockdes;
43    status = apr_os_sock_get(&sockdes, csd);
44    if (status != APR_SUCCESS) {
45        ap_log_perror(APLOG_MARK, APLOG_EMERG, status, ptrans,
46                      "original_dst_accept_func: apr_os_sock_get failed");
47        apr_socket_close(csd);
48        return APR_EGENERAL;
49    }
50
51    socklen_t salen = sizeof(local_addr->sa);
52    status = getsockopt(sockdes, SOL_IP, SO_ORIGINAL_DST, &local_addr->sa, &salen);
53    if (status == 0) {
54        local_addr->salen = salen;
55        apr_sockaddr_vars_set(local_addr, local_addr->sa.sin.sin_family, htons(local_addr->sa.sin.sin_port));
56        return APR_SUCCESS;
57    } else if (errno == ENOENT) {
58        return APR_SUCCESS;
59    } else {
60        ap_log_perror(APLOG_MARK, APLOG_EMERG, errno, ptrans,
61                      "original_dst_accept_func: getsockopt failed");
62        apr_socket_close(csd);
63        return APR_EGENERAL;
64    }
65}
66
67static int original_dst_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
68{
69    ap_listen_rec *lr;
70    for (lr = ap_listeners; lr; lr = lr->next)
71        if (lr->accept_func == MPM_ACCEPT_FUNC)
72            lr->accept_func = original_dst_accept_func;
73    return OK;
74}
75
76static void original_dst_register_hooks(apr_pool_t *p)
77{
78    ap_hook_post_config(original_dst_post_config, NULL, NULL, APR_HOOK_MIDDLE);
79}
80
81module AP_MODULE_DECLARE_DATA original_dst_module =
82{
83    STANDARD20_MODULE_STUFF,
84    NULL,                           /* per-directory config creator */
85    NULL,                           /* dir config merger */
86    NULL,                           /* server config creator */
87    NULL,                           /* server config merger */
88    NULL,                           /* command table */
89    original_dst_register_hooks,    /* set up other request processing hooks */
90};
Note: See TracBrowser for help on using the repository browser.