Total Pageviews

Monday, 15 June 2026

CRLF 和 LF 之间的区别与联系

 CRLF 与 LF:换行到底是什么?

要真正理解 CRLF 与 LF 换行的问题,我们需要复习一些排版历史。

人们使用字母、数字和符号来相互交流。但是计算机只能理解和处理数字。由于计算机上的文件由人类可读的字符串组成,因此我们需要一个允许我们在这两种格式之间来回转换的系统。 ASCII 标准就是这样的系统——它将 A 和 z 等字符映射到数字,弥合了人类语言和计算机语言之间的鸿沟。

有趣的是,ASCII 标准不仅仅适用于字母和数字等可见字符。某个子集是控制字符,也称为非打印字符。它们不用于渲染可见字符;相反,它们用于执行独特的操作,例如删除前一个字符或插入换行符。

LF 和 CR 就是两个这样的控制字符,它们都与文件中的行尾有关。它们的历史可以追溯到打字机时代,因此我将简要介绍其工作原理,以便了解为什么我们有两个不同的控制字符而不是一个。然后,我们将看看这如何影响开发人员的体验。
LF:换行

LF(Line Feed)代表“换行”,但你可能更熟悉术语换行符(转义序列 \n)。简单地说,这个字符代表一行文本的结束。在 Linux 和 Mac 上,这相当于新文本行的开始。这种区别很重要,因为 Windows 不遵循此约定。我们了解回车之后再讨论为什么不同。
CR:回车

CR(Carriage Return)代表回车(转义序列\r),将光标移动到当前行的开头。终端上的下载进度条就是通过 CR 实现的,通过使用回车符,你的终端可以通过将光标返回到当前行的开头并覆盖任何先前呈现的文本来将文本动画化。
打字机和回车(CR)

将一张纸固定在称为托架的机械卷上,为设备送入一张纸。每次击键时,打字机都会使用墨水在您的纸张上打印字母,将笔架向左移动以确保键入的下一个字母会出现在前一个字母的右侧。

当然,一旦当前行的空间用完,打字员就需要向下移动到纸张上的下一行。这是通过旋转滑架将纸张相对于打字机的“笔”向上移动一定距离来完成的。但是还需要重置托架(carriage),以便键入的下一个字符将与纸张的左侧边距对齐。换句话说,打字员需要某种方式将托架返回到其起始位置。而这正是回车的工作:一个金属杆连接到托架的左侧,当推动时,将托架返回到其起始位置。
电传打字机和回车换行(CRLF)

进入 20 世纪初,出现了电传打字机。基本上,它的工作方式与手动打字机相同,除了不是打印到物理纸上,而是通过传输器通过物理电线或无线电波将消息发送给接收方。

虽然打印方式不同,但是同样需要使用换行符 (LF) 和回车符 (CR),而且这些设备需要同时使用换行符 (LF) 和回车符 (CR) 以允许打字员从下一行文本的开头输入。毕竟手动打字机就是这样工作的,只是它没有任何“字符”的概念,因为它是一种机械操作的设备。

我们可以将 LF 和 CR 视为代表水平或垂直方向上的独立运动,而不是同时代表两者,这样更容易将其形象化。为了实现这个功能,电传打字机在一些最早的操作系统中设定了 CRLF 行尾的标准,比如流行的 MS-DOS。将 CR 代表“回车”——CR 控制字符将打印头(“回车”)返回到第 0 列,而无需推进纸张。 LF 代表“换行”——LF 控制字符在不移动打印头的情况下将纸张前进一行。因此,如果您想将打印头返回到第 0 列(准备打印下一行)并推进纸张(以便在新纸上打印),则需要 CR 和 LF。

MS-DOS 使用 CRLF 的两个字符组合来表示文件中的行尾,现代 Windows 计算机一直使用 CRLF 作为行尾。同时,从一开始,Unix 就使用 LF 来表示行尾,为了一致性和简单性而放弃了 CRLF。 Apple 最初仅在 Mac Classic 上使用 CR,但最终在 OS X 上改用了 LF,与 Unix 一致。

虽然这似乎是操作系统之间的差异,但 CRLF 与 LF 的这个问题已经引起人们很长时间的头痛。其实按照今天的标准 CRLF 是多余的——同时使用回车和换行是假设你受到打字机的物理限制,你必须明确地向上移动你的纸,然后重置移动到左边距。但是对于电子文件,将换行符定义为隐式完成换行和回车的工作就足够了。换句话说,只要操作系统定义换行符表示下一行从开头开始而不是从某个任意的列偏移处开始,那么除了换行之外,我们不需要显式回车——一个符号可以完成两者的工作。

现在我们知道 CRLF 和 CR 是如何起源的,接下来我们来学习以下怎么处理相关的问题。
检查和转换行尾(在 Bash 中)

在 bash 中,你可以使用带有 A 标志的 cat 查看特定文件的行尾:

如果文件使用 CRLF,您将在每行末尾看到字符串 ^M$,其中 ^M 表示回车,$ 表示换行。下面是一个示例:

line one^M$
line two^M$
line three^M$

如果文件使用 LF,那么您只会看到美元符号:

line one$
line two$
line three$

ps: 你可以使用dos2unix命令行程序将文件从 CRLF 转换为 LF。
Git 中的行尾

诚然,这需要很多背景知识!但这是值得的,因为我们终于准备好讨论与 git 相关的行尾(以及如何在任何给定的代码库中解决 CRLF 与 LF 的问题)。

我们从前面可以知道 CRLF 和 LF 是不同的字符表示,因此缺少通用行结尾为 git 等版本控制软件带来了麻烦,这类软件依赖于非常精确的字符比较来确定文件自上次签入以来是否发生了变化。如果开发人员使用 Windows 并且另一个使用 Mac 或 Linux,他们每个人都保存和提交相同的文件,他们可能会在他们的 git diff 中看到行结束更改——从 CRLF 到 LF 的转换,反之亦然。由于单字符更改,这会导致不必要的麻烦,非常烦人。
使用 core.autocrlf 在 Git 中配置行尾

可以使用core.autocrlf配置告诉 git 如何处理系统上的行尾。可以通过以下命令完成:

git config --global core.autocrlf [true|false|input]

注意,false 值会关闭行尾转换,这通常是不可取的,除非是团队中的每个人都使用相同的操作系统。当然,我觉得这种情况很少发生,所以慎用(除非你使用 .gitattributes 配置,在这种情况下,它会优先于你的 git 配置——稍后会详细介绍)。

所以,一般来说我们只有两个选择:autocrlf true 和 autocrlf input。这两者有什么区别?
autocrlf true

当 autocrlf 为 true 时(git 默认行为),文件将使用 git 在本地检出为 CRLF,但是每当你提交文件时,CRLF 的所有实例都将替换为 LF。基本上,此设置可确保你的代码库在所有文件的最终版本中始终使用 LF,但在获取时在本地使用 CRLF。这是 Windows 开发人员的推荐设置,因为 CRLF 是 Windows 的本机行结尾。

如果使用此选项,则每次在 Windows 上暂存文件以进行提交时可能会看到下面警告:

warning: CRLF will be replaced by LF in <file-name>.
The file will have its original line endings in your working directory.

这并不是说出现问题, Git 只是警告你,根据此设置的预期行为,你的 CRLF 行结尾将在提交时规范化为 LF。
autocrlf input

使用 autocrlf input,文件在提交时转换为 LF,但在获取时不会转换为任何内容。因此名称为“输入”——你得到是你最初输入的内容。如果一个文件最初被 Windows 开发人员意外提交为 CRLF,你会在本地看到它是 CRLF(如果你修改它,你会强制它变成 LF)。如果文件最初是作为 LF 添加的,您会看到它是 LF。这通常是一件好事,因为这意味着你将始终在代码库中获得 LF 行结尾(假设你从一开始就使用它)。

input 和 true 之间的唯一区别是输入不会在本地获取时处理行尾。这是 Mac/Linux 开发人员的推荐设置,因为这些操作系统默认使用 LF。
使用 .gitattributes 在 Git 中规范行尾

在你的 repo 的根目录创建一个 .gitattributes 文件来一劳永逸地行尾不一致的问题。 Git 会读取此文件并在您本地获取或提交文件时应用其规则,确保无论每个开发人员如何在本地配置 git 或他们使用什么操作系统,都强制执行行尾约定。
一个简单的 .gitattributes 配置

这是一个 .gitattributes 文件,应该涵盖大多数用例:

# We'll let Git's auto-detection algorithm infer if a file is text. If it is,
# enforce LF line endings regardless of OS or git configurations.
* text=auto eol=lf

# Isolate binary files in case the auto-detection algorithm fails and
# marks them as text files (which could brick them).
*.{png,jpg,jpeg,gif,webp,woff,woff2} binary

提交该文件并将其推送到远程服务器。

git 使用一种简单的算法来检测你的 repo 中的特定文件是文本文件还是二进制文件(例如,可执行文件、图像或字体文件)。默认情况下,此算法用于比较已更改的文件,但它也可以用于强制行尾约定。

这就是上面配置中 text=auto 的作用——它告诉 git 应用其自动检测算法来确定文件是否是文本文件。然后, eol=lf 告诉 git 在本地获取和提交时强制执行文本文件的 LF 行结尾。这适用于 Windows 和 Linux,因为现在大多数跨平台文本编辑器都支持 LF。

Git 的自动检测算法相当准确,但如果它无法正确区分文本文件和二进制文件(如图像或字体文件),我们也可以将文件的子集显式标记为二进制文件以避免作为文本文件处理他们。这可以用下面的代码实现:

*.{png,jpg,jpeg,gif,webp,woff,woff2} binary

现在,提交此文件后,最后一步是重新规范化所有在添加 .gitattributes 之前已签入 git 的文件的所有行尾。你可以使用以下命令执行此操作:

git add --renormalize .

这会根据 .gitattributes 配置中定义的规则重新格式化所有文件。如果先前提交的文件在 git 的索引中使用 CRLF 并且由于此重新规范化而转换为 LF,则它们的行尾将在索引中更新,并且这些文件将暂存以进行提交。唯一要做的就是提交这些更改并将它们推送到远程存储库。之后引入的新文件,其行尾都将作为 LF 签入(和签出)。
Git 行尾:工作树与索引

提交这些重新规范化的文件时,您可能会看到以下消息:

warning: CRLF will be replaced by LF in <file-name>.
The file will have its original line endings in your working directory.

这是预期的行为——CRLF 将成为 Git 索引中的 LF,这意味着当你将这些文件推送到你的存储库时,它们将在你的远程代码库中具有 LF 行结尾。任何后来提取或获取该代码的人都会在本地看到 LF 行结尾。

但是 git 实际上并没有更改文件的本地文件(即其工作树中的那些)的行尾。因此,警告消息的最后一点表示刚刚重新规范化的文件仍会继续在本地使用 CRLF。
在 Git 中验证任何文件的行尾

如果想在所有这些步骤之后仔细检查 Git 索引中的文件是否使用正确的行结尾,可以运行以下命令:

git ls-files --eol

这将显示 git 正在跟踪的所有文件的行尾信息,格式如下:

i/lf    w/crlf  attr/text=auto eol=lf   file.txt

从左到右分别是:

    i:索引中的行尾(被推送到你的仓库的行)。应该是 LF。
    w:工作树中的行尾(可能是 CRLF,但如果索引是 LF 也可以)。
    attr:适用于此文件的 .gitattributes 规则。
    文件名。

或者,你可以在将代码推送到远程后,通过在 Windows 机器上重新克隆您的存储库来仔细检查 git 是否正确规范了您的行尾。你应该看到文件的索引和工作树副本都使用 LF 而不是 CRLF(假设 LF 是您选择规范化行尾的方式)。
.editorconfig 文件

从技术上讲,一个 .gitattributes 文件是你执行代码库远程副本上显示的行尾所需的全部内容。但是,正如我们在上面看到的,你可能仍然会在本地看到你创建的文件的 CRLF 行结尾,因为 .gitattributes 不会告诉 git 更改文件的工作副本。

当然,这并不意味着 git 的规范化过程不起作用。但是,如果你还使用 ESLint 和 Prettier 对代码进行 linting,这可能会很烦人,在这种情况下,它们会不断抛出错误并告诉您删除那些额外的 CR.

所以,你可以使用 .editorconfig 文件更进一步;这是一个与编辑器无关的项目,旨在创建用于自定义任何给定文本编辑器行为的标准化格式。许多文本编辑器(包括 VS Code,IDEA,GitHub)支持并自动读取此文件(如果存在)。你可以将这样的内容放在工作区的根目录中,你可以在这里深入了解:
.editorconfig

root = true

[*]
end_of_line = lf

除了一堆其他设置之外,你还可以指定应用于通过此文本编辑器创建的任何新文件的行尾。这样,如果使用 VS Code 在 Windows 上创建一个新文件,你将始终在工作树中看到行结尾为 LF。
参考:

https://stackoverflow.com/a/56858538/5323344

https://www.aleksandrhovhannisyan.com/blog/crlf-vs-lf-normalizing-line-endings-in-git/

https://editorconfig.org/

如何恢复 Windows的EFI 分区

 找到了解决方案,方法倒是不是特别难,用到了一个 Windows 的bcdboot命令(https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/bcdboot-command-line-options-techref-di )

操作流程

第一步,准备一个 Windows 的安装介质,推荐使用Ventoy- https://www.ventoy.net/,开源免费,甚至不用格式化 U 盘

第二步,boot 进 live 安装系统,依次点击Repair Computer > Troubleshoot > Advanced > Command Prompt

第三步,进入命令提示符后,使用以下命令显示分区:

$ diskpart // 运行 diskpart
diskpart> list disk  // 列出所有硬盘,每个硬盘都有一个编号(e.g. 0/1/2)
diskpart> sel disk <disk_id> // 选择 Windows 系统 EFI 分区所在的硬盘,如果不存在,则需要手动创建,具体下方`UPDATED`的详细说明
diskpart> list partition // 列出所有分区
diskpart> sel partition <id> // 选择 EFI 分区
diskpart> assign letter=F // 分配 EFI 一个新盘符
diskpart> exit //退出
$ bcdboot C:\Windows /s F: /f ALL // 创建所有 Windows boot files 到 F 盘
$ reboot //重启即可正常进入 Windows

额外操作

UPDATED:

最近因为某种情况,Windows 启动项又消失了,这次甚至连 EFI 分区都没有了,所以又折腾了很久,这里再更新一下。 如果出现 EFI 分区直接消失的情况,可以通过重建 EFI 分区来解决,以下是具体操作步骤:

// 创建 EFI 类型的新分区
diskpart> create partition efi size=100
// 格式化
diskpart> format quick fs=fat32 label="System"
//分配卷标
diskpart> assign letter=L
diskpart> exit
X:Resources> bcdboot C:\Windows /s F: /f UEFI

如果最后提示以下内容,说明成功创建:

Boot files successfully created.

此时退出 CMD,然后重启电脑,进入 BIOS,应该就能看到 Windows 的启动选项了。

p.s. 有的时候,这里分配给 Windows 的系统分区的 letter 可能不是C,你要自己确认一下,可以使用list partition命令来查看具体在哪个分区(一般都有 label,比如系统或者OS之类的),确认之后,再执行上面的bcdboot,否则会创建失败。
总结

总的来说,EFI 分区消失并不是什么太大问题,恢复起来也不是很麻烦,但是每次出现这个问题就很困扰,我到现在都不知道具体什么原因引起的,猜测应该是跟双系统有关。

PGP的工作原理详解

 前言

最近在浏览博客的时候发现博主的 PGP Key 页面,虽然之前知道是用于邮件通信加密的,但是具体原理及使用却不太清楚,所以找了时间查阅了相关资料,整理一下 PGP 加密的一些内容。
PGP 定义

Pretty Good Privacy(PGP)是一个加密程序,为数据通信提供加密隐私和身份验证。PGP 用于对文本、电子邮件、文件、目录和整个磁盘分区进行签名、加密和解密,并提高电子邮件通信的安全性。PGP 加密使用散列,数据压缩,对称密钥加密,最后是公钥加密的串行组合。其中最关键的是两种形式的加密的组合:对称密钥加密(Symmetric Cryptography)和非对称密钥加密(Asymmetric cryptography)。
PGP 工作原理

在实现 PGP 加密的过程中,首先使用对称密钥加密算法对原始数据进行加密。对称密钥加密算法包括 DES、AES、Blowfish 等,这些算法能够快速地加密和解密数据,但是需要发送方和接收方之间共享密钥。

为了避免在网络上传输密钥,PGP 使用了公钥加密算法。公钥加密算法是一种使用不同的密钥加密和解密的算法,其中公钥用于加密,而私钥用于解密。公钥加密算法包括 RSA、DSA 等,这些算法具有极高的安全性,但是加密和解密速度比对称密钥加密算法慢得多。

PGP 将对称密钥加密,并使用接收方的公钥进行加密。这种方式可以保证密钥的安全性,同时可以确保只有接收方可以解密对称密钥,从而保护了数据的机密性。接收方使用自己的私钥对加密的对称密钥进行解密,然后使用对称密钥对数据进行解密。这种方式既可以保护数据的安全性,也可以提高加解密的速度。




PGP 使用两种类型的加密算法来保护数据:对称密钥加密和公钥加密。对称密钥加密是一种使用相同密钥加密和解密的算法,因此在加密和解密之间需要共享密钥。而公钥加密则是一种使用不同的密钥加密和解密的算法,其中公钥用于加密,而私钥用于解密。下面我将简单介绍一下这两种算法的工作原理。
对称密钥加密

对称密钥加密是一种使用相同密钥加密和解密的算法,因此在加密和解密之间需要共享密钥。对称密钥加密的过程如下:

    发送方选择一个加密密钥,并使用它将原始数据加密。
    加密后的数据被发送到接收方。
    接收方使用相同的密钥将加密的数据解密。

尽管对称密钥加密非常高效,但它有一个明显的缺点,即需要在发送方和接收方之间共享密钥。如果这个密钥被黑客或其他人获取,数据将无法得到保护。为了解决这个问题,PGP 使用了另一种加密算法:公钥加密。
公钥加密

公钥加密是一种使用不同的密钥加密和解密的算法,其中公钥用于加密,而私钥用于解密。公钥加密的过程如下:

    发送方获取接收方的公钥,并使用它将对称密钥加密。
    加密后的对称密钥和加密后的数据被发送到接收方。
    接收方使用自己的私钥将加密的对称密钥解密。
    接收方使用解密后的对称密钥将加密的数据解密。

公钥加密允许发送方使用接收方的公钥加密数据,而无需共享对称密钥。这样,即使黑客获得了加密后的数据,也无法使用它,因为他们没有接收方的私钥来解密对称密钥。
PGP 示例

我用常用的加密电子邮件来举个例子,具体的工作流程是:

用户 A 要给用户 B 发送邮件。

    用户 B 生成一对密钥(公钥和私钥),将公钥发送给用户 A。
    PGP 软件使用算法生成一个随机的会话密钥,这个密钥是一个很大的数字,而且只使用一次。
    用户 A 用刚刚生成的密钥,加密邮件,并使用用户 B 的公钥对该密钥进行加密。
    最后,用户 A 将加密的邮件及密钥发送给用户 B,用户 B 使用自己的私钥进行解密,得到会话密钥,进而可以解密完整的邮件。

PGP 加密用途

PGP 有三个主要用途:

    发送和接收加密电子邮件。
    验证向您发送此消息的人员的身份,即数字签名验证。
    加密数据。

其中,发送安全电子邮件 - 是迄今为止 PGP 的主要应用。数字签名是一种基于公钥加密的技术,用于证明信息的发送者身份和信息完整性,以及防止信息被篡改。发送方使用自己的私钥对消息的摘要进行加密,生成数字签名。接收方使用发送方的公钥对数字签名进行解密,并生成消息的摘要,比对两个摘要是否一致,来验证消息的完整性和身份。如果数字签名验证失败,则说明消息可能被篡改或者来自伪造的发送方。
总结

PGP 使用对称密钥加密算法保护数据机密性,使用公钥加密算法保护对称密钥的安全性,使用数字签名技术验证消息的完整性和身份。这种结合了对称密钥和公钥加密的方法,可以在安全性和效率之间取得平衡。PGP 已经成为一种被广泛应用的数据加密和数字签名的标准,保护了用户的隐私和安全。



Reference:

Pretty Good Privacy - Wikipedia

What is PGP Encryption and How Does It Work? | Varonis

Public Key Cryptography Simply Explained | Hacker Noon



树莓派安装配置 OpenWrt,并设置作为旁路由网关


引言

树莓派是一款功能强大的微型计算机,广泛应用于物联网、嵌入式系统等领域。除了作为单独的计算设备使用外,树莓派还可以通过配置为旁路由,实现局域网内的网络管理和控制。

又翻出来一台吃灰的树莓派,不知道做什么了,想试着做做旁路由,感受一下不一样的上网体验~。
准备工作

在开始配置旁路由之前,你需要准备以下材料和环境:

    一台树莓派(我用的是树莓派 4B)
    一张 SD 卡(越大越好)
    一根网线
    一台电脑(用于配置树莓派)
    一个可用的无线网络

烧录固件

    下载固件:我使用的是开源版的immortalwrt,从以下地址下载自编译的 openwrt 的固件: https://downloads.immortalwrt.org/releases/21.02.6/targets/bcm27xx/bcm2711/immortalwrt-21.02.6-bcm27xx-bcm2711-rpi-4-ext4-factory.img.gz

    烧录固件:使用烧录工具将固件写入 SD 卡,推荐使用balenaEtcher(UI 美观)或者 rufus(轻量简洁),二者均开源免费。

连接树莓派

有两种方式连接树莓派:

    使用电脑打开默认 UI 网页:http://192.168.1.1, 默认账户为:root,密码为:password,登陆后建议修改默认账户密码(有提示指引)。
    通过 SSH 进入,ssh root@192.168.1.1连接到树莓派命令行终端。

修改 LAN 口参数

为了实现旁路由的功能,我们需要把树莓派的 LAN 口的 IP 地址改为静态地址。对于静态 IP 的选择,我们需要知道上级路由器的 IP 子网,这个可以登录到路由器后台查看,或者查看连接到路由器的其他设备(如手机)的 IP 地址。 我的上级路由器 IP 为:192.168.0.1,那么子网范围就是 192.168.0.[1~255],我们可以任意设置一个 2-255 的 IP,但是前提是该 IP 未被分配出去,你可以通过pingIP 来查看是否存在,如果提示Destination host unreachable.,说明该 IP 不存在,可以使用。当然,你也可以使用其他 IP 扫描工具来测试。

这里我们使用 192.168.0.123 作为树莓派的静态 IP 地址。

更简单的配置方法

配置完之后,动了动脑子,感觉这两步可以何在一起直接在配置文件中修改,或者在 OpenWrt 控制台的网络->接口->LAN中修改。虽然我没试过(累了不想动了),但是我验证了配置文件,我觉得没毛病。

🚨 以下均为合理推测 xD🚨
方法 1:直接修改网络配置文件

方法 2:直接在 OpenWrt 控制界面修改

以下我配置的时候,参考的方法:
修改 IP 地址

    如果你是使用网页连接的树莓派,可以从系统->TTYD 终端页面进入树莓派的命令行。

在命令行终端输入一下命令:

uci set network.lan.ipaddr=192.168.0.123
uci commit network
/etc/init.d/network restart

修改网关及 DNS

修改好 IP 地址之后,我们需要修改一些其他的 IP 参数来保证网络的正常运行。

断开并重连电脑与树莓派的连接,如果搜不到树莓派的 WiFi 网络,树莓派重启一下应该就好了(我配置的时候用的 win10,断开之后就检测不到了,重启下就好了,不知道是我的原因还是系统原因。。。)。

浏览器打开 OpenWrt 的界面(http://192.168.0.123),输入默认账户 root,密码 password,进入 web 界面后,先根据指引修改登录的账户密码。

首先,进入网络->接口页面,选中修改LAN接口:

传输协议:静态地址

IPV4 地址:192.168.0.123

IPV4 子网掩码: 255.255.255.0

IPV4 网关:192.168.0.1 (上级路由 IP)

IPV4 广播:192.168.0.255 (把上级路由 IP 最后一段改为 255)

DNS 地址:192.168.0.1

然后,勾选下方基本设置中的忽略此接口。

最后,点击保存&应用。

到这一步,树莓派的内部配置基本已经完成,接下来我们断开电脑与树莓派的连接,将树莓派的网口接入上级路由器的 LAN 口即可,为了保证正常工作,可以手动重启一下树莓派。
客户端配置

然后是客户端的配置,对于每一个需要使用旁路由的设备,我们都需要修改为静态 IP 地址,分配一个路由器子网内的 IP 即可,以上文 IP 网段为例,我们可以使用192.168.0.199。

我们以设置 Windows11 连接到旁路由为例,

IPV4 地址:192.168.0.199

IPV4 子网掩码: 255.255.255.0

IPV4 网关:192.168.0.123 (树莓派 IP)

DNS 服务器:192.168.0.123 (树莓派 IP)

设置保存之后,我们来验证一下是否成功,打开cmd输入ipconfig,查看 WiFi 网卡的基本信息,如果输入类似以下内容,代表静态 IP 配置成功:

Wireless LAN adapter Wi-Fi:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::687b:87f3:b17b:5c1%19
   IPv4 Address. . . . . . . . . . . : 192.168.0.199
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 192.168.0.123  #主要是这里

以防万一,我们打开浏览器,访问一个网站,如果能够正常打开,说明配置成功。

以上,使用树莓派作为旁路由的基本流程就结束了,之后你可以根据自己的需求去定制各种功能,当然,我使用的这个immoralwrt,里面已经内置了很多功能(有魔法,dddd),你可以自由开启关闭。

版本不同可能初始项不同,但是都可以在软件包(系统->软件包)中/手动下载安装.
├── 状态

├── 系统

├── 服务

├── 网络存储

├── VPN

├── 网络

├── 带宽监控

└── 退出


参考资料:

https://doc.openwrt.cc

https://github.com/immortalwrt/immortalwrt

https://github.com/SuLingGG/OpenWrt-Rpi/wiki

https://linux-command-list.vercel.app
配置 openclash

这里记录一下一些 openclash 配置项。
插件配置

带星号标红的是必须要确认的项,其他基本保持默认即可,也可根据自己的需求更改。

    模式设置:运行模式建议使用 Fake-IP 增强模式,性能更好。
    流量控制:可以勾选实验性:绕过中国大陆 IP
    DNS 设置:本地 dns 劫持选择使用 dnsmasq 转发
    流媒体增强:根据个人需求配置,我没需求所以没改。
    黑白名单:根据个人需求配置,我没需求所以没改。
    外部控制:clash 的 UI 面板,设置一下登录密码就行。
    IPv6 设置:根据个人需求配置,我没需求所以没改。
    第三方规则订阅:使用了内置的第三方规则集的,可以配置一下自动更新。
    GEO 数据库订阅:GEO 数据库的订阅及自动更新
    大陆白名单订阅:配置白名单列表订阅及自动更新
    定时重启:设置定时重启
    版本更新:更新内核的界面,使用 meta 内核首次设置需要下载安装
    开发者选项:大佬专属界面,不知道做什么的,之后有机会研究一下
    调试日志:debug 时候用

ChatRoom, React前台+Node.js后台搭建的聊天室.


👋 这是我个人在学习react过程中做的一个练习用项目。

一个聊天室💬,可以登录、创建房间、加入房间以及聊天。

前端基于React + Redux + Typescript + Antd,

后端基于node.js + express + socket.io

🔨 Usage

前端:

cd ChatRoom/chatroom

npm install

npm start

后端:

cd ChatRoom/chatroomServe

npm install

npm start

from  https://github.com/Magren0321/ChatRoom

( https://github.com/brightmann/ChatRoom)


cloud-music


✌️ 该项目是模仿安卓网易云音乐APP的UI制作的移动端网页版网易云音乐,实现了部分功能。

项目基于Vue + Typescript + Vuetify UI构建。

后台由网易云音乐api提供。

👉 本项目是个人学习而制作,正常使用请到网易云音乐

功能

  • 登录
  • 获取歌单
  • 创建歌单
  • 删除/取消收藏歌单
  • 播放歌曲
  • 排行榜
  • 每日推荐
  • 推荐歌单

项目截图

运行

首先请根据网易云音乐api文档配置后台,接着将接口地址填入配置文件(vue.config.js)中。

接着开始运行项目 🚀

npm install

npm run serve

 from  https://github.com/Magren0321/cloud-music

( https://github.com/brightmann/cloud-music)

 

 

DNS 的更新是如何工作的?

已经看到很多人对更新站点的 DNS 记录以更改 IP 地址感到困惑。为什么这么慢?是否真的需要等待 2 天才能更新所有内容?为什么有些人看到新 IP,有些人看到旧 IP?发生了什么?

这里记录一下更新 DNS 背后所发生了些什么。
DNS 的分类:递归 vs 权威 DNS 服务器

首先,我们需要解释一些有关 DNS 的知识。DNS 服务器有两种:权威服务器和递归服务器。

权威DNS 服务器(也称为名称服务器)具有一个负责其每个域名的 IP 地址数据库。例如,github.com 的权威 DNS 服务器是 ns-421.awsdns-52.com。你可以通过 dig 命令来获取 github.com 的 IP。
Terminal window

dig @ns-421.awsdns-52.com github.com

递归DNS 服务器本身对谁拥有什么 IP 地址一无所知。它们通过询问正确的权威 DNS 服务器来确定域名的 IP 地址,然后缓存该 IP 地址,以防再次被问到。8.8.8.8 是递归 DNS 服务器。

当人们访问你的网站时,他们可能正在对递归 DNS 服务器进行 DNS 查询。那么,递归 DNS 服务器如何工作?让我们来看看!
递归 DNS 服务器如何查询 github.com?

我们来看一个递归 DNS 服务器(如 8.8.8.8)在你请求 github.com 的 IP 地址(A 记录)时的功能的示例。首先–如果已经缓存了某些内容,它将为您提供缓存的内容。但是,如果所有缓存均已过期怎么办?这是发生了什么:

步骤 1:在源代码中硬编码根 DNS 服务器的 IP 地址。您可以在unbound 的源代码中看到这一点。假设198.41.0.4从开始就选择。这是这些硬编码 IP 地址的正式来源,也称为“根目录提示文件”。

步骤 2:向根域名服务器查询github.com。

我们可以大致再现发生的情况dig。这给我们提供了一个新的权威名称服务器:.comIP 的名称服务器192.5.6.30。

$ dig @198.41.0.4 github.com
...
com.            172800  IN  NS  a.gtld-servers.net.
...
a.gtld-servers.net.    172800  IN  A   192.5.6.30
...

DNS 响应的详细信息比这要复杂一些–在这种情况下,其中有一个具有一些 NS 记录的授权部分,而另一个具有 A 记录的部分,因此您无需进行额外的查找即可获得这些名称服务器 IP 地址。

(实际上,它已经有 99.99%的时间已经缓存了.com名称服务器的地址,但是我们假装实际上是从头开始的)

步骤 3:向.com域名服务器查询有关github.com。

$ dig @192.5.6.30 github.com
...
github.com.        172800  IN  NS  ns-421.awsdns-52.com.
ns-421.awsdns-52.com.    172800  IN  A   205.251.193.165
...

我们有一个新的 IP 地址要询问!这是github.com的名称服务器。

步骤 4:向github.com域名服务器询问有关github.com。

$ dig @205.251.193.165 github.com

github.com.        60  IN  A   140.82.112.4

OK!我们现在有一个github.com的A记录!现在,递归名称服务器具有github.com的 IP 地址,可以将其返回给您。它通过仅硬编码几个IP 地址即可完成所有这些操作:即根名称服务器的地址。
如何查看所有递归 DNS 服务器: dig+trace

当我想查看解析一个域名时递归 DNS 服务器将执行的操作,我运行以下命令:

$ dig @8.8.8.8 +trace github.com

这显示了它请求的所有 DNS 记录,从根 DNS 服务器开始—我们刚刚完成的所有 4 个步骤。
如何更新 DNS 记录?

既然我们了解了 DNS 工作原理,那么让我们更新一些 DNS 记录,看看会发生什么。

更新 DNS 记录时,有两个主要选项:

    保持相同的名称服务器
    更改名称服务器

关于 TTL

这里我们先说明一下 TTL 这个概念,我们之前说过递归 DNS 服务器将缓存记录直到它们过期,而决定记录是否应过期的方式是查看其TTL(Time To Live)。

下面的示例中,A 记录 github 的名称服务器为其 DNS 记录返回的 TTL 为60,这意味着 60 秒:

$ dig @205.251.193.165 github.com
github.com.        60  IN  A   140.82.112.4

这是一个非常短的 TTL,*从理论上讲,*如果每个人的 DNS 实施都遵循DNS 标准,则意味着如果 Github 决定更改 IP 地址github.com,则每个人都应在 60 秒内获得新的 IP 地址。让我们看看实际情况如何。
选项 1:在相同的名称服务器上更新 DNS 记录

首先,我更新了我的名称服务器(Cloudflare),使其具有新的 DNS 记录:映射test.jvns.ca到的 A 记录 1.2.3.4。

$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca.        299 IN  A   1.2.3.4

这会立即生效!根本不需要等待,因为test.jvns.ca在可以缓存之前没有 DNS 记录。但是看起来新记录被缓存了大约 5 分钟(299 秒)。

那么,如果我们尝试更改该 IP 怎么办?我将其更改为5.6.7.8,然后运行了相同的 DNS 查询。

$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca.        144 IN  A   1.2.3.4

嗯,好像 DNS 服务器的1.2.3.4记录仍在缓存 144 秒。有趣的是,如果我8.8.8.8多次查询实际上却得到不一致的结果–有时它会给我新的 IP,有时会给我旧的 IP,我想是因为 8.8.8.8 实际上将负载平衡到一堆不同的后端,每个后端都有自己的缓存。

我等了 5 分钟后,所有8.8.8.8缓存均已更新,并且始终返回新5.6.7.8记录。不得不说,这相当的快!
你不能总是依靠 TTL

与大多数 Internet 协议一样,并非所有内容都遵循 DNS 规范。某些 ISP DNS 服务器将缓存记录的时间长于 TTL 指定的时间,例如 2 天而不是 5 分钟。人们总是可以在/etc/hosts 中对旧 IP 地址进行硬编码。

在使用 5 分钟的 TTL 更新 DNS 记录时,我期望在实践中会发生的事情是,很大比例的客户端会迅速(例如在 15 分钟之内)移到新 IP,然后会有一些慢的客户端在接下来的几天内会慢慢更新。
选项 2:更新名称服务器

我们已经看到,当您在不更改名称服务器的情况下更新 IP 地址时,许多 DNS 服务器将很快获取新 IP。但是,如果您更改名称服务器会怎样?

我不想更新我的博客的域名服务器,所以examplecat.com。

以前,我的名称服务器设置为 dns1.p01.nsone.net。我决定将它们切换到 Google 的名称服务器-ns-cloud-b1.googledomains.com等等。

进行更改后,我的域名注册商有点不愉快地弹出了消息-“对 examplecat.com 的更改已保存。它们将在接下来的 48 小时内生效。” 然后,我为该域设置了一个新的 A 记录,使其指向1.2.3.4

OK,让我们看看是否有任何作用:

$ dig @8.8.8.8 examplecat.com
examplecat.com.        17  IN  A   104.248.50.87

没变化。如果我询问其他 DNS 服务器,它将返回新 IP 地址:

$ dig @1.1.1.1 examplecat.com
examplecat.com.        299 IN  A   1.2.3.4

但是 8.8.8.8 仍然毫无变化。即使我在 5 分钟前刚刚更改它,1.1.1.1 能看到新 IP 的原因大概是以前没有人向 1.1.1.1 询问过 examplecat.com,因此它的缓存中没有任何内容。
名称服务器的 TTL 更长

我的注册服务商说“这将花费 48 小时”的原因是 NS 记录上的 TTL(这是递归名称服务器如何知道要询问哪个名称服务器)更长!

新的域名服务器肯定会返回新的 IP 地址 examplecat.com

$ dig @ns-cloud-b1.googledomains.com examplecat.com
examplecat.com.        300 IN  A   1.2.3.4

但是还记得当我们查询github.com域名服务器时发生了什么吗?

$ dig @192.5.6.30 github.com
...
github.com.        172800  IN  NS  ns-421.awsdns-52.com.
ns-421.awsdns-52.com.    172800  IN  A   205.251.193.165
...

172800 秒是 48 个小时!因此,与不更改名称服务器而仅更新 IP 地址相比,名称服务器更新通常需要更长的时间才能从缓存中到期并传播。
域名服务器如何更新?

当我更新的域名服务器时examplecat.com,发生的事情是 .com域名服务器获得了NS新域名的新记录。像这样:

dig ns @j.gtld-servers.net examplecat.com

examplecat.com.        172800  IN  NS  ns-cloud-b1.googledomains.com

但是,新的 NS 记录如何到达那里?发生的事情是,我通过在网站上更新域名告诉域名注册商我希望新的域名服务器是什么,然后域名注册商告诉.com域名服务器进行更新。

对于.com,这些更新发生的速度非常快(在几分钟之内),但是我认为对于其他一些 TLD,TLD 域名服务器可能无法尽快应用更新。
程序的 DNS 解析器库可能还会缓存 DNS 记录.

实际中可能不遵守 TTL 的另一个原因:许多程序需要解析 DNS 名称,并且某些程序还将无限期地将 DNS 记录缓存在内存中(直到程序重新启动)。

例如,AWS 有一篇关于为 DNS 名称查找设置 JVM TTL的文章(https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-jvm-ttl.html)。我没有编写太多可以自己进行 DNS 查找的 JVM 代码,但是通过对 JVM 和 DNS 的一些仔细研究,似乎可以配置 JVM,以便它无限期地缓存每个 DNS 查找。(例如此 elasticsearch 问题-
https://github.com/elastic/elasticsearch/issues/16412)

p.s. TTL 不能说明 DNS 工作原理的全部–即使像 8.8.8.8 这样的主要 DNS 服务器,某些递归 DNS 服务器也绝对不尊重 TTL。因此,即使您只是用短的 TTL 更新 A 记录,实际上还是很有可能在一两天内收到对旧 IP 的一些请求。


参考:
https://jvns.ca/blog/how-updating-dns-works

------

What happens when you update your DNS?

 

I’ve seen a lot of people get confused about updating their site’s DNS records to change the IP address. Why is it slow? Do you really have to wait 2 days for everything to update? Why do some people see the new IP and some people see the old IP? What’s happening?

So I wanted to write a quick exploration of what’s happening behind the scenes when you update a DNS record.

how DNS works: recursive vs authoritative DNS servers

First, we need to explain a little bit about DNS. There are 2 kinds of DNS servers: authoritative and recursive.

authoritative DNS servers (also known as nameservers) have a database of IP addresses for each domain they’re responsible for. For example, right now an authoritative DNS server for github.com is ns-421.awsdns-52.com. You can ask it for github.com’s IP like this;

dig @ns-421.awsdns-52.com github.com

recursive DNS servers, by themselves, don’t know anything about who owns what IP address. They figure out the IP address for a domain by asking the right authoritative DNS servers, and then cache that IP address in case they’re asked again. 8.8.8.8 is a recursive DNS server.

When people visit your website, they’re probably making their DNS queries to a recursive DNS server. So, how do recursive DNS servers work? Let’s see!

how does a recursive DNS server query for github.com?

Let’s go through an example of what a recursive DNS server (like 8.8.8.8) does when you ask it for an IP address (A record) for github.com. First – if it already has something cached, it’ll give you what it has cached. But what if all of its caches are expired? Here’s what happens:

step 1: it has IP addresses for the root DNS servers hardcoded in its source code. You can see this in unbound’s source code here. Let’s say it picks 198.41.0.4 to start with. Here’s the official source for those hardcoded IP addresses, also known as a “root hints file”.

step 2: Ask the root nameservers about github.com.

We can roughly reproduce what happens with dig. What this gives us is a new authoritative nameserver to ask: a nameserver for .com, with the IP 192.5.6.30.

$ dig @198.41.0.4 github.com
...
com.			172800	IN	NS	a.gtld-servers.net.
...
a.gtld-servers.net.	172800	IN	A	192.5.6.30
...

The details of the DNS response are a little more complicated than that – in this case, there’s an authority section with some NS records and an additional section with A records so you don’t need to do an extra lookup to get the IP addresses of those nameservers.

(in practice, 99.99% of the time it’ll already have the address of the .com nameservers cached, but we’re pretending we’re really starting from scratch)

step 3: Ask the .com nameservers about github.com.

$ dig @192.5.6.30 github.com
...
github.com.		172800	IN	NS	ns-421.awsdns-52.com.
ns-421.awsdns-52.com.	172800	IN	A	205.251.193.165
...

We have a new IP address to ask! This one is the nameserver for github.com.

step 4: Ask the github.com nameservers about github.com.

We’re almost done!

$ dig @205.251.193.165 github.com

github.com.		60	IN	A	140.82.112.4

Hooray!! We have an A record for github.com! Now the recursive nameserver has github.com’s IP address and can return it back to you. And it could do all of this by only hardcoding a few IP addresses: the addresses of the root nameservers.

how to see all of a recursive DNS server’s steps: dig +trace

When I want to see what a recursive DNS server would do when resolving a domain, I run

$ dig @8.8.8.8 +trace github.com

This shows all the DNS records that it requests, starting at the root DNS servers – all the 4 steps that we just went through.

let’s update some DNS records!

Now that we know the basics of how DNS works, let’s update some DNS records and see what happens.

When you update your DNS records, there are two main options:

  1. keep the same nameservers
  2. change nameservers

let’s talk about TTLs

We’ve forgotten something important though! TTLs! You know how we said earlier that the recursive DNS server will cache records until they expire? The way it decides whether the record should expire is by looking at its TTL or “time to live”.

In this example, the TTL for the A record github’s nameserver returns for its DNS record is 60, which means 60 seconds:

$ dig @205.251.193.165 github.com

github.com.		60	IN	A	140.82.112.4

That’s a pretty short TTL, and in theory if everybody’s DNS implementation followed the DNS standard it means that if Github decided to change the IP address for github.com, everyone should get the new IP address within 60 seconds. Let’s see how that plays out in practice

option 1: update a DNS record on the same nameservers

First, I updated my nameservers (Cloudflare) to have a new DNS record: an A record that maps test.jvns.ca to 1.2.3.4.

$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca.		299	IN	A	1.2.3.4

This worked immediately! There was no need to wait at all, because there was no test.jvns.ca DNS record before that could have been cached. Great. But it looks like the new record is cached for ~5 minutes (299 seconds).

So, what if we try to change that IP? I changed it to 5.6.7.8, and then ran the same DNS query.

$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca.		144	IN	A	1.2.3.4

Hmm, it seems like that DNS server has the 1.2.3.4 record still cached for another 144 seconds. Interestingly, if I query 8.8.8.8 multiple times I actually get inconsistent results – sometimes it’ll give me the new IP and sometimes the old IP, I guess because 8.8.8.8 actually load balances to a bunch of different backends which each have their own cache.

After I waited 5 minutes, all of the 8.8.8.8 caches had updated and were always returning the new 5.6.7.8 record. Awesome. That was pretty fast!

you can’t always rely on the TTL

As with most internet protocols, not everything obeys the DNS specification. Some ISP DNS servers will cache records for longer than the TTL specifies, like maybe for 2 days instead of 5 minutes. And people can always hardcode the old IP address in their /etc/hosts.

What I’d expect to happen in practice when updating a DNS record with a 5 minute TTL is that a large percentage of clients will move over to the new IPs quickly (like within 15 minutes), and then there will be a bunch of stragglers that slowly update over the next few days.

option 2: updating your nameservers

So we’ve seen that when you update an IP address without changing your nameservers, a lot of DNS servers will pick up the new IP pretty quickly. Great. But what happens if you change your nameservers? Let’s try it!

I didn’t want to update the nameservers for my blog, so instead I went with a different domain I own and use in the examples for the HTTP zine: examplecat.com.

Previously, my nameservers were set to dns1.p01.nsone.net. I decided to switch them over to Google’s nameservers – ns-cloud-b1.googledomains.com etc.

When I made the change, my domain registrar somewhat ominously popped up the message – “Changes to examplecat.com saved. They’ll take effect within the next 48 hours”. Then I set up a new A record for the domain, to make it point to 1.2.3.4

Okay, let’s see if that did anything

$ dig @8.8.8.8 examplecat.com
examplecat.com.		17	IN	A	104.248.50.87

No change. If I ask a different DNS server, it knows the new IP:

$ dig @1.1.1.1 examplecat.com
examplecat.com.		299	IN	A	1.2.3.4

but 8.8.8.8 is still clueless. The reason 1.1.1.1 sees the new IP even though I just changed it 5 minutes ago is presumably that nobody had ever queried 1.1.1.1 about examplecat.com before, so it had nothing in its cache.

nameserver TTLs are much longer

The reason that my registrar was saying “THIS WILL TAKE 48 HOURS” is that the TTLs on NS records (which are how recursive nameservers know which nameserver to ask) are MUCH longer!

The new nameserver is definitely returning the new IP address for examplecat.com

$ dig @ns-cloud-b1.googledomains.com examplecat.com
examplecat.com.		300	IN	A	1.2.3.4

But remember what happened when we queried for the github.com nameservers, way back?

$ dig @192.5.6.30 github.com
...
github.com.		172800	IN	NS	ns-421.awsdns-52.com.
ns-421.awsdns-52.com.	172800	IN	A	205.251.193.165
...

172800 seconds is 48 hours! So nameserver updates will in general take a lot longer to expire from caches and propagate than just updating an IP address without changing your nameserver.

how do your nameservers get updated?

When I update the nameservers for examplecat.com, what happens is that he .com nameserver gets a new NS record with the new domain. Like this:

dig ns @j.gtld-servers.net examplecat.com

examplecat.com.		172800	IN	NS	ns-cloud-b1.googledomains.com

But how does that new NS record get there? What happens is that I tell my domain registrar what I want the new nameservers to be by updating it on the website, and then my domain registrar tells the .com nameservers to make the update.

For .com, these updates happen pretty fast (within a few minutes), but I think for some other TLDs the TLD nameservers might not apply updates as quickly.

your program’s DNS resolver library might also cache DNS records

One more reason TTLs might not be respected in practice: many programs need to resolve DNS names, and some programs will also cache DNS records indefinitely in memory (until the program is restarted).

For example, AWS has an article on Setting the JVM TTL for DNS Name Lookups. I haven’t written that much JVM code that does DNS lookups myself, but from a little Googling about the JVM and DNS it seems like you can configure the JVM so that it caches every DNS lookup indefinitely. (like this elasticsearch issue)

that’s all!

I hope this helps you understand what’s going on when updating your DNS!

As a disclaimer, again – TTLs definitely don’t tell the whole story about DNS propagation – some recursive DNS servers definitely don’t respect TTLs, even if the major ones like 8.8.8.8 do. So even if you’re just updating an A record with a short TTL, it’s very possible that in practice you’ll still get some requests to the old IP for a day or two.

Also, I changed the nameservers for examplecat.com back to their old values after publishing this post.

from  https://jvns.ca/blog/how-updating-dns-works/