透明的代理 – 如何将套接字传递给本地服务器而无需修改?

我有一个程序侦听端口443,然后根据检测到的协议redirect到SSH或HTTPS本地服务器。

程序通过连接到本地服务器并通过自己的进程来回传递所有数据。

但是,这会导致本地服务器上的始发主机被logging为本地主机。

有没有办法将套接字直接传递给本地服务器进程(而不是仅仅build立一个新的TCP连接),以便保留sockaddr_in (或sockaddr_in6 )的参数?

这个平台是Linux。

这里是一个来自stunnel的代码片段(如果你想查看所有的代码,可以从local_bind函数中的client.c获得)。

 #ifdef IP_TRANSPARENT int on=1; if(c->opt->option.transparent) { if(setsockopt(c->fd, SOL_IP, IP_TRANSPARENT, &on, sizeof on)) sockerror("setsockopt IP_TRANSPARENT"); /* ignore the error to retain Linux 2.2 compatibility */ /* the error will be handled by bind(), anyway */ } #endif /* IP_TRANSPARENT */ memcpy(&addr, &c->bind_addr.addr[0], sizeof addr); if(ntohs(addr.in.sin_port)>=1024) { /* security check */ if(!bind(c->fd, &addr.sa, addr_len(addr))) { s_log(LOG_INFO, "local_bind succeeded on the original port"); return; /* success */ } if(get_last_socket_error()!=EADDRINUSE #ifndef USE_WIN32 || !c->opt->option.transparent #endif /* USE_WIN32 */ ) { sockerror("local_bind (original port)"); longjmp(c->err, 1); } } 

早些时候,c-> bind_addr被设置为连接对等体的地址,这个代码如下:

  else if(c->opt->option.transparent) memcpy(&c->bind_addr, &c->peer_addr, sizeof(SOCKADDR_LIST)); 

stunnel文档包含了对最近的Linux内核的这个建议:

远程模式(2.2.x和> = 2.6.28)要求stunnel以root身份执行。 setuid选项也会打破这个功能。

Linux> = 2.6.28需要对iptables和路由进行以下设置(可能位于/etc/rc.local或同等文件中):

 iptables -t mangle -N DIVERT iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT iptables -t mangle -A DIVERT -j MARK --set-mark 1 iptables -t mangle -A DIVERT -j ACCEPT ip rule add fwmark 1 lookup 100 ip route add local 0.0.0.0/0 dev lo table 100 

如果你有本地服务器进程的控制权,那么你可以这样做。 在代理进程和服务器进程之间创建一个持久的UNIX域套接字连接,然后在该UNIX域套接字上使用sendmsg()传递一个包含TCP套接字文件描述符的SCM_RIGHTS消息。 代理进程可以关闭其对TCP套接字的句柄。

当服务器进程从SCM_RIGHTS消息中的代理传递一个文件描述符时,它只需将其添加到正常的一组客户端套接字中,就好像它来自accept()