I'm writing a few C line of code using libnet and pcap.
The purpose is to do a 3-way handshake manually sniffing filtered traffic on my NIC, looking for SYN packet and creating a SYN-ACK response using raw ipv4 socket.
I succesfully receive raw SYN packet using pcap_loop()
.
In my custom packet_handler()
I do the following:
void packet_handler(u_char *user_args, const struct pcap_pkthdr *cap_header, const u_char *packet) {
struct libnet_ipv4_hdr *ip = (struct libnet_ipv4_hdr *)(packet + LIBNET_ETH_H);
struct libnet_tcp_hdr *tcp = (struct libnet_tcp_hdr *)(ip + (ip->ip_hl << 2));
printf(
"%s:%"PRIu16" > %s:%"PRIu16"\t[seq: %"PRIu32"\tack: %"PRIu32"]\n",
libnet_addr2name4(ip->ip_src.s_addr, LIBNET_DONT_RESOLVE),
ntohs(tcp->th_sport),
libnet_addr2name4(ip->ip_dst.s_addr, LIBNET_DONT_RESOLVE),
ntohs(tcp->th_dport),
ntohl(tcp->th_seq), ntohl(tcp->th_ack)
);
}
As results of opening a TCP connection I got the following result:
192.168.1.64:0 > 192.168.1.64:0 [seq: 0 ack: 0]
As you can see the IP header is correctly read, but the TCP header is not.
In particular, the problem is the libnet_tcp_hdr
header fields which result to be all zero.
Am I doing something wrong in the pointer assignment?
Firstly, you need to verify that your packet handler only receives IP packets carrying TCP, not e.g. UDP.
However, your pointer arithmetic is wrong. Pointer aritmetic is done based on the type of the pointer, it is not based on bytes. This means this code:
struct libnet_tcp_hdr *tcp = (struct libnet_tcp_hdr *)(ip + (ip->ip_hl << 2));
adds ip->ip_hl << 2 * sizeof(struct struct libnet_ipv4_hdr
bytes to your ip
pointer.
Or if you look at it another way, the above code is exactly the same as:
struct libnet_tcp_hdr *tcp = (struct libnet_tcp_hdr *)(&ip[ip->ip_hl << 2]);
That might show more clearly what is going on.
You need to change that code to something like:
struct libnet_tcp_hdr *tcp = (struct libnet_tcp_hdr *)((unsigned char*)ip + (ip->ip_hl << 2));