【问题标题】:How to read actual destination address from sk_buff?如何从 sk_buff 读取实际目标地址?
【发布时间】:2015-12-11 16:20:30
【问题描述】:

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

我注册了一个 nf 钩子

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 钩子函数

    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钩子函数中获取实际的目的地址?

【问题讨论】:

  • 您确定您的网络浏览器连接到您认为的 IP 吗? Google 因使用奇怪的地址而闻名(除了 8.8.8.8)...
  • 我总是将目标地址设为 10.169.95.255。我的 IP 地址是 10.169.95.73
  • 无论我浏览什么网站,我都会从 IP 标头中获得 10.169.95.255 作为目标 IP
  • 尝试直接连接:"telnet some_wbesite.com 80" 然后"get/http/1.0"
  • 也许看看iptables sources 可能会有所帮助。

标签: linux linux-kernel linux-device-driver


【解决方案1】:

您发布的代码 sn-p 没有任何问题。

当您在网络浏览器中打开 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解析后,我的系统会发送带有dest_ip216.58.220.36的TCP和HTTP消息。

test.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);

罗伊

【讨论】:

    【解决方案2】:

    您的代码看起来不错,没有逻辑错误。您的问题根源于网络结构(如下所述)或网络服务器机器。现在服务器可以检测查询是来自网络浏览器还是其他一些软件 你不能在最终用户互联网电脑上进行这种过滤。问题是,从你的电脑到谷歌服务器有一大堆障碍需要跨越,比如代理、路由器的设置、防火墙/网关。您的电脑似乎只获得自己的本地网络网关/代理地址 解决这个问题的一些建议

    从不同的网络测试您的应用程序,以确认您自己的防火墙/代理不是问题的原因 如果您周围有一些资源,请使用路由器和交换机制作简单的互联网,并尝试访问托管在您自己的互联网上的网站。如果您没有硬件,请尝试一些网络模拟器/模拟器来测试您的代码。 NS2/NS3 和 OMNET 都是免费的,有很多教程。

    问题的关键是您在某种程度上受到防火墙的保护。您的10.169.95.255 是本地 IP,这意味着您无法跨越自己的网络。

    【讨论】:

      猜你喜欢
      • 2012-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 1970-01-01
      • 2022-08-22
      • 1970-01-01
      • 2018-09-21
      相关资源
      最近更新 更多