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 |
|