我正在编写一个注册 netfilter 钩子的内核模块。我正在尝试通过使用sk_buff->saddr
成员来获取调用者的 IP 地址。有没有办法以人类可读的 iexxxx 格式获取 IP?
我找到了这个函数inet_ntop()
,但它似乎在内核头文件中不可用。如何将 \xC0\xA8\x00\x01 转换为 192.168.0.1 ?
我正在编写一个注册 netfilter 钩子的内核模块。我正在尝试通过使用sk_buff->saddr
成员来获取调用者的 IP 地址。有没有办法以人类可读的 iexxxx 格式获取 IP?
我找到了这个函数inet_ntop()
,但它似乎在内核头文件中不可用。如何将 \xC0\xA8\x00\x01 转换为 192.168.0.1 ?
您应该使用 printk() 提供的 %pI4 扩展格式说明符:
printk(KERN_DEBUG "IP addres = %pI4\n", &local_ip);
include/linux/kernel.h 中定义了两个宏
NIPQUAD 用于 ipv4 地址, NIP6 用于 ipv6 地址。
#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));
希望这可以帮助。
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
简单的。“xxxx”格式的 IP 地址被称为点分四线是有原因的。每个数字代表一个字节,地址中总共有 4 个字节。
因此,使用 4 字节地址,您只需打印每个字节的十进制值。
快速而肮脏的示例(将 printf 替换为您选择的输出函数):
unsigned char *addr = (unsigned char*)sk_buff->addr;
printf("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
您可以使用strtol将每个部分转换为整数形式。
/* Convinience union to __be32 to ip address */
union ip_address {
u8 a[4];
__be32 saddr;
};
IP地址可以得到a[0].a[1].a[2].a[3]