我们最近的一个需求是用openresty替换线上的nginx,而线上nginx是开启了支持ipv6的。那么我们openresty也需要在开发环境测试,看看能不能支持ipv6.
nginx怎么支持Ipv6呢,一般在配置文件进行如下配置:
server {
listen 8008;
listen [::]:8008;
server_name xxx;
...
}
即新增一行listen,地址为[::]:端口即可。
我们在openresty也做了同样配置。接下来就是看看怎么测试了。在测试之前,先了解一些ipv6基础知识。
参考了:https://mp.weixin.qq.com/s/dNfvoukfAYRd70NTiDauig
IPv4的地址一般写成数字+点的形式,实际上是32位的二进制数字,每8位二进制数字用一个点隔开。
IPv6是128位二进制数字,每16位二进制数字为一组,用冒号隔开。每16位二进制,又可以分为4组,每1组可以用一个十六进制的数字代替,如:240e:360:2600:ce74:b8b5:240:635:2444。
如果在某两个冒号之间全部都是0,那么这一部分可以缩写成2个冒号。
比如我这边一台服务器的ip是:fe80::250:56ff:fe93:15a2。
文章里提到,只能有一部分可以缩写。
image-20230608161530230
重点看下图的单播地址。
img
单播可分为:全球单播地址(可理解为公网地址---IPv6)、本地链路地址、站点本地地址、回环地址、未指定地址、内嵌IPv4地址。
公网地址是比较难拿到的,我的腾讯云轻量服务器也是不支持ipv6.只有非轻量服务器才支持ipv6地址,而且也很麻烦。
局域网地址不是正式名称,不过我们不细究也没啥。
以fc,fd开头的,这些地址就类似于IPv4的192.168这一类的局域网地址,只能在局域网中进行通讯。
局域网IPv6地址可以被路由,可以跨路由器通讯,而链路本地地址不行。
以fe80开头的这类地址,不是真的可用于互联网通信的ipv6地址,叫**Link-local Address(链路本地地址)**,只能在同一个二层的情况下使用,简单来说,就是只能在同一个交换机相连的情况下才能使用这个地址进行通讯,也就是说,如果两个服务器跨了网段,那就不能用这种地址来通讯。
生成规则如下:
image-20230608162308634
后面的64位,根据以下规则生成:
“例如:MAC地址为0012:3400:ABCD; 首先把MAC地址对半分开,得到
0012:34
,在此插入一个固定值FFFE,再拼接后边部分00:ABCD
; 0012:3400:ABCD ----> 0012:34FF:FE00:ABCD; 再把第七位翻转:0----> 1, 1---->0 0012:34FF:FE00:ABCD ----> 0212:34FF:FE00:ABCD ”
具体可以参考:https://baijiahao.baidu.com/s?id=1736787745342947999
只要你开启了IPv6功能,主机就会自己配置IPv6的链路本地地址,根本不需要路由器进行分配。很多人看到有fe80这个地址,就误认为自己获得了IPv6,这是误区。
类似于IPv4的127.0.0.1,IPv6的本机地址是::1,只能在本机进行通讯,比如你在本机搭建了一个网站,在浏览器上,可以用这个地址来进行测试。
[root@server172 ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
3: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:93:15:a2 brd ff:ff:ff:ff:ff:ff
inet 192.168.11.172/24 brd 192.168.11.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe93:15a2/64 scope link
inet6后面的fe80::250:56ff:fe93:f5c3就是该服务器的链路本地地址
[root@server172 ~]# ping6 ::1
PING ::1(::1) 56 data bytes
64 bytes from ::1: icmp_seq=1 ttl=64 time=0.048 ms
64 bytes from ::1: icmp_seq=2 ttl=64 time=0.049 ms
需指定网卡才能ping通
ping6 -I ens33 fe80::250:56ff:fe93:15a2
PING fe80::250:56ff:fe93:15a2(fe80::250:56ff:fe93:15a2) from fe80::250:56ff:fe93:15a2%ens33 ens33: 56 data bytes
64 bytes from fe80::250:56ff:fe93:15a2%ens33: icmp_seq=1 ttl=64 time=0.045 ms
或
ping6 fe80::250:56ff:fe93:15a2%ens33
PING fe80::250:56ff:fe93:15a2%ens33(fe80::250:56ff:fe93:15a2%ens33) 56 data bytes
64 bytes from fe80::250:56ff:fe93:15a2%ens33: icmp_seq=1 ttl=64 time=0.018 ms
64 bytes from fe80::250:56ff:fe93:15a2%ens33: icmp_seq=2 ttl=64 time=0.040 ms
[root@server172 ~]# telnet ::1 8008
Trying ::1...
Connected to ::1.
Escape character is '^]'.
需加网卡号
[root@server172 ~]# telnet fe80::250:56ff:fe93:15a2%ens33 8008
Trying fe80::250:56ff:fe93:15a2%ens33...
Connected to fe80::250:56ff:fe93:15a2%ens33.
Escape character is '^]'.
检查是否支持ipv6
[root@server172 ~]# curl -V|grep IPv6
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz unix-sockets
如果测试有问题,考虑是否是版本问题
https://www.cnblogs.com/XY-Heruo/p/17100085.html
[root@server172 ~]# curl -6 -g [::1]:8008
image-20230608155925333
要使用link-local地址访问本机服务,我发现还需要指定网卡才行。
image-20230608164556108
因为要访问的服务在本机,所以网卡要指定lo,我试了其他网卡,都报错。
curl -6 -g --interface lo http://[fe80::250:56ff:fe93:15a2]:8008
大概意思是,要指定从那个网卡把ping包发出去,为啥需要这样呢?
man ping,查看-I选项发现,说ping那种link-local地址时,就是需要这样做:
image-20230608152557226
网上找了个文章(https://www.zhihu.com/question/553118543/answer/2674456281):
“fe80::1/10不是回环IP地址,而是不需要配置的局域网IP地址。换句话说是一个局域网内启用了IPv6的主机互相通信的IP地址。在没有配置IPv6地址也没有DHCP6分配地址的时候,每个主机(准确说是每个网卡)把自己的MAC地址扩到64位,放到fe80::的后64位,因为MAC地址是唯一的,fe80的地址也就是唯一的,于是局域网内就可以互相通信了。 但是假设你有2个网卡,都启用了IPv6,现在你要给局域网一个地址为fe80::1122:3344:5566的主机发送报文(不是你本地IPv6地址。48位MAC用EUI扩展转换成64位IPv6主机号不这么简单,这里简化了)。但是如果你只给出这个目标IPv6地址,操作系统不知道应该从哪个网卡发出,因为两个网卡都在fe80::/64的段里面,但是很可能不是在同一个局域网里面。操作系统也不能假设ARP缓存里面有这个地址,或者缓存里面就是你想要的目标主机。这时候就得用"%数字"或者"%设备"告诉操作系统,你是想从哪个网卡给这个IPv6地址发送报文。这个%后的数字或者网络设备名叫做Scope ID,对应到具体的网卡。 IPv6的回环是0::1/128 ”
我这边有两台服务器,两台服务器正好是在同一个局域网内,其ipv6地址如下:
192.168.1.172 fe80::250:56ff:fe93:15a2
192.168.1.171 fe80::250:56ff:fe93:f5c3
在172机器上,ping 171(注意,使用ping6):
[root@server172 ~]# ping6 -I ens33 fe80::250:56ff:fe93:f5c3
image-20230608152005277
现在两台机器已经可以ping通了,但是,想看看具体的网络报文怎么办呢?
我们使用tcpdump来抓包看看。
在172机器上,ping 171机器(fe80::250:56ff:fe93:f5c3):
[root@server172 ~]# ping6 -I ens33 fe80::250:56ff:fe93:f5c3
PING fe80::250:56ff:fe93:f5c3(fe80::250:56ff:fe93:f5c3) from fe80::250:56ff:fe93:15a2%ens33 ens33: 56 data bytes
64 bytes from fe80::250:56ff:fe93:f5c3%ens33: icmp_seq=1 ttl=64 time=0.104 ms
64 bytes from fe80::250:56ff:fe93:f5c3%ens33: icmp_seq=2 ttl=64 time=0.923 ms
同时,我们在171机器,开启抓包(等几秒后ctrl c中断抓包):
root@server171:~# tcpdump -i eth0 host fe80::250:56ff:fe93:15a2 -w ping.pcap
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
^C4 packets captured
38 packets received by filter
0 packets dropped by kernel
wireshark查看包:
image-20230608154533658
在171机器上先打开抓包:
tcpdump -i eth0 host fe80::250:56ff:fe93:15a2 -w telnet.pcap
然后复制一个shell出来,执行telnet:
root@server171:~# telnet fe80::250:56ff:fe93:15a2%eth0 8008
Trying fe80::250:56ff:fe93:15a2%eth0...
Connected to fe80::250:56ff:fe93:15a2%eth0.
Escape character is '^]'.
^CConnection closed by foreign host.
然后ctrl + c,中断抓包。
查看包:
image-20230608173513109
可以看到,ip层是ipv6。
本来上面的实验一直好好的,但是在进行curl跨主机使用link-local地址访问一直有问题。
版本用得是这个:
root@server171:~# /usr/bin/curl-bak -V
curl 7.35.0 (x86_64-pc-linux-gnu) libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP
然后想着要不升级个版本试试:
https://github.com/moparisthebest/static-curl/releases,下载了curl-386版本。
执行:
root@server171:~# ./curl-i386 -6 -g -v --interface eth0 "http://[fe80::250:56ff:fe93:15a2]:8008"
果然ok了:
image-20230608175028171
这块是参考了文档:
https://www.cnblogs.com/XY-Heruo/p/17100085.html
https://blog.csdn.net/bestjie01/article/details/106326522
tcpdump -i any host fe80::250:56ff:fe93:15a2 -w curl.pcap
image-20230608175520966
server {
listen 8008;
#listen [::]:8008;
server_name localhost;
image-20230608175906134
测试结束。