2014-09-24 31 views
2

我正在写一个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; 
} 

预先感谢您的时间!

+0

如果您使用的是Linux操作系统,您是以root身份还是以CAP_NET_RAW身份运行? – 2014-09-24 23:46:16

+0

是的,运行在具有根目录的Linux上 – dreadiscool 2014-09-24 23:48:34

回答

1

我想通了,为什么有人出来示数

自从我重新发送它关闭之前修改数据包中的字段,UDP头的校验和是无效的。我猜测,有些路由器认为UDP数据包被破坏,或者内核将其丢弃在线路末端,导致数据包在路边某处丢失。

快速肮脏的解决方案只是将csum设置为0,以便内核在我通过网络发送出去之前填充校验和。在将来,我将使用有效的校验和算法

+0

如果内核为你填充(并且提供这是记录的行为),请问为什么你觉得这是“快速和肮脏”?看起来没问题,让网络堆栈做它所做的事情...... – remram 2014-09-25 03:31:40

+0

这不是记录的行为,它不会发生在所有系统上 – dreadiscool 2014-09-25 16:53:55

相关问题