void divert_frame(struct sk_buff *skb) { struct ethhdr *eth = eth_hdr(skb); struct iphdr *iph; struct tcphdr *tcph; struct udphdr *udph; struct divert_blk *divert = skb->dev->divert; int i, src, dst; unsigned char *skb_data_end = skb->data + skb->len; /* Packet is already aimed at us, return */ if (!memcmp(eth, skb->dev->dev_addr, ETH_ALEN)) return; /* proto is not IP, do nothing */ if (eth->h_proto != htons(ETH_P_IP)) return; /* Divert all IP frames ? */ if (divert->protos & DIVERT_PROTO_IP) { ETH_DIVERT_FRAME(skb); return; } /* Check for possible (maliciously) malformed IP frame (thanks Dave) */ iph = (struct iphdr *) skb->data; if (((iph->ihl<<2)+(unsigned char*)(iph)) >= skb_data_end) { printk(KERN_INFO "divert: malformed IP packet !\n"); return; } switch (iph->protocol) { /* Divert all ICMP frames ? */ case IPPROTO_ICMP: if (divert->protos & DIVERT_PROTO_ICMP) { ETH_DIVERT_FRAME(skb); return; } break; /* Divert all TCP frames ? */ case IPPROTO_TCP: if (divert->protos & DIVERT_PROTO_TCP) { ETH_DIVERT_FRAME(skb); return; } /* Check for possible (maliciously) malformed IP * frame (thanx Dave) */ tcph = (struct tcphdr *) (((unsigned char *)iph) + (iph->ihl<<2)); if (((unsigned char *)(tcph+1)) >= skb_data_end) { printk(KERN_INFO "divert: malformed TCP packet !\n"); return; } /* Divert some tcp dst/src ports only ?*/ for (i = 0; i < MAX_DIVERT_PORTS; i++) { dst = divert->tcp_dst[i]; src = divert->tcp_src[i]; if ((dst && dst == tcph->dest) || (src && src == tcph->source)) { ETH_DIVERT_FRAME(skb); return; } } break; /* Divert all UDP frames ? */ case IPPROTO_UDP: if (divert->protos & DIVERT_PROTO_UDP) { ETH_DIVERT_FRAME(skb); return; } /* Check for possible (maliciously) malformed IP * packet (thanks Dave) */ udph = (struct udphdr *) (((unsigned char *)iph) + (iph->ihl<<2)); if (((unsigned char *)(udph+1)) >= skb_data_end) { printk(KERN_INFO "divert: malformed UDP packet !\n"); return; } /* Divert some udp dst/src ports only ? */ for (i = 0; i < MAX_DIVERT_PORTS; i++) { dst = divert->udp_dst[i]; src = divert->udp_src[i]; if ((dst && dst == udph->dest) || (src && src == udph->source)) { ETH_DIVERT_FRAME(skb); return; } } break; } }