getsockopt(...,SO_ORIGINAL_DST,...) 偶尔返回客户端地址

Posted

技术标签:

【中文标题】getsockopt(...,SO_ORIGINAL_DST,...) 偶尔返回客户端地址【英文标题】:getsockopt(...,SO_ORIGINAL_DST,...) occasionally returns client address 【发布时间】:2012-07-10 03:47:42 【问题描述】:

我正在做一个接受 HTTP 请求并将它们转发到目的地的项目。我们使用 Linux (2.6.35.14-106.fc14.x86_64) 和 TPROXY。我会在下面详细说明。

我看到的问题是偶尔(1000 次中有 1 次,有时 100 万次中有 1 次),Linux 会返回对等地址作为目标地址。

有人见过这种情况吗?我在网上看到了 2007 年的一篇笔记,所以我认为这可能有点过时了。

我有以下代码(请原谅此处显示的方法不一致):

struct sockaddr clientaddr;
socklen_t clientlen = sizeof(clientaddr);
int status = getpeername(acceptedSocket, &clientaddr, &clientlen);

char clientName[256];
clientName[0] = '\0';
int clientport = 0;
if (status == 0) 
    inet_ntop(AF_INET, (void *) &((struct sockaddr_in *)&clientaddr)->sin_addr, clientName, 256);
    clientport = ntohs(((struct sockaddr_in *)& clientaddr)->sin_port);
    **printf("Socket::acceptConnection: getpeername :  %s:%d\n", clientName, clientport); fflush(stdout);**

else

    LOGINFO(WARNING(352), "Socket::acceptConnection: Could not get client from accepted socket.\n");


status = getsockopt(acceptedSocket, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr *) &destaddr, &destlen);

if (status == 0) 
    inet_ntop(AF_INET, (void *) &destaddr.sin_addr, destinationName, 256);
    int portnumber = ntohs(destaddr.sin_port);
    ssize_t dl = strlen(destinationName);
    sprintf(&destinationName[dl], ":%d", portnumber);
    **printf("Socket::acceptConnection: getsockopt :  %s\n", destinationName); fflush(stdout);**

else

    LOGINFO(WARNING(352), "Socket::acceptConnection: Could not get destination from accepted socket.\n");

发生的情况是 大多数 getpeername 和 getsockopt 报告正确(请参阅下面的 IPTABLE 配置)。

不幸的是偶尔getgetsockopt报告与getpeername相同,即目的地与对等体相同。

IPTABLE 配置:

-A PREROUTING -p tcp -m socket -j DIVERT 
-A PREROUTING -s 10.2.0.203/32 -p tcp -m tcp --dport 80 -j TPROXY --on-port 8080 --on-ip 10.2.0.204 --tproxy-mark 0x1/0xffffffff 
-A DIVERT -j MARK --set-xmark 0x1/0xffffffff 
-A DIVERT -j ACCEPT

我们已经记录了该活动,并且看起来还不错。例如,我们得到以下输出:

Socket::acceptConnection: getpeername :  10.2.0.203:48517
Socket::acceptConnection: getsockopt :  10.2.0.203:48517

但来自 IPTables 的日志显示 IP 地址是正确的:

Jul  9 17:37:06 2U-204 kernel: [258876.105481] IN=eth3 OUT= MAC=00:1b:21:61:03:99:00:1b:21:61:c0:70:08:00 **SRC=10.2.0.203 DST=192.168.200.206** LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=56054 DF PROTO=TCP **SPT=48517 DPT=80** WINDOW=17896 RES=0x00 SYN URGP=0
Jul  9 17:37:06 2U-204 kernel: [258876.105697] IN=eth3 OUT= MAC=00:1b:21:61:03:99:00:1b:21:61:c0:70:08:00 **SRC=10.2.0.203 DST=192.168.200.206** LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=56055 DF PROTO=TCP **SPT=48517 DPT=80** WINDOW=35 RES=0x00 ACK URGP=0

我真的很难过。

【问题讨论】:

【参考方案1】:

您为什么使用getsockopt( ... SOL_IP, SO_ORIGINAL_DST ... )? AFAIK SO_ORIGINAL_DST 旨在与 NAT REDIRECT 目标而不是 TPROXY 一起使用。

改用简单的getsockname()

【讨论】:

以上是关于getsockopt(...,SO_ORIGINAL_DST,...) 偶尔返回客户端地址的主要内容,如果未能解决你的问题,请参考以下文章

getsockopt 返回负 mss(在 CLion 上)

为啥getsockopt optlen 为零?

遇到的错误是: dial tcp [::1]:3000: getsockopt: connection denied

getsockopt(...,SO_ORIGINAL_DST,...) 偶尔返回客户端地址

拨打 tcp 127.0.0.1:8500:getsockopt:consul 中的连接被拒绝

Linux下getsockopt/setsockopt 函数说明