使用 Razor Pages 打造查看真实 IP、IPv6 检测网站系列文章:
碎碎念:上个月居然没写博客,没能把每个月至少一篇坚持下来😭这个月就多发点吧,吼吼吼~
背景
去年(2019年) IPv4 终于耗尽了,终于不用每隔一段时间就看到一次 IPv4 地址即将耗尽的新闻了🙄……
近几年越来越多的 app 启动画面带上了 IPv6 的标志,表示他们开始支持 IPv6 接入。
移动运营商也已经纷纷支持 IPv6,2019 年宣布 IPv4 耗尽那天,我试着用手机网络(辽宁联通)访问了 http://test-ipv6.com/ 发现手机移动网络已经分配到了 IPv6 地址,我还留有当时的截图:
不过当时家里的联通宽带是光猫拨号,公网 IP 分配给了光猫,路由器和网络里其他设备都是内网 IP,并且光猫似乎不支持 IPv6 下发,内网设备都没有分配到 IPv6 地址。进入光猫后台,用网上那些管理员密码等方式也无法连接、修改这个光猫的配置。给联通打电话要求改为路由器拨号的模式,装宽带的小哥推来推去,就是没让改,只能作罢。
然后时间就到了今年(2020年)8月,想把家里闲置的树莓派利用起来,于是想先做个 Web 站点吧,正好利用一下 IPv6 公网地址可以直接访问的特性,也省得内网穿透来穿透去了。于是又给联通打电话,10010 客服娴熟的让我报了个故障让装宽带小哥联系我,结果和去年还是同一个小哥打来电话,心里凉了一半,不过这次小哥很爽快的让我改成了路由器拨号……可能一年过去了,小哥业务水平得到了精进~于是,家里终于覆盖了 IPv6。
好,现在来访问一下 http://test-ipv6.com/ 网站,如果它显示出了“你的公网 IPv6 地址是 XXXX”,则说明你的网络支持 IPv6,否则说明不支持。
这期博客的内容就是要通过 ASP.NET Razor Page 来山寨一个能够显示访问者真实 IPv4 和 IPv6 的站点~如果能显示出 IPv6 地址就说明访问者的网络支持 IPv6。我的山寨版本在这里 https://ip.bun.plus/。
出于简单起见,本文主要是介绍 IPv6 和 Razor Page,显示样式不是重点,最终效果大概是这样:
当然,这两个版本的源代码都可以在我的 GitHub 上找到:
- https://ip.bun.plus/ 对应的是:https://github.com/huhubun/BunIp
- 本文使用的简单版对应:https://github.com/huhubun/BunIp/tree/simple_ver
为了完成山寨,我们会用到:
- IPv6 地址
- 如果想把最终网站发布,还需要有 IPv6 地址
- 如何为 IPv6 地址配置 nginx
- ASP.NET Razor Page
- 使用页面 Page 和模型 Page Model
- 使用 Razor Page 创建 Web API
- 跨域请求配置
- 使用视图组件 View Component
- 配置
appsettings.json
- 如何绑定多个地址进行调试
- 树莓派
- 在树莓派上安装 .NET 5 运行时
- 通过 C# 获取树莓派型号
这期文章内容实在太多,挣扎再三决定分为上中下三篇:
- 本篇为上篇,简单介绍 IPv6 和我们网站的设计思路
- 中篇介绍核心的获取 IP 的编码部分以及 nginx 的配置
- 下篇介绍 ASP.NET Core 视图组件的使用以及树莓派的专属彩蛋
简单了解 IPv6
在 Windows 我们可以通过 ipconfig
命令来查看当前的 IP 地址:
PS C:\Windows\System32> ipconfig
Windows IP 配置
以太网适配器 以太网:
连接特定的 DNS 后缀 . . . . . . . :
IPv6 地址 . . . . . . . . . . . . : 2408:832f:22a1:4310:29b5:1c68:38d9:a5a9
临时 IPv6 地址. . . . . . . . . . : 2408:832f:22a1:4310:9d6c:92ee:f2cd:a1c8
本地链接 IPv6 地址. . . . . . . . : fe80::29b5:1c68:38d9:a5a9%18
IPv4 地址 . . . . . . . . . . . . : 10.0.0.150
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : fe80::5aef:68ff:fe7b:3830%18
10.0.0.1
Linux 通过 ifconfig
查看:
pi@bunpi:~ $ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.0.20 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::30da:fd9b:c9e7:9ef9 prefixlen 64 scopeid 0x20<link>
inet6 2408:832f:22a0:56d0:a754:b831:3299:8a50 prefixlen 64 scopeid 0x0<global>
ether b8:27:eb:4c:22:fc txqueuelen 1000 (Ethernet)
RX packets 17579 bytes 5622398 (5.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2331 bytes 216594 (211.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
如果能看到诸如 2408:832f:22a1:4310:9d6c:92ee:f2cd:a1c8
这种包含冒号 :
的地址,说明你的电脑已经得到了 IPv6 地址。不过 IPv6 和 IPv4 一样,如果是内网地址则只能在内网中访问,无法通过公网访问:例如以 fe80
开头的地址就不能通过公网访问。
你可能会发现,test-ipv6 网站显示的 IPv6 地址和 IPv6 地址
后面的值不一样,这是因为 Windows 系统默认会获取到两个 IPv6 地址,对外通信时使用的是 临时 IPv6 地址
,所以 test-ipv6 只能得到临时 IPv6 地址。
另外我们熟悉的 IPv4 地址 127.0.0.1
在 IPv6 中为 0000:0000:0000:0000:0000:0000:0000:0001
,但是这么多 0
写起来很累也不好阅读,可以用两个冒号 ::
省略连续的 0
,所以可以缩写为 ::1
。
最后就是 ipconfig
的输出结果,有些 IPv6 地址后面带有 %18
这样的后缀,它表示网络接口(网卡)标识,可以用 route print
命令查看到,我这里的 %18
表示 Intel(R) Ethernet Connection (2) I219-V
这个网卡。
C:\Windows\System32> route print
===========================================================================
接口列表
5...00 15 5d cc 6f f7 ......Hyper-V Virtual Ethernet Adapter
18...4c cc 6a 24 81 c1 ......Intel(R) Ethernet Connection (2) I219-V
12...00 ff 68 6e 5d e8 ......Netease UU TAP-Win32 Adapter V9.21
27...00 ff f9 b1 0f 24 ......TAP-Windows Adapter V9
21...00 ff ce 62 2e f7 ......SVN Adapter V1.0
1...........................Software Loopback Interface 1
38...00 15 5d e3 b5 32 ......Hyper-V Virtual Ethernet Adapter #2
55...00 15 5d f2 d4 1c ......Hyper-V Virtual Ethernet Adapter #3
64...00 15 5d 8d 31 75 ......Hyper-V Virtual Ethernet Adapter #4
60...00 15 5d e3 1e aa ......Hyper-V Virtual Ethernet Adapter #5
===========================================================================
要想通过浏览器直接访问 IPv6 地址,直接使用中括号 []
包裹 IPv6 地址,例如访问本机的 80 端口,在浏览器地址栏中输入 [::1]:80
即可。和 IPv4 一样,最后的 :80
可以省略。
![通过浏览器访问 IPv6 地址](https://cdn.bun.plus/blog/2020/11/29/通过浏览器访问_IPv6 地址.png)
简单了解 ASP.NET Razor Pages
Razor Pages 是一种比 ASP.NET MVC 更便捷的页面开发方式。
- 在
Pages
文件夹下创建的 Razor 页面(对应后缀为.cshtml
),文件名与路由通过约定匹配 - 每个页面对应一个
PageModel
,可以理解成 MVC 的 ViewModel,页面可以直接访问到这个对象 - 可以在
PageModel
方法中响应 GET、POST 等动作
总之 Razor Pages 即可以使用 Razor 语法编写页面,也能用 C# 开发后台代码,但又不需要像 MVC 那样创建 Controller 和 View Model。
创建 Razor Pages 项目
我们直接创建一个 .NET 5 的 Razor Pages 应用:打开 Visual Studio - 创建新项目
- ASP.NET Core Web 应用程序
- 设置好项目名称和路径 - ASP.NET Core Web 应用
,这样就可以创建 Razor Page 应用了。
可以看到创建好的 Razor Page 应用的结构
具体的代码将在下一篇文章中介绍。
设计思路
首先我们需要明白,一个访问者可能有多个 IP 地址,比较常见的情况是拥有一个可以访问公网的 IPv4 地址和一个可以访问公网的 IPv6 地址;也可能只拥有 IPv4 地址,甚至拥有多个 IPv4 地址。
当我们访问一个网站时,操作系统和浏览器会根据一些配置,决定使用 IPv4 地址访问还是 IPv6 地址访问,以及如果有多个 IPv4 地址会使用哪个地址访问,想要说的是:在一个 HTTP 请求中,不会使用多个 IP 地址。所以如果拥有多个 IPv4 地址,我们只有可能获取到其中一个,多个 IPv6 也是同理。
因此,正常情况下,通过我们的网站最多只能获取到访问者的一个 IPv4 地址和一个 IPv6 地址。
获取发起请求时的真实 IP 地址的方案
要想获取到访问者的 IP 并非易事——网络上有很多的代理技术,访问者通过代理服务器访问网站,网站接收到的请求来自代理服务器,这样访问者的真实 IP 就被隐藏了。虽然有诸如 X-Forwarded-For
这样的请求头存在,但它可以伪造,不值得信赖。
简单起见,我们直接以服务器接收到的请求的发起方的 IP 地址作为真实 IP 地址,不考虑通过代理访问的情况。
并且因为一般不直接把部署在服务器上的站点直接暴露到公网,因此需要使用 nginx 反向代理我们的站点。nginx 为了能给请求者响应,必然知道请求者的 IP 信息,可以在 nginx 的配置中通过 $remote_addr
获取到。因此我们可以自定义一个名为 X-Real-IP
的头存放 $remote_addr
的值,并在 ASP.NET Razor Page 中获取即可。
当然,我们也需要兼顾本地调试,或者不想配置 nginx 而直接把程序暴露到公网上的情况。
获取其它 IP 地址的方案
如果访问者有多个 IP 地址,上一步只会获得其中一个(只会用一个地址去访问我们的网站),还需要想办法获取访问者的另一个 IP 地址:
- 如果访问者只拥有 IPv4 地址,那么只能访问 IPv4 地址,无法访问 IPv6 地址
- 如果访问者只拥有 IPv6 地址,那么只能访问 IPv6 地址,无法访问 IPv4 地址
- 如果访问者同时拥有 IPv4 和 IPv6 地址,那么 IPv4 地址和 IPv6 地址都可以访问
因此思路很简单:
- 第一步,我们需要有一个即拥有 IPv4 又拥有 IPv6 地址的网站,这样不论访问者拥有什么地址,都可以访问到我们网站的首页
- 第二步,我们还需要拥有一个只能通过 IPv4 访问的网站,以及一个只能通过 IPv6 访问的网站,这两个网站需要以 JSON 的形式返回请求者的 IP 地址
- 当访问者访问到第一步的网站首页后,可以立即知道访问者已经有 IPv4 或者 IPv6 地址,此时需要检查访问者是否还拥有其它的地址
- 如果访问者访问网站首页时使用的是 IPv4,那么通过 ajax 访问我们只能通过 IPv6 访问的网站
- 如果访问者访问网站首页时使用的是 IPv6,那么通过 ajax 访问我们只能通过 IPv4 访问的网站
- 最后,如果 ajax 得到成功的响应,则说明对应地址可以访问,将 ajax 获得的 IP 地址显示到页面上,否则说明访问者没有其它的地址了
也就是说,我们至少需要3个站点,以我的部署情况为例:
ip.bun.plus
既能通过 IPv4 访问,又能通过 IPv6 访问,对应第一步的网站首页ipv4.bun.plus
只能通过 IPv4 访问ipv6.bun.plus
只能通过 IPv6 访问
怎么才能使地址既能通过 IPv4 访问,又能通过 IPv6 访问呢。IPv4 对应 DNS 的 A记录,IPv6 对应 AAAA记录,我们只需要分别添加两条主机值一样,但记录类型不同的解析记录即可。添加好之后可以通过 nslookup
看到效果,返回多个 IP 结果即为成功。当然,域名解析这是后话了,现在不着急配置。
下集预告
好了,方案已经讲解结束,下一篇我们将使用 ASP.NET Razor Pages 开发我们的网站了,敬请期待。