openbsd has a setsockopt option called SO_BINDANY that allows a
process to bind to any ip address, even if it is not local to the
system. the patch below uses it to allow nginx to connect to a
backend server using the ip of the client making the request.
my main goal here is to allow the backend server to know the ip of
the client actually making the request without having to look at
extra hhtp headers
i thought id throw this out there to get some help since this is
my first attempt at tweaking nginx. there are a few issues with
this implementation:
1. it is completely specific to openbsd.
2. it needs root privileges to use the SO_BINDANY sockopt.
3. im not sure if connections to backends are cached. if so then
it is probable that a different client will reuse a previous clients
proxy connection, so it will appear that the same client made both
requests to the backend.
to use this you just configure nginx to run as root and add
"proxy_transparent on" to the sections you want this feature enabled
on. you will need to add appropriate "pass out proto tcp divert-reply"
rules to pf for the SO_BINDANY sockopt to work too.
if anyone has some tips on how to handle problems 2 and 3 i would
be grateful.
cheers,
dlg
--- src/event/ngx_event_connect.c.orig Thu Nov 26 04:03:59 2009
+++ src/event/ngx_event_connect.c Thu Oct 28 23:22:37 2010
@@ -11,7 +11,7 @@
ngx_int_t
-ngx_event_connect_peer(ngx_peer_connection_t *pc)
+ngx_event_connect_peer(ngx_peer_connection_t *pc, ngx_connection_t *cc)
{
int rc;
ngx_int_t event;
@@ -20,6 +20,7 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc)
ngx_socket_t s;
ngx_event_t *rev, *wev;
ngx_connection_t *c;
+ int bindany;
rc = pc->get(pc, pc->data);
if (rc != NGX_OK) {
@@ -46,6 +47,40 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc)
}
return NGX_ERROR;
+ }
+
+ if (cc != NULL) {
+ bindany = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_BINDANY,
+ &bindany, sizeof(bindany)) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ "setsockopt(SO_BINDANY) failed");
+
+ ngx_free_connection(c);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (bind(s, cc->sockaddr, cc->socklen) == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ "bind() failed");
+
+ ngx_free_connection(c);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+
+ return NGX_ERROR;
+ }
}
if (pc->rcvbuf) {
--- src/event/ngx_event_connect.h.orig Tue Nov 3 01:24:02 2009
+++ src/event/ngx_event_connect.h Thu Oct 28 23:22:37 2010
@@ -68,7 +68,8 @@ struct ngx_peer_connection_s {
};
-ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc);
+ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc,
+ ngx_connection_t *cc);
ngx_int_t ngx_event_get_peer(ngx_peer_connection_t *pc, void *data);
--- src/http/modules/ngx_http_proxy_module.c.orig Mon May 24 21:01:05 2010
+++ src/http/modules/ngx_http_proxy_module.c Thu Oct 28 23:42:10 2010
@@ -71,6 +71,7 @@ typedef struct {
ngx_http_proxy_vars_t vars;
ngx_flag_t redirect;
+ ngx_flag_t transparent;
ngx_uint_t headers_hash_max_size;
ngx_uint_t headers_hash_bucket_size;
@@ -196,6 +197,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
0,
NULL },
+ { ngx_string("proxy_transparent"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, transparent),
+ NULL },
+
{ ngx_string("proxy_store"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_proxy_store,
@@ -626,6 +634,7 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
u->abort_request = ngx_http_proxy_abort_request;
u->finalize_request = ngx_http_proxy_finalize_request;
r->state = 0;
+ r->transparent = (plcf->transparent == 1);
if (plcf->redirects) {
u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
@@ -1940,6 +1949,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cyclic_temp_file = 0;
conf->redirect = NGX_CONF_UNSET;
+ conf->transparent = NGX_CONF_UNSET;
conf->upstream.change_buffering = 1;
conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
@@ -2214,6 +2224,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *pa
}
}
}
+
+ ngx_conf_merge_value(conf->transparent, prev->transparent, 0);
/* STUB */
if (prev->proxy_lengths) {
--- src/http/ngx_http_request.h.orig Mon May 24 22:35:10 2010
+++ src/http/ngx_http_request.h Thu Oct 28 23:22:37 2010
@@ -511,6 +511,8 @@ struct ngx_http_request_s {
unsigned stat_writing:1;
#endif
+ unsigned transparent:1;
+
/* used to parse HTTP headers */
ngx_uint_t state;
--- src/http/ngx_http_upstream.c.orig Mon May 24 22:35:10 2010
+++ src/http/ngx_http_upstream.c Thu Oct 28 23:22:37 2010
@@ -1066,7 +1066,8 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_h
u->state->response_sec = tp->sec;
u->state->response_msec = tp->msec;
- rc = ngx_event_connect_peer(&u->peer);
+ rc = ngx_event_connect_peer(&u->peer, r->transparent ?
+ r->connection : NULL);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream connect: %i", rc);
--- src/mail/ngx_mail_auth_http_module.c.orig Fri May 14 19:56:37 2010
+++ src/mail/ngx_mail_auth_http_module.c Thu Oct 28 23:22:37 2010
@@ -191,7 +191,7 @@ ngx_mail_auth_http_init(ngx_mail_session_t *s)
ctx->peer.log = s->connection->log;
ctx->peer.log_error = NGX_ERROR_ERR;
- rc = ngx_event_connect_peer(&ctx->peer);
+ rc = ngx_event_connect_peer(&ctx->peer, NULL);
if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
if (ctx->peer.connection) {
--- src/mail/ngx_mail_proxy_module.c.orig Thu Oct 28 23:32:15 2010
+++ src/mail/ngx_mail_proxy_module.c Thu Oct 28 23:30:53 2010
@@ -147,7 +147,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t
p->upstream.log = s->connection->log;
p->upstream.log_error = NGX_ERROR_ERR;
- rc = ngx_event_connect_peer(&p->upstream);
+ rc = ngx_event_connect_peer(&p->upstream, NULL);
if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
ngx_mail_proxy_internal_server_error(s);
Hi Igor,
attached patch fixes ./configure script for less error-forgiving compilers
(like LLVM/clang) when they are used with -Werror option.
auto/types/sizeof:
- printf() is defined in missing <stdio.h> header,
- sizeof() returns size_t type, which has different signedness on different
operating systems (hence %z).
auto/unix:
- setproctitle() is defined in <stdlib.h> on both: NetBSD and OpenBSD.
Best regards,
Piotr Sikora < piotr.sikora(a)frickle.com >
Hi all, I would like to contribute a patch to provide the cached file
age as a variable $proxy_cache_age , which can then be used together
with add_header Age $proxy_cache_age.
The age calculation is not RFC2616 compliant (13.2.3) as it doesn't take
into consideration the cached origin Age header and Date. Is it feasible
to extract this from the cached headers?
--
regards,
wK
Hi, folks!
Here's the first draft of our nginx module development plan in the
next year or so:
http://agentzh.org/misc/nginx/roadmap.html
We'll keep this roadmap document up to date.
Comments and suggestions will be highly appreciated as usual :)
Cheers,
-agentzh
Hi,
There are any special reason for r->header_in->pos not contain POST
Hidden Input fields?
Test with nginx-0.9.2
<form method="POST" action="frm_handler">
<input type="hidden" value="AA2d" name="entry_id">
<input type="text" value="" name="full_name">
<input type="button" value="Send">
</form>
The field "entry_uid" not appears in r->header_in->pos, why not?
Thanks a lot.
Ranier Vilela
Is there a reason to use only -O instead of -O2 for compiling nginx
0.8.5.4 with gcc? Since it's made for high performance this seems
strange. I'm using gcc 4.4.5 on Debian.
Hello, by default GeoIP returns ISO-8859-1 encoded city names which
is not suitable sometimes (e.g varchar utf8 in the DB may cause broken
names, etc). So attached patch allows to use UTF-8 in city names.
--
br, Denis F. Latypoff.
When auto index is enabled on a directory that contains files with
"special" characters IE "test file.txt" or "funny_file?" it does not
escape them resulting in in-correctly formed and sometimes completely
broken links. The expect result being that "test file.txt" is
transformed into "test%20file.txt" and "funny_file?" transformed into
"funny_file%3F"
I don't really have a suggestion for fixing it as the code in
core/ngx_string.c confuses the heck out of me as I'm only a beginner in
C but I'm sure someone experienced could figure it out quite easily!
Issue appears to exist in 0.8.54 and nginx-0.9.4.
Thanks,
Damian
Hi, list
People keep asking me (and others) why there is no API reference for
nginx internals. The answer is simple: it is still in flux and
changing even in nginx's stable releases.
For this reason, I won't work on such a reference and I bet Igor
Sysoev and Maxim Dounin will not either. (Feel free to prove me wrong!
:))
Nginx 0.8.54 changed the meaning of the return values of rewrite-phase
handlers, which makes Valery's guide to phases out of date even before
it was written:
http://www.nginxguts.com/2011/01/phases/
See my comment at the bottom of that article.
This is not the only API change that is not backward compatible,
rather, just one in many others.
FWIW, the rewrite phase handlers do not even honor NGX_DONE nor
NGX_AGAIN in the version range of 0.8.42 ~ 0.8.53. My mail to this
list reporting this regression got completely ignored:
http://forum.nginx.org/read.php?29,103078,103078
Is it funny? Sure not ;)
We've been adding more and more #if/#else craps to our modules's code
just in the hope of being compatible with more and more versions of
nginx. Let's count how many version checks in ngx_echo:
$ ack '#if' src/|grep nginx_version|wc -l
11
and that's the cost of making ngx_echo work with nginx 0.7.21 ~ 0.9.4.
And the number is similar for ngx_lua:
$ ack '#if' src/|grep nginx_version|wc -l
10
Well, one has to invest enough time on the nginx source and trace
*every* new releases carefully enough and prepare for API changes that
may make your module even fail to compile :) Most of the API changes
will not appear in the change log of the new nginx releases. Someone
(IIRC, it's Marcus Clyne) has requested a change log for nginx C API
in the list, but get ignored as always :)
Anyway, this email should not be taken as a complaint, rather, it is
just a report of the current status of nginx 3rd-party module/patch
development. Yeah, it's the reality. If this mail makes you feel the
other way around, I apologize for that.
We're currently maintaining dozens of nginx 3rd-party modules most of
which were born in the 0.8.x era. Just some of them have been
open-sourced. The maintenance work takes time, efforts and patience :)
But still we've been trying very hard to optimize this process for
fun, not only for maintaining existing modules but also for creating
brand new ones ;)
Hope you good luck!
-agentzh
On Sun, Jan 23, 2011 at 2:25 AM, Ranier <ranier(a)cultura.com.br> wrote:
>
> Hi Agentzh,
Please please do not capitalize my nick.
> Yes I checked this module.
>
> IMO, it has drawbacks!
Sure, it does have drawbacks as a standalone nginx module. I
recommended this module just for the sake of source code references. I
believe this can help you devise a satisfying C level utility for
yourself.
I don't think it will be in the nginx core without a decent input
filter mechanism in the core :)
Please also keep in mind, nginx does not read the request body by
default. It's usually up to the content handler (or any other earlier
phase handlers) to determine whether to actually call the
ngx_http_read_client_request_body function on the C level.
> Drawbacks:
> 1. Need set field by field in nginx.conf ($var)
Sure. Because ngx_form_input fits its user interface into the bigger
picture of nginx.conf scripting :)
> 2. Run the whole module, each time you read one field.
You mean reading one field requires parsing through the whole request
body? Yeah, it's currently designed this way, just like nginx's
$arg_FIELD always walk through the whole query string buffer every
time. One may argue that query strings can not be huge while request
bodies can be of megas of bytes, and I agree it's suboptimal for big
chunk of data when there's lots of fields to be processed :)
> 3. Copy data
Putting data into nginx variables requires an additional data copy.
Are you suggesting any other places that introduces unnecessary data
copies?
> 4. More memory for $var
>
Nginx variables do have their own memory footprint and for the sake of
ngx_form_input's UI, it's inevitable :)
> Core support for POST FIELDS:
> 1. No need set $var in nginx.conf
> 2. Read all fields one pass
> 3. Each field in ngx_str_t variable, no need data copy, less memory
POST fields are (usually) encoded as URI components, are you
suggesting in-place URI decoding? (In-place request body processing
may have bad side-effects that you do not want.) Also...how about the
POST body is big enough for nginx to put it onto temporary disk files?
Cheers,
-agentzh