【问题标题】:Converting network byte order IP to host byte order with ip4 format in kernel module在内核模块中使用 ip4 格式将网络字节顺序 IP 转换为主机字节顺序
【发布时间】:2023-03-11 23:50:02
【问题描述】:

我正在用 语言在 Arch Linux 中编写内核模块。我想将网络IP转换为ip4格式的主机IP:127.0.0.1

我知道在用户程序中可以使用这些功能:

inetntoa()
ntohs()
ntohl()

我尝试包含 socket.hin.h 等并使用以下函数,但它们都不适合我。

所以在内核模块中我无法访问这些函数。 内核模块中是否有此功能的替代品?

【问题讨论】:

    标签: c c networking module linux-kernel ip-address


    【解决方案1】:

    您可以访问ntohl() 和朋友。只需#include <linux/byteorder/generic.h>。 照常使用:

    __le32 le_ipaddr = ntohl(be_ipaddr); /* to flip big-endian IP to little-endian */
    

    您还可以通过 printk() 中的特殊格式说明符 %pI4 轻松打印 IPv4 地址,例如这样:

    __be32 ipaddr /*= gain from somewhere IP in network byte order (__be32 means big endian)*/;
    printk(KERN_INFO "Got IP: %pI4\n", &ipaddr); /* in network byte order */
    printk(KERN_INFO "Got IP: %pI4h\n", &ipaddr); /* in host byte order */
    

    另请阅读:

    IP-address from sk_buff

    How to get printk format specifiers right(来自 Kernel.org):

    通过引用传递。

    IPv4 地址

    ==============

    ::

    %pI4 1.2.3.4

    %pi4 001.002.003.004

    ...

    额外的 hnbl 说明符用于 指定主机、网络、大端或小端顺序地址 分别。如果没有提供说明符,则默认网络/大 使用 endian 顺序。

    ...

    通过引用传递。

    IPv6 地址

    ==============

    ::

    %pI6 0001:0002:0003:0004:0005:0006:0007:0008

    %pi6 00010002000300040005000600070008

    %pI6c 1:2:3:4:5:6:7:8


    附:您可以在 Linux 内核源代码中搜索您需要的功能,例如在本站:https://elixir.bootlin.com/linux/latest/ident/

    【讨论】:

      【解决方案2】:

      如果“网络 IP”是指代表 IPv4 的 32 位大端整数,您希望将其转换为点分十进制字符串表示,那么可以使用 sprintf() 完成。

      int32_t ipv4 = 1234567890; // random example
      
      unsigned char *ptr = (unsigned char *)&ipv4;
      char ipstr[16];
      sprintf(ipstr, "%d.%d.%d.%d", ptr[0], ptr[1],  ptr[2],  ptr[3]);
      

      ipstr 将包含带有 IP 地址的字符串。

      【讨论】:

      • 这可能会调用 UB 或至少取决于目标架构的字节序;更好的解决方案是使用算术将整数分成八位字节。
      • @Ctx 网络是跨架构的大端,没有风险。这就是函数htons()htonl()ntohs()ntohl() 存在的原因,它们在“主机字节序”之间转换为“网络字节序”,即大字节序。如果主机已经是大端,它们什么也不做。
      • 如果 ipv4 表示为整数并存储在整数变量中,它取决于机器的字节序。 IP 的整数表示形式定义明确且与平台无关,例如 127.0.0.1 是 2130706433。使用它而不是 1234567890 并编译您的程序大端和小端,您会得到不同的结果。
      • @Ctx 如果它来自套接字库,则不是。 Little-endian 机器只会错误地解释它。它始终存储在网络字节序(大字节序)中。
      • Endianess 是 cpu 架构的特性,而不是库的特性。你把事情搞混了,用不精确的术语混淆了自己或他人。术语“32 位大端整数”完全具有误导性,整数既不是大端也不是小端,但可以存储内存中的大端或小端。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      • 2013-10-23
      • 1970-01-01
      • 2015-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多