//Hook function for outgoing packets static unsigned int hook_func_out(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct iphdr *ip_header=NULL; //IP header structure struct tcphdr *tcp_header=NULL; //TCP header structure unsigned short int src_port; //TCP source port ip_header=(struct iphdr *)skb_network_header(skb); //The packet is not ip packet (e.g. ARP or others) if (!ip_header) { return NF_ACCEPT; } if(ip_header->protocol==IPPROTO_TCP) //TCP { tcp_header = (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); src_port=htons((unsigned short int) tcp_header->source); if(src_port==5001) { tcp_modify_timestamp(skb,get_tsval()); } } return NF_ACCEPT; }
//Modify incoming TCP packets and return RTT sample value u32 tcp_modify_incoming(struct sk_buff *skb, u32 time) { struct iphdr *ip_header=NULL; //IP header structure struct tcphdr *tcp_header=NULL; //TCP header structure unsigned short tcp_header_len=0; //TCP header length u8 *tcp_opt=NULL; //TCP option pointer u32 *tsecr=NULL; //TCP Timestamp echo reply pointer unsigned short tcplen=0; //TCP packet length u8 tcp_opt_value=0; //TCP option pointer value u32 rtt=0; //Sample RTT //If we can not modify this packet, return 0 if(skb_linearize(skb)!=0) { return 0; } //Get IP header ip_header=(struct iphdr *)skb_network_header(skb); //Get TCP header on the base of IP header tcp_header=(struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); //Get TCP header length tcp_header_len=(unsigned short)(tcp_header->doff*4); //Minimum TCP header length=20(Raw TCP header)+10(TCP Timestamp option) if(tcp_header_len<30) { return 0; } //TCP option offset=IP header pointer+IP header length+TCP header length tcp_opt=(u8*)ip_header+ip_header->ihl*4+20; //printk(KERN_INFO "TCP header length is %hu\n",tcp_header_len); while(1) { //If pointer has moved out off the range of TCP option, stop current loop if(tcp_opt-(u8*)tcp_header>=tcp_header_len) { break; } //Get value of current byte tcp_opt_value=*tcp_opt; if(tcp_opt_value==0x01)//No-Operation (NOP) { //Move to next byte tcp_opt++; } else if(tcp_opt_value==0x08) //TCP option kind: Timestamp (8) { //Get pointer to Timestamp echo reply (TSecr) tsecr=(u32*)(tcp_opt+6); //Get one RTT sample rtt=get_tsval()-ntohl(*tsecr); //printk(KERN_INFO "Echo back value: %u\n",ntohl(*tsecr)); //Modify TCP TSecr back to jiffies //Don't disturb TCP. Wrong TCP timestamp echo reply may reset TCP connections *tsecr=htonl(time); break; } else //Other TCP options (e.g. MSS(2)) { //Move to next byte to get length of this TCP option tcp_opt++; //Get length of this TCP option tcp_opt_value=*tcp_opt; //Move to next TCP option tcp_opt=tcp_opt+1+((unsigned int)tcp_opt_value-2); } } //TCP length=Total length - IP header length //tcplen=(ip_header->tot_len)-(ip_header->ihl<<2); tcplen=skb->len-(ip_header->ihl<<2); tcp_header->check=0; tcp_header->check = csum_tcpudp_magic(ip_header->saddr, ip_header->daddr,tcplen, ip_header->protocol,csum_partial((char *)tcp_header, tcplen, 0)); skb->ip_summed = CHECKSUM_UNNECESSARY; return rtt; }