【问题标题】:How to write proxy program for resending packets?如何编写重新发送数据包的代理程序?
【发布时间】:2015-03-22 18:23:48
【问题描述】:

我需要在两台主机之间的代理服务器上使用 c 语言的原始套接字编写程序。
我已经为它编写了一些代码(并为 iptable 设置了一些规则以将数据包的目标地址更改为代理的接口),我正在接收数据包,打印此数据包中的数据,然后将数据包发送给接收者。

它在原始套接字上的简单客户端/服务器程序上运行,但是当我尝试通过代理建立连接时 - 它不起作用。

您对如何在不使用内核的情况下编写此程序有任何想法吗?

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>

#define PCKT_LEN 8192

int main(void){
  int s;
  char buffer[PCKT_LEN];
  struct sockaddr saddr;
  struct sockaddr_in daddr;
  memset(buffer, 0, PCKT_LEN);

  s = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
  if(s < 0){
     printf("socket() error");
     return -1;
  }

  int saddr_size = sizeof(saddr);
  int header_size = sizeof(struct iphdr) + sizeof(struct tcphdr);
  unsigned int count;

  daddr.sin_family = AF_INET;
  daddr.sin_port = htons(1234);
  daddr.sin_addr.s_addr = inet_addr ("2.2.2.1");

  while(1){
    if(recvfrom(s, buffer, PCKT_LEN , 0, &saddr, &saddr_size) < 0){
       printf("recvfrom() error");
       return -1;
    }
    else{
        int i = header_size;
        for(; i < PCKT_LEN; i++)
            printf("%c", buffer[i]);

      if (sendto (s, buffer, PCKT_LEN, 0, &daddr, &saddr_size) < 0)
        printf("sendto() error");
        return -1;
      }
    }
  }
  close(s);
  return 0;
}

【问题讨论】:

  • 您能否详细说明“通过代理建立连接”?您是在尝试通过代码透明地强制执行代理,还是客户端已经支持代理?
  • 我正在尝试通过代码透明地强制执行代理
  • 你不能仅仅通过重定向数据包来实现透明代理。使用 HTTPS 需要保留原 IP 并建立 CONNECT 隧道;您还需要使用完整而不是相对 URL 等。这是一个非常广泛的问题。

标签: c linux sockets tcp proxy


【解决方案1】:

(您的代码有严重的错误。例如,sendto(2) 的最后一个参数不应该是指针。我假设它不是真正的代码,并且真正的代码编译时没有警告。)

随着唠叨的结束,我认为一个问题是您不小心在发送的数据包中包含了一个额外的 IP 标头。 raw(7) 有以下内容:

除非在套接字上启用了IP_HDRINCL 套接字选项,否则 IPv4 层会在发送数据包时生成 IP 标头。启用后,数据包必须包含 IP 标头。用于接收的 IP 标头始终包含在数据包中。

IP_HDRINCL 默认情况下不启用,除非protocolIPPROTO_RAW(请参阅raw(7) 的更下方),这意味着它在您的情况下被禁用。 (我还检查了getsockopt(2)。)

您必须启用IP_HDRINCL 使用setsockopt(2) 告诉内核您自己提供标头,或者不在sendto() 中包含标头。

最好查看 IP 标头中的 IHL 字段,而不是顺便假设它具有固定大小。 IP 标头可以包含选项。

可能还有其他问题,具体取决于您尝试执行的操作,并且 IPv6 的详细信息可能会有所不同。

【讨论】:

    【解决方案2】:

    无论您在做什么,我都不认为使用原始套接字是一种方式。这些仅用于网络调试。

    首先,请注意,您基本上是从现有的稳定连接中复制内容,而不是通过隧道传输。你没有做建议的事情。

    如果您想捕获到给定服务器的连接:端口(例如 2.2.2.1:1234)到您的应用程序中,以便您可以通过代理对其进行隧道传输,您可以使用 iptables

    iptables -t nat -A OUTPUT -p tcp -d 2.2.2.1 --dport 1234 -j REDIRECT
    

    创建一个绑定到 ip 0.0.0.0 并监听 TCP 端口 1234 的应用程序,并且每次连接到 2.2.2.1:1234 的尝试都将连接到您的应用程序,您可以随心所欲地使用它。

    【讨论】:

    • 我怎样才能通过一个接口重定向所有传入的数据包,通过我的程序传递它并将其发送到服务器,反之亦然?我有客户端 1.1.1.1 和服务器 2.2.2.1 以及具有两个接口的代理 - 连接到客户端的 eth0(1.1.1.2) 和连接到服务器的 eth1(2.2.2.2)
    • @user3425448 在这种情况下,它会复杂得多。我知道在 Windows 上有软件可以做到这一点,我相信它叫做 Proxify。但是您将无法使用 HTTP 代理来隧道 UDP 连接,并且没有支持所有类型流量的代理。我建议为此使用 VPN。
    猜你喜欢
    • 1970-01-01
    • 2020-10-24
    • 2012-12-12
    • 2014-06-14
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    • 2013-01-28
    相关资源
    最近更新 更多