How can i get ip and port under forward proxy

Hi, there

I want to get ip and port under forward proxy use NGINX, a forward 

proxy
sketch like this:

[Client ]-> [NGINX] → [Internet]

so i want to get proxy’s ip and port . i have try and made some
modifications to the source code including ngx_http_upstream.c
ngx_event_connect.c , there are some details: 1、add local_socket
variable to
get socket fd in ngx_event_connect_peer() 2、add local_sockaddr to get
sockaddr structure in ngx_http_upstream_process_header(), because in
this
function the proxy had connected(connect() in ngx_event_connect_peer()
is
nonblocking) to the upstream(web, e.g. google.com) 3、add a
$upstream_laddr
variable in the ngx_http_upstream.c as ngx_http_upstream_addr_variable()
function. 4、set log property like:

fragment


log property start
'$remote_addr:$remote_port ($upstream_laddr) [$time_local] “$request” ’
'$status $body_bytes_sent “$http_referer” ’
‘“$http_user_agent” “$http_x_forwarded_for”’;


log property end

However, everthing does not work properly, the debug.log like this:

2013/06/05 16:35:50 [debug] 4978#0: *1 http upstream process header
2013/06/05 16:35:50 [debug] 4978#0: *1 http upstream connect socket: 12
2013/06/05 16:35:50 [debug] 4978#0: *1 http upstream connect sa_family:
21920
2013/06/05 16:35:50 [debug] 4978#0: *1 http upstream connect uri: /
HTTP/1.1^M
Host
2013/06/05 16:35:50 [debug] 4978#0: *1 http upstream connect ip:
255.127.0.0:5067 note: Worng ip and Port
2013/06/05 16:35:50 [debug] 4978#0: *1 http proxy status 200 “200 OK”

2013/06/05 16:38:57 [debug] 4978#0: *14 http upstream connect sa_family:
29728 note: Worng sa_family type
2013/06/05 16:38:57 [debug] 4978#0: *14 http upstream connect uri:
/static/channel/focustop/focustop/focustop_105e9cbe.js HTTP/1.1^M
Host
2013/06/05 16:38:57 [debug] 4978#0: *14 http upstream connect ip:
112.111.114.97:25965ÿ^? note:Worng IP and Port
2013/06/05 16:38:57 [debug] 4978#0: *14 http proxy status 304 “304 Not
Modified”

2013/06/05 17:05:32 [debug] 4978#0: *62 http upstream connect socket: 20
2013/06/05 17:05:32 [debug] 4978#0: *62 http upstream connect sa_family:
2
2013/06/05 17:05:32 [debug] 4978#0: *62 http upstream connect uri:
/images1/ch/09xwzx/h_1.gif HTTP/1.1^M
Host
2013/06/05 17:05:32 [debug] 4978#0: *62 http upstream connect ip:
192.168.1.163:49217Ëÿ^? note:Correct IP and Port
2013/06/05 17:05:32 [debug] 4978#0: *62 http proxy status 304 “304 Not
Modified”

Does i have made mistake for code or worng understanding of NGINX event
model. how can make this work correctly to get IP and Port.

Thanks in advance.

Posted at Nginx Forum:

Hello!

On Wed, Jun 05, 2013 at 06:26:25AM -0400, honwel wrote:

get socket fd in ngx_event_connect_peer() 2、add local_sockaddr to get
sockaddr structure in ngx_http_upstream_process_header(), because in this
function the proxy had connected(connect() in ngx_event_connect_peer() is
nonblocking) to the upstream(web, e.g. google.com) 3、add a $upstream_laddr
variable in the ngx_http_upstream.c as ngx_http_upstream_addr_variable()
function. 4、set log property like:

[…]

Does i have made mistake for code or worng understanding of NGINX event
model. how can make this work correctly to get IP and Port.

You may want to show your code if you want us to help.

Note well: upstream connection socket’s file descriptor is
available via u->peer.connection->fd after a successful
ngx_event_connect_peer() call in ngx_http_upstream_connect(). At
this point, local sockaddr of the socket should be also valid as
connect() was already called.


Maxim D.
http://nginx.org/en/donation.html

static void
457 ngx_http_upstream_init_request(ngx_http_request_t r)

498 #endif
499
500 u->store = (u->conf->store || u->conf->store_lengths);
501
502 if (!u->store && !r->post_action &&
!u->conf->ignore_client_abort)
{
503 r->read_event_handler =
ngx_http_upstream_rd_check_broken_connection;
504 r->write_event_handler =
ngx_http_upstream_wr_check_broken_connection;
505 }
506
507 if (r->request_body) {
508 u->request_bufs = r->request_body->bufs;
509 }
510
511 if (u->create_request(r) != NGX_OK) {
512 ngx_http_finalize_request(r,
NGX_HTTP_INTERNAL_SERVER_ERROR);
513 return;
514 }
515
516 u->peer.local = u->conf->local;
517 /
init */
518 u->peer.local_sockaddr = ngx_palloc(r->pool, NGX_SOCKADDRLEN);

650 return;
651 }
652
653 ngx_http_upstream_connect(r, u);
}

Posted at Nginx Forum:

Hello!

On Wed, Jun 05, 2013 at 09:10:10PM -0400, honwel wrote:

Ok, code is as follow:

[…]

ngx_peer_connection_t *pc;
u_char            sa[NGX_SOCKADDRLEN];
socklen_t         len;
u_char            text[NGX_SOCKADDR_STRLEN];
u_char            *p;
struct sockaddr_in *sin;

[…]

if (pc->local_socket) {
    if (getsockname(pc->local_socket, (struct sockaddr *) &sa, &len) !=

-1) {

At this point, len is uninitialized. It is used by getsockname()
as an input paramter though, and specifies the length of
supplied sockaddr structure.


Maxim D.
http://nginx.org/en/donation.html

Thanks, i add a line " len = NGX_SOCKADDRLEN ", then , it is ok! thanks
very much.
but i want to know , why? (struct sockaddr *) &sa and &len as are input
paramter, why len need initialized?

Posted at Nginx Forum:

Ok, code is as follow:

Code:
src/event/ngx_event_connect.c In ngx_event_connect_peer()


rc = connect(s, pc->sockaddr, pc->socklen);

if (rc == -1) {
    err = ngx_socket_errno;


    if (err != NGX_EINPROGRESS

#if (NGX_WIN32)
/* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) /
&& err != NGX_EAGAIN
#endif
)
{
if (err == NGX_ECONNREFUSED
#if (NGX_LINUX)
/

* Linux returns EAGAIN instead of ECONNREFUSED
* for unix sockets if listen queue is full
*/
|| err == NGX_EAGAIN
#endif
|| err == NGX_ECONNRESET
|| err == NGX_ENETDOWN
|| err == NGX_ENETUNREACH
|| err == NGX_EHOSTDOWN
|| err == NGX_EHOSTUNREACH)
{
level = NGX_LOG_ERR;
} else {
level = NGX_LOG_CRIT;
}

        ngx_log_error(level, c->log, err, "connect() to %V failed",
                      pc->name);

        ngx_close_connection(c);
        pc->connection = NULL;

        return NGX_DECLINED;
    }
}

pc->local_socket = s;                       /* save socket fd  after

connect() */

Code:
src/http/ngx_http_upstream.c In
ngx_http_upstream_process_header()

ssize_t            n;
ngx_int_t          rc;
ngx_connection_t  *c;

ngx_peer_connection_t *pc;
u_char            sa[NGX_SOCKADDRLEN];
socklen_t         len;
u_char            text[NGX_SOCKADDR_STRLEN];
u_char            *p;
struct sockaddr_in *sin;


pc = &u->peer;

c = u->peer.connection;

ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
               "http upstream process header");

c->log->action = "reading response header from upstream";

if (c->read->timedout) {
    ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
    return;
}

if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) 

{
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
return;
}

/* getsockname by pc->local_socket which saved in

ngx_event_connect_peer()*/

if (pc == NULL) {
    return;
}
if (pc->local_socket) {
    if (getsockname(pc->local_socket, (struct sockaddr *) &sa, &len) 

!=
-1) {
if (pc->local_sockaddr != NULL) {
ngx_memcpy(pc->local_sockaddr, &sa, len);

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 

0,
“http upstream connect socket: %i”,
pc->local_socket);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log,
0,
“http upstream connect sa_family: %i”,
pc->local_sockaddr->sa_family);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log,
0,
“http upstream connect uri: %s”,
r->uri.data);
sin = (struct sockaddr_in *) sa;
p = (u_char *) &sin->sin_addr;
p = ngx_snprintf(text, NGX_SOCKADDR_STRLEN,
“%ud.%ud.%ud.%ud:%d”,
p[0], p[1], p[2], p[3],
ntohs(sin->sin_port));
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log,
0,
“http upstream connect ip: %s”, &text);
}
}
}

Code: src/http/ngx_http_upstream.c

static ngx_int_t
ngx_http_upstream_laddr_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{

ngx_peer_connection_t   *pc;
struct sockaddr_in      *sin;
u_char                  sa[NGX_SOCKADDRLEN];
socklen_t               len;

#if (NGX_HAVE_INET6)
ngx_uint_t i;
struct sockaddr_in6 *sin6;
#endif

ngx_str_t               s;
u_char                  addr[NGX_SOCKADDR_STRLEN];

s.len = NGX_SOCKADDR_STRLEN;
s.data = addr;

if (r->upstream == NULL) {
    return NGX_ERROR;
}

pc = &r->upstream->peer;
if (pc == NULL){
    return NGX_ERROR;
}
if (pc->local_sockaddr == NULL) {
    return NGX_ERROR;

s.len = ngx_sock_ntop(pc->local_sockaddr, s.data, s.len, 1);

s.data = ngx_pnalloc(r->pool, s.len);
if (s.data == NULL) {
    return NGX_ERROR;
}


ngx_memcpy(s.data, addr, s.len);

v->len = s.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = s.data;

return NGX_OK;

}

Posted at Nginx Forum:

Hello!

On Thu, Jun 06, 2013 at 09:29:36PM -0400, honwel wrote:

Thanks, i add a line " len = NGX_SOCKADDRLEN ", then , it is ok! thanks
very much.
but i want to know , why? (struct sockaddr *) &sa and &len as are input
paramter, why len need initialized?

As I already said, len value is used as an input parameter by
getsockname() function, and hence it must be initialized properly.

See here for more details:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html

: The address_len argument points to a socklen_t object which on
: input specifies the length of the supplied sockaddr structure, and
: on output specifies the length of the stored address. If the
: actual length of the address is greater than the length of the
: supplied sockaddr structure, the stored address shall be
: truncated.


Maxim D.
http://nginx.org/en/donation.html