mirror of
https://github.com/CHN-beta/xmurp-ua.git
synced 2026-01-11 09:19:27 +08:00
262 lines
11 KiB
C
262 lines
11 KiB
C
#include "common.h"
|
||
|
||
struct rkpStream
|
||
{
|
||
u_int8_t enum
|
||
{
|
||
__rkpStream_sniffing,
|
||
__rkpStream_waiting
|
||
} status;
|
||
u_int32_t id[3]; // 按顺序存储客户地址、服务地址、客户端口、服务端口,已经转换字节序
|
||
struct sk_buff *buff, *buff_prev, *buff_next;
|
||
u_int32_t seq_ack; // 下一个服务端确认收到的字节的序列号。以后所有的序列号都是以这个为基准的相对序列号。
|
||
u_int32_t seq; // 下一个期待收到的序列号。
|
||
time_t last_active;
|
||
u_int8_t scan_matched;
|
||
u_int8_t win_preserve;
|
||
struct rkpStream* next;
|
||
};
|
||
|
||
struct rkpStream* rkpStream_new(struct sk_buff*); // 构造函数,得到的流的状态是捕获这个数据包之前的状态。内存不够时返回 0。
|
||
void rkpStream_del(struct rkpStream*); // 析构函数
|
||
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);
|
||
struct tcphdr* tcph = tcp_hdr(skb);
|
||
|
||
if(rkps == 0)
|
||
return rkps;
|
||
rkps -> status = rkpStream::__rkpStream_sniffing;
|
||
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);
|
||
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 = rkpSettings_winPreserve(skb);
|
||
rkps -> next = 0;
|
||
return rkps;
|
||
}
|
||
void rkpStream_del(struct rkpStream* rkps)
|
||
{
|
||
__rkpStream_buff_del(&(rkps -> buff));
|
||
__rkpStream_buff_del(&(rkps -> buff_prev));
|
||
__rkpStream_buff_del(&(rkps -> buff_next));
|
||
kfree(rkps);
|
||
}
|
||
u_int8_t rkpStream_belong(struct rkpStream* rkps, struct sk_buff* skb)
|
||
{
|
||
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
|
||
{
|
||
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;
|
||
}
|