如何在 C 中实现 inet_pton()?

How to implement inet_pton() in C?

我正在做一个 IP header 解析和更改源 IP 地址...在我做一些如何使用 NIPQUAD 宏但不能正常工作之前我发现 inet_pton()将字符串 IP 地址更改为网络字节顺序。我没看懂:

NIPQUAD宏:

// use printf("%d.%d.%d.%d",NIPQUAD(iphdr->saddr));
#define NIPQUAD(addr) \
    ((unsigned char *)&addr)[0], \
    ((unsigned char *)&addr)[1], \
    ((unsigned char *)&addr)[2], \
    ((unsigned char *)&addr)[3]

how uint_32 (unsigned int) is being used to hold IP address?

IP 地址只是 0 到 255 之间的 4 个数字,即 4 个字节。它非常适合 uint32_t:

1.2.3.4       -> 0x01020304
127.0.0.1     -> 0x7F000001
192.168.10.20 -> 0xC0A80A14

在 C 中,如果您的机器是 big endian,这将类似于:

uint32_t addr;
uint8_t *tmp = (uint8_t *)&addr;

tmp[0] = 192;
tmp[1] = 168;
tmp[2] = 10;
tmp[3] = 20;

而如果是little endian则需要将IP的4个字节以相反的顺序分配以具有相同的值。 Endianness 可以使用编译器指令或进行运行时检查(第一个选项几乎总是被使用的选项)进行检查。

how this fuction is converting from string IP to network byte order?

inet_pton 只是将字符串中的每个数字转换为一个字节,然后像我上面显示的那样组成最终值。这可以通过使用 strtok 或类似函数在各个点 (.) 上拆分字符串来完成。由于网络顺序意味着 big endian,您的最终结果将始终是 big endian,因此无需交换任何东西。


网上有几种inet_pton()的实现,这里有两种:

事实证明,这两个实现都没有使用 strtok()atoi()strtol() 或任何类似的函数,相反,它们只是一次一个字符地手动解析字符串.转换是逐个字符完成的。

我想你得到了另一个答案,这里是实现部分:

how this fuction is converting from string IP to network byte order? I would appreciate if anyone provide code.


int inet_pton(int af, const char *restrict s, void *restrict a0)
{
    uint16_t ip[8];
    unsigned char *a = a0;
    int i, j, v, d, brk=-1, need_v4=0;

    if (af==AF_INET) {
        for (i=0; i<4; i++) {
            for (v=j=0; j<3 && isdigit(s[j]); j++)
                v = 10*v + s[j]-'0';
            if (j==0 || (j>1 && s[0]=='0') || v>255) return 0;
            a[i] = v;
            if (s[j]==0 && i==3) return 1;
            if (s[j]!='.') return 0;
            s += j+1;
        }
        return 0;
    } else if (af!=AF_INET6) {
        errno = EAFNOSUPPORT;
        return -1;
    }

    if (*s==':' && *++s!=':') return 0;

    for (i=0; ; i++) {
        if (s[0]==':' && brk<0) {
            brk=i;
            ip[i&7]=0;
            if (!*++s) break;
            if (i==7) return 0;
            continue;
        }
        for (v=j=0; j<4 && (d=hexval(s[j]))>=0; j++)
            v=16*v+d;
        if (j==0) return 0;
        ip[i&7] = v;
        if (!s[j] && (brk>=0 || i==7)) break;
        if (i==7) return 0;
        if (s[j]!=':') {
            if (s[j]!='.' || (i<6 && brk<0)) return 0;
            need_v4=1;
            i++;
            break;
        }
        s += j+1;
    }
    if (brk>=0) {
        memmove(ip+brk+7-i, ip+brk, 2*(i+1-brk));
        for (j=0; j<7-i; j++) ip[brk+j] = 0;
    }
    for (j=0; j<8; j++) {
        *a++ = ip[j]>>8;
        *a++ = ip[j];
    }
    if (need_v4 && inet_pton(AF_INET, (void *)s, a-4) <= 0) return 0;
    return 1;
}