我正在写一个UDP代理,并且我使用原始套接字为了创建到后端的“连接”。C原始套接字数据包看起来不错,但不逃避网络
代理具有一系列端口,全部指向单个端口(我的应用程序正在侦听)。其思想是,当代理建立到后端的连接时,它将使用原始套接字来设置源端口,以便后端服务将响应源端口,然后将该端口转发到我的应用程序,然后根据发送到的端口进行处理。
但是,我在开发中遇到了麻烦。我的sendto函数不返回任何错误,并且不会更改errno,并且检查代理上的tcpdump中的流量会显示正在发送的有效UDP数据包。然而,这个数据包似乎永远不会逃离网络并到达后端服务器。我知道这是不是一个iptables的问题,因为当我发送一个UDP数据包,而无需使用SOCK_RAW,它的工作原理没有问题,到达后端
这里是包转储在代理
19:09:57.379502 IP 192.12.88.14.63208 > 192.99.144.204.27015: UDP, length 20
0x0000: 4500 0030 24f7 0000 7011 bc7b c00c 580e E..0$...p..{..X.
0x0010: c063 90cc f6e8 6987 001c 0db9 ffff ffff .c....i.........
0x0020: 7110 c540 0130 3030 3030 3030 3030 3000 [email protected]
19:09:57.379653 IP 192.99.144.204.5004 > 199.21.77.4.27015: UDP, length 20
0x0000: 4500 0030 0000 4000 4011 d573 c063 90cc [email protected]@..s.c..
0x0010: c715 4d04 138c 6987 001c 0db9 ffff ffff ..M...i.........
0x0020: 7110 c540 0130 3030 3030 3030 3030 3000 [email protected]
第一位是数据包从客户端进入到.204,这是UDP代理。然后,UDP代理将其转发到作为后端的.4。
但是,在后端方面,没有任何东西可以通过。
这里是我到目前为止已经写
void relay_traffic(void)
{
int n, ret, t;
struct sockaddr_in cli_addr;
char *buf = (char *)malloc(2048), *pck;
unsigned short buf_seq;
struct raw_udp_hdr *udp_hdr;
struct estab_conn *conn;
len = sizeof (struct sockaddr_in);
while (1)
{
errno = 0;
t = time(NULL);
n = recvfrom(serv_fd, buf, 2048, 0, (struct sockaddr *)&cli_addr, &len);
if (n < 44)
{
bad_packets++;
continue;
}
pck = buf + 20;
udp_hdr = parse_udp_hdr(pck);
memcpy(&buf_seq, buf + 4, 2);
if (cli_addr.sin_addr.s_addr != backend_addr.sin_addr.s_addr)
{
if (udp_hdr->dst_port != htons(SERVER_PORT))
continue;
if (inspect_packet(n, buf) != 1)
{
bad_packets++;
continue;
}
conn = conn_list_recv_addr(cli_addr);
if (conn == NULL)
{
printf("Incoming connection\n");
conn = (struct estab_conn *)malloc(sizeof (struct estab_conn));
conn->cli_addr = cli_addr;
conn->cli_addr.sin_family = AF_INET;
conn->cli_addr.sin_port = udp_hdr->src_port;
conn->used_port = pop_available_port();
conn->next = NULL;
conn_list_push(conn);
}
conn->last_packet = t;
udp_hdr->src_port = htons(conn->used_port->port);
udp_hdr->dst_port = htons(SERVER_PORT);
ret = sendto(back_fd, pck, n - 20, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *)&backend_addr, sizeof (struct sockaddr_in));
if (errno != 0)
conn_list_pop(conn);
printf("(C) Sendto result: %d, errno: %d\n", ret, errno);
}
else
{
conn = conn_list_recv_port(udp_hdr->dst_port);
if (conn == NULL)
{
printf("Response from server, don't know where to route\n");
continue;
}
udp_hdr->src_port = htons(SERVER_PORT);
udp_hdr->dst_port = conn->cli_addr.sin_port;
ret = sendto(back_fd, pck, n - 20, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *)&conn->cli_addr, sizeof (struct sockaddr_in));
if (errno != 0)
conn_list_pop(conn);
printf("Sendto result: %d, errno: %d\n", ret, errno);
}
}
}
这些代码是UDP助手功能
struct raw_udp_hdr {
unsigned short src_port, dst_port, len, csum;
};
struct raw_udp_hdr form_udp_hdr(unsigned short, unsigned short, unsigned short);
struct raw_udp_hdr *parse_udp_hdr(char *);
struct raw_udp_hdr form_udp_hdr(unsigned short src_port, unsigned short dst_port, unsigned short len)
{
struct raw_udp_hdr udp_hdr;
udp_hdr.src_port = src_port;
udp_hdr.dst_port = dst_port;
udp_hdr.len = len;
udp_hdr.csum = 0;
return udp_hdr;
}
inline struct raw_udp_hdr *parse_udp_hdr(char *pck)
{
return (struct raw_udp_hdr *)pck;
}
预先感谢您的时间!
如果您使用的是Linux操作系统,您是以root身份还是以CAP_NET_RAW身份运行? – 2014-09-24 23:46:16
是的,运行在具有根目录的Linux上 – dreadiscool 2014-09-24 23:48:34