如何在我的HTTP代理中查看TCP、IP头?
我在我的Ubuntu 14.04 x86_64上使用以下方案实现了一个分叉HTTP代理(我报告的基本代码和伪代码只是为了展示这个概念):如何在我的HTTP代理中查看TCP、IP头?,c,sockets,networking,http-proxy,packets,C,Sockets,Networking,Http Proxy,Packets,我在我的Ubuntu 14.04 x86_64上使用以下方案实现了一个分叉HTTP代理(我报告的基本代码和伪代码只是为了展示这个概念): socketClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP) bind(socketClient,(struct sockaddr*)&addr,sizeof(addr)) 监听(socketClient,50) newSocket=accept(socketClient,(struct sockaddr*)&cli
socketClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)
李>
bind(socketClient,(struct sockaddr*)&addr,sizeof(addr))
李>
监听(socketClient,50)
李>
newSocket=accept(socketClient,(struct sockaddr*)&cliAddr,sizeof(cliAddr))
李>
fork()
,打开到远程服务器的连接并处理请求李>
GET
请求,则将原始请求发送到服务器,在服务器发送数据时,将数据从服务器发送到客户端李>
CONNECT
请求,则向客户端发送字符串200ok
,并使用select()
轮询客户端套接字描述符和服务器套接字描述符;若我从服务器套接字读取数据,则将该数据发送到客户端;否则,若我从客户端套接字读取数据,则将此数据发送到服务器- 连接跟踪李>
- 发送和接收的数据包数
send()
或recv()
一个完整的数据包时,每当char缓冲区[1500]
中充满数据时,我会对我的计数器执行+1
我意识到这是不正确的:SOCK\u STREAM
没有数据包的概念,它只是一个连续的字节流!我在第7点使用的char缓冲区[1500]
。八,。有一个有用的统计数据,我可以将其容量设置为4096字节,但我无法跟踪发送或接收的TCP数据包,因为TCP有段,而不是数据包
我也无法解析char buffer[]
在TCP报头中查找SYN标志,因为IP和TCP报头是从报头中剥离出来的(因为我正在处理的级别是用IPPROTO\u TCP
标志指定的),而且,如果我理解得很好,char buffer[]
只包含有效负载,对我来说是无用的
因此,如果我的级别太高,我应该降低级别:有一次我看到一个简单的raw
套接字嗅探器,其中无符号字符缓冲区[65535]
被强制转换到struct ethhdr、iphdt、tcphdr
,它可以看到所有标题的所有标志,以及我感兴趣的所有统计信息
喜悦过后,失望之后:由于raw
sockets的工作级别较低,它们没有一些对我的代理至关重要的概念<代码>原始套接字不能绑定
,侦听
和接受
;我的代理正在侦听固定端口,但raw
sockets不知道端口是什么,它属于TCP级别,它们bind
使用setsockopt
将其绑定到指定的接口
因此,如果我想socket(PF_INET,SOCK_RAW,ntohs(ETH_p_ALL))
我应该能够解析我在.7和.8处recv()
和send()
的缓冲区,但是我应该使用recvfrom()
和sendto()
…但是所有这些听起来都很混乱,它为我的代码提供了一个很好的重构
如何保持代理的完整结构(
绑定、侦听、接受固定端口和接口)并增加IP和TCP头的视野?我的建议是在应用程序的另一个线程中打开一个原始套接字。嗅探所有流量,并根据地址和端口号过滤出相关数据包。基本上,您希望实现自己的数据包嗅探器:
int sniff()
{
int sockfd;
int len;
int saddr_size;
struct sockaddr saddr;
unsigned char buffer[65536];
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if (sockfd < 0) {
perror("socket");
return -1;
}
while (1) {
saddr_size = sizeof(saddr);
len = recvfrom(sockfd, buffer, sizeof(buffer), 0, &saddr, &saddr_size);
if (len < 0) {
perror("recvfrom");
close(sockfd);
return -1;
}
// ... do the things you want to do with the packet received here ...
}
close(sockfd);
return 0;
}
使用getpeername()
和getsockname()
函数调用查找TCP连接的本地和远程地址及端口号。您需要按这些数据包过滤数据包。我将编辑问题以了解更多详细信息。您根本不可能获得任何带有HTTP代理的UDP。为什么不使用专用嗅探器,例如wireshark?您可以嗅探特定接口上的所有流量,然后根据协议和端口号进行过滤。您还可以使用原始套接字方法编写自己的嗅探器:您创建的需求似乎与项目的设计有很大的差异。您确定需要了解特定的数据包流量吗?你为什么认为你需要这个?如果您的应用程序是绑定到此接口的唯一通信量,您可以映射到本地接口并查询这些统计信息。或者,您可以破解内核代码以打印或导出所有需要的内容,前提是您有权使用应用程序运行自定义内核(一个可加载的模块也可能足够了,这取决于您到底想做什么)。
setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 4);