-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmyhook_add_tcp_option.c
226 lines (214 loc) · 11.3 KB
/
myhook_add_tcp_option.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//***************************************************************
// http://blog.csdn.net/zhangskd/article/details/22678659
//
// Hook function to be called.
// We modify the packet and add tcp option in the packet
//***************************************************************
#include <linux/netfilter.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/inet.h>
#include <uapi/linux/tcp.h>
#include <linux/netdevice.h>
static char my_buf[64];
static char option_tm[8] = {0xfd, 0x08, 0x03, 0x48, 0x5a, 0x5a, 0x5a, 0x5a}; //the tcp option that will be appended on tcp header
unsigned int my_hookfn(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *)) //user defined function for adding tcp option
{
struct iphdr *iph ;
struct tcphdr *tcph ;
struct net_device *dev ;
char *name ;
int hdr_len ;
char *d ;
int i ;
iph = ip_hdr(skb);
tcph = (struct tcphdr *) skb_transport_header(skb);
dev = skb->dev;
name = & dev->name;
/* log the original src IP */
//if( iph->daddr==0x0c0310ac && tcph->source==0x5000 ){
//printk(KERN_INFO"debug post-routing dest IP %x\n", iph->daddr);
//if( iph->daddr==0x035b8478 ){
//if( iph->daddr==0x080310ac ){ //local pc
//if( iph->daddr==0x6dd94b77 || iph->daddr==0x080310ac ){ //the condition for modify packet
if( tcph->dest==0x5000 ){
printk(KERN_INFO"debug post-routing dest IP=%x\n", iph->daddr);
printk(KERN_INFO"debug post-routing skb->iphdr=\n" );
d = skb_network_header(skb);
for(i=0; i<60; i++) {
printk("%02x", (*d)&0xff); //debug info for print original packet content
d++;
}
if( tcph->syn==1 ) { //the condition for not modify packet
printk(KERN_INFO"debug syn packet come \n");
return NF_ACCEPT;
}
if( skb_headroom(skb)>=22 ) { //the condition for modify packet
printk(KERN_INFO"debug post-routing len =%x \n", skb->len );
printk(KERN_INFO"debug post-routing data_len =%x \n", skb->data_len );
printk(KERN_INFO"debug post-routing mac_len =%x \n", skb->mac_len );
printk(KERN_INFO"debug post-routing hdr_len =%x \n", skb->hdr_len );
printk(KERN_INFO"debug post-routing head =%x \n", skb->head );
printk(KERN_INFO"debug post-routing data =%x \n", skb->data );
printk(KERN_INFO"debug post-routing tail =%x \n", skb->tail );
printk(KERN_INFO"debug post-routing end =%x \n", skb->end );
printk(KERN_INFO"debug iph ->ihl =%x \n", iph ->ihl );
printk(KERN_INFO"debug iph ->tot_len =%x \n", iph ->tot_len );
printk(KERN_INFO"debug tcph->doff =%x \n", tcph->doff );
printk(KERN_INFO"inner_protocol =%x \n", skb->inner_protocol );
printk(KERN_INFO"inner_transport_header =%x \n", skb->inner_transport_header );
printk(KERN_INFO"inner_network_header =%x \n", skb->inner_network_header );
printk(KERN_INFO"inner_mac_header =%x \n", skb->inner_mac_header );
printk(KERN_INFO"transport_header =%x \n", skb->transport_header );
printk(KERN_INFO"network_header =%x \n", skb->network_header );
printk(KERN_INFO"mac_header =%x \n", skb->mac_header );
if( skb->data[0]==0x45 && iph->protocol==0x06 ) { //ipv4 and tcp packet
hdr_len = (iph->ihl + tcph->doff)*4; //original header length, ip header + tcp header
memcpy(my_buf, skb->data, 64 ); //copy original header to tmp buf; copy 64B to tmp buf; 64B is bigger than hdr_len;
memcpy(my_buf+hdr_len, option_tm, 8); //append new tcp option on original header to generate a new header;
d = my_buf;
for(i=0; i<(hdr_len+8); i++) { //print the new header
printk("%02x", (*d)&0xff);
d++;
}
printk(KERN_INFO"debug step3 \n");
skb_pull( skb, hdr_len ); //remove original header
skb_push( skb, hdr_len+8 ); //add new header
memcpy(skb->data, my_buf, hdr_len+8 ); //copy new header into skb;
printk(KERN_INFO"debug step4 \n");
//update header offset in skb
skb->transport_header = skb->transport_header -8 ;
skb->network_header = skb->network_header -8 ;
//update ip header and checksum
printk(KERN_INFO"debug step5 \n");
iph = ip_hdr(skb); //update iph point to new ip header
iph->tot_len = htons(skb->len);
iph->check = 0; //re-calculate ip checksum
iph->check = ip_fast_csum( iph, iph->ihl);
//update tcp header and checksum
printk(KERN_INFO"debug step6 \n");
tcph = (struct tcphdr *) skb_transport_header(skb); //update tcph point to new tcp header
printk(KERN_INFO"old tcp_checksum=%x \n", tcph->check );
tcph->doff = tcph->doff+2;
tcph->check = 0;
int datalen;
datalen = (skb->len - iph->ihl*4); //tcp segment length
//printk(KERN_INFO"tcp datalen =%x \n", datalen );
//printk(KERN_INFO"saddr =%x \n", iph->saddr );
//printk(KERN_INFO"daddr =%x \n", iph->daddr );
//printk(KERN_INFO"protocol =%x \n", iph->protocol );
//printk(KERN_INFO"tcph = \n" );
//d = tcph;
//for(i=0; i<datalen; i++) {
// printk("%02x", (*d & 0xff) );
// d++;
//}
//printk(KERN_INFO"tcph end \n" );
//
////re-calculate tcp checksum
//tcp checksum = tcp segment checksum and tcp pseudo-header checksum
tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, iph->protocol,
csum_partial((char *)tcph, datalen, 0));
skb->ip_summed = CHECKSUM_UNNECESSARY; //the reason is not clear, but without it, it seems the hardware will re-calcuate the checksum
printk(KERN_INFO"new tcp_checksum =%x \n", tcph->check );
printk(KERN_INFO"debug step7 \n");
printk(KERN_INFO"debug post-routing len =%x \n", skb->len );
printk(KERN_INFO"debug post-routing data_len =%x \n", skb->data_len );
printk(KERN_INFO"debug post-routing mac_len =%x \n", skb->mac_len );
printk(KERN_INFO"debug post-routing hdr_len =%x \n", skb->hdr_len );
printk(KERN_INFO"debug post-routing head =%x \n", skb->head );
printk(KERN_INFO"debug post-routing data =%x \n", skb->data );
printk(KERN_INFO"debug post-routing tail =%x \n", skb->tail );
printk(KERN_INFO"debug post-routing end =%x \n", skb->end );
printk(KERN_INFO"debug iph ->ihl =%x \n", iph ->ihl );
printk(KERN_INFO"debug iph ->tot_len =%x \n", iph ->tot_len );
printk(KERN_INFO"debug tcph->doff =%x \n", tcph->doff );
printk(KERN_INFO"inner_protocol =%x \n", skb->inner_protocol );
printk(KERN_INFO"inner_transport_header =%x \n", skb->inner_transport_header );
printk(KERN_INFO"inner_network_header =%x \n", skb->inner_network_header );
printk(KERN_INFO"inner_mac_header =%x \n", skb->inner_mac_header );
printk(KERN_INFO"transport_header =%x \n", skb->transport_header );
printk(KERN_INFO"network_header =%x \n", skb->network_header );
printk(KERN_INFO"mac_header =%x \n", skb->mac_header );
//d = skb_network_header(skb);
//for(i=0; i<(hdr_len+8); i++) {
// printk("%02x", (*d)&0xff);
// d++;
//}
printk(KERN_INFO"debug step8 \n");
}
//debug info
//printk(KERN_INFO"debug post-routing net_device=%s\n", name );
//printk(KERN_INFO"debug post-routing len=%d \n", skb->len );
//printk(KERN_INFO"debug post-routing head=%x \n", skb->head );
//printk(KERN_INFO"debug post-routing data=%x \n", skb->data );
//printk(KERN_INFO"debug post-routing tail=%x \n", skb->tail );
//printk(KERN_INFO"debug post-routing end=%x \n", skb->end );
//printk(KERN_INFO"debug post-routing data_len=%d \n", skb->data_len);
//printk(KERN_INFO"debug post-routing mac_len=%d \n", skb->mac_len);
//printk(KERN_INFO"debug post-routing hdr_len=%d \n", skb->hdr_len);
//printk(KERN_INFO"debug post-routing src IP %pI4\n", &iph->saddr);
//printk(KERN_INFO"debug post-routing src IP %x\n", iph->saddr);
//printk(KERN_INFO"debug post-routing dest IP %x\n", iph->daddr);
//printk(KERN_INFO"debug post-routing src port %x\n", tcph->source);
//printk(KERN_INFO"debug post-routing dest port %x\n", tcph->dest);
//printk(KERN_INFO"debug post-routing head_room=%x\n", skb_headroom(skb) );
//printk(KERN_INFO"debug post-routing tail_room=%x\n", skb_tailroom(skb) );
//d = skb_network_header(skb);
//printk(KERN_INFO"debug post-routing skb->iphdr=\n" );
//for(i=0; i<20; i++) {
// printk("a=%d,%02x", i, (*d)&0xff);
// d++;
//}
//printk(KERN_INFO"debug post-routing skb->tcphdr=\n" );
//for(i=0; i<20; i++) {
// printk("b=%d,%02x", i, (*d)&0xff);
// d++;
//}
//d = skb->data;
//printk(KERN_INFO"debug post-routing skb->data=\n" );
//for(i=0; i<100; i++) {
// //printk("%02x", (*d)&0xff);
// printk("c=%d,%02x", i, (*d)&0xff);
// d++;
//}
}
else { printk(KERN_INFO"head room is not enough\n" ); }
}
/* modify the packet's src IP */
//iph->saddr = in_aton("8.8.8.8");
return NF_ACCEPT;
}
/* A netfilter instance to use */
static struct nf_hook_ops nfho = {
.hook = my_hookfn,
.pf = PF_INET,
//.hooknum = NF_INET_PRE_ROUTING,
.hooknum = NF_INET_POST_ROUTING, //process packet after routing process
.priority = NF_IP_PRI_FIRST,
.owner = THIS_MODULE,
};
static int __init sknf_init(void)
{
if (nf_register_hook(&nfho)) {
printk(KERN_ERR"nf_register_hook() failed\n");
return -1;
}
return 0;
}
static void __exit sknf_exit(void)
{
nf_unregister_hook(&nfho);
}
module_init(sknf_init);
module_exit(sknf_exit);
MODULE_AUTHOR("liaotianyu");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("add tcp option for output packets");