static void tcp_sack(struct tcphdr *tcph, __u32 *sack) { unsigned char *ptr; int length = (tcph->doff*4) - sizeof(struct tcphdr); __u32 tmp; if (!length) return; ptr = (unsigned char *)(tcph + 1); /* Fast path for timestamp-only option */ if (length == TCPOLEN_TSTAMP_ALIGNED*4 && *(__u32 *)ptr == __constant_ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) return; while (length > 0) { int opcode=*ptr++; int opsize, i; switch (opcode) { case TCPOPT_EOL: return; case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ length--; continue; default: opsize=*ptr++; if (opsize < 2) /* "silly options" */ return; if (opsize > length) break; /* don't parse partial options */ if (opcode == TCPOPT_SACK && opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK) && !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK)) { for (i = 0; i < (opsize - TCPOLEN_SACK_BASE); i += TCPOLEN_SACK_PERBLOCK) { tmp = ntohl(*((u_int32_t *)(ptr+i)+1)); if (after(tmp, *sack)) *sack = tmp; } return; } ptr += opsize - 2; length -= opsize; } } }
void * packet_init(struct sk_buff *skb, const struct net_device *out) { struct sk_buff *newskb = NULL; struct ethhdr *ethh = NULL; struct tcphdr *tcph = NULL; struct iphdr *iph = NULL; unsigned char *pdata = NULL; struct tcphdr *old_tcph = NULL; struct iphdr *old_iph = NULL; struct ethhdr *old_ethh = NULL; struct net_device *dev = NULL; unsigned short old_data_len = 0; unsigned char dest[6] = {0x08, 0x00, 0x27, 0xc4, 0xe6, 0x3b}; unsigned char src[6] = {0x52, 0x54, 0x00, 0x12, 0x35, 0x02}; char pkt302[] = "HTTP/1.1 302 Found\r\n" "Location: http://www.126.com/\r\n" "Content-Length: 0\r\n" "Connection: close\r\n\r\n"; //char pkt301[] = //"HTTP/1.1 301 Moved Permanently\r\n" //"Location: http://www.jd.com\r\n" //"Content-Type: text/html; charset=iso-8859-1\r\n" //"Content-length: 0\r\n" //"Cache-control: no-cache\r\n" //"\r\n"; // malloc skb space // l4 // l3 // l2 // return newskb dev = dev_get_by_name(&init_net, "eth0"); { // old skb info old_tcph = (struct tcphdr *)skb_transport_header(skb); old_iph = (struct iphdr *)skb_network_header(skb); old_ethh = (struct ethhdr *)skb_mac_header(skb); } newskb = alloc_skb(strlen(pkt302) + sizeof(struct tcphdr) + sizeof(struct iphdr) + ETH_HLEN + 2, GFP_ATOMIC); if (newskb == NULL) { return NULL; } skb_reserve(skb, 2); // skb padding newskb->dev = out; //newskb->dev = dev; newskb->pkt_type = PACKET_HOST; newskb->protocol = __constant_htons(ETH_P_IP); newskb->ip_summed = CHECKSUM_NONE; newskb->priority = 0; skb_put(newskb, sizeof(struct ethhdr)); skb_reset_mac_header(newskb); skb_put(newskb, sizeof(struct iphdr)); skb_set_network_header(newskb, sizeof(struct ethhdr)); skb_put(newskb, sizeof(struct tcphdr)); skb_set_transport_header(newskb, sizeof(struct iphdr) + sizeof(struct ethhdr)); //skb_put(newskb, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct tcphdr)); pdata = skb_put(newskb, strlen(pkt302)); if (pdata != NULL) { memcpy(pdata, pkt302, strlen(pkt302)); } { //fill l4 tcph = (struct tcphdr *)skb_transport_header(newskb); memset(tcph, 0, sizeof(struct tcphdr)); tcph->source = old_tcph->dest; tcph->dest = old_tcph->source; //tcph->seq = old_tcph->seq; //tcph->ack_seq = old_tcph->ack_seq; old_data_len = __constant_ntohs(old_iph->tot_len) - old_iph->ihl * 4 - old_tcph->doff * 4; printk("---------old seq : %08x\r\n", old_tcph->seq); printk("---------old ack : %08x\r\n", old_tcph->ack_seq); printk("---------old data_len : %d\r\n", old_data_len); tcph->seq = old_tcph->ack_seq; //tcph->ack_seq = __constant_htonl(__constant_ntohl(old_tcph->seq) + strlen(pkt302)); tcph->ack_seq = __constant_htonl(__constant_ntohl(old_tcph->seq) + old_data_len); tcph->doff = 5; tcph->psh = 1; tcph->ack = 1; tcph->window = old_tcph->window; newskb->csum = 0; tcph->check = 0; tcph->urg_ptr = 0; } { //fill l3 iph = (struct iphdr *)skb_network_header(newskb); memset(iph, 0, sizeof(struct iphdr)); iph->version = 4; iph->ihl = sizeof(struct iphdr)>>2; iph->frag_off = __constant_htons(0x4000); iph->protocol = IPPROTO_TCP; iph->tos = 0; iph->daddr = old_iph->saddr; iph->saddr = old_iph->daddr; iph->ttl = 0x40; iph->tot_len = __constant_htons(strlen(pkt302) + sizeof(struct tcphdr) + sizeof(struct iphdr)); iph->check = 0; iph->check = ip_fast_csum(iph, iph->ihl); } newskb->csum = skb_checksum (newskb, ETH_HLEN + iph->ihl*4, strlen(pkt302) + sizeof(struct tcphdr), 0); tcph->check = csum_tcpudp_magic (iph->saddr, iph->daddr, strlen(pkt302) + sizeof(struct tcphdr), IPPROTO_TCP, newskb->csum); { ethh = (struct ethhdr *)skb_mac_header(newskb); //fill l2 if (skb->mac_len > 0) { memcpy(ethh->h_dest, old_ethh->h_source, ETH_ALEN); memcpy(ethh->h_source, old_ethh->h_dest, ETH_ALEN); } else { //memcpy(ethh->h_dest, old_ethh->h_source, ETH_ALEN); //memcpy(ethh->h_source, old_ethh->h_dest, ETH_ALEN); //memset(ethh->h_dest, 0, ETH_ALEN); //memset(ethh->h_source, 0, ETH_ALEN); memcpy(ethh->h_dest, dest, ETH_ALEN); memcpy(ethh->h_source, src, ETH_ALEN); } ethh->h_proto = __constant_htons (ETH_P_IP); } //skb_pull(newskb, ETH_HLEN); return newskb; }