第6章 IP编址

所属:TCP/IP详解 卷2:实现 来源:TCP/IP详解 卷2:实现

本章描述内核中IP地址的表示和管理,包括接口地址结构、地址字节序、地址查找函数等。


6.1 引言

本章讨论的内容

本章讨论的内容:

  • 接口地址结构(in_ifaddr)
  • 地址的字节序
  • 接口地址工具函数
  • 多播地址管理

IP编址是网络栈的基础。


6.2 in_ifaddr结构

Internet接口地址结构

每个接口的每个IP地址对应一个in_ifaddr结构:

struct in_ifaddr {
    struct  ifaddr ia_ifa;      /* 通用接口地址结构 */
    struct  in_ifaddr *ia_next; /* 下一个Internet地址 */
    struct  in_addr ia_addr;    /* IP地址(网络字节序) */
    struct  in_addr ia_netmask; /* 子网掩码(网络字节序) */
    struct  in_addr ia_net;     /* 网络号(网络字节序) */
    struct  in_addr ia_subnet;  /* 子网号(网络字节序) */
    struct  in_addr ia_broadaddr; /* 广播地址(网络字节序) */
    struct  in_addr ia_dstaddr; /* 点对点目的地址 */
    /* ... 其他字段 ... */
};

结构说明

字段说明
ia_ifa通用接口地址结构(ifaddr),第一个成员
ia_next指向下一个in_ifaddr,所有地址链接成链表
ia_addr接口的IP地址
ia_netmask子网掩码
ia_net网络号(地址 & 掩码)
ia_subnet子网号
ia_broadaddr广播地址
ia_dstaddr点对点链路的对端地址

第一个成员是ifaddr,可以强制类型转换。


多地址支持

一个接口可以有多个IP地址:

  • 所有地址链接在ia_next链表中
  • 每个地址有自己的掩码、广播地址等
  • 用于虚拟主机、多网络等场景

全局链表:

  • 所有in_ifaddr结构链接在一个全局链表中
  • 用于全局地址查找
  • in_ifaddr链表头

一个接口多个地址,灵活支持各种场景。


6.3 地址的字节序

两种字节序

类型说明使用场景
网络字节序大端序(big-endian)网络传输、in_addr、sockaddr_in
主机字节序取决于CPU(x86是小端)内核变量、计算

为什么需要两种字节序:

  • 网络字节序:统一网络上的格式,不同CPU可以互通
  • 主机字节序:CPU原生格式,计算效率高

网络传输用网络字节序,本地计算用主机字节序。


转换函数

常用的转换函数:

函数说明
htonl主机到网络(long,32位)
htons主机到网络(short,16位)
ntohl网络到主机(long,32位)
ntohs网络到主机(short,16位)

使用场景:

  • 发送数据前:主机字节序 → 网络字节序
  • 接收数据后:网络字节序 → 主机字节序
  • 地址比较:统一用主机字节序

地址的存储方式

in_addr结构:

struct in_addr {
    u_long s_addr;  /* IP地址,网络字节序 */
};
  • 用于网络传输
  • 用于sockaddr_in
  • 按网络字节序存储

内核变量:

  • 通常用u_long类型
  • 按主机字节序存储
  • 方便计算和比较

地址按主机字节序以u_long变量存储,方便计算;in_addr和sockaddr_in按网络字节序存储,用于网络传输。


6.4 接口地址工具函数

常用的地址查找函数

函数功能
ifa_ifwithaddr精确匹配完整地址
ifa_ifwithdstaddr匹配点对点目的地址
ifa_ifwithnet匹配网络号
ifa_ifwithaf匹配地址族
ifaof_ifpforaddr找指定接口上最合适的地址
ifa_ifwithroute为路由找合适的地址
ifunit根据接口名字找接口结构

ifa_ifwithaddr

精确匹配地址:

struct ifaddr *
ifa_ifwithaddr(addr)
    struct sockaddr *addr;
{
    /*
     * 遍历所有接口的所有地址
     * 精确匹配
     */
}
  • 完全匹配整个地址
  • 用于判断地址是否是本机地址

ifa_ifwithnet

匹配网络号:

struct ifaddr *
ifa_ifwithnet(addr)
    struct sockaddr *addr;
{
    /*
     * 遍历所有接口的所有地址
     * 用掩码匹配网络号
     * 找最匹配的
     */
}
  • 用子网掩码匹配
  • 找在同一个网络的地址
  • 最长匹配优先

ifaof_ifpforaddr

指定接口上找最合适的地址:

struct ifaddr *
ifaof_ifpforaddr(addr, ifp)
    struct sockaddr *addr;
    struct ifnet *ifp;
{
    /*
     * 在指定接口的地址中找
     * 最匹配目标地址的
     */
}
  • 在指定接口上找
  • 用于选择源地址

查找优先级

地址查找的优先级:

  1. 精确匹配主机地址
  2. 匹配子网
  3. 匹配网络
  4. 默认地址

从具体到宽泛,找最匹配的。


6.5 多播地址

IP多播地址

D类地址:

  • 范围:224.0.0.0 - 239.255.255.255
  • 最高四位是1110
  • 用于多播通信

特殊多播地址:

  • 224.0.0.1:所有主机
  • 224.0.0.2:所有路由器
  • 224.0.0.0 - 224.0.0.255:链路本地,不转发

多播地址管理

每个接口维护多播地址列表:

  • ia_multiaddrs链表
  • 每个地址有引用计数
  • 多个进程可以加入同一个组

加入组:

  1. 应用调用setsockopt(IP_ADD_MEMBERSHIP)
  2. 内核检查是否已在列表中
  3. 不在则添加,引用计数=1
  4. 已在则引用计数+1
  5. 通知网卡加入多播组

离开组:

  1. 应用调用setsockopt(IP_DROP_MEMBERSHIP)
  2. 引用计数-1
  3. 计数为0时,从列表移除
  4. 通知网卡离开多播组

引用计数,支持多个进程加入同一组。


6.6 小结

in_ifaddr结构

  1. 结构定义

    • ia_ifa:通用接口地址
    • ia_next:链表指针
    • ia_addr:IP地址
    • ia_netmask:子网掩码
    • ia_broadaddr:广播地址
  2. 多地址支持

    • 一个接口多个地址
    • 全局链表管理
    • 灵活支持各种场景

地址字节序

  1. 两种字节序

    • 网络字节序:大端,用于传输
    • 主机字节序:CPU原生,用于计算
  2. 转换函数

    • htonl / htons:主机到网络
    • ntohl / ntohs:网络到主机
  3. 存储方式

    • in_addr:网络字节序
    • 内核变量:主机字节序

地址工具函数

  1. 查找函数

    • ifa_ifwithaddr:精确匹配
    • ifa_ifwithnet:网络匹配
    • ifaof_ifpforaddr:指定接口查找
    • ifunit:按名找接口
  2. 查找优先级

    • 主机地址 > 子网 > 网络 > 默认
    • 最长匹配优先

多播地址

  1. D类地址

    • 224.0.0.0 - 239.255.255.255
    • 用于多播通信
  2. 管理方式

    • 每个接口一个链表
    • 引用计数
    • 支持多进程加入

关键概念

  1. in_ifaddr

    • 接口IP地址结构
    • 包含地址、掩码、广播等
    • 一个接口可以有多个
  2. 字节序

    • 网络字节序 vs 主机字节序
    • 转换函数
    • 不同场景用不同格式
  3. 地址查找

    • 各种查找函数
    • 最长匹配优先
    • 从具体到宽泛
  4. 多播地址

    • D类地址
    • 链表管理
    • 引用计数

IP编址 in_ifaddr