linux - 如何从 sk_buff 读取实际目标地址?

标签 linux linux-kernel linux-device-driver

我正在编写一个 netfilter 模块来根据目标 IP 检查来丢弃数据包。

我注册了一个nf钩子(Hook)

nfho_out.hook = hook_func_out;
nfho_out.hooknum = NF_INET_LOCAL_OUT;
nfho_out.pf = PF_INET;
nfho_out.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho_out);

这是我的 nf 钩子(Hook)函数

    unsigned int hook_func_out(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) {
        struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
        struct udphdr *udp_header;
        struct tcphdr *tcp_header;
        struct list_head *p;

        unsigned int src_ip = (unsigned int)ip_header->saddr;
        unsigned int dest_ip = (unsigned int)ip_header->daddr;
        unsigned int src_port = 0;
        unsigned int dest_port = 0;

        if (ip_header->protocol==17) {
                udp_header = (struct udphdr *)skb_transport_header(skb);
                src_port = (unsigned int)ntohs(udp_header->source);
        } else if (ip_header->protocol == 6) {
                tcp_header = (struct tcphdr *)skb_transport_header(skb);
                src_port = (unsigned int)ntohs(tcp_header->source);
                dest_port = (unsigned int)ntohs(tcp_header->dest);
        }

        printk(KERN_INFO "OUT packet info: src ip: %u, src port: %u; dest ip: %u, dest port: %u; proto: %u\n", src_ip, src_port, dest_ip, dest_port, ip_header->protocol);
        printk(KERN_DEBUG "IP addres = %pI4  DEST = %pI4\n", &src_ip, &dest_ip);
....
....
}

我在网络浏览器中打开了 google.com,但无法获取 google.com 解析到的实际目标 IP 地址。问题是我总是得到一些奇怪的 IP 地址(因为我怀疑是代理或 dns 服务器)而不是实际的 IP 地址。

如何在nf hook函数中获取实际目的地址?

最佳答案

我没有发现您发布的代码片段有任何问题。

当您在网络浏览器中打开 www.google.com 时,首先解析 DNS,然后交换 HTTP 消息。因此你会看到在 DNS 解析过程中,dest_ipGATEWAY/DNS SERVER ip。解析 DNS 后,在进一步的消息中,dest_ip 始终是 www.google.com 的已解析 IP。

首先通过在终端上发出以下命令来检查 www.google.com 解析了什么:

[s.roy@roy ~]$ nslookup www.google.com
Server:     192.168.1.1
Address:    192.168.1.1#53

Non-authoritative answer:
Name:   www.google.com
Address: 216.58.220.36

如您所见,DNS 服务器 192.168.1.1 将 www.google.com 解析为 216.58.220.36,这也是我的默认网关。请注意,在 nslookup 期间,我的 dest_ip 是 192.168.1.1。

DNS 解析后,我的系统将发送 TCP 和 HTTP 消息,dest_ip216.58.220.36

测试.c

static struct nf_hook_ops nfho_out;

static unsigned int hook_func_out(unsigned int hooknum,
                                  struct sk_buff *skb,
                                  const struct net_device *in,
                                  const struct net_device *out,
                                  int (*okfn)(struct sk_buff *))
{

        struct iphdr *ip_header = (struct iphdr *)skb_network_header(skb);
        struct udphdr *udp_header;
        struct tcphdr *tcp_header;
        struct list_head *p;

        unsigned int src_ip = (unsigned int)ip_header->saddr;
        unsigned int dest_ip = (unsigned int)ip_header->daddr;
        unsigned int src_port = 0;
        unsigned int dest_port = 0;

        if (ip_header->protocol==17) {
                udp_header = (struct udphdr *)skb_transport_header(skb);
                src_port = (unsigned int)ntohs(udp_header->source);
        } else if (ip_header->protocol == 6) {
                tcp_header = (struct tcphdr *)skb_transport_header(skb);
                src_port = (unsigned int)ntohs(tcp_header->source);
                dest_port = (unsigned int)ntohs(tcp_header->dest);
        }

        printk(KERN_DEBUG "IP addres = %pI4  DEST = %pI4\n", &src_ip, &dest_ip);

        return NF_ACCEPT;

}


static int __init test_init(void)
{
    printk(KERN_INFO "Loading \n");

    nfho_out.hook = hook_func_out;
    nfho_out.hooknum = NF_INET_LOCAL_OUT;
    nfho_out.pf = PF_INET;
    nfho_out.priority = NF_IP_PRI_FIRST;
    nf_register_hook(&nfho_out);

    return 0;
}

static void __exit test_exit(void)
{
    printk(KERN_INFO "Unloading \n");
    nf_unregister_hook(&nfho_out);


}

module_init(test_init);
module_exit(test_exit);

罗伊

关于linux - 如何从 sk_buff 读取实际目标地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32585573/

相关文章:

linux - 如何构建一个接受数千个持久网络连接的服务器?

python - 为什么激活虚拟环境后cv2 python模块不再可用?

linux - 使用 Linux Kernel 会支持当前的程序吗?

linux - net_device get_stats函数,如何使用?

linux - 在设备驱动程序中访问 Linux 硬件的引脚

linux - 如何证明 RS 232 全调制解调器、RS 422 工作 PC 到 PC 和 LOOP BACK

php - 无法连接到本地套接字,连接被拒绝

linux - Windows 和 Linux 中的进程控制 block (PCB)

linux - 如何理解 "/proc/[pid]/stack"?

linux-device-driver - tasklet、taskqueue、work-queue——使用哪个?