我需要在两台主机之间的代理服务器上使用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;
}
答案 0 :(得分:0)
(你的代码有严重的错误。例如,sendto(2)
的最后一个参数不应该是指针。我会假设它不是真正的代码,真正的代码在没有警告的情况下编译。)
随着唠叨的出现,我认为一个问题是你不小心在你发送的数据包中加了一个额外的IP头。 raw(7)
有以下内容:
默认情况下,除非在套接字上启用
IP_HDRINCL
套接字选项,否则IPv4层在发送数据包时会生成IP标头。启用后,数据包必须包含IP标头。对于接收IP报头,始终包含在数据包中。
IP_HDRINCL
未启用,除非protocol
为IPPROTO_RAW
(请参阅raw(7)
中的更深一点),这意味着它已在您的情况下被停用。 (我还查看了getsockopt(2)
。)
您必须使用IP_HDRINCL
启用setsockopt(2)
告诉内核您自己提供标头,或者不在sendto()
中添加标头。
最好是查看IP标头中的IHL字段,而不是假设它具有固定大小。 IP标头可以包含选项。
根据您的尝试,可能还有其他问题,IPv6的细节可能会有所不同。
答案 1 :(得分:0)
无论你在做什么,我都不认为使用原始插座就是这样。它们仅用于网络调试。
首先要注意的是,基本上你要从现有的,稳定的连接中复制内容,而不是将其隧道化。你不是在做什么建议。
如果要捕获与给定服务器的连接:端口(例如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
的连接尝试都将连接到您的应用程序,您可以随意使用它。