C-Linux-kernel模块-TCP头

C-Linux-kernel模块-TCP头,c,tcp,module,kernel,ipv4,C,Tcp,Module,Kernel,Ipv4,我正在尝试创建linux内核模块,它将检查传入的数据包。目前,我正在提取数据包的TCP头并读取源端口和目标端口->但是我得到了不正确的值。我有钩子功能: unsigned int hook_func(unsigned int hooknum,struct sk_buff*skb, const struct net_device*in, const结构网络设备*out, int(*okfn)(结构sk_buff*)) { 结构iphdr*ipp=(结构iphdr*)skb_网络_头(skb); 结

我正在尝试创建linux内核模块,它将检查传入的数据包。目前,我正在提取数据包的TCP头并读取源端口和目标端口->但是我得到了不正确的值。我有钩子功能:

unsigned int hook_func(unsigned int hooknum,struct sk_buff*skb,
const struct net_device*in,
const结构网络设备*out,
int(*okfn)(结构sk_buff*))
{
结构iphdr*ipp=(结构iphdr*)skb_网络_头(skb);
结构tcphdr*hdr;
/*使用此选项可以过滤来自另一台机器的数据*/
无符号长ok_ip=2396891328;
/*出现问题,网络数据包为空。请立即停止*/
if(!skb)
返回NF_接受;
/*只跟踪来自1个IP的数据包*/
如果(ipp->SADD!=正常\u ip)
返回NF_接受;
/*输入数据包是TCP*/
如果(ipp->协议==IPPROTO\U TCP){
hdr=(struct tcphdr*)skb_传输_头(skb);
printk(“TCP端口:源:%d,目标:%d。\n”,ntohs(hdr->source),
ntohs(hdr->dest);
}
}
现在,当我尝试telnet端口21(不在那里收听时,我得到):

当我telnet端口22-SSH deamon在那里监听时:

[ 4299.239940]  TCP ports: source: 17664, dest: 52 .
[ 4299.240527]  TCP ports: source: 17664, dest: 40 .
[ 4299.552566]  TCP ports: source: 17664, dest: 40 .

从输出中可以看到,我得到了非常奇怪的结果,有人知道问题来自哪里吗?编译模块时,我没有错误/警告。内核版本(头文件):3.7.10。没有使用SELinux或类似工具。

我在为一个网络类编写一个小型防火墙时遇到了同样的问题,我刚刚发现了这个问题。我把tcp头投错了。尝试强制转换到tcp,然后访问端口

下面是它的一段代码

struct iphdr *ip_header;       // ip header struct
struct tcphdr *tcp_header;     // tcp header struct
struct udphdr *udp_header;     // udp header struct
struct sk_buff *sock_buff;

unsigned int sport ,
             dport;


sock_buff = skb;

if (!sock_buff)
    return NF_ACCEPT;

ip_header = (struct iphdr *)skb_network_header(sock_buff);
if (!ip_header)
    return NF_ACCEPT;


//if TCP PACKET
if(ip_header->protocol==IPPROTO_TCP)
{
    //tcp_header = (struct tcphdr *)skb_transport_header(sock_buff); //doing the cast this way gave me the same problem

    tcp_header= (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); //this fixed the problem

    sport = htons((unsigned short int) tcp_header->source); //sport now has the source port
    dport = htons((unsigned short int) tcp_header->dest);   //dport now has the dest port
}

要从套接字缓冲区(
skb
)获取IP头或TCP头,只需应用函数
IP\u hdr(skb)
TCP\u hdr(skb)

,这可能与NAT重定向有关。即使您的数据包应该在端口21和22上离开,路由器也会将其转换为动态端口,然后服务器实际上会从该端口收到一个请求。在返回的过程中,服务器的头显示了这一点,路由器将其转发给您。我不认为报头实际上被改变了(或封装了),因为我认为路由器进入报头并改变了它。你也应该试着打印输出数据包。如果它们显示正确的端口,那么是路由器为您更改这些值。没有NAT。两台机器都在ESX server上,没有VLAN。机器有IP:192.168.221.141/24和192.168.221.142/24,所以我看不出数据包有任何可能被任何东西修改。此外,没有iptables规则,所有都设置为接受。您需要定义它们如何连接到网络。它们是在虚拟局域网上(你说不是),还是连接到你的物理网络?如果它们在vlan上,我可以看到没有交换机/路由器,但是如果它们的入口点是物理的,那么我100%怀疑它没有通过路由器/交换机。谢谢,
tcp_header=(struct tcphdr*)(((uuuuu32*)ip_header+ip_header->ihl)修复了我的问题。您还可以使用这两个函数获取IP头和TCP头
IP\u hdr(sock\u buff)
TCP\u hdr(sock\u buff)
struct iphdr *ip_header;       // ip header struct
struct tcphdr *tcp_header;     // tcp header struct
struct udphdr *udp_header;     // udp header struct
struct sk_buff *sock_buff;

unsigned int sport ,
             dport;


sock_buff = skb;

if (!sock_buff)
    return NF_ACCEPT;

ip_header = (struct iphdr *)skb_network_header(sock_buff);
if (!ip_header)
    return NF_ACCEPT;


//if TCP PACKET
if(ip_header->protocol==IPPROTO_TCP)
{
    //tcp_header = (struct tcphdr *)skb_transport_header(sock_buff); //doing the cast this way gave me the same problem

    tcp_header= (struct tcphdr *)((__u32 *)ip_header+ ip_header->ihl); //this fixed the problem

    sport = htons((unsigned short int) tcp_header->source); //sport now has the source port
    dport = htons((unsigned short int) tcp_header->dest);   //dport now has the dest port
}