How to recover a TCP stream from multiple IP packets?

I am working on a TUN-based VPN server, the purpose of which is to analyze the packets it receives before redirecting them to their destination. I am currently receiving IP packets from the TUN interface and just sending them to the destination unchanged.

I understand that analyzing the contents of UDP packets will be as simple as deleting IP and UDP headers. However, to analyze the contents of TCP traffic, I will need to recover the message from several IP packets. Is there an easy way to do this without re-implementing TCP? Are there easily accessible C / C ++ libraries designed for this task? I would prefer Linux system libraries and / or open source libraries, non-virus / non-copyleft.

One thing that I have already considered is to make a copy of each IP packet and change the recipient's IP address to a local host so that the other part of my server can receive these TCP requests and responses, completely reconstructed and without headers. However, I would not be able to associate the destination IP addresses with the traffic content that I want.

+7
c ++ networking sockets tcp vpn
source share
2 answers

You will probably need functionality that will always be closely related to package dissection. Good protocol dissectors are really necessary to extract the necessary information. So my suggestion is to use the best open source tool available - wireshark.org

It provides the functionality of "Follow TCP stream":

enter image description here

It doesn't seem like you can easily extract some of the Wireshark dissection logic, but at least there is a good example of 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 */ 

Basically, there is a separate logic for extracting logic; pay attention to 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; } 

Actual logic is well documented and available 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))) { 

So I actually suggest using the EPAN library . You can extract this library and use it yourself. Be careful with the license.

+5
source share

You might be interested in libipq , the iptables user queue package library.

 #include <linux/netfilter.h> #include <libipq.h> 

Netfilter provides a mechanism for transferring packets from the stack for a queue to user space, then receiving these packets back to the kernel with a verdict that determines what to do with the packets (for example, ACCEPT OR SURE). These packages can also be modified to be reinstalled back into the kernel. For each supported protocol, a kernel module, called a queue handler, can register with Netfilter before performing mechanics of sending packets to and from user space.

The standard queue handler for IPv4 is ip_queue. It is provided as an experimental module with 2.4 kernels and uses a Netlink socket for kernel / user space.

After loading ip_queue, IP packets can be selected using iptables and queued for processing user space using the QUEUE target

Here is a brief example of how to decompose the tcp / ip package:

 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); 

fast intro

If this is not what you are looking for, you can try using the wirehark EPAN library .

+1
source share

All Articles