note/network

网络常识

对于网络我其实是一知半解,这篇文章基本上是我知道什么就写些什么,因此十分零碎。

协议

传输协议有好几层,这些层级环环相扣,物理层我们就不说了。

底层是 IP;
往上是 TCP 或 UDP;
再往上是 可选的 传输加密层 TLS;
最后是 HTTP、FTP、WebSocket、socks、 Shadowsocks 或 VMESS 等。

传输层一般来说有 TCP 和 UDP 两种选择。TCP 会建立连接,并且提供不错的校验纠错功能,而代价就是减小了数据位占比。而 UDP 则是一种无连接的传输层协议。现在还有一些新兴的类传输层协议,如 KCP,他们一般运行在 UDP 之上,提供比 UDP 好的数据校验,比 TCP 高的传输效率。

TLS 层是用来加密的,如 HTTP 协议之下没有 TLS 层,是明文传输的。有些顶层协议如 socks Shadowsocks VMESS 已经自带加密了,一般用不着 TLS 层。

VMESS 是一种宽泛的协议,不管前几层是什么都叫 VMESS。而 Shadowsocks socks HTTP 下面没有 TLS 层,第二层必须是 TCP。有了 TLS 后 HTTP 就不叫 HTTP 了,改叫 HTTPS。

关于 TLS 为什么要找第三方签发证书:

https://flyhigher.top/develop/1093.html

简单来说就是普通的非对称加密在传输密钥方面有漏洞,容易遭受中间人攻击(MITM Attack)。

IP 、域名以及 DNS

IP 是一台计算机在网络上的唯一识别码,有 IPv4 和 IPv6 两个版本。IPv4 地址为一串 32 位的数字,标准的表示方法为每 8 位用一个 0~255 的十进制数表示,中间用 . 分开,如 123.123.123.123。如你所见,只有 32 位的 IPv4 可以分配的 IP 地址十分有限。随着接入互联网的计算机增多,IPv4 已经接近枯竭。为了解决这个问题,多数网络运营商给普通用户分配的 IPv4 地址为动态地址。

于是人们又提出了 IPv6。IPv6 地址为一串 128 位的数字,标准的表示方法是每 16 位用一个 0x0000~0xffff 的十六进制数表示,中间用 : 分开,如 6553:d35f:d35f:189c:1846:beef:dad1:5658

有一些特殊的 IP 是需要记住的,127.0.0.1 代指本机,host 在这个 IP 上的程序只有本机可以访问;0.0.0.0 也代指本机,不过 host 在这里的程序其他机器也是可以访问的;192.168.1.* 常常是局域网里各台机器的 IP。

域名

很早期的互联网是用来一对一通信的(虽然现在的本质也是如此),没有域名这种东西。比如我要给小王发送一条信息,我得知道小王的 IP 地址,然后向这个 IP 地址发送信息。后来出现了网站这种东西。别人要访问我的网站,那岂不是要记住我的 IP?记忆数字不是人类的强项。于是为了解救人类的 虚荣心 大脑,人类发明了 域名 这种东西。域名的最终管理收费组织为 ICANN

首先是顶级域名(TLD)。人们熟知的顶级域名如 com, org, net, cn 等。ICANN 把这些一级域名交给不同的组织管理。这些组织把顶级域名的子域名——二级域名开放给他人注册。如 land 为 Donuts Inc. 所有,我要注册 melty.land 最终就是向这个组织提的申请。一般来说人们注册的域名都是二级域名,有了二级域名你就可以在你的二级域名上添加子域名,具体方法是设置 Name Server。

DNS

DNS,全称 Domain Name System。 DNS 服务器,即是用来回应你对域名所指向的 IP 地址的请求的。

比如我要访问 blabla.com ,那么我会向一台 DNS 服务器请求 blabla.com 所指向的 IP 地址。DNS 服务器告诉我这个 IP 为 216.58.217.206 。于是我向 216.58.217.206 发出请求,让他把网页发给我就是了。这被称作一个 A record。

正常情况下你访问一个网站,浏览器就向 ICANN 的 DNS 服务器上请求这个域名指向的 IP。通常这个结果会在本地暂存一段时间,不会立即刷新。历史原因,DNS 请求是明文传输的,可能被截获也可能被污染,让你找不到真正的 IP。

就像镜像站一样,除了 ICANN 的 DNS 服务器,还有很多第三方的 DNS 服务。比如 Google 的 dns.google (8.8.8.8)、OpenDNS(208.67.222.222, 208.67.220.220)、CloudFlare 的 1.1.1.1 等。

Name Server

除了指向一个 A record,域名还可以指向一个 Name Server。客户端获取域名指向的 Name Server 后,再从 Name Server 获取 A record。这样的话如果你有很多台服务器你就可以安排 Name Server 每次返回不同的 IP,从而动态地分流到各台服务器。还可以在 Name Server 上指定子域名的 A record 或 Name Server 等。

端口

一台计算机有多个端口,取值为 0~65535。特别地,80 端口为 HTTP 的默认端口,443 为 HTTPS 的默认端口。访问 http://example.org 即表示访问 http://example.org:80

代理

客户端的请求打包、发往代理服务器,代理服务器将请求数据解包、发往目标服务器;目标服务器收到代理服务器的请求后、将回应的数据发往代理服务器,最后代理服务器将回应的数据打包、发到客户端。

代理的用途很广,中间人攻击、抓包进行网络数据分析都是通过代理来完成的。此外,代理还可以用于绕过防火墙的过滤。

反向代理

反向代理和前向代理是一样的原理,区别只在于哪部分对外面的互联网是可见的。前向代理对服务器隐藏了客户端的 IP,反向代理对客户端隐藏了服务器的原始地址。

HTTP

HTTP/HTTPS 是使用得最广泛的两种网络传输协议。网页即是通过 HTTP 传输。HTTP 是一种基于请求和回应的协议:客户端向服务器发出请求,服务器将内容回应给客户端。

请求方式

  • GET: 让服务器将一个 URI 对应的内容发给我。网页就是这么加载的。

  • POST: 我先给服务器发送一点信息,服务器将我发送信息后处理的结果发给我。比如一个网络知识竞赛,我把每题的答案和我的身份信息发送给服务器,然后服务器返回给我我当前的排名之类的。

    对于键值对数据,POST 的主体有三种,他们的 MIME type 分别是 multipart/form-dataapplication/x-www-form-url-encodedapplication/jsonapplication/x-www-form-url-encoded 是将键值对数据按照 query string 的方式编码,很多时候比 multipart/form-data 更紧凑些。而 application/json 就是 JSON 字符串了。

    • curl 的 -F key=value 发送的是 multipart/form-data-d key=value 发送的是 application/x-www-form-url-encoded
    • 浏览器的 fetch API 当 body 是 FormData 时发送 multipart/form-data,当 body 是 URLSearchParams 时发送 application/x-www-form-url-encoded
    • Python requests 中,request.post() 通过可选参数 data= 发送的是 application/x-www-form-url-encoded,通过 json= 发送的是 application/json

Headers

List of HTTP header fileds - Wikipedia

出现在请求和回应中,描述传输的文件类型和安全选项等。下面列出了一些通用的 headers 名,除了通用的 headers 之外也可以自行指定,比如 AWS 就在 Application Load Balancer 中使用了 X-Amzn-Trace-Id header。

Content-Type 指定文件的类型,是 HTML(text/html)、JSON(application/json)、还是纯文本(text/plain),这决定了返回的内容应该被浏览器渲染出来、以纯文本显示还是作为下载。所有 MIME 类型列表

Access-Control-Allow-Origin 回应中出现,是否允许别的站点在浏览器上运行时引用我的内容,设为 * 即为允许。

Accept-Language 请求中出现,告诉服务器你的语言。

Referer 请求中出现,告诉服务器你从哪个链接过来的。比如在手机浏览器上从其他搜索引擎跳转到百度知道时会出现一个“返回百度”的按钮,就是通过这个实现的。

CookiesSet-Cookie 见下。

Cookies

Cookies 是一列储存在浏览器中的短文本列表,可以用来储存身份信息、登录状态等。在发送请求时,浏览器会将储存的该网站的 cookies 用 Cookies header 发出;收到服务器的回应时,浏览器会根据 Set-Cookie header 中的子段更改储存的 cookies。

Cookies 本质上只是一对被浏览器特殊照顾的 HTTP headers 而已,除浏览器外其他环境中要指定请求中发送的 cookies 完全是可以的。比如 cURL 可以用 --cookie 'key=value' 来发送 cookie,用 --cookie-jar filename.cookies 指定接收到的 Set-Cookie 储存在那个文件中;Python 的 requests 库可以使用 requests.get('some-url.com', cookies={'key': 'value'}) 来发送 cookies,还可以在一个 requests.Session 中创建请求来保存从回应中获得的 cookies。

About Me