mirror of
https://github.com/CHN-beta/xmurp-ua.git
synced 2026-01-11 01:09:25 +08:00
框架写好了
This commit is contained in:
16
README.md
16
README.md
@@ -64,7 +64,8 @@ sniffing 状态下,收集包直到得到全部的 HTTP 头,修改后发出
|
||||
|
||||
* `0x01` 位:表示这个包是否属于这个流。置为 1 时表示属于。
|
||||
* `0x02` 位:表示这个包是否需要被截留。置为 1 时表示需要。
|
||||
* `0x04` 位:发生了某些错误,上层函数应该向用户发出警告,将所有流中的数据放出,并停止模块的运行。
|
||||
0x04 是否被丢弃
|
||||
* `0x08` 位:发生了某些错误,上层函数应该向用户发出警告,将所有流中的数据放出,并停止模块的运行。
|
||||
|
||||
事实上,可能的返回结果和处理方法:
|
||||
|
||||
@@ -78,13 +79,22 @@ sniffing 状态下,收集包直到得到全部的 HTTP 头,修改后发出
|
||||
|
||||
* `0x1`:包是客户端的请求。除非设置这个位,其它位都没有意义。
|
||||
* `0x2`:包是携带了应用层数据。除非设置这个位,否则之后的都没有意义。
|
||||
* `0x4`:包是属于未来的。
|
||||
* `0x8`:包是属于过去的。这两个都没设置的话,说明包是现在的。
|
||||
* `0x4`:包是属于过去的。
|
||||
* `0x8`:包是属于未来的。这两个都没设置的话,说明包是现在的。只有这两个都没设置,之后的内容才有意义。
|
||||
* `0x10`:包中出现了 http 头部结尾。只有在流为 sniffing 时可能设置这个。
|
||||
* `0x20`:包有设置 push。
|
||||
`0x40`:包需要使用现有的包来替代。
|
||||
|
||||
* `void rkpStream_execute(struct rkpStream*, struct sk_buff*, u_int32_t)`:执行需要执行的动作。第三个参数传入 `rkpStream_judge` 对于这个包的返回值,它的低八位会被忽略。它要做的事情完全由 `rkpStream_judge` 的返回值来通知。以下数值是指 `rtn & 0xff00 >> 8` 的值。
|
||||
|
||||
收到后马上更新时间
|
||||
如果不是客户端发出,更新sck后返回。
|
||||
如果没有应用层数据,返回
|
||||
如果属于过去,如果需要替代,替代后返回;如果不需要替代,返回。
|
||||
如果是属于未来,截留。
|
||||
如果是waiting,那么更新序列号,如果psh则设置状态,返回。
|
||||
如果是sniffing,那么
|
||||
|
||||
* `0x0`:返回。
|
||||
* `0x1`:更新时间,然后返回。
|
||||
* `0x2`:更新时间、确认序列号,释放 `buff_prev` 中的部分数据包。
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
config xmurp-ua
|
||||
tristate "xmurp-ua"
|
||||
config rkp-ua
|
||||
tristate "rkp-ua"
|
||||
@@ -1 +1 @@
|
||||
obj-${CONFIG_xmurp-ua} += xmurp-ua.o
|
||||
obj-${CONFIG_rkp-ua} += rkp-ua.o
|
||||
64
src/common.h
64
src/common.h
@@ -12,10 +12,16 @@
|
||||
#include <linux/random.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/limits.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
const char* str_ua = "User-Agent: ";
|
||||
const char* str_end = "\r\n\r\n";
|
||||
const char* str_win = "Windows NT";
|
||||
const unsigned char* str_ua = "User-Agent: ";
|
||||
const unsigned char* str_end = "\r\n\r\n";
|
||||
const unsigned char* str_win = "Windows NT";
|
||||
|
||||
u_int8_t mode_advanced = 0;
|
||||
module_param(mode_advanced, bool, 0);
|
||||
u_int8_t mode_winPreserve = 0;
|
||||
module_param(mode_winPreserve, bool, 0);
|
||||
|
||||
u_int32_t mark_capture = 0x100;
|
||||
module_param(mark_capture, uint, 0);
|
||||
@@ -26,3 +32,55 @@ module_param(mark_first, uint, 0);
|
||||
u_int32_t mark_winPreserve = 0x800;
|
||||
module_param(mark_winPreserve, uint, 0);
|
||||
|
||||
u_int8_t rkpSettings_capture(struct sk_buff*);
|
||||
u_int8_t rkpSettings_request(struct sk_buff*);
|
||||
u_int8_t rkpSettings_first(struct sk_buff*);
|
||||
u_int8_t rkpSettings_winPreserve(struct sk_buff*);
|
||||
|
||||
u_int8_t rkpSettings_capture(struct sk_buff* skb)
|
||||
{
|
||||
if(mode_advanced)
|
||||
return skb -> mark & mark_capture == mark_capture;
|
||||
else
|
||||
{
|
||||
if(ip_hdr(skb) -> protocol != IPPROTO_TCP)
|
||||
return 0;
|
||||
else if(tcp_hdr(skb) -> dport == 80)
|
||||
return 1;
|
||||
else if(tcp_hdr(skb) -> sport == 80 && tcp_hdr(skb) -> ack)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u_int8_t rkpSettings_request(struct sk_buff* skb)
|
||||
{
|
||||
if(mode_advanced)
|
||||
return skb -> mark & mark_request == mark_request;
|
||||
else
|
||||
return ip_hdr(skb) -> daddr == 80;
|
||||
}
|
||||
|
||||
u_int8_t rkpSettings_first(struct sk_buff* skb)
|
||||
{
|
||||
if(mode_advanced)
|
||||
return skb -> mark & mark_first == mark_first;
|
||||
else
|
||||
return tcp_hdr(skb) -> syn && !tcp_hdr(skb) -> ack;
|
||||
}
|
||||
|
||||
u_int8_t rkpSettings_winPreserve(struct sk_buff* skb)
|
||||
{
|
||||
if(mode_advanced)
|
||||
return skb -> mark & mark_winPreserve == mark_winPreserve;
|
||||
else
|
||||
return mode_winPreserve;
|
||||
}
|
||||
|
||||
time_t now()
|
||||
{
|
||||
struct timespec* ts;
|
||||
getnstimeofday(ts);
|
||||
return ts -> tv_sec;
|
||||
}
|
||||
|
||||
15
src/rkpManager.h
Normal file
15
src/rkpManager.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "rkpStream.h"
|
||||
|
||||
struct rkpManager
|
||||
{
|
||||
struct rkpStream** data; // 按照首包的两端口之和的低 8 位放置
|
||||
};
|
||||
|
||||
struct rkpManager* rkpManager_new(); // 构造函数
|
||||
void rkpManager_del(struct rkpManager*); // 析构函数
|
||||
|
||||
u_int8_t rkpManager_execute(struct rkpManager*, struct sk_buff*); // 处理一个数据包。返回值:0,出错,1,accept,2,stolen,3,drop
|
||||
void rkpManager_refresh(struct rkpManager*); // 清理过时的流
|
||||
|
||||
struct rkpStream* __rkpManager_find(struct rkpManager*, struct sk_buff*); // 寻找一个数据包属于哪个流
|
||||
void __rkpManager_stream_add(struct rkpManager*, struct sk_buff*); // 增加一个流
|
||||
249
src/rkpStream.h
249
src/rkpStream.h
@@ -9,7 +9,8 @@ struct rkpStream
|
||||
} status;
|
||||
u_int32_t id[3]; // 按顺序存储客户地址、服务地址、客户端口、服务端口,已经转换字节序
|
||||
struct sk_buff *buff, *buff_prev, *buff_next;
|
||||
u_int32_t seq, seq_ack; // 下一个服务端发出的字节的序列号,以及下一个服务端确认收到的字节的序列号
|
||||
u_int32_t seq_ack; // 下一个服务端确认收到的字节的序列号。以后所有的序列号都是以这个为基准的相对序列号。
|
||||
u_int32_t seq; // 下一个期待收到的序列号。
|
||||
time_t last_active;
|
||||
u_int8_t scan_matched;
|
||||
u_int8_t win_preserve;
|
||||
@@ -18,17 +19,35 @@ struct rkpStream
|
||||
|
||||
struct rkpStream* rkpStream_new(struct sk_buff*); // 构造函数,得到的流的状态是捕获这个数据包之前的状态。内存不够时返回 0。
|
||||
void rkpStream_del(struct rkpStream*); // 析构函数
|
||||
u_int32_t rkpStream_judge(struct rkpStream*, struct sk_buff*); // 判断一个数据包是否属于这个流以及如何处理它
|
||||
u_int8_t rkpStream_execute(struct rkpStream*, struct sk_buff*, u_int32_t); // 执行上面判断的结果(如果包属于这个流)
|
||||
void __rkpStream_refresh(struct rkpStream*); // 刷新流的时间戳
|
||||
u_int8_t __rkpStream_belong(struct rkpStream*, struct sk_buff*); // 判断一个数据包是否属于一个流
|
||||
u_int8_t rkpStream_belong(struct rkpStream*, struct sk_buff*); // 判断一个数据包是否属于一个流
|
||||
u_int8_t rkpStream_execute(struct rkpStream*, struct sk_buff*); // 处理一个数据包(假定包属于这个流)
|
||||
|
||||
void __rkpStream_refresh_ack(struct rkpStream*, u_int32_t); // 刷新确认序列号。第二个参数就是即将设定的确认号。会自动重新计算序列号的偏移,以及释放 buff_prev 中的多余数据包
|
||||
|
||||
unsigned char* __rkpStream_skb_appStart(struct sk_buff*); // 返回一个包的应用层数据起始位置
|
||||
u_int16_t __rkpStream_skb_appLen(struct sk_buff*); // 返回一个包的应用层数据长度
|
||||
int32_t __rkpStream_skb_seq(u_int32_t, u_int32_t); // 返回一个序列号的相对序列号。两个参数分别为流的确认号、包的序列号(已经转换字节序)。
|
||||
|
||||
void __rkpStream_skb_send(struct sk_buff*); // 发送一个数据包
|
||||
struct sk_buff* __rkpStream_skb_copy(struct sk_buff*); // 复制一个数据包
|
||||
void __rkpStream_skb_del(struct sk_buff*); // 删除一个数据包
|
||||
|
||||
u_int16_t __rkpStream_data_scan(unsigned char*, u_int16_t, unsigned char*, u_int8_t); // 在指定字符串中扫描子字符串。返回值最低位表示是否完整地找到,其余 15 位表示匹配的长度(如果没有完整地找到)或子串结束时相对于起始时的位置
|
||||
|
||||
void __rkpStream_buff_retain_end(struct sk_buff**, struct sk_buff*); // 将一个数据包置入数据包链的末尾
|
||||
void __rkpStream_buff_retain_auto(struct sk_buff**, struct sk_buff*); // 将一个数据包置入数据包链的合适位置
|
||||
void __rkpStream_buff_rejudge(struct rkpStream*, struct sk_buff**); // 重新判定数据包链中的每个数据包
|
||||
void __rkpStream_buff_del(struct sk_buff**); // 删除数据包链
|
||||
struct sk_buff* __rkpStream_buff_find(struct sk_buff*, u_int32_t);
|
||||
// 在一个已经按照序列号排序的数据包链中寻找序列号相符的包。如果没有相符的包,就返回最后一个序列号比要求的小的包。如果没有这样的包,就返回 0。第二个参数是要查找的序列号(绝对值,已转换字节序)
|
||||
|
||||
void __rkpStream_buff_execute_core(struct sk_buff**, u_int16_t); // 最核心的步骤。集齐头部后,搜索、替换。
|
||||
|
||||
struct rkpStream* rpStream_new(struct sk_buff* skb)
|
||||
{
|
||||
struct rkpStream* rkps = kmalloc(sizeof(struct rkpStream), GFP_KERNEL);
|
||||
struct iphdr* iph = ip_hdr(skb);
|
||||
strcut tcphdr* tcph = tcp_hdr(skb);
|
||||
u_int16_t app_data_len = ntohs(iph -> tot_len) - iph -> ihl * 4 - tcph -> doff * 4;
|
||||
struct tcphdr* tcph = tcp_hdr(skb);
|
||||
|
||||
if(rkps == 0)
|
||||
return rkps;
|
||||
@@ -36,39 +55,207 @@ struct rkpStream* rpStream_new(struct sk_buff* skb)
|
||||
rkps -> id[0] = ntohl(iph -> saddr);
|
||||
rkps -> id[1] = ntohl(iph -> daddr);
|
||||
rkps -> id[2] = (((u_int32_t)ntohs(tcph -> sport)) << 16 ) + ntohs(tcph -> dport);
|
||||
buff = buff_prev = buff_next = 0;
|
||||
seq = seq_ack = ntohl(tcph -> seq);
|
||||
__rkpStream_refresh(rkps);
|
||||
rkps -> buff = rkps -> buff_prev = rkps -> buff_next = 0;
|
||||
rkps -> seq_ack = ntohl(tcph -> seq);
|
||||
rkps -> seq = 1;
|
||||
rkps -> last_active = now();
|
||||
rkps -> scan_matched = 0;
|
||||
rkps -> win_preserve = (skb -> mark & mark_winPreserve != 0);
|
||||
rkps -> win_preserve = rkpSettings_winPreserve(skb);
|
||||
rkps -> next = 0;
|
||||
return rkps;
|
||||
}
|
||||
|
||||
void rkpStream_del(struct rkpStream* rkps)
|
||||
{
|
||||
kfree_skb_list(rkps -> buff);
|
||||
kfree_skb_list(rkps -> buff_prev);
|
||||
kfree_skb_list(rkps -> buff_next);
|
||||
kfree(kkps);
|
||||
__rkpStream_buff_del(&(rkps -> buff));
|
||||
__rkpStream_buff_del(&(rkps -> buff_prev));
|
||||
__rkpStream_buff_del(&(rkps -> buff_next));
|
||||
kfree(rkps);
|
||||
}
|
||||
|
||||
u_int32_t rkpStream_judge(struct rkpStream* rkps, struct sk_buff* skb)
|
||||
u_int8_t rkpStream_belong(struct rkpStream* rkps, struct sk_buff* skb)
|
||||
{
|
||||
u_int32_t rtn = 0;
|
||||
if(!__rkpStream_belong(rkps, skb))
|
||||
return rtn;
|
||||
if(rkpSettings_request(skb))
|
||||
{
|
||||
if(rkps -> id[0] != ntohl(ip_hdr(skb) -> saddr))
|
||||
return 0;
|
||||
if(rkps -> id[1] != ntohl(ip_hdr(skb) -> daddr))
|
||||
return 0;
|
||||
if(rkps -> id[2] != ntohs(tcp_hdr(skb) -> sport) << 16 + ntohs(tcp_hdr(skb) -> dport);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtn &= 0x01;
|
||||
if(!(skb -> mark & mark_request))
|
||||
return rtn;
|
||||
else
|
||||
{
|
||||
rtn &= (0x01 << 8);
|
||||
|
||||
}
|
||||
|
||||
if(rkps -> id[0] != ntohl(ip_hdr(skb) -> daddr))
|
||||
return 0;
|
||||
if(rkps -> id[1] != ntohl(ip_hdr(skb) -> saddr))
|
||||
return 0;
|
||||
if(rkps -> id[2] != ntohs(tcp_hdr(skb) -> dport) << 16 + ntohs(tcp_hdr(skb) -> sport);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
u_int8_t rkpStream_execute(struct rkpStream* rkps, struct sk_buff* skb)
|
||||
// 不要害怕麻烦,咱们把每一种情况都慢慢写一遍。
|
||||
{
|
||||
int32_t seq;
|
||||
|
||||
// 肯定需要更新时间
|
||||
rkps -> last_active = now();
|
||||
|
||||
// 服务端返回确认包的情况,更新一下确认号,返回 sccept。以后的情况,都是客户端发往服务端的了。
|
||||
if(!rkpSettings_request(skb))
|
||||
{
|
||||
int32_t seq = __rkpStream_skb_seq(rkps -> seq_ack, ntohl(tcp_hdr(skb) -> ack_seq));
|
||||
if(seq > 0)
|
||||
char __rkpStream_refresh_ack(rkps, ntohl(tcp_hdr(skb) -> ack_seq));
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
// 不携带应用层数据的情况。直接接受即可。以后的情况,都是含有应用层数据的包了。
|
||||
if(__rkpStream_skb_appLen(skb) == 0)
|
||||
return NF_ACCEPT;
|
||||
|
||||
|
||||
// 检查数据包是否是将来的数据包。如果是的话,需要放到 buff_next 等待处理。
|
||||
seq = __rkpStream_skb_seq(rkps -> seq_ack, ntohl(tcp_hdr(skb) -> seq));
|
||||
if(seq > rkps -> seq)
|
||||
{
|
||||
__rkpStream_buff_retain_auto(rkps -> buff_next, skb);
|
||||
return NF_STOLEN;
|
||||
}
|
||||
|
||||
// 检查数据包是否是已经被确认的数据包。应该不会出现这种情况。出现的话就把它丢掉吧。
|
||||
if(seq < 0)
|
||||
{
|
||||
printk("rkp-ua::rkpStream: Re-transmission of asked package. Drop it.\n");
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
// 检查数据包是否是重传数据包。如果是的话,可能需要修改数据。然后,将它发出。接下来的情况,就一定是刚好是需要的序列号的情况了
|
||||
if(seq < rkps -> seq)
|
||||
{
|
||||
struct sk_buff* skb_prev = __rkpStream_buff_find(rkps -> buff_prev, ntohl(skb -> seq));
|
||||
if(skb_prev != 0 && tcp_hdr(skb_prev) -> seq == tcp_hdr(skb) -> seq)
|
||||
// 存在相符的数据包。将数据拷贝过去。
|
||||
{
|
||||
if(skb_ensure_writable(skb, __rkpStream_skb_appStart(skb) - skb -> data + __rkpStream_skb_appLen(skb)))
|
||||
{
|
||||
printk("rkp-ua::rkpStream::rkpStream_execute: Can not make skb writable, may caused by leasing memory. Drop it.\n");
|
||||
return NF_DROP;
|
||||
}
|
||||
memcpy(__rkpStream_skb_appStart(skb), __rkpStream_skb_appStart(skb_prev), __rkpStream_skb_appLen(skb_prev));
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
// 如果是在 sniffing 的情况下,那一定先扫描一下再说
|
||||
if(rkps -> status == __rkpStream_sniffing)
|
||||
{
|
||||
u_int16_t scan = __rkpStream_data_scan(__rkpStream_skb_appStart(skb), __rkpStream_skb_appLen(skb),
|
||||
str_end, rkps -> scan_matched);
|
||||
|
||||
if(scan & 0x1)
|
||||
// 扫描找到了 HTTP 头的结尾,那么将这个数据包补到 buff 中,更新 seq,开始查找、替换、发出,然后根据情况设置状态,再考虑 buff_next 中的包,最后返回 STOLEN
|
||||
{
|
||||
struct sk_buff* skbp = rkps -> buff;
|
||||
|
||||
// 追加到 buff 后面
|
||||
__rkpStream_buff_retain_end(&(rkps -> buff), skb);
|
||||
rkps -> seq = __rkpStream_skb_seq(rkps -> ack_seq, ntohl(tcp_hdr(skb) -> seq)) + __rkpStream_skb_appLen(skb);
|
||||
|
||||
// 查找、替换
|
||||
__rkpStream_buff_execute_core(&(rkps -> buff), scan >> 1);
|
||||
|
||||
// 循环复制一份到 buff_prev 下面,同时发出
|
||||
while(skbp != 0)
|
||||
{
|
||||
struct sk_buff* skbp2 = skbp -> next;
|
||||
__rkpStream_buff_retain_end(rkps -> buff_prev, __rkpStream_skb_copy(skbp));
|
||||
__rkpStream_skb_send(skbp);
|
||||
skbp = skbp2;
|
||||
}
|
||||
|
||||
// 清空查找情况,重新设置状态
|
||||
rkps -> scan_length = 0;
|
||||
if(!(tcp_hdr(skb) -> psh))
|
||||
rkps -> status = waiting;
|
||||
|
||||
// 考虑之前截留的数据包
|
||||
__rkpStream_buff_rejudge(rkps, &(skps -> buff_prev));
|
||||
|
||||
return NF_STOLEN;
|
||||
}
|
||||
else if(tcp_hdr(skb) -> psh)
|
||||
// 如果没有找到却读到了 PUSH,这就比较迷了。打印一句警告,更新 seq,然后把截留的包都放行,然后考虑 buff_prev 里的数据。
|
||||
{
|
||||
struct sk_buff* skbp = rkps -> buff;
|
||||
|
||||
// 打印警告
|
||||
printk("rkp-ua::rkpStream::rkpStream_execute: Find PSH before header ending found. Send without modification.\n");
|
||||
|
||||
// 更新 seq
|
||||
rkps -> seq = __rkpStream_skb_seq(rkps -> ack_seq, ntohl(tcp_hdr(skb) -> seq)) + __rkpStream_skb_appLen(skb);
|
||||
|
||||
// 放行截留的包
|
||||
while(skbp != 0)
|
||||
{
|
||||
struct sk_buff* skbp2 = skbp -> next;
|
||||
__rkpStream_skb_send(skbp);
|
||||
skbp = skbp2;
|
||||
}
|
||||
|
||||
// 清空查找情况
|
||||
rkps -> scan_length = 0;
|
||||
|
||||
// 考虑之前截留的数据包
|
||||
__rkpStream_buff_rejudge(rkps, &(skps -> buff_prev));
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
else
|
||||
// 没有找到结尾,也没有push。那么,将这个数据包补到 buff 中,更新 seq 和 查找状态,再考虑 buff_next 中的包,最后返回 STOLEN
|
||||
{
|
||||
// 追加到 buff
|
||||
__rkpStream_buff_retain_end(rkps -> buff, skb);
|
||||
|
||||
// 更新 seq 和查找状态
|
||||
rkps -> seq = __rkpStream_skb_seq(rkps -> ack_seq, ntohl(tcp_hdr(skb) -> seq)) + __rkpStream_skb_appLen(skb);
|
||||
rkps -> matched_length = scan >> 1;
|
||||
|
||||
// 考虑 buff_next 中的包
|
||||
__rkpStream_buff_rejudge(rkps, &(skps -> buff_prev));
|
||||
|
||||
return NF_STOLEN;
|
||||
}
|
||||
}
|
||||
else
|
||||
// 如果是在 waiting 的状态下,那么设置 seq 和状态,然后考虑 buff_next 中的包,然后返回 ACCEPT 就可以了
|
||||
{
|
||||
// 设置 seq 和状态
|
||||
rkps -> seq = __rkpStream_skb_seq(rkps -> ack_seq, ntohl(tcp_hdr(skb) -> seq)) + __rkpStream_skb_appLen(skb);
|
||||
if(tcp_hdr(skb) -> psh)
|
||||
rkps -> status = sniffing;
|
||||
|
||||
// 考虑 buff_next
|
||||
__rkpStream_buff_rejudge(rkps, &(skps -> buff_prev));
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
void __rkpStream_refresh_ack(struct rkpStream* rkps, u_int32_t ack)
|
||||
{
|
||||
struct sk_buff* skbp;
|
||||
|
||||
// 重新计算 seq 偏移
|
||||
rkps -> seq -= ack - rkps -> seq_ack;
|
||||
|
||||
// 丢弃 buff_prev 中已经确认收到的数据包
|
||||
skbp = rkps -> buff_prev;
|
||||
while(skbp != 0)
|
||||
}
|
||||
|
||||
u_int16_t __rkpStream_dataLen(strct sk_buff* skb)
|
||||
{
|
||||
return ntohs(ip_hdr(skb) -> tot_len) - ip_hdr(skb) -> ihl * 4 - tcp_hdr(skb) -> doff * 4;
|
||||
}
|
||||
|
||||
182
src/scanner.h
182
src/scanner.h
@@ -1,182 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
const char str_ua[] const = "User-Agent: ";
|
||||
const char str_headtail[] const = "\r\n\r\n";
|
||||
const char str_uaend[] const = "\r\n";
|
||||
const char str_windows[] const = "Windows NT";
|
||||
|
||||
struct scanner
|
||||
// 字符串扫描(跨 skb)需要的一些状态变量以及函数
|
||||
{
|
||||
struct sk_buff* skb; // 当前正在扫描的字符所在的 skb
|
||||
char* data_start;
|
||||
char* data_end; // skb 的应用层起始位置和终止位置,记下来避免每次计算
|
||||
char* pos; // 现在扫描到的位置
|
||||
|
||||
const char* target; // 要匹配的字符串
|
||||
u_int8_t target_legth; // 要匹配的字符串的长度
|
||||
|
||||
u_int8_t enum
|
||||
{
|
||||
matching_none,
|
||||
matching_content,
|
||||
matching_headtail
|
||||
} matching_status; // 当前匹配的状态:没有正在匹配的,正在匹配所给的内容,正在匹配 http 头结尾
|
||||
u_int16_t matched_length; // 如果正在匹配给定的内容或者头结尾,这里指示已经匹配的长度(包含当前的字符)
|
||||
};
|
||||
void scanner_init(struct scanner* scn, struct sk_buff* skb, u_int16_t pos, const char* target)
|
||||
// 初始化扫描器
|
||||
// pos 指指针相对于给定的 skb 的应用层第一个字节的位置。skb 的第一个应用层字节的位置为 0。
|
||||
{
|
||||
// 找到目标字节真正所的 skb
|
||||
while(true)
|
||||
{
|
||||
register struct tcphdr *tcph = tcp_hdr(skb);
|
||||
register struct iphdr *iph = ip_hdr(skb);
|
||||
u_int16_t data_length = ntohs(iph -> tot_len) - iph -> ihl * 4 - tcph -> doff * 4;
|
||||
if(pos >= data_length)
|
||||
pos -= data_length;
|
||||
}
|
||||
scn -> skb = skb;
|
||||
scn -> data_start = (char*)tcph + tcph -> doff * 4;
|
||||
scn -> data_end = (char*)tcph + ntohs(iph -> tot_len) - iph -> ihl * 4;
|
||||
scn -> pos = scn -> data_start + pos;
|
||||
scn -> target = target;
|
||||
scn -> target_length = strlen(target);
|
||||
scn -> matching_status = scn -> matching_none;
|
||||
scn -> matched_length = 0;
|
||||
}
|
||||
u_int8_t scanner_next(struct scanner* scn)
|
||||
// 尝试将指针移动到下一个字节。会自动跨 skb。
|
||||
// 返回值:0 没有匹配完毕什么;1 目标字符串匹配完毕;2 http 头匹配完毕;-1 需要下一个 skb(下一个 skb 的指针是 0,或者根据序列判断并不是紧邻的下一个 skb
|
||||
// 注意到,如果要匹配 "\r\n" 之类以 '\r' 开头的字符串时,不能正确地识别 http 头结尾;以及,匹配长度为 1 的字符串时也会出错。但这并不影响最终结果。
|
||||
{
|
||||
// 尝试将指针移动到下一个位置
|
||||
if(scn -> pos + 1 == scn -> data_end)
|
||||
{
|
||||
if(scn -> skb -> next == 0)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
register u_int32_t target_seq = ntohl(tcp_hdr(scn -> skb) -> seq) + (scn -> data_end - scn -> data_start);
|
||||
if(target_seq != ntolh(scn -> skb -> next -> seq))
|
||||
return -1
|
||||
else
|
||||
{
|
||||
scn -> skb = scn -> skb -> next;
|
||||
register struct tcphdr *tcph = tcp_hdr(scn -> skb);
|
||||
register struct iphdr *iph = ip_hdr(scn -> skb);
|
||||
scn -> data_start = (char*)tcph + tcph -> doff * 4;
|
||||
scn -> data_end = (char*)tcph + ntohs(iph -> tot_len) - iph -> ihl * 4;
|
||||
scn -> pos = scn -> data_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
scn -> pos++;
|
||||
|
||||
// 检查匹配情况
|
||||
if(scn -> matching_status == scn -> matching_none)
|
||||
{
|
||||
if(scn -> pos[0] == scn -> target[0])
|
||||
{
|
||||
scn -> matching_status == scn -> matching_target;
|
||||
scn -> matched_length = 1;
|
||||
return 0;
|
||||
}
|
||||
else if(scn -> pos[0] == str_headtail[0])
|
||||
{
|
||||
scn -> matching_status == scn -> matching_headtail;
|
||||
scn -> matched_length = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if(scn -> matching_status == scn -> matching_target)
|
||||
{
|
||||
if(scn -> pos[0] == scn -> target[scn -> matched_length])
|
||||
{
|
||||
scn -> matched_length++;
|
||||
if(scn -> matched_length == scn -> matched_length)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if(scn -> pos[0] == str_headtail[0])
|
||||
{
|
||||
scn -> matching_status == scn -> matching_headtail;
|
||||
scn -> matched_length = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scn -> matching_status == scn -> matching_none;
|
||||
scn -> matched_length = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if(scn -> matching_status == scn -> matching_target)
|
||||
{
|
||||
if(scn -> pos[0] == str_headtail[scn -> matched_length])
|
||||
{
|
||||
scn -> matched_length++;
|
||||
if(scn -> matched_length == 4)
|
||||
return 2;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if(scn -> pos[0] == scn -> target[0])
|
||||
{
|
||||
scn -> matching_status == scn -> matching_target;
|
||||
scn -> matched_length = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scn -> matching_status == scn -> matching_none;
|
||||
scn -> matched_length = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
void scanner_prev(struct scanner* scn)
|
||||
// 将指针移动到上一个字节。会自动跨 skb。
|
||||
// 不需要考虑匹配的状态。保证上一个 skb 一定存在。
|
||||
{
|
||||
if(scn -> pos == scn -> data_start)
|
||||
{
|
||||
scn -> skb = scn -> skb -> prev;
|
||||
register struct tcphdr *tcph = tcp_hdr(scn -> skb);
|
||||
register struct iphdr *iph = ip_hdr(scn -> skb);
|
||||
scn -> data_start = (char*)tcph + tcph -> doff * 4;
|
||||
scn -> data_end = (char*)tcph + ntohs(iph -> tot_len) - iph -> ihl * 4;
|
||||
scn -> pos = scn -> data_end - 1;
|
||||
}
|
||||
else
|
||||
scn -> pos--;
|
||||
}
|
||||
void scanner_next_noscan(struct scanner* scn)
|
||||
{
|
||||
if(scn -> pos + 1 == scn -> data_end)
|
||||
{
|
||||
scn -> skb = scn -> skb -> next;
|
||||
register struct tcphdr *tcph = tcp_hdr(scn -> skb);
|
||||
register struct iphdr *iph = ip_hdr(scn -> skb);
|
||||
scn -> data_start = (char*)tcph + tcph -> doff * 4;
|
||||
scn -> data_end = (char*)tcph + ntohs(iph -> tot_len) - iph -> ihl * 4;
|
||||
scn -> pos = scn -> data_start;
|
||||
}
|
||||
else
|
||||
scn -> pos++;
|
||||
}
|
||||
187
src/stm_info.h
187
src/stm_info.h
@@ -1,187 +0,0 @@
|
||||
#include "scanner.h"
|
||||
|
||||
struct stm_info
|
||||
// 用于存储每一条流的信息。
|
||||
{
|
||||
u_int8_t modify_finished:1, // 标识是否已经被修改完成。对于修改完成的流,肯定没有存储任何 skb,之后都不会再捕获。对于不需要修改的流,最初的时候就会被置为“已经修改完成”而直接放行。
|
||||
modify_force:1, // 是否强制修改这个流(而不论目标地址,也不论是否是 windows 主机),与 mark 中的内容对应。
|
||||
scan_finished:1, // 是否已经扫描完成;也就是说,已经完整地找到了 ua,或者完整地拿到了 http 头。之后不再会捕获这个流,但流中可能还有缓存的 skb 没有发出。windows 也已经被扫描(除非没有必要)。
|
||||
scan_ua_found:1, // 是否找到了 ua。只要找到了 "User-Agent: " 这一项就被置为 1,ua_start 同时被设置;ua_end 则会等到 scan_finished 才被设置。
|
||||
scan_windows:1, // ua 是否是 windows 的 ua。在完整地找到 ua 后,除非 modify_force 被设置,否则会再扫描一遍 ua 来确定这个值。
|
||||
preserved:3;
|
||||
u_int32_t saddr; // 源地址
|
||||
u_int16_t sport; // 源端口。通过这两项应该足够区分不同的流。
|
||||
u_int32_t seq_offset; // 应用层字节的编号的偏移,减去偏移后,第一个应用层字节的编号为 0
|
||||
u_int32_t ua_start; // "User-Agent: xxxxx\r\n" 中,第一个 'x' 的位置(已经减去偏移)
|
||||
u_int32_t ua_end; // "User-Agent: xxxxx\r\n?" 中,‘\r’ 的位置(已经减去偏移)
|
||||
struct sk_buff* skb;
|
||||
struct scanner* scn;
|
||||
};
|
||||
void stm_init(struct stm_info* stm, struct sk_buff* skb)
|
||||
// 初始化 stm_info
|
||||
{
|
||||
stm -> modify_finished = 0;
|
||||
if(skb -> mark & 0x20)
|
||||
stm -> modify_force = 1;
|
||||
else
|
||||
stm -> modify_force = 0;
|
||||
stm -> scan_finished = 0;
|
||||
stm -> saddr = ntohl(ip_hdr(skb) -> daddr);
|
||||
stm -> sport = ntohs(tcp_hdr(skb) -> dest);
|
||||
stm -> seq_offset = ntohl(tcp_hdr(skb) -> ack_seq);
|
||||
stm -> skb = 0;
|
||||
stm -> scn = 0;
|
||||
}
|
||||
u_int32_t stm_realseq(struct stm_info* stm, struct sk_buff* skb)
|
||||
// 计算 skb 的真实偏移
|
||||
{
|
||||
register u_int32_t real_seq = ntohl(tcp_hdr(skb) -> ack_seq);
|
||||
if(real_seq >= stm -> seq_offset)
|
||||
real_seq -= stm -> seq_offset;
|
||||
else
|
||||
real_seq += 0xffffffff - stm -> seq_offset + 1;
|
||||
return real_seq;
|
||||
}
|
||||
void stm_append(struct stm_info* stm, struct sk_buff* skb)
|
||||
// 追加一个 skb 到合适的位置。
|
||||
{
|
||||
register u_int32_t real_seq;
|
||||
register struct sk_buff* i;
|
||||
if(stm -> skb == 0)
|
||||
{
|
||||
stm -> skb = skb;
|
||||
skb -> next = skb -> prev = 0;
|
||||
}
|
||||
|
||||
real_seq = stm_realseq(stm, skb);
|
||||
if(stm_realseq(stm, stm -> skb) > real_seq)
|
||||
{
|
||||
stm -> skb -> prev = skb;
|
||||
skb -> next = stm -> skb;
|
||||
stm -> skb = skb;
|
||||
}
|
||||
|
||||
//尝试寻找最后一个序号比待插入 skb 小的 skb
|
||||
for(i = stm -> skb;;i = i -> next)
|
||||
{
|
||||
if(i -> next == 0)
|
||||
{
|
||||
i -> next = skb;
|
||||
skb -> prev = i;
|
||||
skb -> next = 0;
|
||||
}
|
||||
else if(stm_realseq(stm, i -> next) > real_seq)
|
||||
{
|
||||
i -> next -> prev = skb;
|
||||
skb -> next = i -> next;
|
||||
i -> next = skb;
|
||||
skb -> prev = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
void stm_scan(struct stm_info* stm)
|
||||
// 扫描直到头部末尾或者 ua 结束(总之是使得 scan_finished)或者不能再继续扫描了(需要下一个包)。也会扫描 windows,如果有必要。
|
||||
{
|
||||
// 如果没有初始化扫描器,就尝试初始化
|
||||
if(stm -> scn == 0)
|
||||
{
|
||||
if(stm -> skb == 0 || stm_realseq(stm, stm -> skb) != 0)
|
||||
return;
|
||||
else
|
||||
{
|
||||
stm -> scn = kmalloc(sizeof(scanner), GFP_KERNEL);
|
||||
scanner_init(stm -> scn, stm -> skb, 0, str_ua);
|
||||
}
|
||||
}
|
||||
|
||||
static char* ua_end = 0; // 仅仅用来扫描 windows 时使用一下。记录 ua 的结束位置,当扫描到这里时还没有 windows,那就是没有了。
|
||||
while(true)
|
||||
{
|
||||
u_int8_t rtn = scanner_next(stm -> scn);
|
||||
if(rtn == 0 && stm -> scn -> pos == ua_end)
|
||||
// 没有找到 windows
|
||||
{
|
||||
stm -> scan_finished = 1;
|
||||
ua_end = 0;
|
||||
}
|
||||
else if(rtn == 0)
|
||||
continue;
|
||||
else if(rtn == 1 && stm -> scn -> target == str_ua)
|
||||
{
|
||||
// 将结果记录,然后去扫描 ua 尾。
|
||||
stm -> scan_ua_found;
|
||||
stm -> ua_start = stm_realseq(stm, stm -> scn -> skb) + (stm -> scn -> pos - stm -> scn -> data_start);
|
||||
scanner_init(stm -> scn, stm -> scn -> skb, stm -> scn -> pos - stm -> scn -> data_start, str_uaend);
|
||||
}
|
||||
else if(rtn == 1 && stm -> scn -> target == str_uaend)
|
||||
{
|
||||
// 将结果记录,然后去扫描 windows 或者结束。
|
||||
stm -> ua_end = stm_realseq(stm, stm -> scn -> skb) + (stm -> scn -> pos - stm -> scn -> data_start) + 1;
|
||||
if(!stm -> modify_force)
|
||||
scanner_init(stm -> scn, stm -> skb, stm -> ua_start, str_windows);
|
||||
else
|
||||
{
|
||||
stm -> scan_finished = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(rtn == 1 && stm -> scn -> target == str_windows)
|
||||
// 将结果记录,结束
|
||||
{
|
||||
stm -> scan_windows = 1;
|
||||
stm -> scan_finished = 1;
|
||||
ua_end = 0;
|
||||
return;
|
||||
}
|
||||
else if(rtn == 2)
|
||||
{
|
||||
stm -> scan_finished;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
void stm_modify_send(struct stm_info* stm)
|
||||
// 将 ua 替换为 "XMURP/1.0" 加许多的空格
|
||||
{
|
||||
struct sk_buff* skb_start;
|
||||
struct sk_buff* skb_end; // 两个 skb 之间的(包含这两个 skb)都需要重新计算校验和
|
||||
sturct sk_buff* skb;
|
||||
u_int16_t i;
|
||||
scanner_init(stm -> scn, stm -> skb, stm -> ua_start, str_ua);
|
||||
skb_start = stm -> scn -> skb;
|
||||
scanner_prev(stm -> scn);
|
||||
for(int i = 0; i < stm -> ua_end - stm -> ua_start; i++)
|
||||
{
|
||||
scanner_next_noscan(stm -> scn);
|
||||
if(i < strlen("XMURP/1.0"))
|
||||
*(stm -> scn -> pos) = "XMURP/1.0"[i];
|
||||
else
|
||||
*(stm -> scn -> pos) = ' ';
|
||||
}
|
||||
skb_end = stm -> scn -> skb -> next;
|
||||
|
||||
skb = skb_start;
|
||||
do
|
||||
{
|
||||
register struct tcp_hdr* tcph = tcp_hdr(skb);
|
||||
register struct ip_hdr* iph = ip_hdr(skb);
|
||||
tcph->check = 0;
|
||||
iph->check = 0;
|
||||
skb->csum = skb_checksum(skb, iph->ihl * 4, ntohs(iph->tot_len) - iph->ihl * 4, 0);
|
||||
iph->check = ip_fast_csum(iph, iph->ihl);
|
||||
tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, ntohs(iph->tot_len) - iph->ihl * 4, IPPROTO_TCP, skb->csum);
|
||||
}
|
||||
while((skb = skb -> next) != skb_end);
|
||||
|
||||
skb = stm -> skb;
|
||||
while(skb != 0)
|
||||
{
|
||||
dev_queue_xmit(skb);
|
||||
skb = skb -> next;
|
||||
}
|
||||
|
||||
stm -> modify_finished = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "stm_info.h"
|
||||
|
||||
struct stm_vec
|
||||
// 用于存储一条条流的向量,包含了扩大等函数。
|
||||
{
|
||||
struct stm_info* data;
|
||||
u_int16_t max_size;
|
||||
u_int16_t size;
|
||||
};
|
||||
void stm_vec_init(struct stm_vec* stmv)
|
||||
// 初始化 skb_vec
|
||||
{
|
||||
stmv -> max_size = 4;
|
||||
stmv -> size = 0;
|
||||
stmv -> data = kmalloc(sizeof(stm_info) * stmv -> max_size, GFP_KERNEL)
|
||||
}
|
||||
void stm_vec_insert(struct stm_vec* stmv)
|
||||
// 为 skb_vec 增加一条流。不会初始化新增的流。
|
||||
{
|
||||
if(stmv -> size == stmv -> max_size) // 如果满了,就扩大
|
||||
{
|
||||
struct stm_info* temp = stmv -> data;
|
||||
stmv -> max_size *= 2;
|
||||
stmv -> data = kmalloc(sizeof(stm_info) * stmv -> max_size, GFP_KERNEL)
|
||||
memcpy(stmv -> data, temp, sizeof(stm_info) * stmv -> size);
|
||||
kfree(temp);
|
||||
printk("xmurp-ua: Streams buff expanded to %d.\n", stmv -> max_size);
|
||||
}
|
||||
stmv -> size++;
|
||||
}
|
||||
u_int16_t stm_vec_find(struct stm_vec* stmv, struct sk_buff* skb)
|
||||
// 根据一个数据包来寻找它属于哪个流。数据包必须是客户端发给服务端的。如果没有找到,返回 0xffff。
|
||||
{
|
||||
int i;
|
||||
u_int32_t saddr = ntohl(ip_hdr(skb) -> saddr;
|
||||
u_int32_t sport = ntohs(tcp_hdr(skb) -> src);
|
||||
for(i = 0; i < stmv -> size; i++)
|
||||
if(saddr == stmv -> data[i].saddr && sport == stmv -> data[i].sport)
|
||||
return i;
|
||||
return 0xffff;
|
||||
}
|
||||
void stm_vec_del(struct stm_vec* stmv, u_int16_t pos)
|
||||
// 删除指定流,后面的往前移。
|
||||
{
|
||||
int i;
|
||||
for(i = pos; i < size - 1; i++)
|
||||
stmv -> data[i] = stv -> data[i + 1];
|
||||
stmv -> size--;
|
||||
}
|
||||
257
src/xmurp-ua.c
257
src/xmurp-ua.c
@@ -1,268 +1,73 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include "rkpManager.h"
|
||||
|
||||
static struct nf_hook_ops nfho;
|
||||
static struct rkpManager* rkpm;
|
||||
static time_t last_flush;
|
||||
|
||||
enum char_scan_enum
|
||||
{
|
||||
next,
|
||||
modified_and_next,
|
||||
scan_finish,
|
||||
reset,
|
||||
};
|
||||
|
||||
enum skb_scan_ret
|
||||
{
|
||||
need_next_frag = 1,
|
||||
ua_modified = 2,
|
||||
};
|
||||
|
||||
// 根据得到的指针尝试扫描,发现结尾或发现UA或更改UA后返回对应结果。
|
||||
// 输入零指针则为重置状态。
|
||||
inline u_int8_t char_scan(char *data)
|
||||
{
|
||||
const char str_ua_head[] = "User-Agent: ", str_ua[] = "XMURP/1.0", str_end[] = "\r\n\r\n";
|
||||
// 不算'\0',长度分别为12、9、4
|
||||
static enum
|
||||
{
|
||||
nothing_matching,
|
||||
ua_head_matching,
|
||||
ua_modifying,
|
||||
end_matching,
|
||||
} status = nothing_matching;
|
||||
static u_int8_t covered_length;
|
||||
|
||||
if(data == 0)
|
||||
{
|
||||
status = nothing_matching;
|
||||
covered_length = 0;
|
||||
return reset;
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(status == nothing_matching)
|
||||
{
|
||||
if(*data == str_ua_head[0])
|
||||
{
|
||||
status = ua_head_matching;
|
||||
covered_length = 1;
|
||||
return next;
|
||||
}
|
||||
else if(*data == str_end[0])
|
||||
{
|
||||
status = end_matching;
|
||||
covered_length = 1;
|
||||
return next;
|
||||
}
|
||||
else
|
||||
return next;
|
||||
}
|
||||
else if(status == ua_head_matching)
|
||||
{
|
||||
if(*data == str_ua_head[covered_length])
|
||||
{
|
||||
covered_length++;
|
||||
if(covered_length == 12)
|
||||
{
|
||||
status = ua_modifying;
|
||||
covered_length = 0;
|
||||
return next;
|
||||
}
|
||||
else
|
||||
return next;
|
||||
}
|
||||
else
|
||||
status = nothing_matching;
|
||||
}
|
||||
else if(status == ua_modifying)
|
||||
{
|
||||
if(*data == '\r')
|
||||
{
|
||||
status = nothing_matching;
|
||||
return scan_finish;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(covered_length < 9)
|
||||
*data = str_ua[covered_length];
|
||||
else
|
||||
*data = ' ';
|
||||
covered_length++;
|
||||
return modified_and_next;
|
||||
}
|
||||
}
|
||||
else if(status == end_matching)
|
||||
{
|
||||
if(*data == str_end[covered_length])
|
||||
{
|
||||
covered_length++;
|
||||
if(covered_length == 4)
|
||||
{
|
||||
status = nothing_matching;
|
||||
return scan_finish;
|
||||
}
|
||||
else
|
||||
return next;
|
||||
}
|
||||
else
|
||||
status = nothing_matching;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将数据逐字节发送给下一层,根据下一层的结果(扫描到结尾、扫描到UA、已更改UA),确定是否扫描完毕,以及是否发生了改动,返回到上一层。
|
||||
inline u_int8_t skb_scan(char *data_start, char *data_end)
|
||||
{
|
||||
register char *i;
|
||||
register u_int8_t ret, modified = 0;
|
||||
for(i = data_start; i < data_end; i++)
|
||||
{
|
||||
ret = char_scan(i);
|
||||
if(ret == scan_finish)
|
||||
return modified;
|
||||
else if(ret == modified_and_next)
|
||||
modified = ua_modified;
|
||||
}
|
||||
return modified + need_next_frag;
|
||||
}
|
||||
|
||||
// 捕获数据包,检查是否符合条件。如果符合,则送到下一层,并根据下一层返回的结果,如果必要的话,重新计算校验和以及继续捕获下一个分片。
|
||||
// ip地址、端口号、iph->tot_len需要网络顺序到主机顺序的转换。校验和时,除长度字段外,不需要手动进行网络顺序和主机顺序的转换。
|
||||
unsigned int hook_funcion(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
|
||||
{
|
||||
register struct tcphdr *tcph;
|
||||
register struct iphdr *iph;
|
||||
register char *data_start, *data_end;
|
||||
u_int8_t rtn;
|
||||
static u_int8_t crashed = 0;
|
||||
|
||||
static u_int8_t catch_next_frag = 0;
|
||||
static u_int32_t saddr, daddr, seq;
|
||||
static u_int16_t sport, dport;
|
||||
|
||||
static u_int32_t n_ua_modified = 0, n_ua_modify_faild = 0;
|
||||
static u_int8_t mark_matched = 0;
|
||||
|
||||
register u_int8_t jump_to_next_function = 0, ret;
|
||||
|
||||
// 过滤发往外网的HTTP请求的包,且要求包的应用层内容不短于3字节
|
||||
if(skb == 0)
|
||||
if(crashed)
|
||||
return NF_ACCEPT;
|
||||
iph = ip_hdr(skb);
|
||||
if((ntohl(iph->daddr) & 0xffff0000) == 0xc0a80000)
|
||||
if(!rkpSettings_capture(skb))
|
||||
return NF_ACCEPT;
|
||||
if(iph->protocol != IPPROTO_TCP)
|
||||
return NF_ACCEPT;
|
||||
tcph = tcp_hdr(skb);
|
||||
if(ntohs(tcph->dest) != 80)
|
||||
return NF_ACCEPT;
|
||||
data_start = (char *)tcph + tcph->doff * 4;
|
||||
data_end = (char *)tcph + ntohs(iph->tot_len) - iph->ihl * 4;
|
||||
if(data_end - data_start < 4)
|
||||
return NF_ACCEPT;
|
||||
if(skb->mark & 0x100)
|
||||
rtn = rkpManager_execute(rkpm, skb);
|
||||
if(rtn == NF_DROP_ERR(1))
|
||||
{
|
||||
if(!mark_matched)
|
||||
{
|
||||
mark_matched = 1;
|
||||
printk("xmurp-ua: Mark matched. Note that all packages with the mark will be ACCEPT without modify.\n");
|
||||
printk("xmurp-ua: If the mark is not set manually, it maybe a conflict there. "
|
||||
"Find out which app is using the desired bit and let it use others, or modify and recompile me.\n");
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
printk("rkp-ua: Crashed.\n");
|
||||
crashed = 1;
|
||||
rkpManager_del(rkpm);
|
||||
return NF_STOLEN;
|
||||
}
|
||||
|
||||
// 决定是否发送到下一层
|
||||
if(catch_next_frag && iph->saddr == saddr && iph->daddr == daddr &&
|
||||
tcph->seq == seq && tcph->source == sport && tcph->dest == dport)
|
||||
jump_to_next_function = 1;
|
||||
else if(data_end - data_start > 3)
|
||||
if(memcmp(data_start, "GET", 3) == 0 || memcmp(data_start, "POST", 4) == 0)
|
||||
{
|
||||
if(catch_next_frag)
|
||||
{
|
||||
n_ua_modify_faild++;
|
||||
char_scan(0);
|
||||
catch_next_frag = 0;
|
||||
}
|
||||
jump_to_next_function = 1;
|
||||
}
|
||||
if(!jump_to_next_function)
|
||||
return NF_ACCEPT;
|
||||
|
||||
// 发送到下一层,并回收数据
|
||||
ret = skb_scan(data_start, data_end);
|
||||
|
||||
// 处理返回值
|
||||
if(ret & need_next_frag)
|
||||
{
|
||||
if(!catch_next_frag)
|
||||
{
|
||||
catch_next_frag = 1;
|
||||
saddr = iph->saddr;
|
||||
daddr = iph->daddr;
|
||||
sport = tcph->source;
|
||||
dport = tcph->dest;
|
||||
}
|
||||
seq = tcph->seq + (data_end - data_start);
|
||||
}
|
||||
else
|
||||
catch_next_frag = 0;
|
||||
if(ret & ua_modified)
|
||||
{
|
||||
n_ua_modified++;
|
||||
if(n_ua_modified % 0x10000 == 0)
|
||||
printk("xmurp-ua: Successfully modified %d packages, faild to modify %d packages.\n",
|
||||
n_ua_modified, n_ua_modify_faild);
|
||||
tcph->check = 0;
|
||||
iph->check = 0;
|
||||
skb->csum = skb_checksum(skb, iph->ihl * 4, ntohs(iph->tot_len) - iph->ihl * 4, 0);
|
||||
iph->check = ip_fast_csum(iph, iph->ihl);
|
||||
tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, ntohs(iph->tot_len) - iph->ihl * 4, IPPROTO_TCP, skb->csum);
|
||||
}
|
||||
|
||||
return NF_ACCEPT;
|
||||
else
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static int __init hook_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rkpm = rkpManager_new();
|
||||
last_flush = now();
|
||||
|
||||
nfho.hook = hook_funcion;
|
||||
nfho.pf = NFPROTO_IPV4;
|
||||
nfho.hooknum = NF_INET_POST_ROUTING;
|
||||
nfho.priority = NF_IP_PRI_FILTER;
|
||||
nfho.priority = NF_IP_PRI_NAT_SRC;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
ret = nf_register_net_hook(&init_net, &nfho);
|
||||
#else
|
||||
ret = nf_register_hook(&nfho);
|
||||
#endif
|
||||
printk("xmurp-ua: Started.\n");
|
||||
printk("xmurp-ua: nf_register_hook returnd %d.\n", ret);
|
||||
|
||||
printk("rkp-ua: Started, version %s\n", VERSION);
|
||||
printk("rkp-ua: mode_advanced=%c, mode_winPreserve=%c, mark_capture=0x%x, "
|
||||
"mark_request=0x%x, mark_first=0x%x, mark_winPreserve=0x%x.\n",
|
||||
'n' + mode_advanced * ('y' - 'n'), 'n' + mode_winPreserve * ('y' - 'n'),
|
||||
mark_capture, mark_request, mark_first, mark_winPreserve);
|
||||
printk("rkp-ua: nf_register_hook returnd %d.\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//卸载模块
|
||||
static void __exit hook_exit(void)
|
||||
{
|
||||
rkpManager_del(rkpm);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
nf_unregister_net_hook(&init_net, &nfho);
|
||||
#else
|
||||
nf_unregister_hook(&nfho);
|
||||
#endif
|
||||
printk("xmurp-ua: Stopped.\n");
|
||||
printk("rkp-ua: Stopped.\n");
|
||||
}
|
||||
|
||||
module_init(hook_init);
|
||||
module_exit(hook_exit);
|
||||
|
||||
MODULE_AUTHOR("Haonan Chen");
|
||||
MODULE_DESCRIPTION("Modify UA in HTTP for anti-detection of router in XMU.");
|
||||
MODULE_DESCRIPTION("Modify UA in HTTP for anti-detection about amount of devices behind NAT.");
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user