#include /* standard kernel header */ /* standard module headers */ #include #include /* for networking structures */ #include #include #include #include #include #include /* for jiffies */ #include /* for ntoh(l/s) */ #include #define IS_IP_PACKET(skb) (skb->data[12] == 8 && skb->data[13] == 0) #define IS_TCP_PACKET(skb) (skb->data[23] == 6) #define TCP_HDR_OFFSET(skb) (14+4*(skb->data[14] & 0xf)) #define GET_BIT(bitfield,bit) ((bitfield[bit/8] >> (bit%8)) & 0x01) #define KEY "" #define KEY_LENGHT 0 #define MESSAGE "Devcc Test Message 123456789" /* A bunch of functions for beating elements out of an skb */ static inline u32 get_32_bit_field(struct sk_buff *skb, int offset) { return ((skb->data[offset]<<24) | (skb->data[offset+1]<<16) | (skb->data[offset+2]<<8) | skb->data[offset+3]); } static inline u32 get_32_bit_tcphdr(struct sk_buff *skb, int offset) { return get_32_bit_field(skb,offset + TCP_HDR_OFFSET(skb)); } static inline int has_tcp_timestamp(struct sk_buff *skb) { return (skb->data[TCP_HDR_OFFSET(skb)+12]>>4 == 8 && skb->data[TCP_HDR_OFFSET(skb)+20] == 1 && skb->data[TCP_HDR_OFFSET(skb)+21] == 1 && skb->data[TCP_HDR_OFFSET(skb)+22] == 8 && skb->data[TCP_HDR_OFFSET(skb)+23] == 10); } static inline u32 get_tcp_timestamp(struct sk_buff *skb) { return get_32_bit_tcphdr(skb,24); } static inline u32 get_tcp_tsreply(struct sk_buff *skb) { return get_32_bit_tcphdr(skb,28); } /* A funtion for incrementing timestamp (and fixing the checksum) */ static inline void inc_tcp_timestamp(struct sk_buff *skb) { if (++(skb->data[TCP_HDR_OFFSET(skb)+27]) == 0) if (++(skb->data[TCP_HDR_OFFSET(skb)+26]) == 0) if (++(skb->data[TCP_HDR_OFFSET(skb)+25]) == 0) (skb->data[TCP_HDR_OFFSET(skb)+27])++; if (skb->data[TCP_HDR_OFFSET(skb)+17]-- == 0) if (skb->data[TCP_HDR_OFFSET(skb)+16]-- ==0) { skb->data[TCP_HDR_OFFSET(skb)+17] = 0; skb->data[TCP_HDR_OFFSET(skb)+16] = 0; } } /* This is where the old start_hard_xmit function pointer gets stored */ static int (*tmp) (struct sk_buff *skb, struct net_device *dev) = NULL; /* our message */ static char message[32]; /* the host to send to; 0 means send to everyone */ static u32 target_host = 0; static ssize_t my_write (struct file *file, const char *buf, size_t count, loff_t *ppos) { size_t n = *ppos+count > 28 ? 28-*ppos : count; copy_from_user(message, buf, n); devcc_append_checksum(message); *ppos += n; return n; } static int my_ioctl(struct inode *inode, struct file *fipl, unsigned int cmd, unsigned long arg) { target_host = (u32) arg; return 0; } static ssize_t my_read (struct file *file, char *buf, size_t count, loff_t *ppos) { size_t n = *ppos+count > 28 ? 28-*ppos : count; copy_to_user(buf, message, n); *ppos += n; return n; } struct file_operations my_proc_operations = { read: my_read, ioctl: my_ioctl, write: my_write }; /* This is the clever bit. In this function we examine the packet and hash the headers to generate an index and key bit. Then we determing how much we should add to the timestamp to encode our data. */ static int get_ts_increment(u32 ts, u32 tsreply, struct tcphdr *hdr) { int index; int key_bit, pt_bit, ct_bit; int retval; retval = 0; index = get_index(ntohs(hdr->source), ntohs(hdr->dest), ntohl(hdr->seq), KEY, KEY_LENGHT); key_bit = get_key_bit(ntohs(hdr->source), ntohs(hdr->dest), ntohl(hdr->seq), ntohl(hdr->ack_seq), ntohs(hdr->window), 0,/* We can't use the checksum because it changes with the timestamp */ ts & 0xfffffffe, tsreply, KEY, KEY_LENGHT); pt_bit = GET_BIT(message,index); ct_bit = pt_bit ^ key_bit; printk(KERN_DEBUG "Key bit: %d\n",key_bit); printk(KERN_DEBUG "Plaintext bit: %d\n",pt_bit); printk(KERN_DEBUG "Ciphertext bit: %d\n",ct_bit); printk(KERN_DEBUG "Index: %d\n",index); if (ct_bit != (ts & 0x01)) { ts++; if ((ts & 0x01) == 0) { return get_ts_increment(ts,tsreply,hdr)+1; } retval = 1; } return retval; } /* Here's out new hard_start_xmit function. It basically checks to see if the packet is a tcp packet with a timestamp, and, if so, it calculates what the timestamp should be raised, raises it and waits that long */ static int my_hard_start_xmit (struct sk_buff *skb, struct net_device *dev) { int incr; struct tcphdr *my_header; if (IS_IP_PACKET(skb) && IS_TCP_PACKET(skb) && has_tcp_timestamp(skb)) { /* Make sure the timestamp isn't in the past */ while (get_tcp_timestamp(skb) < jiffies) inc_tcp_timestamp(skb); /* target a specific host */ if (target_host == 0 || ntohl(*((u32 *)(skb->data+14+16))) == target_host) { printk(KERN_DEBUG "Timestamp: %u\n",get_tcp_timestamp(skb)); /* This looks sketchy but the rest of the kernel does it too, so we're probably okay. */ my_header = (struct tcphdr *) ((skb->data)+TCP_HDR_OFFSET(skb)); incr = get_ts_increment(get_tcp_timestamp(skb), get_tcp_tsreply(skb), my_header); while (incr > 0) { unsigned long j = jiffies + 1; while (j > jiffies); inc_tcp_timestamp(skb); incr--; } printk(KERN_DEBUG "New timestamp: %u\n",get_tcp_timestamp(skb)); } } /* call the real function so the packet actually get sent */ return tmp(skb, dev); } /* compute the checksum for the message block */ static void init_message() { int i; char *m = MESSAGE; for (i=0;i<28;i++) message[i] = m[i]; devcc_append_checksum(message); } /* Init swaps our wrapper function for the real function */ int my_init(void) { struct net_device *d; struct proc_dir_entry *entry; init_message(); entry = create_proc_entry("cc",0,NULL); if (!entry) return -1; entry->proc_fops = &my_proc_operations; d = dev_base; /* FIXME: should look for a specified device and not assume we want the second one. */ d = d->next; tmp = d->hard_start_xmit; d->hard_start_xmit = &my_hard_start_xmit; return 0; } /* Cleanup puts the real function back. */ void my_cleanup(void) { struct net_device *d; d = dev_base; d = d->next; d->hard_start_xmit = tmp; remove_proc_entry("cc",NULL); } module_init(my_init); module_exit(my_cleanup);