View | Details | Raw Unified | Return to bug 59829
Collapse All | Expand All

(-)httpd-fbc5e20ead005fd3a2bec05924f9e90dfd195406/modules/metadata/mod_remoteip.c (-56 / +168 lines)
Lines 44-53 Link Here
44
     * from the proxy-via IP header value list)
44
     * from the proxy-via IP header value list)
45
     */
45
     */
46
    const char *proxies_header_name;
46
    const char *proxies_header_name;
47
    /** A header that may indicate user is using a
48
     * HTTPS connection to the reverse-proxy, and
49
     * the value that it must match for it to do so.
50
     */
51
    const char *secure_header_name;
52
    const char *secure_header_value;
47
    /** A list of trusted proxies, ideally configured
53
    /** A list of trusted proxies, ideally configured
48
     *  with the most commonly encountered listed first
54
     *  with the most commonly encountered listed first
49
     */
55
     */
50
    apr_array_header_t *proxymatch_ip;
56
    apr_array_header_t *proxymatch_ip;
57
    /** The fixed scheme names http (derived from
58
      * original server configuration) and https
59
      * (set statically).
60
      */
61
    const char *orig_scheme;
62
    const char *secure_scheme;
63
    /** The configured ports for http (derived from
64
      * server configuration) and https (defaults to
65
      * 443 and may be overwritten by the user.
66
      */
67
    int orig_port;
68
    int secure_port;	
51
} remoteip_config_t;
69
} remoteip_config_t;
52
70
53
typedef struct {
71
typedef struct {
Lines 65-70 Link Here
65
    /* config->header_name = NULL;
83
    /* config->header_name = NULL;
66
     * config->proxies_header_name = NULL;
84
     * config->proxies_header_name = NULL;
67
     */
85
     */
86
87
    config->secure_port = 443;
88
    config->orig_port = s->port;
89
90
    config->secure_scheme = apr_pstrdup(p, "https");
91
    config->orig_scheme = s->server_scheme;
92
68
    return config;
93
    return config;
69
}
94
}
70
95
Lines 85-90 Link Here
85
    config->proxymatch_ip = server->proxymatch_ip
110
    config->proxymatch_ip = server->proxymatch_ip
86
                          ? server->proxymatch_ip
111
                          ? server->proxymatch_ip
87
                          : global->proxymatch_ip;
112
                          : global->proxymatch_ip;
113
    config->secure_header_name = server->secure_header_name
114
                                ? server->secure_header_name
115
                                : global->secure_header_name;
116
    config->secure_header_value = server->secure_header_value
117
                                ? server->secure_header_value
118
                                : global->secure_header_value;
119
    config->secure_port = server->secure_port
120
                        ? server->secure_port
121
                        : global->secure_port;
88
    return config;
122
    return config;
89
}
123
}
90
124
Lines 106-111 Link Here
106
    return NULL;
140
    return NULL;
107
}
141
}
108
142
143
static const char *secure_header_set(cmd_parms *cmd, void *dummy,
144
                                           const char *name, const char *value)
145
{
146
    remoteip_config_t *config = ap_get_module_config(cmd->server->module_config,
147
                                                     &remoteip_module);
148
    config->secure_header_name = name;
149
    config->secure_header_value = value;
150
    return NULL;
151
}
152
153
static const char *secure_port_set(cmd_parms *cmd, void *dummy, const char *value)
154
{
155
    remoteip_config_t *config = ap_get_module_config(cmd->server->module_config,
156
                                                     &remoteip_module);
157
    config->secure_port = atoi(value);
158
    return NULL;
159
}
160
109
/* Would be quite nice if APR exported this */
161
/* Would be quite nice if APR exported this */
110
/* apr:network_io/unix/sockaddr.c */
162
/* apr:network_io/unix/sockaddr.c */
111
static int looks_like_ip(const char *ipstr)
163
static int looks_like_ip(const char *ipstr)
Lines 215-220 Link Here
215
    return NULL;
267
    return NULL;
216
}
268
}
217
269
270
static int is_trusted_proxy(remoteip_config_t *config, apr_sockaddr_t *sa, void *internal) {
271
    int i;
272
273
    if (config->proxymatch_ip) {
274
        remoteip_proxymatch_t *match;
275
        match = (remoteip_proxymatch_t *)config->proxymatch_ip->elts;
276
        for (i = 0; i < config->proxymatch_ip->nelts; ++i) {
277
            if (apr_ipsubnet_test(match[i].ip, sa)) {
278
                if (internal) {
279
                    /* Allow an internal proxy to present an external proxy,
280
                       but do not allow an external proxy to present an internal proxy.
281
                       In this case, the presented internal proxy will be considered external.
282
                     */
283
                    internal = match[i].internal;
284
                }
285
                return 1;
286
            }
287
        }
288
    }
289
290
    return 0;
291
}
292
218
static int remoteip_modify_request(request_rec *r)
293
static int remoteip_modify_request(request_rec *r)
219
{
294
{
220
    conn_rec *c = r->connection;
295
    conn_rec *c = r->connection;
Lines 229-234 Link Here
229
    char *proxy_ips = NULL;
304
    char *proxy_ips = NULL;
230
    char *parse_remote;
305
    char *parse_remote;
231
    char *eos;
306
    char *eos;
307
    char *pchar = NULL;
308
    /* The protocol to be set: http(0), https(1). */
309
    int secure = 0;
310
    /* Flag whether allowed to change the request, here: the protocol. */
311
    int trusted_proxy = 0;
232
    unsigned char *addrbyte;
312
    unsigned char *addrbyte;
233
313
234
    /* If no RemoteIPInternalProxy, RemoteIPInternalProxyList, RemoteIPTrustedProxy
314
    /* If no RemoteIPInternalProxy, RemoteIPInternalProxyList, RemoteIPTrustedProxy
Lines 237-243 Link Here
237
     */
317
     */
238
    void *internal = NULL;
318
    void *internal = NULL;
239
319
240
    if (!config->header_name) {
320
    if (!config->header_name && !config->secure_header_name) {
321
        return DECLINED;
322
    }
323
324
    /* When using mod_rewrite, the HTTPS environment variable has to be reset,
325
       but no further processing has to be done, because the processed headers
326
       have been already unset.
327
       Decline this module to be run once again.
328
    */
329
    if (apr_table_get(r->connection->notes, "remoteip_env_https")) {
330
        apr_table_set(r->subprocess_env, "HTTPS", "on");
331
    }
332
    if (apr_table_get(r->connection->notes, "remoteip_done")) {
241
        return DECLINED;
333
        return DECLINED;
242
    }
334
    }
243
 
335
 
Lines 248-286 Link Here
248
         */
340
         */
249
        internal = (void *) 1;
341
        internal = (void *) 1;
250
    }
342
    }
251
343
  
252
    remote = (char *) apr_table_get(r->headers_in, config->header_name);
344
    remote = (char *) apr_table_get(r->headers_in, config->header_name);
253
    if (!remote) {
345
    temp_sa = c->client_addr;
254
        return OK;
346
    if (remote) {
347
        remote = apr_pstrdup(r->pool, remote);
255
    }
348
    }
256
    remote = apr_pstrdup(r->pool, remote);
349
    /* Loop through all entries the remoteip_header.
257
350
     * For further use, flag the var trusted_proxy if a trusted proxy was seen.
258
    temp_sa = r->useragent_addr ? r->useragent_addr : c->client_addr;
351
     */
259
352
    while ((trusted_proxy|=is_trusted_proxy(config, temp_sa, internal))==1 && remote) {
260
    while (remote) {
261
262
        /* verify user agent IP against the trusted proxy list
263
         */
264
        if (config->proxymatch_ip) {
265
            int i;
266
            remoteip_proxymatch_t *match;
267
            match = (remoteip_proxymatch_t *)config->proxymatch_ip->elts;
268
            for (i = 0; i < config->proxymatch_ip->nelts; ++i) {
269
                if (apr_ipsubnet_test(match[i].ip, temp_sa)) {
270
                    if (internal) {
271
                        /* Allow an internal proxy to present an external proxy,
272
                           but do not allow an external proxy to present an internal proxy.
273
                           In this case, the presented internal proxy will be considered external.
274
                         */
275
                        internal = match[i].internal;
276
                    }
277
                    break;
278
                }
279
            }
280
            if (i && i >= config->proxymatch_ip->nelts) {
281
                break;
282
            }
283
        }
284
353
285
        if ((parse_remote = strrchr(remote, ',')) == NULL) {
354
        if ((parse_remote = strrchr(remote, ',')) == NULL) {
286
            parse_remote = remote;
355
            parse_remote = remote;
Lines 389-426 Link Here
389
        apr_sockaddr_ip_get(&req->useragent_ip, req->useragent_addr);
458
        apr_sockaddr_ip_get(&req->useragent_ip, req->useragent_addr);
390
    }
459
    }
391
460
392
    /* Nothing happened? */
461
    /* Is there a client IP to be set? */
393
    if (!req) {
462
    if (req) {
394
        return OK;
463
        req->proxied_remote = remote;
464
        req->proxy_ips = proxy_ips;
465
466
        if (req->proxied_remote) {
467
            apr_table_setn(r->headers_in, config->header_name,
468
                            req->proxied_remote);
469
        }
470
        else {
471
            apr_table_unset(r->headers_in, config->header_name);
472
        }
473
        if (req->proxy_ips) {
474
            apr_table_setn(r->notes, "remoteip-proxy-ip-list", req->proxy_ips);
475
            if (config->proxies_header_name) {
476
                apr_table_setn(r->headers_in, config->proxies_header_name,
477
                               req->proxy_ips);
478
            }
479
        }
480
481
        r->useragent_addr = req->useragent_addr;
482
        r->useragent_ip = req->useragent_ip;
483
484
        /* Flag not to be called again when running with mod_rewrite */
485
        apr_table_set(r->connection->notes, "remoteip_done", "1");
486
487
        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
488
                      req->proxy_ips
489
                          ? "Using %s as client's IP by proxies %s via"
490
                          : "Using %s as client's IP by internal proxies %s",
491
                      req->useragent_ip,
492
                      (req->proxy_ips ? req->proxy_ips : ""));
395
    }
493
    }
396
494
397
    req->proxied_remote = remote;
495
    /* Handle the secure_header_name if the request was sent via a trusted proxy.
398
    req->proxy_ips = proxy_ips;
496
     * As the request object may be reused without resetting the scheme and
497
     * server port, we'll always have to set port and scheme.
498
     */
499
    if (config->secure_header_name && trusted_proxy == 1) {
500
        pchar = (char *) apr_table_get(r->headers_in, config->secure_header_name);
501
        if (pchar && 0 == strcmp(pchar, config->secure_header_value)) {
502
           secure = 1;
503
        }
504
    }
399
505
400
    if (req->proxied_remote) {
506
    if (secure) {
401
        apr_table_setn(r->headers_in, config->header_name,
507
        apr_table_setn(r->subprocess_env, "HTTPS", "on");
402
                       req->proxied_remote);
508
        r->server->port = config->secure_port;
509
        r->server->server_scheme = config->secure_scheme;
510
        r->parsed_uri.port = r->server->port;
511
        
512
        /* Header available, matched and processed. May be unset now.
513
           When using mod_rewrite, the HTTPS env will be unset, so set
514
           a flag for setting the env var again. */
515
        apr_table_unset(r->headers_in, config->secure_header_name);
516
        apr_table_set(r->connection->notes, "remoteip_env_https", "1");
517
518
        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
519
                      "Setting scheme https and server's port %d",
520
                      r->server->port);
403
    }
521
    }
404
    else {
522
    else {
405
        apr_table_unset(r->headers_in, config->header_name);
523
        r->server->port = config->orig_port;
406
    }
524
        r->server->server_scheme = config->orig_scheme;
407
    if (req->proxy_ips) {
408
        apr_table_setn(r->notes, "remoteip-proxy-ip-list", req->proxy_ips);
409
        if (config->proxies_header_name) {
410
            apr_table_setn(r->headers_in, config->proxies_header_name,
411
                           req->proxy_ips);
412
        }
413
    }
525
    }
414
526
415
    r->useragent_addr = req->useragent_addr;
527
    /* Set port in environment variable as well*/
416
    r->useragent_ip = req->useragent_ip;
528
    apr_table_setn(r->subprocess_env, "SERVER_PORT", apr_itoa(r->pool, r->server->port));
417
529
418
    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
419
                  req->proxy_ips
420
                      ? "Using %s as client's IP by proxies %s"
421
                      : "Using %s as client's IP by internal proxies%s",
422
                  req->useragent_ip,
423
                  (req->proxy_ips ? req->proxy_ips : ""));
424
    return OK;
530
    return OK;
425
}
531
}
426
532
Lines 447-452 Link Here
447
                  RSRC_CONF | EXEC_ON_READ,
553
                  RSRC_CONF | EXEC_ON_READ,
448
                  "The filename to read the list of internal proxies, "
554
                  "The filename to read the list of internal proxies, "
449
                  "see the RemoteIPInternalProxy directive"),
555
                  "see the RemoteIPInternalProxy directive"),
556
    AP_INIT_TAKE2("SecureIndicatorHeader", secure_header_set, NULL, RSRC_CONF,
557
                  "Specifies a request header and value that indicates a secure connection, "
558
                  "e.g. \"X-Forwarded-Proto https\" or \"X-Secure-Connection on\""),
559
    AP_INIT_TAKE1("SecureIndicatorSSLPort", secure_port_set, NULL, RSRC_CONF,
560
                  "Port to be used for redirections if SecureIndicatorHeader is set, "
561
                  "Default is \"SecureInidcatorSSLPort 443\" "),
450
    { NULL }
562
    { NULL }
451
};
563
};
452
564

Return to bug 59829