Linux内核中网络地址相关的工具函数Linux内核提供了丰富的网络地址处理函数主要用于协议栈内部和内核模块开发。以下是内核中可用的网络地址工具函数分类介绍。一、地址转换函数1.1 字符串与二进制转换核心函数#includelinux/inet.h#includelinux/socket.h#includenet/ipv6.h// IPv4地址转换 // 字符串转二进制点分十进制 - 网络字节序32位整数intin4_pton(constchar*src,intsrclen,u8*dst,intdelim,constchar**end);// 返回值1成功0失败// srclen: 字符串长度0表示自动检测// delim: 分隔符通常为.0表示无分隔符// 二进制转字符串网络字节序32位整数 - 点分十进制intin4_ntop(__be32 addr,char*buf,intbuflen);// 或使用辅助函数char*ip4_string(unsignedchar*addr,char*buf,intbuflen);// IPv6地址转换 // 字符串转二进制intin6_pton(constchar*src,intsrclen,u8*dst,intdelim,constchar**end);// 二进制转字符串intin6_ntop(conststructin6_addr*addr,char*buf,intbuflen);实际使用示例#includelinux/inet.h// IPv4地址转换voidconvert_ipv4(void){__be32 addr;charbuf[INET_ADDRSTRLEN];// 字符串 - 二进制if(in4_pton(192.168.1.100,-1,(u8*)addr,.,NULL)){printk(Converted to 0x%x\n,addr);}// 二进制 - 字符串addrhtonl(0xC0A80164);// 192.168.1.100in4_ntop(addr,buf,sizeof(buf));printk(IP: %s\n,buf);}// IPv6地址转换voidconvert_ipv6(void){structin6_addraddr;charbuf[INET6_ADDRSTRLEN];// 字符串 - 二进制if(in6_pton(2001:db8::1,-1,addr.s6_addr,:,NULL)){// 使用地址}// 二进制 - 字符串in6_ntop(addr,buf,sizeof(buf));printk(IPv6: %s\n,buf);}二、地址类型判断函数2.1 IPv4地址类型判断#includelinux/ip.h// 判断地址类型boolipv4_is_loopback(__be32 addr);// 环回地址 (127.0.0.0/8)boolipv4_is_multicast(__be32 addr);// 组播地址 (224.0.0.0/4)boolipv4_is_local_multicast(__be32 addr);// 本地组播 (224.0.0.0/24)boolipv4_is_lbcast(__be32 addr);// 链路层广播boolipv4_is_zeronet(__be32 addr);// 零网络 (0.0.0.0/8)boolipv4_is_private_10(__be32 addr);// 私有地址 10.0.0.0/8boolipv4_is_private_172(__be32 addr);// 私有地址 172.16.0.0/12boolipv4_is_private_192(__be32 addr);// 私有地址 192.168.0.0/16// 通用私有地址判断boolipv4_is_private(__be32 addr);实际使用示例#includelinux/ip.hvoidcheck_address_type(__be32 addr){if(ipv4_is_multicast(addr)){printk(Multicast address\n);}elseif(ipv4_is_loopback(addr)){printk(Loopback address\n);}elseif(ipv4_is_private(addr)){printk(Private address\n);}elseif(ipv4_is_lbcast(addr)){printk(Limited broadcast\n);}}2.2 IPv6地址类型判断内核核心函数#includenet/ipv6.h// IPv6地址类型判断核心函数int__ipv6_addr_type(conststructin6_addr*addr);// 返回的地址类型标志定义在 include/net/ipv6.h// IPV6_ADDR_ANY - 未指定地址 (::)// IPV6_ADDR_LOOPBACK - 环回地址 (::1)// IPV6_ADDR_MULTICAST - 组播地址// IPV6_ADDR_LINKLOCAL - 链路本地地址 (fe80::/10)// IPV6_ADDR_SITELOCAL - 站点本地地址 (fec0::/10已弃用)// IPV6_ADDR_UNICAST - 单播地址// IPV6_ADDR_MAPPED - IPv4映射地址 (::ffff:0:0/96)// IPV6_ADDR_COMPATv4 - 兼容IPv4地址 (::/96)// 便捷判断宏#defineipv6_addr_type(addr)__ipv6_addr_type(addr)#defineipv6_addr_any(addr)\(ipv6_addr_type(addr)IPV6_ADDR_ANY)#defineipv6_addr_loopback(addr)\(ipv6_addr_type(addr)IPV6_ADDR_LOOPBACK)#defineipv6_addr_multicast(addr)\(!!(ipv6_addr_type(addr)IPV6_ADDR_MULTICAST))#defineipv6_addr_linklocal(addr)\(!!(ipv6_addr_type(addr)IPV6_ADDR_LINKLOCAL))实际使用示例#includenet/ipv6.hvoidcheck_ipv6_address_type(structin6_addr*addr){inttypeipv6_addr_type(addr);if(typeIPV6_ADDR_MULTICAST){printk(IPv6 multicast address\n);if(typeIPV6_ADDR_LINKLOCAL){printk( Link-local scope\n);}}elseif(typeIPV6_ADDR_LOOPBACK){printk(IPv6 loopback address\n);}elseif(typeIPV6_ADDR_LINKLOCAL){printk(IPv6 link-local address\n);}elseif(typeIPV6_ADDR_MAPPED){printk(IPv4-mapped IPv6 address\n);}}三、地址操作函数3.1 地址比较函数#includenet/ipv6.h#includelinux/ip.h// IPv4地址比较staticinlineboolipv4_addr_equal(__be32 a1,__be32 a2){returna1a2;}// IPv6地址比较高效实现staticinlineboolipv6_addr_equal(conststructin6_addr*a1,conststructin6_addr*a2){return(a1-s6_addr32[0]a2-s6_addr32[0]a1-s6_addr32[1]a2-s6_addr32[1]a1-s6_addr32[2]a2-s6_addr32[2]a1-s6_addr32[3]a2-s6_addr32[3]);}// 带掩码的地址比较boolipv6_addr_equal_with_mask(conststructin6_addr*a1,conststructin6_addr*a2,unsignedintprefix_len);3.2 地址复制和初始化#includenet/ipv6.h// IPv6地址复制staticinlinevoidipv6_addr_copy(structin6_addr*dst,conststructin6_addr*src){dst-s6_addr32[0]src-s6_addr32[0];dst-s6_addr32[1]src-s6_addr32[1];dst-s6_addr32[2]src-s6_addr32[2];dst-s6_addr32[3]src-s6_addr32[3];}// IPv6地址设置为任意地址::staticinlinevoidipv6_addr_set_any(structin6_addr*addr){addr-s6_addr32[0]0;addr-s6_addr32[1]0;addr-s6_addr32[2]0;addr-s6_addr32[3]0;}// IPv6地址设置为环回地址::1staticinlinevoidipv6_addr_set_loopback(structin6_addr*addr){addr-s6_addr32[0]0;addr-s6_addr32[1]0;addr-s6_addr32[2]0;addr-s6_addr32[3]htonl(1);}3.3 地址作用域判断#includenet/ipv6.h// IPv6地址作用域// IPV6_ADDR_SCOPE_NODELOCAL - 节点本地// IPV6_ADDR_SCOPE_LINKLOCAL - 链路本地// IPV6_ADDR_SCOPE_SITELOCAL - 站点本地// IPV6_ADDR_SCOPE_GLOBAL - 全局intipv6_addr_scope(conststructin6_addr*addr);四、网络字节序与主机字节序转换4.1 基本字节序函数#includelinux/byteorder/generic.h// 主机字节序 - 网络字节序__be16htons(uint16_thost);__be32htonl(uint32_thost);__be64htonll(uint64_thost);// 64位版本// 网络字节序 - 主机字节序uint16_tntohs(__be16 net);uint32_tntohl(__be32 net);uint64_tntohll(__be64 net);// 通用宏根据CPU架构自动优化#definecpu_to_be16(x)htons(x)#definecpu_to_be32(x)htonl(x)#definebe16_to_cpu(x)ntohs(x)#definebe32_to_cpu(x)ntohl(x)4.2 地址常量定义#includelinux/in.h// IPv4特殊地址常量#defineINADDR_ANY0x00000000// 0.0.0.0#defineINADDR_LOOPBACK0x7f000001// 127.0.0.1#defineINADDR_BROADCAST0xffffffff// 255.255.255.255#defineINADDR_NONE0xffffffff// 无效地址// IPv6特殊地址定义在 net/ipv6.hexternconststructin6_addrin6addr_any;// ::externconststructin6_addrin6addr_loopback;// ::1五、地址前缀和掩码操作5.1 IPv4掩码函数#includelinux/ip.h// 根据前缀长度生成掩码staticinline__be32ipv4_prefix_mask(unsignedintprefix_len){if(prefix_len0)return0;if(prefix_len32)returnhtonl(0xFFFFFFFF);returnhtonl(0xFFFFFFFF(32-prefix_len));}// 获取网络地址地址 掩码staticinline__be32ipv4_net_addr(__be32 addr,__be32 mask){returnaddrmask;}5.2 IPv6前缀操作#includenet/ipv6.h// IPv6前缀匹配staticinlineboolipv6_prefix_equal(conststructin6_addr*a1,conststructin6_addr*a2,unsignedintprefix_len){// 按32位字比较if(prefix_len32){if(a1-s6_addr32[0]!a2-s6_addr32[0])returnfalse;prefix_len-32;}else{__be32 maskhtonl(~((1(32-prefix_len))-1));if((a1-s6_addr32[0]mask)!(a2-s6_addr32[0]mask))returnfalse;returntrue;}// 继续比较剩余部分...}六、实用地址处理函数6.1 获取地址族字符串#includelinux/socket.hconstchar*sockaddr_family_name(intfamily){switch(family){caseAF_INET:returnAF_INET;caseAF_INET6:returnAF_INET6;caseAF_UNIX:returnAF_UNIX;default:returnUNKNOWN;}}6.2 地址结构初始化#includelinux/in.h#includenet/ipv6.h// 初始化IPv4地址结构staticinlinevoidinit_ipv4_addr(structsockaddr_in*sin,__be32 addr,__be16 port){sin-sin_familyAF_INET;sin-sin_addr.s_addraddr;sin-sin_portport;}// 初始化IPv6地址结构staticinlinevoidinit_ipv6_addr(structsockaddr_in6*sin6,conststructin6_addr*addr,__be16 port){sin6-sin6_familyAF_INET6;sin6-sin6_addr*addr;sin6-sin6_portport;sin6-sin6_flowinfo0;sin6-sin6_scope_id0;}七、完整的实际使用示例7.1 网络驱动中的地址处理#includelinux/inet.h#includelinux/ip.h#includenet/ipv6.hstructmy_netdev_stats{u64 rx_bytes;u64 rx_packets;__be32 local_ip;structin6_addrlocal_ipv6;};// 处理接收到的数据包提取源地址voidrx_packet_handler(structsk_buff*skb,structmy_netdev_stats*stats){structiphdr*ipv4_hdr;structipv6hdr*ipv6_hdr;if(ip_hdr(skb)-version4){ipv4_hdrip_hdr(skb);// 检查是否是发往本机的包if(ipv4_addr_equal(ipv4_hdr-daddr,stats-local_ip)){stats-rx_packets;stats-rx_bytesskb-len;}}elseif(ip_hdr(skb)-version6){ipv6_hdripv6_hdr(skb);// 检查IPv6地址类型if(ipv6_addr_type(ipv6_hdr-daddr)IPV6_ADDR_LINKLOCAL){// 处理链路本地地址stats-rx_packets;stats-rx_bytesskb-len;}}}7.2 地址配置管理// 配置网络接口的IP地址intconfigure_ip_address(structnet_device*dev,constchar*ip_str){structin_device*in_dev;structin_ifaddr*ifa;__be32 addr;// 转换字符串地址if(!in4_pton(ip_str,-1,(u8*)addr,.,NULL)){printk(KERN_ERRInvalid IP address: %s\n,ip_str);return-EINVAL;}// 获取接口的in_device结构in_devin_dev_get(dev);if(!in_dev)return-ENODEV;// 检查是否是私有地址if(ipv4_is_private(addr)){printk(KERN_INFOConfiguring private address\n);}elseif(ipv4_is_multicast(addr)){printk(KERN_WARNINGCannot configure multicast address\n);in_dev_put(in_dev);return-EINVAL;}// 添加地址到接口简化示例ifainet_alloc_ifa();if(!ifa){in_dev_put(in_dev);return-ENOMEM;}ifa-ifa_addressaddr;ifa-ifa_maskipv4_prefix_mask(24);// 255.255.255.0ifa-ifa_localaddr;ifa-ifa_devin_dev;inet_insert_ifa(ifa);in_dev_put(in_dev);return0;}7.3 地址打印调试#includelinux/skbuff.h#includenet/ip.hvoidprint_packet_address(structsk_buff*skb){structiphdr*ip4;structipv6hdr*ip6;charsrc_str[INET6_ADDRSTRLEN];chardst_str[INET6_ADDRSTRLEN];switch(skb-protocol){casehtons(ETH_P_IP):ip4ip_hdr(skb);in4_ntop(ip4-saddr,src_str,sizeof(src_str));in4_ntop(ip4-daddr,dst_str,sizeof(dst_str));printk(IPv4: %s - %s\n,src_str,dst_str);break;casehtons(ETH_P_IPV6):ip6ipv6_hdr(skb);in6_ntop(ip6-saddr,src_str,sizeof(src_str));in6_ntop(ip6-daddr,dst_str,sizeof(dst_str));// 同时打印地址类型if(ipv6_addr_type(ip6-saddr)IPV6_ADDR_LINKLOCAL){printk(IPv6 (link-local): %s - %s\n,src_str,dst_str);}else{printk(IPv6: %s - %s\n,src_str,dst_str);}break;}}八、相关头文件总结头文件主要内容linux/inet.hin4_pton、in4_ntop、in6_pton、in6_ntoplinux/ip.hIPv4地址判断函数、掩码操作net/ipv6.hIPv6地址类型判断、比较、复制函数linux/byteorder/generic.h字节序转换函数linux/in.hIPv4地址常量、struct in_addrlinux/socket.h地址族定义、struct sockaddr九、注意事项字节序内核中网络地址通常使用网络字节序__be32转换时注意使用htonl/ntohl线程安全与用户态inet_ntoa不同内核的in4_ntop/in6_ntop需要调用者提供缓冲区因此是线程安全的性能考虑在数据平面如软中断中避免频繁调用地址转换函数尽量使用二进制形式IPv6作用域处理IPv6链路本地地址时需要正确设置sin6_scope_idRCU保护访问接口地址列表时需要使用RCU读锁保护以上函数是Linux内核网络协议栈的核心工具函数可用于内核模块开发、网络驱动实现、防火墙规则处理等场景。