我正在嘗試編寫一個將任意UDP數據包轉換爲自定義協議並返回的透明代理。我試圖使用透明代理來讀取需要轉換的傳入UDP數據包,並寫入剛剛被反向轉換的傳出UDP數據包。MSG_PROXY無法爲透明代理提供/指定備用地址
我對我使用UDP套接字的兩種口味的插座設置如下:
static int
setup_clear_sock(uint16_t proxy_port)
{
struct sockaddr_in saddr;
int sock;
int val = 1;
socklen_t ttllen = sizeof(std_ttl);
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0)
{
perror("Failed to create clear proxy socket");
return -1;
}
if (getsockopt(sock, IPPROTO_IP, IP_TTL, &std_ttl, &ttllen) < 0)
{
perror("Failed to read IP TTL option on clear proxy socket");
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
{
perror("Failed to set reuse address option on clear socket");
return -1;
}
if (setsockopt(sock, IPPROTO_IP, IP_TRANSPARENT, &val, sizeof(val)) < 0)
{
perror("Failed to set transparent proxy option on clear socket");
return -1;
}
saddr.sin_family = AF_INET;
saddr.sin_port = htons(proxy_port);
saddr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
{
perror("Failed to bind local address to clear proxy socket");
return -1;
}
return sock;
}
我有兩個不同的,但可能相關的問題。首先,當我從這個套接字讀取傳入的UDP數據包,使用此代碼:
struct sock_double_addr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port_a;
struct in_addr sin_addr_a;
sa_family_t sin_family_b;
in_port_t sin_port_b;
struct in_addr sin_addr_b;
unsigned char sin_zero[sizeof(struct sockaddr) - __SOCKADDR_COMMON_SIZE - 8
- sizeof(struct in_addr) - sizeof(in_port_t)];
};
void
handle_clear_sock(void)
{
ssize_t rcvlen;
uint16_t nbo_udp_len, coded_len;
struct sockaddr_in saddr;
struct sock_double_addr_in sdaddr;
bch_coding_context_t ctx;
socklen_t addrlen = sizeof(sdaddr);
rcvlen = recvfrom(sock_clear, &clear_buf, sizeof(clear_buf),
MSG_DONTWAIT | MSG_PROXY,
(struct sockaddr *) &sdaddr, &addrlen);
if (rcvlen < 0)
{
perror("Failed to receive a packet from clear socket");
return;
}
....
我沒有看到一個目的地址回來sdaddr。 sin_family_b,sin_addr_b和sin_port_b字段全部爲零。我在gdb中完成了塊結構的內存轉儲,實際上字節從內核回到零(這在我的結構定義中並不是一個錯誤的位置)。
爲了測試的目的,通過硬編碼一個固定的IP地址和端口來臨時解決這個問題,我可以調試我的代理應用程序的其餘部分,直到我發送一個剛剛被反向轉換的傳出UDP數據包。使用此代碼會發生這種情況:
....
udp_len = ntohs(clear_buf.u16[2]);
if (udp_len + 6 > decoded_len)
fprintf(stderr, "Decoded fewer bytes (%u) than outputting in clear "
"(6 + %u)!\n", decoded_len, udp_len);
sdaddr.sin_family = AF_INET;
sdaddr.sin_port_a = clear_buf.u16[0];
sdaddr.sin_addr_a.s_addr = coded_buf.u32[4];
sdaddr.sin_family_b = AF_INET;
sdaddr.sin_port_b = clear_buf.u16[1];
sdaddr.sin_addr_b.s_addr = coded_buf.u32[3];
if (sendto(sock_clear, &(clear_buf.u16[3]), udp_len, MSG_PROXY,
(struct sockaddr *) &sdaddr, sizeof(sdaddr)) < 0)
perror("Failed to send a packet on clear socket");
}
並且數據包從不出現。我檢查了我構建的sdaddr結構的全部內容,並且所有字段都很好看。 UDP有效負載數據看起來不錯。從sendto()系統調用返回沒有錯誤 - 實際上,它返回零。數據包從來沒有出現在wireshark中。
那麼我的透明代理髮生了什麼?我如何得到這個工作? (FWIW:開發主機是一個通用的x86_64 ubuntu 14.04 LTS盒。)謝謝!