我正在开发一个基于TUN的VPN服务器,其目的是在将数据包转发到目的地之前分析它收到的数据包。目前,我正在从TUN接口接收IP数据包,只是将它们发送到目的地未经修改。
据我所知,分析UDP数据包的内容就像剥离IP和UDP标头一样简单。但是,为了分析TCP流量的内容,我需要从多个IP数据包重建消息。有没有重新实现TCP的简单方法呢?是否有任何易于访问的C / C ++库用于此任务?我更喜欢Linux系统库和/或开源,非病毒/非copyleft库。
我已经考虑过的一件事是制作每个IP数据包的副本,并将副本的目标IP更改为localhost,以便我的服务器的不同部分可以接收这些TCP请求和响应完全重建且没有标头。但是,我无法将目标IP与流量内容相关联,这是我想要的。
答案 0 :(得分:6)
您需要的功能可能始终与数据包解析紧密结合。确实需要良好的协议解析器来提取所需信息。所以我的建议是使用最好的开源工具 - wireshark.org
它提供"关注TCP流"功能性:
我看起来你不能轻易提取部分Wireshark解剖逻辑,但至少有一个很好的例子packet-tcp:
typedef struct _tcp_flow_t {
guint32 base_seq; /* base seq number (used by relative sequence numbers)
* or 0 if not yet known.
*/
tcp_unacked_t *segments;
guint32 fin; /* frame number of the final FIN */
guint32 lastack; /* last seen ack */
nstime_t lastacktime; /* Time of the last ack packet */
guint32 lastnondupack; /* frame number of last seen non dupack */
guint32 dupacknum; /* dupack number */
guint32 nextseq; /* highest seen nextseq */
guint32 maxseqtobeacked;/* highest seen continuous seq number (without hole in the stream) from the fwd party,
* this is the maximum seq number that can be acked by the rev party in normal case.
* If the rev party sends an ACK beyond this seq number it indicates TCP_A_ACK_LOST_PACKET contition */
guint32 nextseqframe; /* frame number for segment with highest
* sequence number
*/
基本上,有单独的会话提取逻辑,请注意find_conversation
usage:
/* Attach process info to a flow */
/* XXX - We depend on the TCP dissector finding the conversation first */
void
add_tcp_process_info(guint32 frame_num, address *local_addr, address *remote_addr, guint16 local_port, guint16 remote_port, guint32 uid, guint32 pid, gchar *username, gchar *command) {
conversation_t *conv;
struct tcp_analysis *tcpd;
tcp_flow_t *flow = NULL;
conv = find_conversation(frame_num, local_addr, remote_addr, PT_TCP, local_port, remote_port, 0);
if (!conv) {
return;
}
实际逻辑已有详细记录,可用here:
/*
* Given two address/port pairs for a packet, search for a conversation
* containing packets between those address/port pairs. Returns NULL if
* not found.
*
* We try to find the most exact match that we can, and then proceed to
* try wildcard matches on the "addr_b" and/or "port_b" argument if a more
* exact match failed.
* ...
*/
conversation_t *
find_conversation(const guint32 frame_num, const address *addr_a, const address *addr_b, const port_type ptype,
const guint32 port_a, const guint32 port_b, const guint options)
{
conversation_t *conversation;
/*
* First try an exact match, if we have two addresses and ports.
*/
if (!(options & (NO_ADDR_B|NO_PORT_B))) {
所以我实际建议的是使用EPAN library。可以提取此库并单独使用它。请注意许可证。
答案 1 :(得分:1)
也许您可能对libipq - iptables用户空间数据包排队库感兴趣。
#include <linux/netfilter.h>
#include <libipq.h>
Netfilter提供了一种将数据包传递出堆栈的机制 排队到用户空间,然后将这些数据包接收回来 带有判定的内核,用于指定如何处理数据包(例如 接受或删除)。也可以在用户空间之前修改这些分组 重新注入内核。对于每个支持的协议,a 称为队列处理程序的内核模块可以向Netfilter注册 执行将数据包传入和传出用户空间的机制。
IPv4的标准队列处理程序是ip_queue。它是作为一个提供的 带有2.4内核的实验模块,并使用Netlink套接字 内核/用户空间通信。
加载ip_queue后,可以使用iptables和选择IP数据包 通过QUEUE目标排队等待用户空间处理
这里是如何分解tcp / ip数据包的简要示例:
ipq_packet_msg_t *m = ipq_get_packet(buf);
struct iphdr *ip = (struct iphdr*) m->payload;
struct tcphdr *tcp = (struct tcphdr*) (m->payload + (4 * ip->ihl));
int port = htons(tcp->dest);
status = ipq_set_verdict(h, m->packet_id,
NF_ACCEPT, 0, NULL);
if (status < 0)
die(h);
快速intro
如果这不是您要找的内容,您可以尝试使用wireshark EPAN library。