如何在 C 中实现 inet_pton()?
How to implement inet_pton() in C?
我正在做一个 IP header 解析和更改源 IP 地址...在我做一些如何使用 NIPQUAD
宏但不能正常工作之前我发现 inet_pton()
将字符串 IP 地址更改为网络字节顺序。我没看懂:
- 如何使用 uint_32 (unsigned int) 来保存 IP 地址?
- 这个函数如何将字符串 IP 转换为网络字节顺序?
- 如何显示 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;
}
我正在做一个 IP header 解析和更改源 IP 地址...在我做一些如何使用 NIPQUAD
宏但不能正常工作之前我发现 inet_pton()
将字符串 IP 地址更改为网络字节顺序。我没看懂:
- 如何使用 uint_32 (unsigned int) 来保存 IP 地址?
- 这个函数如何将字符串 IP 转换为网络字节顺序?
- 如何显示 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;
}