android2009 |
05-13-2014 08:27 PM |
[Need help] Remote server doesn't respond to modified SYNC TCP packet
I am trying to modify IP destination address for all outgoing packets. Currently trying this on VirtualBox Ubuntu guest (kernel version 3.8.0) on Windows 7.
In my program below I built a hash table to map fake ip addresses to real ip addresses (google, ncsu etc.), for example, 100.100.100.100 maps to google, 100.100.100.101 maps to something else.
From wireshark I can see the TCP SYNC packets were successfully modified and sent to google when I put 'http://100.100.100.100' in a web browser, also checksums of TCP and IP packets are correct calculated. However there is no [SYNC, ACK] packets coming back from google, neither does any error message. I also tried other servers they also don't respond.
Does anyone have idea what might be wrong here ? Any suggestion is well appreciated.
Code:
/* postRoute hook */
unsigned int out_hook(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)) {
struct sk_buff *sock_buff;
struct iphdr *ip_header;
struct udphdr *udp_header;
struct tcphdr *tcp_header;
unsigned int udp_len;
unsigned int tcp_len;
printk(KERN_INFO "out_hook: entering function\n");
if (!skb) {
printk(KERN_INFO "out_hook: skb is NULL\n");
return NF_ACCEPT;
}
if (!(skb->network_header)) {
printk(KERN_INFO "out_hook: Error in networkheader\n");
return NF_ACCEPT;
}
sock_buff = skb;
printk(KERN_INFO "out_hook: Getting ip_header\n");
/* Retrieve ip header */
ip_header = ip_hdr(sock_buff);
char source[16];
snprintf(source, 16, "%pI4", &ip_header->daddr);
printk(KERN_INFO "out_hook: ip address is %s\n", source);
/* Handle udp protocol, only forward packets based on hashtable */
if (ip_header->protocol == IPPROTO_UDP) {
printk(KERN_INFO "out_hook: Handling udp packet\n");
udp_header = udp_hdr(sock_buff);
udp_len = sock_buff->len - (ip_header->ihl << 2);
printk(KERN_INFO "out_hook: old outgoing daddr %u\n", ip_header->daddr);
unsigned int ret = search_fake_to_real_ip_table(ip_header->daddr);
/* Check if ip_header->daddr is a fake address or not, if so, replace it with real address from hashtable */
if (ret!=0)
{
char source[16];
char dest[16];
snprintf(source, 16, "%pI4", &ip_header->daddr);
snprintf(dest, 16, "%pI4", &ret);
printk(KERN_INFO "%s is mapping to %s\n", source,dest);
/* Update hashtable for incoming packets */
insert_real_to_fake_ip_table(ret, ip_header->daddr);
/* Replace fake address with real address */
ip_header->daddr = ret;
printk(KERN_INFO "out_hook: new outgoing daddr %u\n", ip_header->daddr);
/* If UDP checksum is enabled, need to re-calculate */
if (udp_header->check) {
printk(KERN_INFO "out_hook: old udp checksum %u\n", udp_header->check);
udp_header->check = csum_tcpudp_magic(ip_header->saddr, ip_header->daddr, udp_len, IPPROTO_UDP, csum_partial(udp_header, udp_len, 0));
printk(KERN_INFO "out_hook: new udp checksum %u\n", udp_header->check);
}
/* Recaculate IP checksum */
printk(KERN_INFO "out_hook: recalculating ip checksum %u\n", ip_header->check);
ip_header->check = 0x000;
ip_header->check = ip_fast_csum((unsigned char *)ip_header, ip_header->ihl);
printk(KERN_INFO "out_hook: recalculated ip checksum %u\n", ip_header->check);
return NF_ACCEPT;
}
return NF_ACCEPT;
}
/* Handle tcp protocol */
else if (ip_header->protocol == IPPROTO_TCP) {
printk(KERN_INFO "outhook: Handling tcp packet\n");
tcp_header = tcp_hdr(sock_buff); //tcp_header = (struct tcphdr *)((unsigned long int *)ip_header + ip_header->ihl);
tcp_len = sock_buff->len - (ip_header->ihl << 2);
unsigned int ret = search_fake_to_real_ip_table(ip_header->daddr);
if (ret!=0)
{
char source[16];
char dest[16];
snprintf(source, 16, "%pI4", &ip_header->daddr);
snprintf(dest, 16, "%pI4", &ret);
printk(KERN_INFO "%s is mapping to %s\n", source,dest);
/* Update hashtable for incoming packets */
insert_real_to_fake_ip_table(ret, ip_header->daddr);
/* Replace fake address with real address */
ip_header->daddr = ret;
printk(KERN_INFO "out_hook: new outgoing daddr %u\n", ip_header->daddr);
/* New tcp checksum */
if (tcp_header->check) {
tcp_header->check = 0;
tcp_header->check = csum_tcpudp_magic(ip_header->saddr, ip_header->daddr, tcp_len, IPPROTO_TCP, csum_partial((char *)tcp_header, tcp_len, 0));
}
printk(KERN_INFO "Recalculating tcp/ip checksum");
/* New ip checksum */
ip_header->check = 0x000;
ip_header->check = ip_fast_csum((unsigned char *)ip_header, ip_header->ihl);
return NF_ACCEPT;
}
return NF_ACCEPT;
}
/* Let go all other non-udp/tcp packets */
else {
return NF_ACCEPT;
}
}
|