【问题标题】:IP-address from sk_buff来自 sk_buff 的 IP 地址
【发布时间】:2009-02-25 04:27:00
【问题描述】:

我正在编写一个注册 netfilter 钩子的内核模块。我正在尝试使用 sk_buff->saddr 成员获取调用者的 IP 地址。有没有办法以人类可读的方式获取 IP,即 x.x.x.x 格式?

我找到了函数inet_ntop(),但它似乎在内核头文件中不可用。如何将 \xC0\xA8\x00\x01 转换为 192.168.0.1 ?

【问题讨论】:

  • inet_ntop() 和它的兄弟 inet_pton() 实际上在 arpa/inet.h 中,我现在正在寻找内核实现。
  • 嗯,netfilter 的日志目标必须这样做......我会去那里看看。
  • &Rohit:说实话,如果你不知道如何格式化字符串中的字节,你可能不应该编写内核模块。先尝试一些用户空间的东西。
  • &Evan:我同意,但对此我无能为力。火洗礼是我的看法。

标签: c linux-kernel netfilter


【解决方案1】:

您应该使用 printk() 提供的 %pI4 扩展格式说明符:

printk(KERN_DEBUG "IP addres = %pI4\n", &local_ip);

【讨论】:

    【解决方案2】:

    include/linux/kernel.h中定义了两个宏

    用于 ipv4 地址的 NIPQUAD 和用于 ipv6 地址的 NIP6。

    #define NIPQUAD(addr) \
        ((unsigned char *)&addr)[0], \
        ((unsigned char *)&addr)[1], \
        ((unsigned char *)&addr)[2], \
        ((unsigned char *)&addr)[3]
    
    #define NIP6(addr) \
        ntohs((addr).s6_addr16[0]), \
        ntohs((addr).s6_addr16[1]), \
        ntohs((addr).s6_addr16[2]), \
        ntohs((addr).s6_addr16[3]), \
        ntohs((addr).s6_addr16[4]), \
        ntohs((addr).s6_addr16[5]), \
        ntohs((addr).s6_addr16[6]), \
        ntohs((addr).s6_addr16[7])
    

    内核源代码中有大量示例利用这些示例以人类可读的格式打印 IP 地址。例如:

    printk(KERN_DEBUG "Received packet from source address: %d.%d.%d.%d!\n",NIPQUAD(iph->saddr));
    

    希望这会有所帮助。

    【讨论】:

    • 我现在遇到了这个问题。为了其他可能偶然发现此问题的人的利益,NIPQUAD 在 2.6.38 之后已被删除。请改用%pI4
    • 后来遇到了这个。现在在 /net/core/utils.c 中有in4_pton()
    • @BonBon: in4_pton() 正好相反。
    【解决方案3】:

    printk 可以直接处理这个:

    IPv4 地址:

    %pI4    1.2.3.4
    %pi4    001.002.003.004
    %p[Ii]4[hnbl]
    
    For printing IPv4 dot-separated decimal addresses. The 'I4' and 'i4'
    specifiers result in a printed address with ('i4') or without ('I4')
    leading zeros.
    
    The additional 'h', 'n', 'b', and 'l' specifiers are used to specify
    host, network, big or little endian order addresses respectively. Where
    no specifier is provided the default network/big endian order is used.
    
    Passed by reference.
    

    IPv6 地址:

    %pI6    0001:0002:0003:0004:0005:0006:0007:0008
    %pi6    00010002000300040005000600070008
    %pI6c   1:2:3:4:5:6:7:8
    
    For printing IPv6 network-order 16-bit hex addresses. The 'I6' and 'i6'
    specifiers result in a printed address with ('I6') or without ('i6')
    colon-separators. Leading zeros are always used.
    
    The additional 'c' specifier can be used with the 'I' specifier to
    print a compressed IPv6 address as described by
    http://tools.ietf.org/html/rfc5952
    
    Passed by reference.
    

    参考:https://www.kernel.org/doc/Documentation/printk-formats.txt

    【讨论】:

      【解决方案4】:

      简单。出于某种原因,“x.x.x.x”格式的 IP 地址被称为 dotted-quad。每个数字代表一个字节,在您的地址中总共有 4 个字节。

      因此,使用 4 字节地址,您只需打印每个字节的十进制值。

      快速而肮脏的示例(将 printf 替换为您选择的输出函数):

      unsigned char *addr = (unsigned char*)sk_buff->addr;
      printf("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
      

      【讨论】:

        【解决方案5】:

        您可以使用strtol 将每个部分转换为整数形式。

        【讨论】:

        • 我几乎可以肯定存在一个可以做到这一点的宏,但我在 ATM 上找不到它。
        【解决方案6】:
        /* Convinience union to __be32 to ip address  */
        union ip_address {
            u8 a[4];
            __be32 saddr;
        };
        

        IP地址可以得到a[0].a[1].a[2].a[3]

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-20
          • 2021-11-14
          • 2010-12-30
          相关资源
          最近更新 更多