mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
commit
9b889a32e9
102
published/20200731 Why we open sourced our Python platform.md
Normal file
102
published/20200731 Why we open sourced our Python platform.md
Normal file
@ -0,0 +1,102 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "zepoch"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-13533-1.html"
|
||||
[#]: subject: "Why we open sourced our Python platform"
|
||||
[#]: via: "https://opensource.com/article/20/7/why-open-source"
|
||||
[#]: author: "Meredydd Luff https://opensource.com/users/meredydd-luff"
|
||||
|
||||
为什么我们要开源我们的 Python 平台
|
||||
======
|
||||
|
||||
> 开源开发的理念使得 Anvil 的整个解决方案更加有用且值得信赖。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202106/29/041151fpvlz4a75ihlr0lv.jpg)
|
||||
|
||||
Anvil 团队最近开源了 [Anvil App Server][2], 一个用于托管完全用 Python 构建的 Web 程序的运行时引擎。
|
||||
|
||||
社区的反应十分积极,我们 Anvil 团队已经将许多反馈纳入了我们的 [下一个版本][3]。但是我们不断被问到的问题是,“为什么你们选择开源这个产品的核心呢?”
|
||||
|
||||
### 我们为何创造 Anvil
|
||||
|
||||
[Anvil][4] 是一个可以使得构建 Web 应用更加简单的工具。我们让你们有能力仅使用一种语言—— Python —— 就可以来构建你的整个应用。
|
||||
|
||||
在 Anvil 之前,如果你想要构建一个 Web app,你需要写很多代码,用很多的技术,比如 HTML、Javascript、CSS、Python、SQL、React、Redux、Bootstrap、Sass、Webpack 等。这需要花费很长时间来学习。对于一个简单的应用便是这样子;相信我,一般的应用其实 [更加复杂][5]。
|
||||
|
||||
![A complex framework of development tools needed for a simple web app][6]
|
||||
|
||||
*是的。对于一个简单的 web 应用便是需要如此多的技术。*
|
||||
|
||||
但即使如此,你还没有完成!你需要了解有关 Git 和云托管提供商的所有信息、如何保护(很有可能是)Linux 操作系统、如何调整数据库,然后随时待命以保持其运行。一直如此。
|
||||
|
||||
因此,我们开发出了 Anvil,这是一个在线 IDE,你可以在用 [拖放编辑器][7] 来设计你的 UI 界面,用 Python 编写你的 [逻辑][8],然后 Anvil 会负责其余的工作。我们将所有的繁杂的技术栈进行了替换,只用 Python 就行啦!
|
||||
|
||||
### 简单的 Web 托管很重要,但还不够
|
||||
|
||||
Anvil 还可以为你托管你的应用程序。为什么不呢?部署 Web 应用程序非常复杂,因此运行我们自己的云托管服务是提供我们所需的简单性的唯一方法。在 Anvil 编辑器中构建一个应用程序,[单击按钮][9],它就在网上发布了。
|
||||
|
||||
但我们不断听到有人说,“那太好了,但是……”
|
||||
|
||||
* “我需要在没有可靠互联网接入的海外平台上运行这个应用。”
|
||||
* “我想要将我的应用程序嵌入到我售出的 IoT 设备中”
|
||||
* "如果我把我的宝都压到你的 Anvil 上,我怎么能确定十年后我的应用仍然能够运行呢?”
|
||||
|
||||
这些都是很好的观点!云服务并不是适合所有人的解决方案。如果我们想为这些用户提供服务,就必须有一些方法让他们把自己的应用从 Anvil 中取出来,在本地运行,由他们自己完全控制。
|
||||
|
||||
### 开源是一个逃生舱,而不是弹射座椅
|
||||
|
||||
在会议上,我们有时会被问到,“我可以将它导出为 Flask+JS 的应用程序吗?” 当然,我们可以将 Anvil 项目分别导出为 Python 和 JavaScript —— 我们可以生成一个服务器包,将客户端中的 Python 编译为 Javascript,然后生成一个经典的 Web 应用程序。但它会有严重的缺点,因为:**代码生成是一个弹射座椅。**
|
||||
|
||||
![Code generation is an ejector seat from a structured platform][10]
|
||||
|
||||
生成的代码聊胜于无;至少你可以编辑它!但是在你编辑该代码的那一刻,你就失去了生成它的系统的所有好处。如果你使用 Anvil 是因为它的 [拖放编辑器][12] 和 [运行在浏览器中的 Python][13],那么你为什么必须使用 vim 和 Javascript 才能在本地托管你的应用程序?
|
||||
|
||||
我们相信 [逃生舱,而不是弹射座椅][14]。所以我们选择了一个正确的方式——我们 [开源了 Anvil 的运行引擎][2],这与在我们的托管服务中为你的应用程序提供服务的代码相同。这是一个独立的应用程序;你可以使用文本编辑器编辑代码并在本地运行。但是你也可以将它直接用 `git` 推回到我们的在线 IDE。这不是弹射座椅;没有爆炸性的转变。这是一个逃生舱;你可以爬出来,做你需要做的事情,然后再爬回来。
|
||||
|
||||
### 如果它开源了,它还可靠吗
|
||||
|
||||
开源中的一个看似矛盾的是,它的免费可用性是它的优势,但有时也会产生不稳定的感觉。毕竟,如果你不收费,你如何保持这个平台的长期健康运行?
|
||||
|
||||
我们正在做我们一直在做的事情 —— 提供一个开发工具,使构建 Web 应用程序变得非常简单,尽管你使用 Anvil 构建的应用程序 100% 是你的。我们为 Anvil 应用程序提供托管,并为 [企业客户][15] 提供整个现场开发和托管平台。这使我们能够提供免费计划,以便每个人都可以将 Anvil 用于业余爱好或教育目的,或者开始构建某些东西并查看它的发展。
|
||||
|
||||
### 得到的多,失去的少
|
||||
|
||||
开源我们的运行引擎并没有减少我们的业务 —— 它使我们的在线 IDE 在今天和未来变得更有用、更值得信赖。我们为需要它的人开放了 Anvil App Server 的源代码,并提供最终的安全保障。对于我们的用户来说,这是正确的举措 —— 现在他们可以放心地进行构建,因为他们知道开源代码 [就在那里][3],如果他们需要的话。
|
||||
|
||||
如果我们的开发理念与你产生共鸣,何不亲自尝试 Anvil?
|
||||
|
||||
-----
|
||||
|
||||
这篇文章改编自 [Why We Open Sourced the Anvil App Server][16],经许可重复使用。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/7/why-open-source
|
||||
|
||||
作者:[Meredydd Luff][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zepoch](https://github.com/zepoch)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/meredydd-luff
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUS_OSwhy_520x292_ma.png?itok=lqfhAs8L "neon sign with head outline and open source why spelled out"
|
||||
[2]: https://anvil.works/blog/open-source
|
||||
[3]: https://github.com/anvil-works/anvil-runtime
|
||||
[4]: https://anvil.works/
|
||||
[5]: https://github.com/kamranahmedse/developer-roadmap#introduction
|
||||
[6]: https://opensource.com/sites/default/files/uploads/frameworks.png "A complex framework of development tools needed for a simple web app"
|
||||
[7]: https://anvil.works/docs/client/ui
|
||||
[8]: https://anvil.works/docs/client/python
|
||||
[9]: https://anvil.works/docs/deployment
|
||||
[10]: https://opensource.com/sites/default/files/uploads/ejector-seat-opensourcecom.jpg "Code generation is an ejector seat from a structured platform"
|
||||
[11]: https://commons.wikimedia.org/wiki/File:Crash.arp.600pix.jpg
|
||||
[12]: https://anvil.works/docs/editor
|
||||
[13]: https://anvil.works/docs/client
|
||||
[14]: https://anvil.works/blog/escape-hatches-and-ejector-seats
|
||||
[15]: https://anvil.works/docs/overview/enterprise
|
||||
[16]: https://anvil.works/blog/why-open-source
|
||||
|
145
published/20210622 Replace du with dust on Linux.md
Normal file
145
published/20210622 Replace du with dust on Linux.md
Normal file
@ -0,0 +1,145 @@
|
||||
[#]: subject: (Replace du with dust on Linux)
|
||||
[#]: via: (https://opensource.com/article/21/6/dust-linux)
|
||||
[#]: author: (Sudeshna Sur https://opensource.com/users/sudeshna-sur)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13532-1.html)
|
||||
|
||||
在 Linux 上用 dust 代替 du
|
||||
======
|
||||
|
||||
> dust 命令是用 Rust 编写的对 du 命令的一个更直观实现。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202106/29/033403l8x83x7a4tt4fq84.jpg)
|
||||
|
||||
如果你在 Linux 命令行上工作,你会熟悉 `du` 命令。了解像 `du` 这样的命令,可以快速返回磁盘使用情况,是命令行使程序员更有效率的方法之一。然而,如果你正在寻找一种方法来节省更多的时间,使你的生活更加容易,看看 [dust][2],它是用 Rust 重写的 `du`,具有更多的直观性。
|
||||
|
||||
简而言之,`dust` 是一个提供文件类型和元数据的工具。如果你在一个目录中运行了 `dust`,它将以几种方式报告该目录的磁盘利用率。它提供了一个信息量很大的图表,告诉你哪个文件夹使用的磁盘空间最大。如果有嵌套的文件夹,你可以看到每个文件夹使用的空间百分比。
|
||||
|
||||
### 安装 dust
|
||||
|
||||
你可以使用 Rust 的 Cargo 包管理器安装 `dust`:
|
||||
|
||||
```
|
||||
$ cargo install du-dust
|
||||
```
|
||||
|
||||
另外,你可以在 Linux 上的软件库中找到它,在 macOS 上,可以使用 [MacPorts][3] 或 [Homebrew][4]。
|
||||
|
||||
### 探索 dust
|
||||
|
||||
在一个目录中执行 `dust` 命令,会返回一个图表,以树状格式显示其内容和每个项目所占的百分比。
|
||||
|
||||
|
||||
```
|
||||
$ dust
|
||||
5.7M ┌── exa │ ██ │ 2%
|
||||
5.9M ├── tokei │ ██ │ 2%
|
||||
6.1M ├── dust │ ██ │ 2%
|
||||
6.2M ├── tldr │ ██ │ 2%
|
||||
9.4M ├── fd │ ██ │ 4%
|
||||
2.9M │ ┌── exa │ ░░░█ │ 1%
|
||||
15M │ ├── rustdoc │ ░███ │ 6%
|
||||
18M ├─┴ bin │ ████ │ 7%
|
||||
27M ├── rg │ ██████ │ 11%
|
||||
1.3M │ ┌── libz-sys-1.1.3.crate │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
1.4M │ ├── libgit2-sys-0.12.19+1.1.0.crate │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 1%
|
||||
4.5M │ ┌─┴ github.com-1ecc6299db9ec823 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 2%
|
||||
4.5M │ ┌─┴ cache │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 2%
|
||||
1.0M │ │ ┌── git2-0.13.18 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 0%
|
||||
1.4M │ │ ├── exa-0.10.1 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
1.5M │ │ │ ┌── src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
2.2M │ │ ├─┴ idna-0.2.3 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
1.2M │ │ │ ┌── linux │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 0%
|
||||
1.6M │ │ │ ┌─┴ linux_like │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
2.6M │ │ │ ┌─┴ unix │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
3.1M │ │ │ ┌─┴ src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
3.1M │ │ ├─┴ libc-0.2.94 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
1.2M │ │ │ ┌── test │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 0%
|
||||
2.6M │ │ │ ┌─┴ zlib-ng │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
904K │ │ │ │ ┌── vstudio │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 0%
|
||||
2.0M │ │ │ │ ┌─┴ contrib │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
3.4M │ │ │ ├─┴ zlib │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
6.1M │ │ │ ┌─┴ src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓██ │ 2%
|
||||
6.1M │ │ ├─┴ libz-sys-1.1.3 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓██ │ 2%
|
||||
1.6M │ │ │ ┌── pcre │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
2.5M │ │ │ ┌─┴ deps │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
3.8M │ │ │ ├── src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
7.4M │ │ │ ┌─┴ libgit2 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓██ │ 3%
|
||||
7.6M │ │ ├─┴ libgit2-sys-0.12.19+1.1.0 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓██ │ 3%
|
||||
26M │ │ ┌─┴ github.com-1ecc6299db9ec823 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██████ │ 10%
|
||||
26M │ ├─┴ src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██████ │ 10%
|
||||
932K │ │ ┌── .cache │ ░░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█ │ 0%
|
||||
11M │ │ │ ┌── pack-c3e3a51a17096a3078196f3f014e02e5da6285aa.idx │ ░░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓███ │ 4%
|
||||
135M │ │ │ ├── pack-c3e3a51a17096a3078196f3f014e02e5da6285aa.pack│ ░░░░░░▓▓███████████████████████████ │ 53%
|
||||
147M │ │ │ ┌─┴ pack │ ░░░░░░█████████████████████████████ │ 57%
|
||||
147M │ │ │ ┌─┴ objects │ ░░░░░░█████████████████████████████ │ 57%
|
||||
147M │ │ ├─┴ .git │ ░░░░░░█████████████████████████████ │ 57%
|
||||
147M │ │ ┌─┴ github.com-1ecc6299db9ec823 │ ░░░░░░█████████████████████████████ │ 57%
|
||||
147M │ ├─┴ index │ ░░░░░░█████████████████████████████ │ 57%
|
||||
178M ├─┴ registry │ ███████████████████████████████████ │ 69%
|
||||
257M ┌─┴ . │██████████████████████████████████████████████████ │ 100%
|
||||
$
|
||||
```
|
||||
|
||||
将 `dust` 应用于一个特定的目录:
|
||||
|
||||
```
|
||||
$ dust ~/Work/
|
||||
```
|
||||
|
||||
![Dust output from a specific directory][5]
|
||||
|
||||
`-r` 选项以相反的顺序显示输出,“根”在底部:
|
||||
|
||||
```
|
||||
$ dust -r ~/Work/
|
||||
```
|
||||
|
||||
使用 `dust -d 3` 会返回三层的子目录和它们的磁盘利用率:
|
||||
|
||||
```
|
||||
$ dust -d 3 ~/Work/wildfly/jaxrs/target/classes
|
||||
4.0K ┌── jaxrs.xml │ █ │ 1%
|
||||
4.0K ┌─┴ subsystem-templates │ █ │ 1%
|
||||
4.0K │ ┌── org.jboss.as.controller.transform.ExtensionTransformerRegistration│ █ │ 1%
|
||||
4.0K │ ├── org.jboss.as.controller.Extension │ █ │ 1%
|
||||
8.0K │ ┌─┴ services │ █ │ 2%
|
||||
8.0K ├─┴ META-INF │ █ │ 2%
|
||||
4.0K │ ┌── jboss-as-jaxrs_1_0.xsd │ ░█ │ 1%
|
||||
8.0K │ ├── jboss-as-jaxrs_2_0.xsd │ ░█ │ 2%
|
||||
12K ├─┴ schema │ ██ │ 3%
|
||||
408K │ ┌── as │ ████████████████████████████████████████ │ 94%
|
||||
408K │ ┌─┴ jboss │ ████████████████████████████████████████ │ 94%
|
||||
408K ├─┴ org │ ████████████████████████████████████████ │ 94%
|
||||
432K ┌─┴ classes │██████████████████████████████████████████ │ 100%
|
||||
$
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
`dust` 的魅力在于它是一个小而简单的、易于理解的命令。它使用颜色方案来表示最大的子目录,使你的目录易于可视化。这是一个受欢迎的项目,欢迎大家来贡献。
|
||||
|
||||
你是否使用或考虑使用 `dust`?如果是,请在下面的评论中告诉我们你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/6/dust-linux
|
||||
|
||||
作者:[Sudeshna Sur][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/sudeshna-sur
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/sand_dunes_desert_hills_landscape_nature.jpg?itok=wUByylBb
|
||||
[2]: https://github.com/bootandy/dust
|
||||
[3]: https://opensource.com/article/20/11/macports
|
||||
[4]: https://opensource.com/article/20/6/homebrew-mac
|
||||
[5]: https://opensource.com/sites/default/files/uploads/dust-work.png (Dust output from a specific directory)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
@ -1,392 +0,0 @@
|
||||
[#]: subject: (How to look at the stack with gdb)
|
||||
[#]: via: (https://jvns.ca/blog/2021/05/17/how-to-look-at-the-stack-in-gdb/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (amwps290)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
How to look at the stack with gdb
|
||||
======
|
||||
|
||||
I was chatting with someone yesterday and they mentioned that they don’t really understand exactly how the stack works or how to look at it.
|
||||
|
||||
So here’s a quick walkthrough of how you can use gdb to look at the stack of a C program. I think this would be similar for a Rust program, but I’m going to use C because I find it a little simpler for a toy example and also you can do Terrible Things in C more easily.
|
||||
|
||||
### our test program
|
||||
|
||||
Here’s a simple C program that declares a few variables and reads two strings from standard input. One of the strings is on the heap, and one is on the stack.
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
char stack_string[10] = "stack";
|
||||
int x = 10;
|
||||
char *heap_string;
|
||||
|
||||
heap_string = malloc(50);
|
||||
|
||||
printf("Enter a string for the stack: ");
|
||||
gets(stack_string);
|
||||
printf("Enter a string for the heap: ");
|
||||
gets(heap_string);
|
||||
printf("Stack string is: %s\n", stack_string);
|
||||
printf("Heap string is: %s\n", heap_string);
|
||||
printf("x is: %d\n", x);
|
||||
}
|
||||
```
|
||||
|
||||
This program uses the extremely unsafe function `gets` which you should never use, but that’s on purpose – we learn more when things go wrong.
|
||||
|
||||
### step 0: compile the program.
|
||||
|
||||
We can compile it with `gcc -g -O0 test.c -o test`.
|
||||
|
||||
The `-g` flag compiles the program with debugging symbols, which is going to make it a lot easier to look at our variables.
|
||||
|
||||
`-O0` tells gcc to turn off optimizations which I did just to make sure our `x` variable didn’t get optimized out.
|
||||
|
||||
### step 1: start gdb
|
||||
|
||||
We can start gdb like this:
|
||||
|
||||
```
|
||||
$ gdb ./test
|
||||
```
|
||||
|
||||
It prints out some stuff about the GPL and then gives a prompt. Let’s create a breakpoint on the `main` function.
|
||||
|
||||
```
|
||||
(gdb) b main
|
||||
```
|
||||
|
||||
Then we can run the program:
|
||||
|
||||
```
|
||||
(gdb) b main
|
||||
Starting program: /home/bork/work/homepage/test
|
||||
Breakpoint 1, 0x000055555555516d in main ()
|
||||
|
||||
(gdb) run
|
||||
Starting program: /home/bork/work/homepage/test
|
||||
|
||||
Breakpoint 1, main () at test.c:4
|
||||
4 int main() {
|
||||
```
|
||||
|
||||
Okay, great! The program is running and we can start looking at the stack
|
||||
|
||||
### step 2: look at our variables’ addresses
|
||||
|
||||
Let’s start out by learning about our variables. Each of them has an address in memory, which we can print out like this:
|
||||
|
||||
```
|
||||
(gdb) p &x
|
||||
$3 = (int *) 0x7fffffffe27c
|
||||
(gdb) p &heap_string
|
||||
$2 = (char **) 0x7fffffffe280
|
||||
(gdb) p &stack_string
|
||||
$4 = (char (*)[10]) 0x7fffffffe28e
|
||||
```
|
||||
|
||||
So if we look at the stack at those addresses, we should be able to see all of these variables!
|
||||
|
||||
### concept: the stack pointer
|
||||
|
||||
We’re going to need to use the stack pointer so I’ll try to explain it really quickly.
|
||||
|
||||
There’s an x86 register called ESP called the “stack pointer”. Basically it’s the address of the start of the stack for the current function. In gdb you can access it with `$sp`. When you call a new function or return from a function, the value of the stack pointer changes.
|
||||
|
||||
### step 3: look at our variables on the stack at the beginning of `main`
|
||||
|
||||
First, let’s look at the stack at the start of the `main` function. Here’s the value of our stack pointer right now:
|
||||
|
||||
```
|
||||
(gdb) p $sp
|
||||
$7 = (void *) 0x7fffffffe270
|
||||
```
|
||||
|
||||
So the stack for our current function starts at `0x7fffffffe270`. Cool.
|
||||
|
||||
Now let’s use gdb to print out the first 40 words (aka 160 bytes) of memory after the start of the current function’s stack. It’s possible that some of this memory isn’t part of the stack because I’m not totally sure how big the stack is here. But at least the beginning of this is part of the stack.
|
||||
|
||||
```
|
||||
(gdb) x/40x $sp
|
||||
0x7fffffffe270: 0x00000000 0x00000000 0x55555250 0x00005555
|
||||
0x7fffffffe280: 0x00000000 0x00000000 0x55555070 0x00005555
|
||||
0x7fffffffe290: 0xffffe390 0x00007fff 0x00000000 0x00000000
|
||||
0x7fffffffe2a0: 0x00000000 0x00000000 0xf7df4b25 0x00007fff
|
||||
0x7fffffffe2b0: 0xffffe398 0x00007fff 0xf7fca000 0x00000001
|
||||
0x7fffffffe2c0: 0x55555169 0x00005555 0xffffe6f9 0x00007fff
|
||||
0x7fffffffe2d0: 0x55555250 0x00005555 0x3cae816d 0x8acc2837
|
||||
0x7fffffffe2e0: 0x55555070 0x00005555 0x00000000 0x00000000
|
||||
0x7fffffffe2f0: 0x00000000 0x00000000 0x00000000 0x00000000
|
||||
0x7fffffffe300: 0xf9ce816d 0x7533d7c8 0xa91a816d 0x7533c789
|
||||
```
|
||||
|
||||
I’ve bolded approximately where the `stack_string`, `heap_string`, and `x` variables are and colour coded them:
|
||||
|
||||
* `x` is red and starts at `0x7fffffffe27c`
|
||||
* `heap_string` is blue and starts at `0x7fffffffe280`
|
||||
* `stack_string` is purple and starts at `0x7fffffffe28e`
|
||||
|
||||
|
||||
|
||||
I think I might have bolded the location of some of those variables a bit wrong here but that’s approximately where they are.
|
||||
|
||||
One weird thing you might notice here is that `x` is the number `0x5555`, but we set `x` to 10! That because `x` doesn’t actually get set until after our `main` function starts, and we’re at the very beginning of `main`.
|
||||
|
||||
### step 3: look at the stack again on line 10
|
||||
|
||||
Let’s skip a few lines and wait for our variables to actually get set to the values we initialized them to. By the time we get to line 10, `x` should be set to 10.
|
||||
|
||||
First, we need to set another breakpoint:
|
||||
|
||||
```
|
||||
(gdb) b test.c:10
|
||||
Breakpoint 2 at 0x5555555551a9: file test.c, line 11.
|
||||
```
|
||||
|
||||
and continue the program running:
|
||||
|
||||
```
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
|
||||
Breakpoint 2, main () at test.c:11
|
||||
11 printf("Enter a string for the stack: ");
|
||||
```
|
||||
|
||||
Okay! Let’s look at all the same things again! `gdb` is formatting the bytes in a slightly different way here and I don’t actually know why. Here’s a reminder of where to find our variables on the stack:
|
||||
|
||||
* `x` is red and starts at `0x7fffffffe27c`
|
||||
* `heap_string` is blue and starts at `0x7fffffffe280`
|
||||
* `stack_string` is purple and starts at `0x7fffffffe28e`
|
||||
|
||||
|
||||
|
||||
```
|
||||
(gdb) x/80x $sp
|
||||
0x7fffffffe270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe278: 0x50 0x52 0x55 0x55 0x0a 0x00 0x00 0x00
|
||||
0x7fffffffe280: 0xa0 0x92 0x55 0x55 0x55 0x55 0x00 0x00
|
||||
0x7fffffffe288: 0x70 0x50 0x55 0x55 0x55 0x55 0x73 0x74
|
||||
0x7fffffffe290: 0x61 0x63 0x6b 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe298: 0x00 0x80 0xf7 0x8a 0x8a 0xbb 0x58 0xb6
|
||||
0x7fffffffe2a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe2a8: 0x25 0x4b 0xdf 0xf7 0xff 0x7f 0x00 0x00
|
||||
0x7fffffffe2b0: 0x98 0xe3 0xff 0xff 0xff 0x7f 0x00 0x00
|
||||
0x7fffffffe2b8: 0x00 0xa0 0xfc 0xf7 0x01 0x00 0x00 0x00
|
||||
```
|
||||
|
||||
There are a couple of interesting things to discuss here before we go further in the program.
|
||||
|
||||
### how `stack_string` is represented in memory
|
||||
|
||||
Right now (on line 10) `stack_string` is set to “stack”. Let’s take a look at how that’s represented in memory.
|
||||
|
||||
We can print out the bytes in the string like this:
|
||||
|
||||
```
|
||||
(gdb) x/10x stack_string
|
||||
0x7fffffffe28e: 0x73 0x74 0x61 0x63 0x6b 0x00 0x00 0x00
|
||||
0x7fffffffe296: 0x00 0x00
|
||||
```
|
||||
|
||||
The string “stack” is 5 characters which corresponds to 5 ASCII bytes – `0x73`, `0x74`, `0x61`, `0x63`, and `0x6b`. `0x73` is `s` in ASCII, `0x74` is `t`, etc.
|
||||
|
||||
We can also get gdb to show us the string with `x/1s`:
|
||||
|
||||
```
|
||||
(gdb) x/1s stack_string
|
||||
0x7fffffffe28e: "stack"
|
||||
```
|
||||
|
||||
### how `heap_string` and `stack_string` are different
|
||||
|
||||
You’ll notice that `stack_string` and `heap_string` are represented in very different ways on the stack:
|
||||
|
||||
* `stack_string` has the contents of the string (“stack”)
|
||||
* `heap_string` is a pointer to an address somewhere else in memory
|
||||
|
||||
|
||||
|
||||
Here are the bytes on the stack for the `heap_string` variable:
|
||||
|
||||
```
|
||||
0xa0 0x92 0x55 0x55 0x55 0x55 0x00 0x00
|
||||
```
|
||||
|
||||
These bytes actually get read backwards because x86 is little-endian, so the memory address of `heap_string` is `0x5555555592a0`
|
||||
|
||||
Another way to see the address of `heap_string` in gdb is just to print it out with `p`:
|
||||
|
||||
```
|
||||
(gdb) p heap_string
|
||||
$6 = 0x5555555592a0 ""
|
||||
```
|
||||
|
||||
### the bytes that represent the integer `x`
|
||||
|
||||
`x` is a 32-bit integer, and the bytes that represent it are `0x0a 0x00 0x00 0x00`.
|
||||
|
||||
We need to read these bytes backwards again (the same way reason we read the bytes for `heap_string` address backwards), so this corresponds to the number `0x000000000a`, or `0xa`, which is 10.
|
||||
|
||||
That makes sense! We set `int x = 10;`!
|
||||
|
||||
### step 4: read input from standard input
|
||||
|
||||
Okay, we’ve initialized the variables, now let’s see how the stack changes when this part of the C program runs:
|
||||
|
||||
```
|
||||
printf("Enter a string for the stack: ");
|
||||
gets(stack_string);
|
||||
printf("Enter a string for the heap: ");
|
||||
gets(heap_string);
|
||||
```
|
||||
|
||||
We need to set another breakpoint:
|
||||
|
||||
```
|
||||
(gdb) b test.c:16
|
||||
Breakpoint 3 at 0x555555555205: file test.c, line 16.
|
||||
```
|
||||
|
||||
and continue running the program
|
||||
|
||||
```
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
```
|
||||
|
||||
We’re prompted for 2 strings, and I entered `123456789012` for the stack string and `bananas` for the heap.
|
||||
|
||||
### let’s look at `stack_string` first (there’s a buffer overflow!)
|
||||
|
||||
```
|
||||
(gdb) x/1s stack_string
|
||||
0x7fffffffe28e: "123456789012"
|
||||
```
|
||||
|
||||
That seems pretty normal, right? We entered `123456789012` and now it’s set to `123456789012`.
|
||||
|
||||
But there’s something weird about this. Here’s what those bytes look like on the stack. They’re highlighted in purple again.
|
||||
|
||||
```
|
||||
0x7fffffffe270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe278: 0x50 0x52 0x55 0x55 0x0a 0x00 0x00 0x00
|
||||
0x7fffffffe280: 0xa0 0x92 0x55 0x55 0x55 0x55 0x00 0x00
|
||||
0x7fffffffe288: 0x70 0x50 0x55 0x55 0x55 0x55 0x31 0x32
|
||||
0x7fffffffe290: 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30
|
||||
0x7fffffffe298: 0x31 0x32 0x00 0x8a 0x8a 0xbb 0x58 0xb6
|
||||
0x7fffffffe2a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe2a8: 0x25 0x4b 0xdf 0xf7 0xff 0x7f 0x00 0x00
|
||||
0x7fffffffe2b0: 0x98 0xe3 0xff 0xff 0xff 0x7f 0x00 0x00
|
||||
0x7fffffffe2b8: 0x00 0xa0 0xfc 0xf7 0x01 0x00 0x00 0x00
|
||||
```
|
||||
|
||||
The weird thing about this is that **stack_string was only supposed to be 10 bytes**. But now suddenly we’ve put 13 bytes in it? What’s happening?
|
||||
|
||||
This is a classic buffer overflow, and what’s happening is that `stack_string` wrote over other data from the program. This hasn’t caused a problem yet in our case, but it can crash your program or, worse, open you up to Very Bad Security Problems.
|
||||
|
||||
For example, if `stack_string` were before `heap_string` in memory, then we could overwrite the address that `heap_string` points to. I’m not sure exactly what’s in memory after `stack_string` here but we could probably use this to do some kind of shenanigans.
|
||||
|
||||
### something actually detects the buffer overflow
|
||||
|
||||
When I cause this buffer overflow problem, here’s
|
||||
|
||||
```
|
||||
./test
|
||||
Enter a string for the stack: 01234567891324143
|
||||
Enter a string for the heap: adsf
|
||||
Stack string is: 01234567891324143
|
||||
Heap string is: adsf
|
||||
x is: 10
|
||||
*** stack smashing detected ***: terminated
|
||||
fish: Job 1, './test' terminated by signal SIGABRT (Abort)
|
||||
```
|
||||
|
||||
My guess about what’s happening here is that the `stack_string` variable is actually at the end of this function’s stack, and so the extra bytes are going into a different region of memory.
|
||||
|
||||
When you do this intentionally as a security exploit it’s called “stack smashing”, and somehow something is detecting that this is happening. I’m not totally sure how this is being detected.
|
||||
|
||||
I also thing this is interesting because the program gets killed, but it doesn’t get killed immediately when the buffer overflow happens – a few more lines of code run after the buffer overflow and the program gets killed later. Weird!
|
||||
|
||||
That’s all I have to say about buffer overflows.
|
||||
|
||||
### now let’s look at `heap_string`
|
||||
|
||||
We also read a value (`bananas`) into the `heap_string` variable. Let’s see what that looks like in memory.
|
||||
|
||||
Here’s what `heap_string` looks on the stack after we read the variable in.
|
||||
|
||||
```
|
||||
(gdb) x/40x $sp
|
||||
0x7fffffffe270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe278: 0x50 0x52 0x55 0x55 0x0a 0x00 0x00 0x00
|
||||
0x7fffffffe280: 0xa0 0x92 0x55 0x55 0x55 0x55 0x00 0x00
|
||||
0x7fffffffe288: 0x70 0x50 0x55 0x55 0x55 0x55 0x31 0x32
|
||||
0x7fffffffe290: 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30
|
||||
```
|
||||
|
||||
The thing to notice here is that it looks exactly the same! It’s an address, and the address hasn’t changed. But let’s look at what’s at that address.
|
||||
|
||||
```
|
||||
(gdb) x/10x 0x5555555592a0
|
||||
0x5555555592a0: 0x62 0x61 0x6e 0x61 0x6e 0x61 0x73 0x00
|
||||
0x5555555592a8: 0x00 0x00
|
||||
```
|
||||
|
||||
Those are the bytes for `bananas`! Those bytes aren’t in the stack at all, they’re somewhere else in memory (on the heap)
|
||||
|
||||
### where are the stack and the heap?
|
||||
|
||||
We’ve talked about how the stack and the heap are different regions of memory, but how can you tell where they are in memory?
|
||||
|
||||
There’s a file for each process called `/proc/$PID/maps` that shows you the memory maps for each process. Here’s where you can see the stack and the heap in there.
|
||||
|
||||
```
|
||||
$ cat /proc/24963/maps
|
||||
... lots of stuff omitted ...
|
||||
555555559000-55555557a000 rw-p 00000000 00:00 0 [heap]
|
||||
... lots of stuff omitted ...
|
||||
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
|
||||
```
|
||||
|
||||
One thing to notice is that here the heap addresses start with `0x5555` and the stack addresses start with `0x7fffff`. So it’s pretty easy to tell the difference between an address on the stack and an address on the heap.
|
||||
|
||||
### playing about with gdb like this is really helpful
|
||||
|
||||
This was kind of a whirlwind tour and I didn’t explain everything, but hopefully seeing what the data actually looks like in memory makes it a little more clear what the stack actually is.
|
||||
|
||||
I really recommend playing around with gdb like this – even if you don’t understand every single thing that you see in memory, I find that actually seeing the data in my program’s memory like this makes these abstract concepts like “the stack” and “the heap” and “pointers” a lot easier to understand.
|
||||
|
||||
### ideas for more exercises
|
||||
|
||||
A few ideas (in no particular order) for followup exercises to think about the stack:
|
||||
|
||||
* try adding another function to `test.c` and make a breakpoint at the beginning of that function and see if you can find the stack from `main`! They say that “the stack grows down” when you call a function, can you see that happening in gdb?
|
||||
* return a pointer from a function to a string on the stack and see what goes wrong. Why is it bad to return a pointer to a string on the stack?
|
||||
* try causing a stack overflow in C and try to understand exactly what happens when the stack overflows by looking at it in gdb!
|
||||
* look at the stack in a Rust program and try to find the variables!
|
||||
* try some of the buffer overflow challenges in the [nightmare course][1]. The README for each challenge is the solution so avoid reading it if you don’t want to be spoiled. The idea with all of those challenges is that you’re given a binary and you need to figure out how to cause a buffer overflow to get it to print out the “flag” string.
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2021/05/17/how-to-look-at-the-stack-in-gdb/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/guyinatuxedo/nightmare
|
@ -1,230 +0,0 @@
|
||||
[#]: subject: (Use open source tools to set up a private VPN)
|
||||
[#]: via: (https://opensource.com/article/21/5/open-source-private-vpn)
|
||||
[#]: author: (Lukas Janėnas https://opensource.com/users/lukasjan)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Use open source tools to set up a private VPN
|
||||
======
|
||||
Use OpenWRT and Wireguard to create your own virtual private network on
|
||||
your router.
|
||||
![scrabble letters used to spell "VPN"][1]
|
||||
|
||||
Getting from one place to another over a computer network can be a tricky thing. Aside from knowing the right address and opening the right ports, there's the question of security. For Linux, SSH is a popular default, and while there's a lot you can do with SSH it's still "just" a secure shell (that's what SSH stands for, in fact.) A broader protocol for encrypted traffic is VPN, which creates a unique, virtual private network between two points. With it, you can log in to a computer on another network and use all of its services (file shares, printers, and so on) just as if you were physically sitting in the same room, and every bit of data is encrypted from point to point.
|
||||
|
||||
Normally, in order to make a VPN connection possible, the gateways into each network must accept VPN traffic, and some computer on your target network must be listening for VPN traffic. However, it's possible to run your own router firmware that runs a VPN server, enabling you to connect to your target network without having to worry about forwarding ports or thinking at all about internal topography. My favorite firmware is OpenWrt, and in this article I demonstrate how to set it up, and how to enable VPN on it.
|
||||
|
||||
### What is OpenWrt?
|
||||
|
||||
[OpenWrt][2] is an open source project that uses Linux to target embedded devices. It's been around for more than 15 years and has a large and active community.
|
||||
|
||||
There are many ways to use OpenWrt, but its main purpose is in routers. It provides a fully writable filesystem with package management, and because it is open source, you can see and modify the code and contribute to the ecosystem. If you would like to have more control over your router, this is the system you want to use.
|
||||
|
||||
OpenWrt supports many routers, including famous brands such as [Cisco][3], [ASUS][4], [MikroTik][5], [Teltonika Networks][6], [D-Link][7], [TP-link][8], [Buffalo][9], [Ubiquiti][10], and [many others][11].
|
||||
|
||||
### What is Wireguard?
|
||||
|
||||
[Wireguard][12] is open source virtual private network (VPN) software that is much faster, simpler, and more secure than other options such as OpenVPN. It uses state-of-the-art cryptography: ChaCha20 for symmetric cryptography; Curve 25519 (which uses elliptic curves) for key agreement; and BLAKE2 for hashing. These algorithms are designed in a way that is efficient on embedded systems. WIreguard is also available on a wide variety of operating system [platforms][13].
|
||||
|
||||
### Prerequisites
|
||||
|
||||
For this project, you will need:
|
||||
|
||||
* [Teltonika RUT955][14] or another router supported by OpenWrt
|
||||
* A public IP address to connect to your VPN from outside your network
|
||||
* An Android phone
|
||||
|
||||
|
||||
|
||||
### Install OpenWrt
|
||||
|
||||
To get started, download the OpenWrt image for your router. Use the [firmware selector][15] to check if OpenWrt supports your router and download the firmware. Enter your router's model, and it will show your options:
|
||||
|
||||
![OpenWRT firmware selector][16]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
Select the firmware version you want to download by using the drop-down input on the right side of the search box.
|
||||
|
||||
Download the factory image.
|
||||
|
||||
![Downloading the Factory Image][18]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
Many routers allow you to flash unauthorized firmware from the web interface, but Teltonika Networks does not. To flash the OpenWrt firmware to a router like this, you need to use the bootloader. To do so, follow these steps:
|
||||
|
||||
1. Unplug the router's power cable.
|
||||
2. Press and hold the Reset button.
|
||||
3. Plug in the router's power cable.
|
||||
4. Continue holding the reset button for 5 to 8 seconds after you plug the power cable in.
|
||||
5. Set computer's IP address to `192.168.1.15` and the netmask to `255.255.255.0`.
|
||||
6. Connect the router and your computer with an Ethernet cable over a LAN port.
|
||||
7. Open a web browser and enter `192.168.1.1:/index.html`.
|
||||
8. Upload and flash the firmware.
|
||||
|
||||
|
||||
|
||||
The flashing process can take up to three minutes. Afterward, you should be able to reach the router's web interface by entering `192.168.1.1` in a browser. There is no password set by default.
|
||||
|
||||
![OpenWrt authorization][19]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
### Configure network connectivity
|
||||
|
||||
Network connectivity is a requirement. If your Internet service provider (ISP) assigns your IP address automatically using DHCP, you just need to plug your Ethernet cable into the WAN port of your router.
|
||||
|
||||
If you need to assign the IP address manually, navigate to **Network → Interfaces**. Select **Edit** to edit your WAN interface. From the **Protocol** field, select **Static address**, and select **Switch protocol**.
|
||||
|
||||
![Assigning IP address manually][20]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
In the **IPv4 address** field, enter your router's address. Set **IPv4 netmask** to match your network subnet; enter the **IPv4 gateway** address you will use to connect to the network; and enter the DNS server's address in the **Use custom DNS servers** field. Save the configuration.
|
||||
|
||||
That's it! You have successfully configured your WAN interface to get network connectivity.
|
||||
|
||||
### Install the necessary packages
|
||||
|
||||
The firmware doesn't include many packages by default, but OpenWrt has a package manager with a selection of packages you can install. Navigate to **System → Software** and update your package manager by selecting **Update lists…**
|
||||
|
||||
![OpenWrt package manager][21]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
In the Filter input, type **Wireguard**, and wait until the system finds all the packages that include this keyword. Find and install the package named **luci-app-wireguard**.
|
||||
|
||||
![luci-app-wireguard package][22]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
This package includes a web interface to configure Wireguard and installs all the dependencies necessary for Wireguard to work.
|
||||
|
||||
If you get a warning that a package is missing and can't be found in the repositories before installing the Wireguard package, just ignore it and proceed.
|
||||
|
||||
Next, find and install the package named **luci-app-ttyd**. This will be used to access the terminal later.
|
||||
|
||||
After these packages are installed, reboot your router for the changes to take effect.
|
||||
|
||||
### Configure the Wireguard interface
|
||||
|
||||
Next, create the Wireguard interface. Navigate to **Network → Interfaces** and select **Add new interface…** on the bottom-left. In the pop-up window, enter your desired name for the interface, choose **Wireguard VPN** from the drop-down list, and select **Create interface** on the lower-right.
|
||||
|
||||
![Creating Wireguard interface][23]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
In the new pop-up window, select **Generate Key** to generate a private key for the Wireguard interface. In the **Listen Port** field, enter your desired port. I will use the default Wireguard port, **51820**. In the **IP Addresses** field, assign the IP address which will be used for the Wireguard interface. In this example, I use `10.0.0.1/24`. The number **24** indicates the size of my subnet.
|
||||
|
||||
![Creating Wireguard interface][24]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
Save the configuration and restart the interface.
|
||||
|
||||
Navigate to **Services → Terminal**, log into the shell, and enter the command `wg show`. You will see some information about your Wiregaurd interface, including its public key. Copy down the public key—you will need it to create peers later.
|
||||
|
||||
![Wireguard public key][25]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
### Configure the firewall
|
||||
|
||||
Navigate to **Network → Firewall** and select the **Traffic Rules** tab. On the bottom of the page, select **Add**. In the **Name** field of the pop-up window, give your rule a name, e.g., **Allow-wg**. Next, change the **Destination zone** from **Lan** to **Device**, and set the **Destination port** to 51820.
|
||||
|
||||
![Wireguard firewall setup][26]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
Save the configuration.
|
||||
|
||||
### Configure Wireguard on an Android phone
|
||||
|
||||
Install the [Wireguard app][27] on your phone from Google Play. Once it's installed, open the app and create a new interface from scratch. In the **Name** field, enter the name you want to use for your interface. In the **Private key** field, press the double-arrow icon on the right to generate a key pair. You will need the public key from above to create a peer between your phone and router. In the **Addresses** field, assign the IP address you will use to reach the phone over VPN. I will use `10.0.0.2/24`. In **Listen port**, enter a port; I will again use the default port.
|
||||
|
||||
![Setting up VPN interface on Android][28]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
Save the configuration.
|
||||
|
||||
To add a peer to the configuration, select **Add peer**. In the **Public key** field, enter your router's Wireguard public key. In the **Endpoint** field, enter your router's public IP address and port separated by a colon, e.g., `12.34.56.78:51820`. In the **Allowed IP**s field, enter the IP addresses you want to reach through the Wireguard interface. (You can enter your router's VPN interface IP address and LAN interface address.) The IP addresses must be separated by commas. You can also define the size of the subnet.
|
||||
|
||||
![Adding a VPN peer on an Android][29]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
Save the configuration.
|
||||
|
||||
There's one last step left in the configuration: adding a peer on the router.
|
||||
|
||||
### Add a peer on the router
|
||||
|
||||
Navigate to **Network → Interfaces** and select your Wireguard interface. Go to the **Peers** tab and select **Add peer**. In the **Description** field, enter the peer's name. In the **Public Key** field, enter your phone's Wireguard interface public key, and in the **Allowed IPs** field, enter your phone's Wireguard interface IP address. Check the **Route Allowed IPs** checkbox.
|
||||
|
||||
![Adding a peer on the router][30]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
Save the configuration and restart the interface.
|
||||
|
||||
### Test the configuration
|
||||
|
||||
Open a web browser on your phone. In the URL bar, enter the IP address `10.0.0.1` or `192.168.1.1`. You should be able to reach your router's website.
|
||||
|
||||
![Logging into the VPN from Android][31]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
### Your very own VPN
|
||||
|
||||
There are lots of VPN services being advertised these days, but there's a lot to be said for owning and controlling your own infrastructure, especially when that infrastructure only exists to boost security. There's no need to rely on somebody else to provide you with a secure connection to your data. Using OpenWrt and Wireguard, you can have your own open source VPN solution.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/5/open-source-private-vpn
|
||||
|
||||
作者:[Lukas Janėnas][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/lukasjan
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/vpn_scrabble_networking.jpg?itok=pdsUHw5N (scrabble letters used to spell "VPN")
|
||||
[2]: https://openwrt.org/
|
||||
[3]: https://www.cisco.com/c/en/us/products/routers/index.html
|
||||
[4]: https://www.asus.com/Networking-IoT-Servers/WiFi-Routers/All-series/
|
||||
[5]: https://mikrotik.com/
|
||||
[6]: https://teltonika-networks.com/
|
||||
[7]: https://www.dlink.com/en/consumer
|
||||
[8]: https://www.tp-link.com/us/
|
||||
[9]: https://www.buffalotech.com/products/category/wireless-networking
|
||||
[10]: https://www.ui.com/
|
||||
[11]: https://openwrt.org/toh/views/toh_fwdownload
|
||||
[12]: https://www.wireguard.com/
|
||||
[13]: https://www.wireguard.com/install/
|
||||
[14]: https://teltonika-networks.com/product/rut955/
|
||||
[15]: https://firmware-selector.openwrt.org/
|
||||
[16]: https://opensource.com/sites/default/files/uploads/openwrt_firmware-selector.png (OpenWRT firmware selector)
|
||||
[17]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[18]: https://opensource.com/sites/default/files/uploads/downloadfactoryimage.png (Downloading the Factory Image)
|
||||
[19]: https://opensource.com/sites/default/files/uploads/openwrt_authorization.png (OpenWrt authorization)
|
||||
[20]: https://opensource.com/sites/default/files/uploads/openwrt_staticaddress.png (Assigning IP address manually)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/openwrt_update-lists.png (OpenWrt package manager)
|
||||
[22]: https://opensource.com/sites/default/files/uploads/wireguard-package.png (luci-app-wireguard package)
|
||||
[23]: https://opensource.com/sites/default/files/uploads/wireguard_createinterface.png (Creating Wireguard interface)
|
||||
[24]: https://opensource.com/sites/default/files/uploads/wireguard_createinterface2.png (Creating Wireguard interface)
|
||||
[25]: https://opensource.com/sites/default/files/uploads/wireguard_publickey.png (Wireguard public key)
|
||||
[26]: https://opensource.com/sites/default/files/uploads/wireguard-firewallsetup.png (Wireguard firewall setup)
|
||||
[27]: https://play.google.com/store/apps/details?id=com.wireguard.android&hl=lt&gl=US
|
||||
[28]: https://opensource.com/sites/default/files/uploads/vpn_inferfacesetup.png (Setting up VPN interface on Android)
|
||||
[29]: https://opensource.com/sites/default/files/uploads/addpeeronphone.png (Adding a VPN peer on an Android)
|
||||
[30]: https://opensource.com/sites/default/files/uploads/addpeeronrouter.png (Adding a peer on the router)
|
||||
[31]: https://opensource.com/sites/default/files/uploads/android-vpn-login.png (Logging into the VPN from Android)
|
@ -2,7 +2,7 @@
|
||||
[#]: via: (https://itsfoss.com/reset-linux-password-wsl/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
91
sources/tech/20210628 How to archive files on FreeDOS.md
Normal file
91
sources/tech/20210628 How to archive files on FreeDOS.md
Normal file
@ -0,0 +1,91 @@
|
||||
[#]: subject: (How to archive files on FreeDOS)
|
||||
[#]: via: (https://opensource.com/article/21/6/archive-files-freedos)
|
||||
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
How to archive files on FreeDOS
|
||||
======
|
||||
There's a version of tar on FreeDOS, but the de facto standard archiver
|
||||
on DOS is Zip and Unzip.
|
||||
![Filing cabinet for organization][1]
|
||||
|
||||
On Linux, you may be familiar with the standard Unix archive command: `tar`. There's a version of `tar` on FreeDOS too (and a bunch of other popular archive programs), but the de facto standard archiver on DOS is Zip and Unzip. Both Zip and Unzip are installed in FreeDOS 1.3 RC4 by default.
|
||||
|
||||
The Zip file format was originally conceived in 1989 by Phil Katz of PKWARE, for the PKZIP and PKUNZIP pair of DOS archive utilities. Katz released the specification for Zip files as an open standard, so anyone could create Zip archives. As a result of the open specification, Zip became a standard archive on DOS. The [Info-ZIP][2] project implements an open source set of `ZIP` and `UNZIP` programs.
|
||||
|
||||
### Zipping files and directories
|
||||
|
||||
You can use `ZIP` at the DOS command line to create archives of files and directories. This is a handy way to make a backup copy of your work or to release a "package" to use in a future FreeDOS distribution. For example, let's say I wanted to make a backup of my project source code, which contains these source files:
|
||||
|
||||
![dir][3]
|
||||
|
||||
I'd like to archive these files
|
||||
(Jim Hall, [CC-BY SA 4.0][4])
|
||||
|
||||
`ZIP` sports a ton of command-line options to do different things, but the command line options I use most are `-r` to process directories and subdirectories _recursively_, and `-9` to provide the maximum compression possible. `ZIP` and `UNZIP` use a Unix-like command line, so you can combine options behind the dash: `-9r` will give maximum compression and include subdirectories in the Zip file.
|
||||
|
||||
![zip][5]
|
||||
|
||||
Zipping a directory tree
|
||||
(Jim Hall, [CC-BY SA 4.0][4])
|
||||
|
||||
In my example, `ZIP` was able to compress my source files from about 33 kilobytes down to about 22 kilobytes, saving me 11 kilobytes of valuable disk space. You might get different compression ratios depending on what options you give to `ZIP` or what files (and how many) you are trying to store in a Zip file. Generally, very long text files (such as source code) yield good compression—very small text files (like DOS "batch" files of only a few lines) are usually too short to compress well.
|
||||
|
||||
### Unzipping files and directories
|
||||
|
||||
Saving files into a Zip file is great, but you'll eventually need to extract those files somewhere. Let's start by examining what's inside the Zip file we just created. For this, use the `UNZIP` command. You can use a bunch of different options with `UNZIP`, but I find I use just a few common options.
|
||||
|
||||
To list the contents of a Zip file, use the `-l` ("list") option:
|
||||
|
||||
![unzip -l][6]
|
||||
|
||||
Listing the archive file contents with unzip
|
||||
(Jim Hall, [CC-BY SA 4.0][4])
|
||||
|
||||
The output allows me to see the 14 entries in the Zip file: 13 files plus the `SRC` directory entry.
|
||||
|
||||
If I want to extract the entire Zip file, I could just use the `UNZIP` command and provide the Zip file as a command-line option. That extracts the Zip file starting at my current working directory. Unless I'm restoring a previous version of something, I usually don't want to overwrite my current files. In that case, I will want to extract the Zip file to a new directory. You can specify the destination path with the `-d` ("destination") command-line option:
|
||||
|
||||
![unzip -d temp][7]
|
||||
|
||||
You can unzip into a destination path with -d
|
||||
(Jim Hall, [CC-BY SA 4.0][4])
|
||||
|
||||
Sometimes I want to extract a single file from a Zip file. In this example, let's say I wanted to extract `TEST.EXE`, a DOS executable program. To extract a single file, you specify the full path _from the Zip file_ that you want to extract. By default, `UNZIP` will extract this file using the path provided in the Zip file. To omit the path information, you can add the `-j` ("junk the path") option.
|
||||
|
||||
You can also combine options. Let's extract the `SRC\TEST.EXE` program from the Zip file, but omit the full path and save it in the `TEMP` directory:
|
||||
|
||||
![unzip -j][8]
|
||||
|
||||
Combining options with unzip
|
||||
(Jim Hall, [CC-BY SA 4.0][4])
|
||||
|
||||
Because Zip files are an open standard, we continue to see Zip files today. Every Linux distribution supports Zip files using the Info-ZIP programs. Your Linux file manager may also have Zip file support—on the GNOME file manager, you should be able to right-click on a folder and select "Compress" from the drop-down menu. You'll have the option to create a new archive file, including a Zip file.
|
||||
|
||||
Creating and managing Zip files is a key skill for any DOS user. You can learn more about `ZIP` and `UNZIP` at the Info-ZIP website, or use the `-h` ("help") option on the command line to print out a list of options.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/6/archive-files-freedos
|
||||
|
||||
作者:[Jim Hall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jim-hall
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/files_documents_organize_letter.png?itok=GTtiiabr (Filing cabinet for organization)
|
||||
[2]: http://infozip.sourceforge.net/
|
||||
[3]: https://opensource.com/sites/default/files/uploads/dir.png (I'd like to archive these files)
|
||||
[4]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/zip-9r.png (Zipping a directory tree)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/unzip-l.png (Listing the archive file contents with unzip)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/unzip-d.png (You can unzip into a destination path with -d)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/unzip-j.png (Combining options with unzip)
|
@ -0,0 +1,155 @@
|
||||
[#]: subject: (How to parse Bash program configuration files)
|
||||
[#]: via: (https://opensource.com/article/21/6/bash-config)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
How to parse Bash program configuration files
|
||||
======
|
||||
Separating config files from code enables anyone to change their
|
||||
configurations without any special programming skills.
|
||||
![bash logo on green background][1]
|
||||
|
||||
Keeping program configurations separate from code is important. It enables non-programmers to alter configurations without having to modify the program's code. With compiled binary executables, that would be impossible for non-programmers because it not only requires access to source files (which we do have with open source programs) but also a programmer's skill set. Few people have that, and most people don't want to learn.
|
||||
|
||||
With shell languages such as Bash, source code access is available by definition since shell scripts are not compiled into binary formats. Despite that openness, it is not a particularly good idea for non-programmers to root around in shell scripts and alter them. Even knowledgeable developers and sysadmins can make accidental changes that cause errors or worse.
|
||||
|
||||
So placing configuration items into easily maintained text files provides separation and allows non-programmers to edit configuration elements without the danger of making unintentional changes to the code. Many developers do this for programs written in compiled languages because they don't expect the users to be developers. For many of the same reasons, it also makes sense to do this with interpreted shell languages.
|
||||
|
||||
### The usual way
|
||||
|
||||
As with many other languages, you can write code for a Bash program that reads and parses ASCII text configuration files, reads the variable name, and sets values as the program code executes. For example, a configuration file might look like this:
|
||||
|
||||
|
||||
```
|
||||
var1=LinuxGeek46
|
||||
var2=Opensource.com
|
||||
```
|
||||
|
||||
The program would read that file, parse each line, and set the values into each variable.
|
||||
|
||||
### Sourcing
|
||||
|
||||
Bash uses a much easier method for parsing and setting variables called _sourcing_. Sourcing an external file from an executable shell program is a simple method for including the content of that file into a shell program in its entirety. In one sense, this is very much like compiled language `include` statements that include library files at runtime. Such a file can include any type of Bash code, including variable assignments.
|
||||
|
||||
As usual, it is easier to demonstrate than to explain.
|
||||
|
||||
First, create a `~/bin` directory (if it does not already exist), and make it the present working directory (PWD). The [Linux Filesystem Hierarchical Standard][2] defines `~/bin` as the appropriate place for users to store their executable files.
|
||||
|
||||
Create a new file in this directory. Name it `main` and make it executable:
|
||||
|
||||
|
||||
```
|
||||
[dboth@david bin]$ touch main
|
||||
[dboth@david bin]$ chmod +x main
|
||||
[dboth@david bin]$
|
||||
```
|
||||
|
||||
Add the following content to this executable file:
|
||||
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
Name="LinuxGeek"
|
||||
echo $Name
|
||||
```
|
||||
|
||||
And execute this Bash program:
|
||||
|
||||
|
||||
```
|
||||
[dboth@david bin]$ ./main
|
||||
LinuxGeek
|
||||
[dboth@david bin]$
|
||||
```
|
||||
|
||||
Create a new file and call it `~/bin/data`. This file does not need to be executable. Add the following information to it:
|
||||
|
||||
|
||||
```
|
||||
# Sourced code and variables
|
||||
echo "This is the sourced code from the data file."
|
||||
FirstName="David"
|
||||
LastName="Both"
|
||||
```
|
||||
|
||||
Add three lines to the `main` program so that it looks like this:
|
||||
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
Name="LinuxGeek"
|
||||
echo $Name
|
||||
source ~/bin/data
|
||||
echo "First name: $FirstName"
|
||||
echo "LastName: $LastName"
|
||||
```
|
||||
|
||||
Rerun the program:
|
||||
|
||||
|
||||
```
|
||||
[dboth@david bin]$ ./main
|
||||
LinuxGeek
|
||||
This is the sourced code from the data file.
|
||||
First name: David
|
||||
LastName: Both
|
||||
[dboth@david bin]$
|
||||
```
|
||||
|
||||
There is one more really cool thing to know about sourcing. You can use a single dot (`.`) as a shortcut for the `source` command. Change the `main` file to substitute the `.` in place of `source`:
|
||||
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
Name="LinuxGeek"
|
||||
echo $Name
|
||||
. ~/bin/data
|
||||
echo "First name: $FirstName"
|
||||
echo "LastName: $LastName"
|
||||
```
|
||||
|
||||
And run the program again. The result should be exactly the same as the previous run.
|
||||
|
||||
### Starting Bash
|
||||
|
||||
Every Linux host that uses Bash—which is pretty much all of them since Bash is the default shell for all distributions—includes some excellent, built-in examples of sourcing.
|
||||
|
||||
Whenever a Bash shell starts, its environment must be configured so that it is usable. There are five main files and one directory that are used to configure the Bash environment. They are listed here along with their main functions:
|
||||
|
||||
* `/etc/profile`: System-wide environment and startup programs
|
||||
* `/etc/bashrc`: System-wide functions and aliases
|
||||
* `/etc/profile.d/`: Directory that contains system-wide scripts for configuring various command-line tools such as `vim` and `mc` and any custom configuration scripts a sysadmin creates
|
||||
* `~/.bash_profile`: User-specific environment and startup programs
|
||||
* `~/.bashrc`: User-specific aliases and functions
|
||||
* `~/.bash_logout`: User-specific commands to execute when the user logs out
|
||||
|
||||
|
||||
|
||||
Try to trace the execution sequence through these files and determine which sequence it uses for a non-login Bash initialization versus a log-in Bash initialization. I did this in Chapter 17 of Volume 1 in my Linux training series, [_Using and administering Linux: Zero to sysadmin_][3].
|
||||
|
||||
I'll give you one hint. It all starts with the `~/.bashrc` script.
|
||||
|
||||
### Conclusion
|
||||
|
||||
This article explored sourcing for pulling code and variable assignments into a Bash program. This method of parsing variables from a configuration file is fast, easy, and flexible. It provides a method for separating Bash code from variable assignments to allow non-programmers to set the values of those variables.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/6/bash-config
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dboth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bash_command_line.png?itok=k4z94W2U (bash logo on green background)
|
||||
[2]: http://refspecs.linuxfoundation.org/fhs.shtml
|
||||
[3]: http://www.both.org/?page_id=1183
|
304
sources/tech/20210628 Introduction to image builder.md
Normal file
304
sources/tech/20210628 Introduction to image builder.md
Normal file
@ -0,0 +1,304 @@
|
||||
[#]: subject: (Introduction to image builder)
|
||||
[#]: via: (https://fedoramagazine.org/introduction-to-image-builder/)
|
||||
[#]: author: (Andy Mott https://fedoramagazine.org/author/amott/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Introduction to image builder
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Photo by [Marcel Strauß][2] on [Unsplash][3]
|
||||
|
||||
Image Builder is a tool that allows you to create custom OS images (based on the upstream project Weldr), and it’s included in the base repos so you can build images right from the start.
|
||||
|
||||
You can use the command line or a Cockpit plugin, and it’s a fairly simple and straightforward process which allows you to create images for most of the major platforms – Libvirt/KVM (RHV or general Linux virtualisation), VMware, Openstack, AWS and Azure. You can also deploy these images from Satellite.
|
||||
|
||||
### Installing Image Builder
|
||||
|
||||
To install Image Builder, run this command:
|
||||
|
||||
```
|
||||
sudo dnf install -y osbuild-composer composer-cli cockpit-composer
|
||||
```
|
||||
|
||||
If you’re not using Cockpit then omit that last package and you’ll just have the cli tool.
|
||||
|
||||
If you are using Cockpit, then make sure you add the service to firewalld to allow access like this:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --add-service=cockpit && sudo firewall-cmd --runtime-to-permanent
|
||||
```
|
||||
|
||||
You need to enable the osbuild-composer socket (and cockpit if you installed it and haven’t yet enabled it):
|
||||
|
||||
```
|
||||
sudo systemctl enable --now osbuild-composer.socket
|
||||
sudo systemctl enable --now cockpit.socket
|
||||
```
|
||||
|
||||
Image Builder is now running and ready to use so let’s create an image using the cli first, then move on to using Cockpit.
|
||||
|
||||
### Image Builder CLI
|
||||
|
||||
The main cli command is _composer-cli,_ which you use to create, list, examine and delete blueprints. It is also used to build, list, delete and download images for upload to their intended platform.
|
||||
|
||||
#### Available commands
|
||||
|
||||
The following is a list of the Image Builder commands and their functions:
|
||||
|
||||
**Blueprint manipulation** |
|
||||
---|---
|
||||
List all available blueprints | sudo composer-cli blueprints list
|
||||
Show a blueprint contents in the toml format | sudo composer-cli blueprints show _blueprint-name_
|
||||
Save (export) blueprint contents in the toml format into a file _blueprint-name.toml_ | sudo composer-cli blueprints save _blueprint-name_
|
||||
Remove a blueprint | sudo composer-cli blueprints delete _blueprint-name_
|
||||
Push (import) a blueprint file in the toml format into Image Builder | sudo composer-cli blueprints push _blueprint-name_
|
||||
**Composing images from blueprints** |
|
||||
Start a compose | sudo composer-cli compose start _blueprint-name_ _image-type_
|
||||
List all composes | sudo composer-cli compose list
|
||||
List all composes and their status | sudo composer-cli compose status
|
||||
Cancel a running compose | sudo composer-cli compose cancel _compose-uuid_
|
||||
Delete a finished compose | sudo composer-cli compose delete _compose-uuid_
|
||||
Show detailed information about a compose | sudo composer-cli compose info _compose-uuid_
|
||||
Download image file of a compose | sudo composer-cli compose image _compose-uuid_
|
||||
**Additional resources** |
|
||||
The composer-cli man page provides a full list of the available subcommands and options | man composer-cli
|
||||
The composer-cli command provides help on the subcommands and options | sudo composer-cli help
|
||||
|
||||
#### Creating an image blueprint
|
||||
|
||||
The first step in using Image Builder is to use your favorite editor to create the blueprint of the image itself. The blueprint includes everything the image needs to run. Let’s create a really simple one to begin with, then take it from there.
|
||||
|
||||
##### **Create the blueprint file**
|
||||
|
||||
Blueprint files are .toml files, created in your favorite editor, and the minimal required information is shown here:
|
||||
|
||||
```
|
||||
name = "image-name"
|
||||
description = "my image blueprint"
|
||||
version = "0.0.1"
|
||||
modules = []
|
||||
groups = []
|
||||
```
|
||||
|
||||
The file above can be used to create a minimal image with just the essential software required to run. Typically, images need a few more things, so let’s add in some additional packages. Add in the following below the groups item to add in extra packages:
|
||||
|
||||
```
|
||||
[[packages]]
|
||||
name = "bash-completion"
|
||||
version = "*"
|
||||
```
|
||||
|
||||
You will need to repeat this block for every package you wish to install. The version can be a specific version or the asterisk to denote the latest.
|
||||
|
||||
Going into a bit more detail, the groups declaration is used to add any groups you might need in the image. If you’re not adding any you can use the format above, but if you need to create a group remove the line shown above:
|
||||
|
||||
```
|
||||
groups = []
|
||||
```
|
||||
|
||||
and add this:
|
||||
|
||||
```
|
||||
[[groups]]
|
||||
name = "mygroup"
|
||||
```
|
||||
|
||||
Again, you need to repeat this block for every group you want to add.
|
||||
|
||||
It is recommended that you create at least a “root” user using something similar to this:
|
||||
|
||||
```
|
||||
[[customizations.user]]
|
||||
name = "root"
|
||||
description = "root"
|
||||
password = "$6$ZkdAX1t8QwEAc/GH$Oi3NY3fyTH/87ALiPfCzZTwpCoKv7P3bCVnoD9JnI8f5gV9I3A0bq5mZrKrw6isuYatmRQ.SVq3Vq27v3X2yu."
|
||||
home = "/home/root/"
|
||||
shell = "/usr/bin/bash"
|
||||
groups = ["root"]
|
||||
```
|
||||
|
||||
An example blueprint is available at <https://github.com/amott-rh/image-builder-blueprint> and it contains an explanation for creating the password hash. It doesn’t cover everything, but has the majority of the options shown.
|
||||
|
||||
##### **Push the blueprint to Image Builder**
|
||||
|
||||
Once you have your blueprint ready, you need to push it to Image Builder. This command pushes file _blueprint-name.toml_ to Image Builder:
|
||||
|
||||
```
|
||||
sudo composer-cli blueprints push blueprint-name.toml
|
||||
```
|
||||
|
||||
Check that it has been pushed with the _blueprints list_ command:
|
||||
|
||||
```
|
||||
sudo composer-cli blueprints list
|
||||
```
|
||||
|
||||
##### Generate the image
|
||||
|
||||
Now you have your blueprint uploaded and can use it to generate images. Use the _compose-cli start_ command for this, giving the blueprint name and the output format you want (qcow, ami, vmdk, etc):
|
||||
|
||||
```
|
||||
sudo composer-cli compose start blueprint-name qcow2
|
||||
```
|
||||
|
||||
You can obtain a list of image types with:
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
sudo composer-cli compose types
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
The _compose_ step creates a minimally-sized image – if you want more space on your OS disk then add _–size_ and a size, in Gb, to the command.
|
||||
|
||||
The image compose will take a short time, and you can see the status of any images with the
|
||||
|
||||
compose status
|
||||
|
||||
command:
|
||||
|
||||
```
|
||||
sudo composer-cli compose status
|
||||
```
|
||||
|
||||
##### Using the image
|
||||
|
||||
When the image build is complete the status will show “FINISHED” and you can download it and use it to build your VM:
|
||||
|
||||
```
|
||||
sudo composer-cli compose image image-uuid
|
||||
```
|
||||
|
||||
The image UUID is displayed when you start the compose. It can also be found at the beginning of the compose status command output.
|
||||
|
||||
The downloaded image file is named with the UUID of the image plus the appropriate extension for the image type. You can copy this file to an image repository and rename as appropriate before creating a VM with it.
|
||||
|
||||
A simple qemu/kvm machine is started like this:
|
||||
|
||||
```
|
||||
sudo qemu-kvm --name test-image -m 1024 -hda ./UUID-disk.qcow2
|
||||
```
|
||||
|
||||
Alternatively, you can copy this image to a new file and use that file as the OS disk for a new VM.
|
||||
|
||||
### Image Builder in Cockpit
|
||||
|
||||
If you want to use Image Builder in Cockpit, you need to install the cockpit-composer package as described in the installation section above.
|
||||
|
||||
After installation, log into your Cockpit URL (localhost:9090) and select _Image Builder_ in the _Tools>Applications_ section. This will take you to the initial Image Builder page, where you can create new blueprints:
|
||||
|
||||
![][4]
|
||||
|
||||
#### Create a blueprint
|
||||
|
||||
Selecting the _Create blueprint_ button will display a dialogue box where you need to enter a name for your blueprint plus an optional description:
|
||||
|
||||
![][5]
|
||||
|
||||
After you enter a name and select _Create_, you move to the add packages page. Create a minimal image here by simply selecting the _Create Image_ button, or add extra packages by entering the name in the search box under _Available Components_ and then selecting the + button to add it to your image. Any dependencies required by the package will also be added to the image. Add as many packages as you require.
|
||||
|
||||
![][6]
|
||||
|
||||
After adding your packages, select the _Commit_ button to save your blueprint. You will be shown the changes your actions will make with the option to continue with your commit or discard the changes next.
|
||||
|
||||
When the commit has been made, you will be returned to the same screen where you can add more packages. If you’re done with that, select the name of your blueprint in the breadcrumbs at the top left of the screen to go to the main screen for that blueprint. From here you can add customizations (users, groups etc), more packages, or create the image:
|
||||
|
||||
![][7]
|
||||
|
||||
If your image requires any specific users, or if you want to edit the root user (I’d recommend this, either to set a password or add an ssh key so you can log in without having to further edit or customize the image), then you can do this here. You can also create a hostname, which is useful for a single-use image but less so if the image will be used as the base for multiple deployments.
|
||||
|
||||
To add a user, select the _Create user_ _account_ button. If you name this user root you can update the root account as you need. Enter a user name, description, any password and/or ssh public key, and if this user will be an administrative user (like root) then tick the box to signify this:
|
||||
|
||||
![][8]
|
||||
|
||||
Select the _Create_ button at the bottom to create the user and return to the main blueprint page. Here you will see the new user, and can create more as necessary. Once you’ve created all your users and added all your packages you can create am image from the blueprint by selecting the _Create image_ button at the upper right.
|
||||
|
||||
![][9]
|
||||
|
||||
#### Create an image
|
||||
|
||||
In the Create image dialogue select an image type from the dropdown list, then select a size. This will effectively be the size of the disk available in the OS, just like you’d specify the virtual disk size when creating a VM manually. This will be thin-provisioned, so the actual image file won’t be this size! Select _Creat_e, when finished, to add your image to a build queue.
|
||||
|
||||
![][10]
|
||||
|
||||
Building images takes a little time, and you can check progress or view completed images in the Images page:
|
||||
|
||||
![][11]
|
||||
|
||||
You can create multiple image types from the same blueprint, so you can deploy the exact same image on multiple platforms, increasing your security and making maintenance and administration easier.
|
||||
|
||||
#### Download the image
|
||||
|
||||
To use your image, you need to download it, then upload to your chosen platform. To download the image, select the 3-dot menu next to the image and choose _Download_:
|
||||
|
||||
![][12]
|
||||
|
||||
That’s it – your image is ready to deploy. For a simple QEMU/KVM example use the same command from the CLI section above.
|
||||
|
||||
```
|
||||
sudo qemu-kvm --name test-image -m 1024 -hda ./UUID-disk.qcow2
|
||||
```
|
||||
|
||||
#### Final thoughts
|
||||
|
||||
* You can always edit your blueprints at a later date. The Cockpit UI will automatically increment the version number, but you will need to do this yourself in the toml file if using the CLI. Once you’ve edited the blueprint you will also need to create a new image.
|
||||
* You may verify the TOML format using this web site <https://www.toml-lint.com/> Note that this verifies only the file formatting, not correctness of the content.
|
||||
* You can create images with different sizes if your environment has such requirements.
|
||||
* Create a different blueprint for each specific image you need – don’t update the same one with different packages and version numbers then create images from those.
|
||||
* Image Builder does not allow disks to be partitioned. The output types that have a partitioned disk will have a single partition and additionally any platform-specific partitions that are required to boot the system image. For example, qcow2 image type has a single root partition, and possibly a platform specific boot partition – like PReP for PPC64 system – that the image requires to boot.
|
||||
* Images types that may be created are listed in the following table:
|
||||
|
||||
**Description** | **CLI name** | **File Extension**
|
||||
---|---|---
|
||||
QEMU QCOW2 Image | qcow2 | .qcow2
|
||||
Ext4 File System Image | 80 | .qcow2
|
||||
Raw Partitioned Disk Image | partitiond-disk | .img
|
||||
Live Bootable ISO | live-iso | .iso
|
||||
TAR Archive | tar | .tar
|
||||
Amazon Machine Image Disk | ami | .ami
|
||||
VMware Virtual Machine Disk | vmdk | .vmdk
|
||||
Openstack | openstack | .qcow2
|
||||
|
||||
Image Builder is a fantastic tool for anyone who needs to have repeatable based images for their environment. It’s definitely still a work in progress, but new features are coming all the time, with plans to allow uploading directly into various hypervisors and cloud platforms and other cool stuff.
|
||||
|
||||
#### Image Builder documentation
|
||||
|
||||
Official Weldr documentation: <https://weldr.io/lorax/>
|
||||
|
||||
RHEL 8: <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/composing_a_customized_rhel_system_image/index>
|
||||
|
||||
RHEL 7: <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/image_builder_guide/index>
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/introduction-to-image-builder/
|
||||
|
||||
作者:[Andy Mott][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/amott/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2021/05/image_builder-816x345.jpg
|
||||
[2]: https://unsplash.com/@martzzl?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/s/photos/builder?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: https://fedoramagazine.org/wp-content/uploads/2021/05/image-builder-start-page-1024x198.png
|
||||
[5]: https://fedoramagazine.org/wp-content/uploads/2021/05/Screenshot-from-2021-05-25-10-20-34.png
|
||||
[6]: https://fedoramagazine.org/wp-content/uploads/2021/05/image-builder-add-components-1024x456.png
|
||||
[7]: https://fedoramagazine.org/wp-content/uploads/2021/05/image-builder-main-blueprint-page-1024x226.png
|
||||
[8]: https://fedoramagazine.org/wp-content/uploads/2021/05/image-builder-add-user.png
|
||||
[9]: https://fedoramagazine.org/wp-content/uploads/2021/05/image-builder-main-page-2-1024x303.png
|
||||
[10]: https://fedoramagazine.org/wp-content/uploads/2021/05/image-builder-create-image-2-1024x701.png
|
||||
[11]: https://fedoramagazine.org/wp-content/uploads/2021/05/image-builder-images-page-1024x252.png
|
||||
[12]: https://fedoramagazine.org/wp-content/uploads/2021/05/image-builder-download-image-1024x255.png
|
@ -0,0 +1,343 @@
|
||||
[#]: subject: (Query your Linux operating system like a database)
|
||||
[#]: via: (https://opensource.com/article/21/6/osquery-linux)
|
||||
[#]: author: (Gaurav Kamathe https://opensource.com/users/gkamathe)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Query your Linux operating system like a database
|
||||
======
|
||||
Use database-style queries to get system information easily.
|
||||
![Magnifying glass on code][1]
|
||||
|
||||
Linux offers a lot of commands to help users gather information about their host operating system: listing files or directories to check attributes; querying to see what packages are installed, processes are running, and services start at boot; or learning about the system's hardware.
|
||||
|
||||
Each command uses its own output format to list this information. You need to use tools like `grep`, `sed`, and `awk` to filter the results to find specific information. Also, a lot of this information changes frequently, leading to changes in the system's state.
|
||||
|
||||
It would be helpful to view all of this information formatted like the output of a database SQL query. Imagine that you could query the output of the `ps` and `rpm` commands as if you were querying an SQL database table with similar names.
|
||||
|
||||
Fortunately, there is a tool that does just that and much more: [Osquery][2] is an [open source][3] "SQL powered operating system instrumentation, monitoring, and analytics framework."
|
||||
|
||||
Many applications that handle security, DevOps, compliance, and inventory management (to name a few) depend upon the core functionalities provided by Osquery at their heart.
|
||||
|
||||
### Install Osquery
|
||||
|
||||
Osquery is available for Linux, macOS, Windows, and FreeBSD. Install the latest version for your operating system by following its [installation instructions][4]. (I'll use version 4.7.0 in these examples.)
|
||||
|
||||
After installation, verify it's working:
|
||||
|
||||
|
||||
```
|
||||
$ rpm -qa | grep osquery
|
||||
osquery-4.7.0-1.linux.x86_64
|
||||
$
|
||||
$ osqueryi --version
|
||||
osqueryi version 4.7.0
|
||||
$
|
||||
```
|
||||
|
||||
### Osquery components
|
||||
|
||||
Osquery has two main components:
|
||||
|
||||
* **osqueri** is an interactive SQL query console. It is a standalone utility that does not need super-user privileges (unless you are querying tables that need that level of access).
|
||||
* **osqueryd** is like a monitoring daemon for the host it is installed on. This daemon can schedule queries to execute at regular intervals to gather information from the infrastructure.
|
||||
|
||||
|
||||
|
||||
You can run the osqueri utility without having the osqueryd daemon running. Another utility, **osqueryctl**, controls starting, stopping, and checking the status of the daemon.
|
||||
|
||||
|
||||
```
|
||||
$ rpm -ql osquery-4.8.0-1.linux.x86_64 | grep bin
|
||||
/usr/bin/osqueryctl
|
||||
/usr/bin/osqueryd
|
||||
/usr/bin/osqueryi
|
||||
$
|
||||
```
|
||||
|
||||
### Use the osqueryi interactive prompt
|
||||
|
||||
You interact with Osquery much like you would use an SQL database. In fact, osqueryi is a modified version of the SQLite shell. Running the `osqueryi` command drops you into an interactive shell where you can run commands specific to Osquery, which often start with a `.`:
|
||||
|
||||
|
||||
```
|
||||
$ osqueryi
|
||||
Using a virtual database. Need help, type '.help'
|
||||
osquery>
|
||||
```
|
||||
|
||||
To quit the interactive shell, run the `.quit` command to get back to the operating system's shell:
|
||||
|
||||
|
||||
```
|
||||
osquery>
|
||||
osquery> .quit
|
||||
$
|
||||
```
|
||||
|
||||
### Find out what tables are available
|
||||
|
||||
As mentioned, Osquery makes data available as the output of SQL queries. Information in databases is often saved in tables. But how can you query these tables if you don't know their names? Well, you can run the `.tables` command to list all the tables that you can query. If you are a long-time Linux user or a sysadmin, the table names will be familiar, as you have been using operating system commands to get this information:
|
||||
|
||||
|
||||
```
|
||||
osquery> .tables
|
||||
=> acpi_tables
|
||||
=> apparmor_events
|
||||
=> apparmor_profiles
|
||||
=> apt_sources
|
||||
|
||||
<< snip >>
|
||||
|
||||
=> arp_cache
|
||||
=> user_ssh_keys
|
||||
=> users
|
||||
=> yara
|
||||
=> yara_events
|
||||
=> ycloud_instance_metadata
|
||||
=> yum_sources
|
||||
osquery>
|
||||
```
|
||||
|
||||
### Check the schema for individual tables
|
||||
|
||||
Now that you know the table names, you can see what information each table provides. As an example, choose `processes`, since the `ps` command is used quite often to get this information. Run the `.schema` command followed by the table name to see what information is saved in this table. If you want to check the results, you could quickly run `ps -ef` or `ps aux` and compare the output with the contents of the table:
|
||||
|
||||
|
||||
```
|
||||
osquery> .schema processes
|
||||
CREATE TABLE processes(`pid` BIGINT, `name` TEXT, `path` TEXT, `cmdline` TEXT, `state` TEXT, `cwd` TEXT, `root` TEXT, `uid` BIGINT, `gid` BIGINT, `euid` BIGINT, `egid` BIGINT, `suid` BIGINT, `sgid` BIGINT, `on_disk` INTEGER, `wired_size` BIGINT, `resident_size` BIGINT, `total_size` BIGINT, `user_time` BIGINT, `system_time` BIGINT, `disk_bytes_read` BIGINT, `disk_bytes_written` BIGINT, `start_time` BIGINT, `parent` BIGINT, `pgroup` BIGINT, `threads` INTEGER, `nice` INTEGER, `is_elevated_token` INTEGER HIDDEN, `elapsed_time` BIGINT HIDDEN, `handle_count` BIGINT HIDDEN, `percent_processor_time` BIGINT HIDDEN, `upid` BIGINT HIDDEN, `uppid` BIGINT HIDDEN, `cpu_type` INTEGER HIDDEN, `cpu_subtype` INTEGER HIDDEN, `phys_footprint` BIGINT HIDDEN, PRIMARY KEY (`pid`)) WITHOUT ROWID;
|
||||
osquery>
|
||||
```
|
||||
|
||||
To drive home the point, use the following command to see the schema for the RPM packages and compare the information with `rpm -qa` and `rpm -qi` operating system commands:
|
||||
|
||||
|
||||
```
|
||||
osquery>
|
||||
osquery> .schema rpm_packages
|
||||
CREATE TABLE rpm_packages(`name` TEXT, `version` TEXT, `release` TEXT, `source` TEXT, `size` BIGINT, `sha1` TEXT, `arch` TEXT, `epoch` INTEGER, `install_time` INTEGER, `vendor` TEXT, `package_group` TEXT, `pid_with_namespace` INTEGER HIDDEN, `mount_namespace_id` TEXT HIDDEN, PRIMARY KEY (`name`, `version`, `release`, `arch`, `epoch`, `pid_with_namespace`)) WITHOUT ROWID;
|
||||
osquery>
|
||||
```
|
||||
|
||||
You learn more in Osquery's [tables documentation][5].
|
||||
|
||||
### Use the PRAGMA command
|
||||
|
||||
In case that schema information is too cryptic for you, there is another way to print the table information in a verbose, tabular format: the `PRAGMA` command. For example, I'll use `PRAGMA` to see information for the `rpm_packages` table in a nice format:
|
||||
|
||||
|
||||
```
|
||||
`osquery> PRAGMA table_info(rpm_packages);`
|
||||
```
|
||||
|
||||
One benefit of this tabular information is that you can focus on the field you want to query and see the type of information that it provides:
|
||||
|
||||
|
||||
```
|
||||
osquery> PRAGMA table_info(users);
|
||||
+-----+-------------+--------+---------+------------+----+
|
||||
| cid | name | type | notnull | dflt_value | pk |
|
||||
+-----+-------------+--------+---------+------------+----+
|
||||
| 0 | uid | BIGINT | 1 | | 1 |
|
||||
| 1 | gid | BIGINT | 0 | | 0 |
|
||||
| 2 | uid_signed | BIGINT | 0 | | 0 |
|
||||
| 3 | gid_signed | BIGINT | 0 | | 0 |
|
||||
| 4 | username | TEXT | 1 | | 2 |
|
||||
| 5 | description | TEXT | 0 | | 0 |
|
||||
| 6 | directory | TEXT | 0 | | 0 |
|
||||
| 7 | shell | TEXT | 0 | | 0 |
|
||||
| 8 | uuid | TEXT | 1 | | 3 |
|
||||
+-----+-------------+--------+---------+------------+----+
|
||||
osquery>
|
||||
```
|
||||
|
||||
### Run your first query
|
||||
|
||||
Now that you have all the required information from the table, the schema, and the items to query, run your first SQL query to view the information. The query below returns the users that are present on the system and each one's user ID, group ID, home directory, and default shell. Linux users could get this information by viewing the contents of the `/etc/passwd` file and doing some `grep`, `sed`, and `awk` magic.
|
||||
|
||||
|
||||
```
|
||||
osquery>
|
||||
osquery> select uid,gid,directory,shell,uuid FROM users LIMIT 7;
|
||||
+-----+-----+----------------+----------------+------+
|
||||
| uid | gid | directory | shell | uuid |
|
||||
+-----+-----+----------------+----------------+------+
|
||||
| 0 | 0 | /root | /bin/bash | |
|
||||
| 1 | 1 | /bin | /sbin/nologin | |
|
||||
| 2 | 2 | /sbin | /sbin/nologin | |
|
||||
| 3 | 4 | /var/adm | /sbin/nologin | |
|
||||
| 4 | 7 | /var/spool/lpd | /sbin/nologin | |
|
||||
| 5 | 0 | /sbin | /bin/sync | |
|
||||
| 6 | 0 | /sbin | /sbin/shutdown | |
|
||||
+-----+-----+----------------+----------------+------+
|
||||
osquery>
|
||||
```
|
||||
|
||||
### Run queries without entering interactive mode
|
||||
|
||||
What if you want to run a query without entering the osqueri interactive mode? This could be very useful if you are writing shell scripts around it. In this case, you could `echo` the SQL query and pipe it to osqueri right from the Bash shell:
|
||||
|
||||
|
||||
```
|
||||
$ echo "select uid,gid,directory,shell,uuid FROM users LIMIT 7;" | osqueryi
|
||||
+-----+-----+----------------+----------------+------+
|
||||
| uid | gid | directory | shell | uuid |
|
||||
+-----+-----+----------------+----------------+------+
|
||||
| 0 | 0 | /root | /bin/bash | |
|
||||
| 1 | 1 | /bin | /sbin/nologin | |
|
||||
| 2 | 2 | /sbin | /sbin/nologin | |
|
||||
| 3 | 4 | /var/adm | /sbin/nologin | |
|
||||
| 4 | 7 | /var/spool/lpd | /sbin/nologin | |
|
||||
| 5 | 0 | /sbin | /bin/sync | |
|
||||
| 6 | 0 | /sbin | /sbin/shutdown | |
|
||||
+-----+-----+----------------+----------------+------+
|
||||
$
|
||||
```
|
||||
|
||||
### Learn what services start when booting up
|
||||
|
||||
Osquery can also return all the services set to start at boot. For example, to query the `startup_items` table and get the name, status, and path of the first five services that run at startup:
|
||||
|
||||
|
||||
```
|
||||
osquery> SELECT name,type,status,path FROM startup_items LIMIT 5;
|
||||
name = README
|
||||
type = Startup Item
|
||||
status = enabled
|
||||
path = /etc/rc.d/init.d/README
|
||||
|
||||
name = anamon
|
||||
type = Startup Item
|
||||
status = enabled
|
||||
path = /etc/rc.d/init.d/anamon
|
||||
|
||||
name = functions
|
||||
type = Startup Item
|
||||
status = enabled
|
||||
path = /etc/rc.d/init.d/functions
|
||||
|
||||
name = osqueryd
|
||||
type = Startup Item
|
||||
status = enabled
|
||||
path = /etc/rc.d/init.d/osqueryd
|
||||
|
||||
name = AT-SPI D-Bus Bus
|
||||
type = Startup Item
|
||||
status = enabled
|
||||
path = /usr/libexec/at-spi-bus-launcher --launch-immediately
|
||||
osquery>
|
||||
```
|
||||
|
||||
### Look up ELF information for a binary
|
||||
|
||||
Imagine you want to find out more details about the `ls` binary. Usually, you would do it with the `readelf -h` command followed by the `ls` command's path. You can query the `elf_info` table with Osquery and get the same information:
|
||||
|
||||
|
||||
```
|
||||
osquery> SELECT * FROM elf_info WHERE path="/bin/ls";
|
||||
class = 64
|
||||
abi = sysv
|
||||
abi_version = 0
|
||||
type = dyn
|
||||
machine = 62
|
||||
version = 1
|
||||
entry = 24064
|
||||
flags = 0
|
||||
path = /bin/ls
|
||||
osquery>
|
||||
```
|
||||
|
||||
Now you have a taste of how to use osqueri to look for information of interest to you. However, this information is stored on a huge number of tables; one system I queried had 156 different tables, which can be overwhelming:
|
||||
|
||||
|
||||
```
|
||||
$ echo ".tables" | osqueryi | wc -l
|
||||
156
|
||||
$
|
||||
```
|
||||
|
||||
To make things easier, you can start with these tables to get information about your Linux system:
|
||||
|
||||
**System information table**
|
||||
|
||||
|
||||
```
|
||||
`osquery> select * from system_info;`
|
||||
```
|
||||
|
||||
**System limit information**
|
||||
|
||||
|
||||
```
|
||||
`osquery> select * from ulimit_info;`
|
||||
```
|
||||
|
||||
**Files opened by various processes**
|
||||
|
||||
|
||||
```
|
||||
`osquery> select * from process_open_files;`
|
||||
```
|
||||
|
||||
**Open ports on a system**
|
||||
|
||||
|
||||
```
|
||||
`osquery> select * from listening_ports;`
|
||||
```
|
||||
|
||||
**Running processes information**
|
||||
|
||||
|
||||
```
|
||||
`osquery> select * from processes;`
|
||||
```
|
||||
|
||||
**Installed packages information**
|
||||
|
||||
|
||||
```
|
||||
`osquery> select * from rpm_packages;`
|
||||
```
|
||||
|
||||
**User login information**
|
||||
|
||||
|
||||
```
|
||||
`osquery> select * from last;`
|
||||
```
|
||||
|
||||
**System log information**
|
||||
|
||||
|
||||
```
|
||||
`osquery> select * from syslog_events;`
|
||||
```
|
||||
|
||||
### Learn more
|
||||
|
||||
Osquery is a powerful tool that provides a lot of host information that can be used to solve various use cases. You can learn more about Osquery by [reading its documentation][6].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/6/osquery-linux
|
||||
|
||||
作者:[Gaurav Kamathe][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/gkamathe
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/find-file-linux-code_magnifying_glass_zero.png?itok=E2HoPDg0 (Magnifying glass on code)
|
||||
[2]: https://osquery.io/
|
||||
[3]: https://github.com/osquery/osquery
|
||||
[4]: https://osquery.io/downloads/official
|
||||
[5]: https://osquery.io/schema/4.8.0/
|
||||
[6]: https://osquery.readthedocs.io/en/latest/
|
@ -0,0 +1,91 @@
|
||||
[#]: subject: (Fotoxx: An Open Source App for Managing and Editing Large Photo Collection)
|
||||
[#]: via: (https://itsfoss.com/fotoxx/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Fotoxx: An Open Source App for Managing and Editing Large Photo Collection
|
||||
======
|
||||
|
||||
When it comes to [photo management software in Linux][1], Shotwell is perhaps the most famous of them all. No wonder it comes preinstalled in many distributions.
|
||||
|
||||
But if you are looking for a Shotwell like application which is a bit faster, Fotoxx could be a good choice.
|
||||
|
||||
It may not have a modern user interface, but it is fast in handling a large collection of photos. And it matters because indexing and showing thumbnails for thousands of photos could take considerable time and computing resources.
|
||||
|
||||
### Manage photos and edit them in Linux with Fotoxx
|
||||
|
||||
![Fotoxx interface][2]
|
||||
|
||||
As you can see in the screenshot above, it is not the nicest interface. Looks more like an application from around 2010. What it lacks in the visual department, it makes up with features and performance.
|
||||
|
||||
You can import a huge collection of photos, including RAW images. The images stay where they are. They are not copied or moved. They just get indexed in the application.
|
||||
|
||||
You can edit image metadata like tags, geotags, dates, ratings, captions etc. You can search images based on these matadata.
|
||||
|
||||
It also has a map feature that groups and displays images belonging to a certain location (based on geotag data on the images).
|
||||
|
||||
![Map view][3]
|
||||
|
||||
Since it focuses on managing large collection of photos, it has several batch functions to rename, resize, copy/move, convert image format and edit metadata.
|
||||
|
||||
You can select images to create albums and slideshows and all this happens without duplicating the images. Photos can be combined to create 360-degree panoramas.
|
||||
|
||||
Fotoxx also has several editing functions that can be used to retouch the images, add effect (like sketching, painting), trim, rotate and more.
|
||||
|
||||
There is also options for removing red eyes and dust spots from the old, scanned photo prints.
|
||||
|
||||
I can go on with the features list but it won’t end. Its website describes its full capabilities and you should check it out.
|
||||
|
||||
[Fotoxx Feature Overview][4]
|
||||
|
||||
If it interests you, you can watch this video that demonstrates the features of Fotoxx:
|
||||
|
||||
[Subscribe to It’s FOSS YouTube channel][5]
|
||||
|
||||
### Installing Fotoxx on Linux
|
||||
|
||||
Please keep in mind that **Fotoxx developer recommends a strong computer** with 4+ CPU cores, 16+ GB memory for proper functioning. Lesser computers may be slow or may fail to edit large images.
|
||||
|
||||
Fotoxx is available in the repositories of most Linux distributions like Debian, Ubuntu, Fedora and Arch Linux. Just use your distribution’s package manager or software center to search for Fotoxx and install it.
|
||||
|
||||
On Ubuntu and Debian based distributions, you can use the apt command to install it like this:
|
||||
|
||||
```
|
||||
sudo apt install fotoxx
|
||||
```
|
||||
|
||||
When you first run it, it will ask to search the home directory for images. You may continue with it or limit the search location to selected folders.
|
||||
|
||||
![][6]
|
||||
|
||||
I noticed that despite indexing over 4,700 in a minute or so, it didn’t start displaying the images immediately. I had to **click on Gallery->All Folders and the select the folder(s) and then it showed the images**. So, this is something to keep in mind.
|
||||
|
||||
Fotoxx is an extensive tool and it will take some time in getting used to it and explore all its features. Its webapge lists several examples that you should have a look at.
|
||||
|
||||
[Fotoxx Feature Examples][4]
|
||||
|
||||
As I said earlier, it is not the prettiest application, but it gets the job done with a huge list of features. If you are a photographer or have a large collection of images, you may give Fotoxx a try and see if it fits your need. And when you do that, please do share your experience with it in the comment section.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/fotoxx/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/linux-photo-management-software/
|
||||
[2]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/06/fotoxx-interface.jpg?resize=800%2C561&ssl=1
|
||||
[3]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/06/fotoxx-geotag-map-view.jpg?resize=800%2C466&ssl=1
|
||||
[4]: https://kornelix.net/fotoxx/fotoxx.html
|
||||
[5]: https://www.youtube.com/c/itsfoss?sub_confirmation=1
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/06/fotoxx-indexing.png?resize=800%2C617&ssl=1
|
@ -1,108 +0,0 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "zepoch"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: subject: "Why we open sourced our Python platform"
|
||||
[#]: via: "https://opensource.com/article/20/7/why-open-source"
|
||||
[#]: author: "Meredydd Luff https://opensource.com/users/meredydd-luff"
|
||||
|
||||
为什么我们要开源我们的 Python 平台
|
||||
======
|
||||
|
||||
开源开发的理念使得 Anvil 的整个解决方案更加有用且值得信赖。
|
||||
![neon sign with head outline and open source why spelled out][1]
|
||||
|
||||
Anvil 团队最近开源了 [Anvil App Server][2], 一个用于托管 Python Web 程序的运行引擎。
|
||||
|
||||
社区的反应十分积极,我们 Anvil 团队已经将许多反馈纳入了我们的 [next release][3]。但是我们不断被问到的问题是,“为什么你们选择开源这个产品的核心呢?”
|
||||
|
||||
|
||||
|
||||
### 我们为何创造 Anvil
|
||||
|
||||
[Anvil][4] 是一个可以使得构建 web app 更加简单的工具。我们让你们有能力仅使用一种语言——Python 就可以来构建你的整个应用。
|
||||
|
||||
在 Anvil 之前,如果你想要构建一个 web app,你需要写很多代码,用很多的技术,比如 HTML、Javascript、CSS、Python、SQL、React、Redux、Bootstrap、Sass、Webpack 等。这需要花费很长时间来学习。对于一个简单的应用便是这样子;相信我,一般的应用其实[更加复杂][5]。
|
||||
|
||||
![A complex framework of development tools needed for a simple web app][6]
|
||||
|
||||
是的。对于一个简单的 web app 便是需要如此多的技术。
|
||||
|
||||
但是从此之后,你便不再需要这样子做了。您仅仅需要了解有关 Git 和云托管提供商的所有信息、如何保护(最有可能的)Linux 操作系统、如何调整数据库,然后随时待命以保持其运行。
|
||||
|
||||
因此,相反的,我们开发出了 Anvil,一个在线 IDE,你可以在用一个[拖放编辑器][7]来设计你的 UI 界面,编写你的 [Python 逻辑][8],然后 Anvil 会负责其余的工作。我们将所有的繁杂的技术栈进行了替换,只用 Python 就行啦!
|
||||
|
||||
### 简单的网络托管很重要,但还不够
|
||||
|
||||
Anvil 还可以为您托管您的应用程序。 那么为什么还不够呢? 部署 Web 应用程序非常复杂,因此运行我们自己的云托管服务是提供我们所需的简单性的唯一方法。 在 Anvil 编辑器中构建一个应用程序,[单击按钮][9],它就在网上发布了。
|
||||
|
||||
但我们不断听到有人说,“那太好了,但是……”
|
||||
|
||||
* “我需要在不联网的本地平台来运行这个应用。”
|
||||
* “我想要将我的应用程序嵌入到我售出的 IoT 设备中”
|
||||
* "如果我把我的宝都压到你的 Anvil 上,我怎么能确定十年后我的应用仍然能够运行呢?”
|
||||
|
||||
|
||||
|
||||
这些都是好点子!云服务并不是适合所有人的解决方案。如果我们想为这些用户提供服务,他们必须通过某种方式让他们的应用程序脱离 Anvil 并在他们自己的完全控制下在本地运行。
|
||||
|
||||
### 开源是一个逃生舱,而不是弹射座椅
|
||||
|
||||
在会议上,我们有时会被问到,“我可以将它导出为 Flask+JS 的应用程序吗?” 当然,我们可以将 Anvil 项目分别导出为一个单独的 Python 和 JavaScript ——我们可以生成一个服务器包,将客户端中的 Python 编译为 Javascript,然后生成一个经典的 Web 应用程序。 但它会有严重的缺点,因为:**代码生成是一个弹射座椅。**
|
||||
|
||||
![Code generation is an ejector seat from a structured platform][10]
|
||||
|
||||
([图片][11] 公共许可)
|
||||
|
||||
生成的代码总比没有好;至少你可以编辑它!但是在您编辑该代码的那一刻,您就失去了生成它的系统的所有好处。如果您使用 Anvil 是因为它的[拖放编辑器][12] 和 [浏览器中的 Python][13],那么您为什么必须使用 vim 和 Javascript 才能在本地托管您的应用程序?
|
||||
|
||||
我们相信[逃生舱口,而不是弹射座椅][14]。 所以我们选择了一个正确的方式——我们[开源了 Anvil 的运行引擎][2],这与在我们的托管服务中为您的应用程序提供服务的代码相同。这是一个独立的应用程序;您可以使用文本编辑器编辑代码并在本地运行。但是您也可以将它直接“git push”回我们的在线 IDE。这不是弹射座椅;没有爆炸性的转变。这是一个逃生舱口;你可以爬出来,做你需要做的事情,然后再爬回来。
|
||||
|
||||
### If it's open, is it reliable?如果它开源了,它还可靠吗
|
||||
|
||||
开源中的一个看似矛盾的是,它的免费可用性是它的优势,但有时也会产生不稳定的感觉。 毕竟,如果你不收费,你如何保持这个平台的长期健康运行?
|
||||
|
||||
我们正在做我们一直在做的事情——提供一个开发工具,使构建 Web 应用程序变得非常简单,尽管您使用 Anvil 构建的应用程序 100% 是您的。 我们为 Anvil 应用程序提供托管,并为 [企业客户][15] 提供整个现场开发和托管平台。 这使我们能够提供免费计划,以便每个人都可以将 Anvil 用于业余爱好或教育目的,或者开始构建某些东西并查看它的去向。
|
||||
|
||||
### 得到的多,失去的少
|
||||
|
||||
开源我们的运行引擎并没有减少我们的业务——它使我们的在线 IDE 在今天和未来变得更有用、更值得信赖。我们为需要它的人开放了 Anvil App Server 的源代码,并提供最终的安全保障。 对于我们的用户来说,这是正确的举措——现在他们可以放心地进行构建,因为他们知道开源代码 [就在那里][3],如果他们需要的话。
|
||||
|
||||
如果我们的开发理念与您产生共鸣,何不亲自尝试 Anvil?
|
||||
|
||||
|
||||
\-----
|
||||
|
||||
这篇文章改编自 [Why We Open Sourced the Anvil App Server][16],经许可重复使用。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/7/why-open-source
|
||||
|
||||
作者:[Meredydd Luff][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zepoch](https://github.com/zepoch)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/meredydd-luff
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUS_OSwhy_520x292_ma.png?itok=lqfhAs8L "neon sign with head outline and open source why spelled out"
|
||||
[2]: https://anvil.works/blog/open-source
|
||||
[3]: https://github.com/anvil-works/anvil-runtime
|
||||
[4]: https://anvil.works/
|
||||
[5]: https://github.com/kamranahmedse/developer-roadmap#introduction
|
||||
[6]: https://opensource.com/sites/default/files/uploads/frameworks.png "A complex framework of development tools needed for a simple web app"
|
||||
[7]: https://anvil.works/docs/client/ui
|
||||
[8]: https://anvil.works/docs/client/python
|
||||
[9]: https://anvil.works/docs/deployment
|
||||
[10]: https://opensource.com/sites/default/files/uploads/ejector-seat-opensourcecom.jpg "Code generation is an ejector seat from a structured platform"
|
||||
[11]: https://commons.wikimedia.org/wiki/File:Crash.arp.600pix.jpg
|
||||
[12]: https://anvil.works/docs/editor
|
||||
[13]: https://anvil.works/docs/client
|
||||
[14]: https://anvil.works/blog/escape-hatches-and-ejector-seats
|
||||
[15]: https://anvil.works/docs/overview/enterprise
|
||||
[16]: https://anvil.works/blog/why-open-source
|
||||
|
394
translated/tech/20210517 How to look at the stack with gdb.md
Normal file
394
translated/tech/20210517 How to look at the stack with gdb.md
Normal file
@ -0,0 +1,394 @@
|
||||
[#]: subject: "How to look at the stack with gdb"
|
||||
[#]: via: "https://jvns.ca/blog/2021/05/17/how-to-look-at-the-stack-in-gdb/"
|
||||
[#]: author: "Julia Evans https://jvns.ca/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
使用 GDB 查看程序中栈空间
|
||||
======
|
||||
|
||||
昨天我和一些人在闲聊的时候,他们说他们并不了解栈是如何工作的,而且也不知道如何去查看栈空间。
|
||||
|
||||
这是一个快速教程,介绍如何使用 GDB 查看 C 程序的栈空间。我认为这对于 Rust 程序来说也是相似的。但我这里仍然使用 C 语言,因为我发现用它更简单,而且用 C 语言也更容易写出错误的程序。
|
||||
|
||||
### 我们的测试程序
|
||||
|
||||
这里是一个简单的 C 程序,声明了一些变量,从标准输入读取两个字符串。一个字符串在堆上,另一个字符串在栈上。
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
char stack_string[10] = "stack";
|
||||
int x = 10;
|
||||
char *heap_string;
|
||||
|
||||
heap_string = malloc(50);
|
||||
|
||||
printf("Enter a string for the stack: ");
|
||||
gets(stack_string);
|
||||
printf("Enter a string for the heap: ");
|
||||
gets(heap_string);
|
||||
printf("Stack string is: %s\n", stack_string);
|
||||
printf("Heap string is: %s\n", heap_string);
|
||||
printf("x is: %d\n", x);
|
||||
}
|
||||
```
|
||||
|
||||
这个程序使用了一个你可能从来不会使用的极为不安全的函数 `gets` 。但我是故意这样写的。当出现错误的时候,你就知道是为什么了。
|
||||
|
||||
### 第 0 步:编译这个程序
|
||||
|
||||
我们使用 `gcc -g -O0 test.c -o test` 命令来编译这个程序。
|
||||
|
||||
`-g` 选项会在编译程序中将调式信息也编译进去。这将会使我们查看我们的变量更加容易。
|
||||
|
||||
`-O0` 选项告诉 gcc 不要进行优化,我要确保我们的 `x` 变量不会被优化掉。
|
||||
|
||||
### 第一步:启动 GDB
|
||||
|
||||
像这样启动 GDB
|
||||
|
||||
```
|
||||
$ gdb ./test
|
||||
```
|
||||
|
||||
它打印出一些 GPL 东西,然后给出一个提示符。让我们在 `main` 函数这里设置一个断点
|
||||
|
||||
```
|
||||
(gdb) b main
|
||||
```
|
||||
|
||||
然后我们就可以运行程序:
|
||||
|
||||
```
|
||||
(gdb) b main
|
||||
Starting program: /home/bork/work/homepage/test
|
||||
Breakpoint 1, 0x000055555555516d in main ()
|
||||
|
||||
(gdb) run
|
||||
Starting program: /home/bork/work/homepage/test
|
||||
|
||||
Breakpoint 1, main () at test.c:4
|
||||
4 int main() {
|
||||
```
|
||||
|
||||
好了,现在程序已经运行起来了。我们就可以开始查看栈空间了。
|
||||
|
||||
### 第二步:查看我们变量的地址
|
||||
|
||||
让我们从了解我们的变量开始。 它们每个都在内存中有一个地址,我们可以像这样打印出来:
|
||||
|
||||
|
||||
```
|
||||
(gdb) p &x
|
||||
$3 = (int *) 0x7fffffffe27c
|
||||
(gdb) p &heap_string
|
||||
$2 = (char **) 0x7fffffffe280
|
||||
(gdb) p &stack_string
|
||||
$4 = (char (*)[10]) 0x7fffffffe28e
|
||||
```
|
||||
|
||||
因此,如果我们查看栈的地址,那我们应该能够看到所有的这些变量!
|
||||
|
||||
### 概念:栈指针
|
||||
|
||||
我们将需要使用栈指针,因此我将尽力对其进行快速解释。
|
||||
|
||||
有一个名为 ESP 的 x86 寄存器,称为“栈指针”。 基本上,它是当前函数的栈起始地址。 在 GDB 中,您可以使用 `$sp` 来访问它。 当您调用新函数或从函数返回时,栈指针的值会更改。
|
||||
|
||||
### 第三步:在 `main` 函数开始的时候,我们查看一下在栈上的变量
|
||||
|
||||
首先,让我们看一下 main 函数开始时的栈。 现在是我们的堆栈指针的值:
|
||||
|
||||
```
|
||||
(gdb) p $sp
|
||||
$7 = (void *) 0x7fffffffe270
|
||||
```
|
||||
|
||||
因此,我们当前函数的栈起始地址是 `0x7fffffffe270`,酷极了。
|
||||
|
||||
现在,让我们使用 GDB 打印出当前函数堆栈开始后的前 40 个字(即160个字节)。 某些内存可能不是栈的一部分,因为我不太确定这里的堆栈有多大。 但是至少开始的地方是栈的一部分。
|
||||
|
||||
```
|
||||
(gdb) x/40x $sp
|
||||
0x7fffffffe270: 0x00000000 0x00000000 0x55555250 0x00005555
|
||||
0x7fffffffe280: 0x00000000 0x00000000 0x55555070 0x00005555
|
||||
0x7fffffffe290: 0xffffe390 0x00007fff 0x00000000 0x00000000
|
||||
0x7fffffffe2a0: 0x00000000 0x00000000 0xf7df4b25 0x00007fff
|
||||
0x7fffffffe2b0: 0xffffe398 0x00007fff 0xf7fca000 0x00000001
|
||||
0x7fffffffe2c0: 0x55555169 0x00005555 0xffffe6f9 0x00007fff
|
||||
0x7fffffffe2d0: 0x55555250 0x00005555 0x3cae816d 0x8acc2837
|
||||
0x7fffffffe2e0: 0x55555070 0x00005555 0x00000000 0x00000000
|
||||
0x7fffffffe2f0: 0x00000000 0x00000000 0x00000000 0x00000000
|
||||
0x7fffffffe300: 0xf9ce816d 0x7533d7c8 0xa91a816d 0x7533c789
|
||||
```
|
||||
|
||||
我已粗体显示了 stack_string,heap_string 和 x 变量的位置,并改变了颜色(译者注:可以在原网页查看):
|
||||
|
||||
* `x` 是红色字体,并且起始地址是 `0x7fffffffe27c`
|
||||
* `heap_string` 是蓝色字体,起始地址是 `0x7fffffffe280`
|
||||
* `stack_string` 是紫色字体,起始地址是 `0x7fffffffe28e`
|
||||
|
||||
我想在此处将一些变量的位置加粗了一点点可能会有点偏差,但这大概是它们所在的位置。
|
||||
|
||||
您可能会在这里注意到的一件奇怪的事情是 x 的值是 0x5555,但是我们将 x 设置为 10! 那是因为直到我们的 `main` 函数运行之后才真正设置 `x` ,而我们现在才到了 `main` 最开始的地方。
|
||||
|
||||
### 第三步:运行到第十行代码后,再次查看一下我们的堆栈
|
||||
|
||||
让我们跳过几行,等待变量实际设置为其初始化值。 到第 10 行时,`x` 应该设置为10。
|
||||
|
||||
首先我们需要设置另一个断点:
|
||||
|
||||
```
|
||||
(gdb) b test.c:10
|
||||
Breakpoint 2 at 0x5555555551a9: file test.c, line 11.
|
||||
```
|
||||
|
||||
然后继续执行程序:
|
||||
|
||||
```
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
|
||||
Breakpoint 2, main () at test.c:11
|
||||
11 printf("Enter a string for the stack: ");
|
||||
```
|
||||
|
||||
好的! 让我们再来看看堆栈里的内容! `gdb` 在这里格式化字节的方式略有不同,实际上我也不太关心这些(译者注:可以查看 GDB 手册中 x 命令,可以指定 c 来控制输出的格式)。 这里提醒一下您,我们的变量在栈上的位置:
|
||||
|
||||
|
||||
* `x` 是红色字体,并且起始地址是 `0x7fffffffe27c`
|
||||
* `heap_string` 是蓝色字体,起始地址是 `0x7fffffffe280`
|
||||
* `stack_string` 是紫色字体,起始地址是 `0x7fffffffe28e`
|
||||
|
||||
|
||||
|
||||
```
|
||||
(gdb) x/80x $sp
|
||||
0x7fffffffe270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe278: 0x50 0x52 0x55 0x55 0x0a 0x00 0x00 0x00
|
||||
0x7fffffffe280: 0xa0 0x92 0x55 0x55 0x55 0x55 0x00 0x00
|
||||
0x7fffffffe288: 0x70 0x50 0x55 0x55 0x55 0x55 0x73 0x74
|
||||
0x7fffffffe290: 0x61 0x63 0x6b 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe298: 0x00 0x80 0xf7 0x8a 0x8a 0xbb 0x58 0xb6
|
||||
0x7fffffffe2a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe2a8: 0x25 0x4b 0xdf 0xf7 0xff 0x7f 0x00 0x00
|
||||
0x7fffffffe2b0: 0x98 0xe3 0xff 0xff 0xff 0x7f 0x00 0x00
|
||||
0x7fffffffe2b8: 0x00 0xa0 0xfc 0xf7 0x01 0x00 0x00 0x00
|
||||
```
|
||||
|
||||
在继续往下看之前,这里有一些有趣的事情要讨论。
|
||||
|
||||
### `stack_string` 在内存中是如何表示的
|
||||
|
||||
现在(第10行),`stack_string` 被设置为 “stack”。 让我们看看它在内存中的表示方式。
|
||||
|
||||
我们可以像这样打印出字符串中的字节(译者注:可以通过 c 选项直接显示为字符):
|
||||
|
||||
```
|
||||
(gdb) x/10x stack_string
|
||||
0x7fffffffe28e: 0x73 0x74 0x61 0x63 0x6b 0x00 0x00 0x00
|
||||
0x7fffffffe296: 0x00 0x00
|
||||
```
|
||||
|
||||
|
||||
"stack" 是一个长度为 5 的字符串,相对应 5 个 ASCII 码-`0x73`, `0x74`, `0x61`, `0x63`, 和 `0x6b`。`0x73` 是字符 `s` 的 ASCII 码。 `0x74` 是 `t` 的 ASCII 码。等等...
|
||||
|
||||
同时我们也使用 `x/1s` 可以让 GDB 以字符串的方式显示:
|
||||
|
||||
```
|
||||
(gdb) x/1s stack_string
|
||||
0x7fffffffe28e: "stack"
|
||||
```
|
||||
|
||||
|
||||
|
||||
### `heap_string` 与 `stack_string` 有何不同
|
||||
|
||||
你已经注意到了 `stack_string` 和 `heap_string` 在栈上的表示非常不同:
|
||||
|
||||
* `stack_string` 是一段字符串内容("stack")
|
||||
* `heap_string` 是一个指针,指向内存中的某个位置
|
||||
|
||||
这里是 `heap_string` 变量在内存中的内容:
|
||||
|
||||
```
|
||||
0xa0 0x92 0x55 0x55 0x55 0x55 0x00 0x00
|
||||
```
|
||||
|
||||
这些字节实际上应该是从右向左读:因为 X86 是小端模式,因此,`heap_string` 中所存放的内存地址 `0x5555555592a0`
|
||||
|
||||
另一种方式查看 `heap_string` 中存放的内存地址就是使用 `p` 命令直接打印 :
|
||||
|
||||
```
|
||||
(gdb) p heap_string
|
||||
$6 = 0x5555555592a0 ""
|
||||
```
|
||||
|
||||
### 整数 x 的字节表示
|
||||
|
||||
`x` 是一个 32 位的整数,可由 `0x0a 0x00 0x00 0x00` 来表示。
|
||||
|
||||
我们还是需要反向来读取这些字节(和我们读取 `heap_string` 需要反过来读是一样的),因此这个数表示的是 `0x000000000a` 或者是 `0x0a`, 它是一个 10;
|
||||
|
||||
这就让我把把 x 设置成了 10;
|
||||
|
||||
### 第四步:从标准输入读取
|
||||
|
||||
好了,现在我们已经初始化我们的变量,我们来看一下当这段程序运行的时候,栈空间会如何变化:
|
||||
|
||||
```
|
||||
printf("Enter a string for the stack: ");
|
||||
gets(stack_string);
|
||||
printf("Enter a string for the heap: ");
|
||||
gets(heap_string);
|
||||
```
|
||||
|
||||
我们需要设置另外一个断点:
|
||||
|
||||
```
|
||||
(gdb) b test.c:16
|
||||
Breakpoint 3 at 0x555555555205: file test.c, line 16.
|
||||
```
|
||||
|
||||
|
||||
然后继续执行程序:
|
||||
|
||||
```
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
```
|
||||
|
||||
我们输入两个字符串,为栈上存储的变量输入 `123456789012` 并且为在堆上存储的变量输入 `bananas`;
|
||||
|
||||
### 让我们先来看一下 `stack_string` (这里有一个缓存区溢出)
|
||||
|
||||
```
|
||||
(gdb) x/1s stack_string
|
||||
0x7fffffffe28e: "123456789012"
|
||||
```
|
||||
|
||||
这看起来相当正常,对吗?我们输入了 `12345679012`,然后现在它也被设置成了 `12345679012`(译者注:实测 gcc 8.3 环境下,会直接段错误)。
|
||||
|
||||
但是现在有一些很奇怪的事。这是我们程序的栈空间的内容。有一些紫色高亮的内容。
|
||||
|
||||
```
|
||||
0x7fffffffe270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe278: 0x50 0x52 0x55 0x55 0x0a 0x00 0x00 0x00
|
||||
0x7fffffffe280: 0xa0 0x92 0x55 0x55 0x55 0x55 0x00 0x00
|
||||
0x7fffffffe288: 0x70 0x50 0x55 0x55 0x55 0x55 0x31 0x32
|
||||
0x7fffffffe290: 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30
|
||||
0x7fffffffe298: 0x31 0x32 0x00 0x8a 0x8a 0xbb 0x58 0xb6
|
||||
0x7fffffffe2a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe2a8: 0x25 0x4b 0xdf 0xf7 0xff 0x7f 0x00 0x00
|
||||
0x7fffffffe2b0: 0x98 0xe3 0xff 0xff 0xff 0x7f 0x00 0x00
|
||||
0x7fffffffe2b8: 0x00 0xa0 0xfc 0xf7 0x01 0x00 0x00 0x00
|
||||
```
|
||||
|
||||
令人奇怪的是 **stack_string 只支持 10 个字节**。但是现在当我们输入了 13 个字符以后,发生了什么?
|
||||
|
||||
这是一个典型的缓冲区溢出,`stack_string` 将自己的数据写在了程序中的其他地方。在我们的案例中,这还没有造成问题,但它会使你的程序崩溃,或者更糟糕的是,使你面临非常糟糕的安全问题。
|
||||
|
||||
例如,假设 `stack_string` 在内存里的位置刚好在 `heap_string` 之前。那我们就可能覆盖 `heap_string` 所指向的地址。我并不确定 `stack_string` 之后的内存里有一些什么。但我们也许可以用它来做一些诡异的事情。
|
||||
|
||||
### 确实检测到了有缓存区溢出
|
||||
|
||||
当我故意写很多字符的时候:
|
||||
|
||||
```
|
||||
./test
|
||||
Enter a string for the stack: 01234567891324143
|
||||
Enter a string for the heap: adsf
|
||||
Stack string is: 01234567891324143
|
||||
Heap string is: adsf
|
||||
x is: 10
|
||||
*** stack smashing detected ***: terminated
|
||||
fish: Job 1, './test' terminated by signal SIGABRT (Abort)
|
||||
```
|
||||
|
||||
这里我猜是 `stack_string` 已经到达了这个函数栈的底部,因此额外的字符将会被写在另一块内存中。
|
||||
|
||||
当你故意去使用这个安全漏洞时,它被称为“堆栈粉碎”,我也不完全了解这是如何检测到的。
|
||||
|
||||
我也觉得这很有趣,虽然程序被杀死了,但是当缓冲区溢出发生时它不会立即被杀死——在缓冲区溢出之后再运行几行代码,程序才会被杀死。 好奇怪!
|
||||
|
||||
这些就是关于缓存区溢出的所有内容。
|
||||
|
||||
### 现在我们来看一下 `heap_string`
|
||||
|
||||
我们仍然将 `bananas` 输入到 `heap_string` 变量中。让我们来看一下内存中的样子。
|
||||
|
||||
这是在我们读取了字符串以后,`heap_string` 在栈空间上的样子:
|
||||
|
||||
```
|
||||
(gdb) x/40x $sp
|
||||
0x7fffffffe270: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||
0x7fffffffe278: 0x50 0x52 0x55 0x55 0x0a 0x00 0x00 0x00
|
||||
0x7fffffffe280: 0xa0 0x92 0x55 0x55 0x55 0x55 0x00 0x00
|
||||
0x7fffffffe288: 0x70 0x50 0x55 0x55 0x55 0x55 0x31 0x32
|
||||
0x7fffffffe290: 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x30
|
||||
```
|
||||
|
||||
需要注意的是,这里的值是一个地址。并且这个地址并没有改变,但是我们来看一下指向的内存上的内容。
|
||||
|
||||
```
|
||||
(gdb) x/10x 0x5555555592a0
|
||||
0x5555555592a0: 0x62 0x61 0x6e 0x61 0x6e 0x61 0x73 0x00
|
||||
0x5555555592a8: 0x00 0x00
|
||||
```
|
||||
|
||||
看到了吗,这就是字符串 `bananas` 的字节表示。这些字节并不在栈空间上。他们存在于内存中的堆上。
|
||||
|
||||
### 堆和栈到底在哪里?
|
||||
|
||||
我们已经讨论过栈和堆是不同的内存区域,但是你怎么知道它们在内存中的位置呢?
|
||||
|
||||
每个进程都有一个名为 `/proc/$PID/maps` 的文件,它显示了每个进程的内存映射。 在这里您可以看到其中的栈和堆。
|
||||
|
||||
```
|
||||
$ cat /proc/24963/maps
|
||||
... lots of stuff omitted ...
|
||||
555555559000-55555557a000 rw-p 00000000 00:00 0 [heap]
|
||||
... lots of stuff omitted ...
|
||||
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
|
||||
```
|
||||
|
||||
需要注意的一件事是,这里堆地址以 `0x5555` 开头,栈地址以 `0x7fffff` 开头。 所以很容易区分栈上的地址和堆上的地址之间的区别。
|
||||
|
||||
### 像这样使用 gdb 真的很有帮助
|
||||
|
||||
这有点像旋风之旅,虽然我没有解释所有内容,但希望看到数据在内存中的实际情况可以使你更清楚地了解堆栈的实际情况。
|
||||
|
||||
我真的建议像这样来把玩一下 gdb —— 即使你不理解你在内存中看到的每一件事,我发现实际上像这样看到我程序内存中的数据会使抽象的概念,比如“栈”和“ 堆”和“指针”更容易理解。
|
||||
|
||||
### 更多练习
|
||||
|
||||
一些关于思考栈的后续练习的想法(没有特定的顺序):
|
||||
|
||||
* 尝试将另一个函数添加到 `test.c` 并在该函数的开头创建一个断点,看看是否可以从 `main` 中找到堆栈! 他们说当你调用一个函数时“堆栈会变小”,你能在 gdb 中看到这种情况吗?
|
||||
* 从函数返回一个指向栈上字符串的指针,看看哪里出了问题。 为什么返回指向栈上字符串的指针是不好的?
|
||||
* 尝试在 C 中引起堆栈溢出,并尝试通过在 gdb 中查看堆栈溢出来准确理解会发生什么!
|
||||
* 查看 Rust 程序中的堆栈并尝试找到变量!
|
||||
* 在 [噩梦课程][1] 中尝试一些缓冲区溢出挑战。每个问题的答案写在 README 文件中,因此如果您不想被宠坏,请避免先去看答案。 所有这些挑战的想法是给你一个二进制文件,你需要弄清楚如何导致缓冲区溢出以使其打印出 “flag” 字符串。
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2021/05/17/how-to-look-at-the-stack-in-gdb/
|
||||
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[amwps290](https://github.com/amwps290)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/guyinatuxedo/nightmare
|
@ -0,0 +1,225 @@
|
||||
[#]: subject: (Use open source tools to set up a private VPN)
|
||||
[#]: via: (https://opensource.com/article/21/5/open-source-private-vpn)
|
||||
[#]: author: (Lukas Janėnas https://opensource.com/users/lukasjan)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
使用开源工具创建私有 VPN
|
||||
======
|
||||
使用 OpenWRT 和 Wireguard 在路由器上创建自己的虚拟专用网络。
|
||||
![拼写为 “VPN”][1]
|
||||
|
||||
通过计算机网络从一个地方到另一个地方可能是一件棘手的事情。除了知道正确的地址和打开正确的端口之外,还有安全问题。 对于 Linux,SSH 是一种流行的默认设置,虽然您可以使用 SSH 做很多事情,但它仍然“只是”一个安全外壳(实际上,这就是 SSH 代表的)。用于加密流量的更广泛的协议是 VPN,它创建了一个独特的两点之间的虚拟专用网络。有了它,您可以登录到另一个网络上的计算机并使用它的所有服务(文件共享、打印机,等等),就像您坐在同一个房间里一样,并且全部的数据都是从点到点加密的。
|
||||
|
||||
通常,为了使 VPN 连接成为可能,进入每个网络的网关必须接受 VPN 流量,并且必须侦听目标网络上的某些计算机的 VPN 流量。但是,可以运行您自己的运行 VPN 服务器的路由器固件,使您能够连接到目标网络,而无需担心转发端口或完全考虑内部拓扑。我最喜欢的固件是 OpenWrt,在本文中我将演示如何设置它,以及如何启用 VPN。
|
||||
|
||||
### 什么是 OpenWrt?
|
||||
|
||||
[OpenWrt][2] 是一个使用 Linux 面向嵌入式设备的开源项目。它已经存在超过 15 年,拥有庞大而活跃的社区。
|
||||
|
||||
使用 OpenWrt 的方法有很多种,但它的主要用途是在路由器中。它提供了一个具有包管理功能的完全可写的文件系统,并且由于它是开源的,您可以查看和修改代码并为生态系统做出贡献。如果您想对路由器进行更多控制,这就是您想要使用的系统。
|
||||
|
||||
OpenWrt 支持很多路由器,包括 [Cisco][3],[ASUS][4],[MikroTik][5],[Teltonika Networks][6],[D-Link][7],[TP-link][8],[Buffalo][9],[Ubiquiti][10] 等知名品牌和 [许多其他品牌][11]。
|
||||
|
||||
### Wireguard 是什么?
|
||||
|
||||
[Wireguard][12] 是开源虚拟专用网络 (VPN) 软件,它比 OpenVPN 等其他选项更快、更简单且更安全。它使用最先进的密码学:ChaCha20 用于对称密码学;用于密钥协商的曲线 25519(使用椭圆曲线);和用于散列的 BLAKE2 。这些算法的设计方式在嵌入式系统上是高效的。WIreguard 也可用于各种操作系统[平台][13]。
|
||||
|
||||
### 先决条件
|
||||
|
||||
对于这个项目,你需要:
|
||||
|
||||
* [Teltonika RUT955][14] 或支持 OpenWrt 的其他路由器
|
||||
* 用于从外部网络连接到 VPN 的公网 IP 地址
|
||||
* 一部安卓手机
|
||||
|
||||
### 安装 OpenWrt
|
||||
|
||||
首先,下载路由器的 OpenWrt 镜像。使用[固件选择器][15]检查 OpenWrt 是否支持您的路由器并下载固件。输入您的路由器型号,将显示选项:
|
||||
|
||||
![OpenWRT 固件选择器][16]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
使用搜索框右侧的下拉输入选择要下载的固件版本。
|
||||
|
||||
下载出厂镜像。
|
||||
|
||||
![下载出厂镜像][18]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
许多路由器允许您从 Web 界面刷入未经授权的固件,但 Teltonika Networks 不允许。要将 OpenWrt 固件刷入这样的路由器,您需要使用引导加载程序。为此,请按照下列步骤操作:
|
||||
|
||||
1. 拔掉路由器的电源线。
|
||||
2. 按住重置按钮。
|
||||
3. 插入路由器的电源线。
|
||||
4. 插入电源线后,继续按住重置按钮 5 到 8 秒。
|
||||
5. 将计算机的 IP 地址设置为 `192.168.1.15`,将网络掩码设置为 `255.255.255.0`。
|
||||
6. 使用以太网电缆通过 LAN 端口连接路由器和计算机。
|
||||
7. 打开网页浏览器并输入`192.168.1.1:/index.html`。
|
||||
8. 上传并刷写固件。
|
||||
|
||||
刷机过程可能占用三分钟。之后,您应该可以通过在浏览器中输入 `192.168.1.1` 来访问路由器的 Web 界面。 默认情况下没有设置密码
|
||||
|
||||
![OpenWrt 授权][19]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
### 配置网络连接
|
||||
|
||||
网络连接是必要条件。如果您的 Internet 服务提供商 (ISP) 使用 DHCP 自动分配您的 IP 地址,您只需将以太网电缆插入路由器的 WAN 端口。
|
||||
|
||||
如果您需要手动分配 IP 地址,导航至 **Network → Interfaces**。选择 **Edit** 编辑您的 WAN 接口。从 **Protocol** 字段中,选择 **Static address**,然后选择 **Switch protocol**。
|
||||
|
||||
![手动分配 IP 地址][20]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
在 **IPv4 address** 字段中,输入您的路由器地址。设置 **IPv4 netmask** 以匹配您的网络子网;输入您将用于连接到网络的 **IPv4 gateway** 地址; 并在 **Use custom DNS servers** 字段中输入 DNS 服务器的地址。保存配置。
|
||||
|
||||
就是这样!您已成功配置 WAN 接口以获得网络连接。
|
||||
|
||||
### 安装必要的包
|
||||
|
||||
默认情况下,固件不包含很多包,但 OpenWrt 有一个选择可安装的包管理器。导航到 **System → Software** 并通过选择 **Update list...** 更新您的包管理器。
|
||||
|
||||
![OpenWrt 包管理器][21]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
在过滤器输入中,键入 **Wireguard**,等待系统找到所有包含该关键字的包。找到并安装名为 **luci-app-wireguard** 的包。
|
||||
|
||||
![luci-app-wireguard 包][22]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
该软件包包括一个用于配置 Wireguard 的 Web 界面,并安装 Wireguard 所必需的所有依赖项。
|
||||
|
||||
如果您在安装 Wireguard 软件包之前收到一个软件包丢失的警告并且在存储库中找不到,请忽略它并继续。
|
||||
|
||||
接下来,找到并安装名为 **luci-app-ttyd** 的包。这将用于稍后访问终端。
|
||||
|
||||
安装这些软件包后,重新启动路由器以使更改生效。
|
||||
|
||||
### 配置 Wireguard 接口
|
||||
|
||||
接下来,创建 Wireguard 接口。导航到 **Network → Interfaces** 并选择左下角的 **Add new interface...**。在弹出窗口中,输入您想要的接口名称,从下拉列表中选择 **Wireguard VPN**,然后选择右下角的 **Create interface**。
|
||||
|
||||
![创建 Wireguard 接口][23]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
在新弹出的窗口中,选择 **Generate Key** 为 Wireguard 接口生成私钥。在 **Listen Port** 字段中,输入所需的端口。我将使用默认的 Wireguard 端口,**51820**。在 **IP Addresses** 字段中,分配将用于 Wireguard 接口的 IP 地址。在这个例子中,我使用了 `10.0.0.1/24`。数字 **24** 表明我的子网的大小。
|
||||
|
||||
![创建 Wireguard 接口][24]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
保存配置并重启接口。
|
||||
|
||||
导航到 **Services → Terminal**,登录到 shell,然后输入命令 `wg show`。您将看到有关 Wiregaurd 接口的一些信息,包括其公钥。复制公钥——稍后您将需要它来创建对等点。
|
||||
|
||||
![Wireguard 公钥][25]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
### 配置防火墙
|
||||
|
||||
导航到 **Network → Firewall** 并选择 **Traffic Rules** 选项卡。在页面底部,选择 **Add**。在弹出窗口的 **Name** 字段中,为您的规则命名,例如 **Allow-wg**。接下来,将 **Destination zone** 从 **Lan** 更改为 **Device**,并将 **Destination port** 设置为 51820。
|
||||
|
||||
![Wireguard 防火墙设置][26]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
保存配置。
|
||||
|
||||
### 手机上配置 Wireguard
|
||||
|
||||
从 Google Play 在您的手机上安装 [Wireguard 应用程序][27]。安装后,打开应用程序并从头开始创建一个新接口。在 **Name** 字段中,输入要用于接口的名称。在 **Private key** 字段中,按右侧的双箭头图标生成密钥对。您将需要上面的公钥来在您的手机和路由器之间创建一个对等点。在 **Addresses** 字段中,分配您将用于通过 VPN 访问电话的 IP 地址。我将使用 `10.0.0.2/24`。在 **Listen port**中,输入端口;我将再次使用默认端口。
|
||||
|
||||
![在 Android 上设置 VPN 接口][28]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
保存配置。
|
||||
|
||||
要向配置中添加对等点,请选择 **Add peer**。在 **Public key** 字段中,输入路由器的 Wireguard 公钥。在 **Endpoint** 字段中,输入路由器的公共 IP 地址和端口,以冒号分隔,例如 `12.34.56.78:51820`。在 **Allowed IP** 字段中,输入要通过 Wireguard 接口访问的 IP 地址。 (您可以输入路由器的 VPN 接口 IP 地址和 LAN 接口地址。)IP 地址必须用逗号分隔。您还可以定义子网的大小。
|
||||
|
||||
![在 Android 上添加 VPN 对等点][29]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
保存配置。
|
||||
|
||||
配置中还剩下最后一步:在路由器上添加一个对等点。
|
||||
|
||||
### 在路由器上添加一个对等点
|
||||
|
||||
导航到 **Network → Interfaces** 并选择您的 Wireguard 接口。转到 **Peers** 选项卡并选择 **Add peer**。 在 **Description** 字段中,输入对等方的名称。在 **Public Key** 字段中输入手机的 Wireguard 接口公钥,在 **Allowed IPs** 字段中输入手机的 Wireguard 接口 IP 地址。选中 **Route Allowed IPs** 复选框。
|
||||
|
||||
![在路由器上添加一个对等点][30]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
保存配置并重启接口。
|
||||
|
||||
### 测试配置
|
||||
|
||||
在手机上打开网络浏览器。在 URL 栏中,输入 IP 地址 `10.0.0.1` 或 `192.168.1.1`。您应该能够访问路由器的网站。
|
||||
|
||||
![从 Android 登录 VPN][31]
|
||||
|
||||
(Lukas Janenas, [CC BY-SA 4.0][17])
|
||||
|
||||
### 您自己的 VPN
|
||||
|
||||
这些天有很多 VPN 服务商在做广告,但是拥有和控制自己的基础设施还有很多话要说,尤其是当该基础设施仅用于提高安全性时。无需依赖其他人为您提供安全的数据连接。使用 OpenWrt 和 Wireguard,您可以拥有自己的开源 VPN 解决方案。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/5/open-source-private-vpn
|
||||
|
||||
作者:[Lukas Janėnas][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/lukasjan
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/vpn_scrabble_networking.jpg?itok=pdsUHw5N (scrabble letters used to spell "VPN")
|
||||
[2]: https://openwrt.org/
|
||||
[3]: https://www.cisco.com/c/en/us/products/routers/index.html
|
||||
[4]: https://www.asus.com/Networking-IoT-Servers/WiFi-Routers/All-series/
|
||||
[5]: https://mikrotik.com/
|
||||
[6]: https://teltonika-networks.com/
|
||||
[7]: https://www.dlink.com/en/consumer
|
||||
[8]: https://www.tp-link.com/us/
|
||||
[9]: https://www.buffalotech.com/products/category/wireless-networking
|
||||
[10]: https://www.ui.com/
|
||||
[11]: https://openwrt.org/toh/views/toh_fwdownload
|
||||
[12]: https://www.wireguard.com/
|
||||
[13]: https://www.wireguard.com/install/
|
||||
[14]: https://teltonika-networks.com/product/rut955/
|
||||
[15]: https://firmware-selector.openwrt.org/
|
||||
[16]: https://opensource.com/sites/default/files/uploads/openwrt_firmware-selector.png (OpenWRT firmware selector)
|
||||
[17]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[18]: https://opensource.com/sites/default/files/uploads/downloadfactoryimage.png (Downloading the Factory Image)
|
||||
[19]: https://opensource.com/sites/default/files/uploads/openwrt_authorization.png (OpenWrt authorization)
|
||||
[20]: https://opensource.com/sites/default/files/uploads/openwrt_staticaddress.png (Assigning IP address manually)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/openwrt_update-lists.png (OpenWrt package manager)
|
||||
[22]: https://opensource.com/sites/default/files/uploads/wireguard-package.png (luci-app-wireguard package)
|
||||
[23]: https://opensource.com/sites/default/files/uploads/wireguard_createinterface.png (Creating Wireguard interface)
|
||||
[24]: https://opensource.com/sites/default/files/uploads/wireguard_createinterface2.png (Creating Wireguard interface)
|
||||
[25]: https://opensource.com/sites/default/files/uploads/wireguard_publickey.png (Wireguard public key)
|
||||
[26]: https://opensource.com/sites/default/files/uploads/wireguard-firewallsetup.png (Wireguard firewall setup)
|
||||
[27]: https://play.google.com/store/apps/details?id=com.wireguard.android&hl=lt&gl=US
|
||||
[28]: https://opensource.com/sites/default/files/uploads/vpn_inferfacesetup.png (Setting up VPN interface on Android)
|
||||
[29]: https://opensource.com/sites/default/files/uploads/addpeeronphone.png (Adding a VPN peer on an Android)
|
||||
[30]: https://opensource.com/sites/default/files/uploads/addpeeronrouter.png (Adding a peer on the router)
|
||||
[31]: https://opensource.com/sites/default/files/uploads/android-vpn-login.png (Logging into the VPN from Android)
|
@ -1,151 +0,0 @@
|
||||
[#]: subject: (Replace du with dust on Linux)
|
||||
[#]: via: (https://opensource.com/article/21/6/dust-linux)
|
||||
[#]: author: (Sudeshna Sur https://opensource.com/users/sudeshna-sur)
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
在 Linux 上用 dust 代替 du
|
||||
======
|
||||
dust 命令是用 Rust 编写的对 du 命令的一个更直观实现。
|
||||
![Sand dunes][1]
|
||||
|
||||
如果你在 Linux 命令行上工作,你会熟悉 `du` 命令。了解像 `du` 这样的可以快速返回磁盘使用情况命令,是命令行使程序员更有效率的方法之一。然而,如果你正在寻找一种方法来节省更多的时间,使你的生活更加容易,看看 [dust][2],它是用 Rust 重写的 `du`,具有更多的直观性。
|
||||
|
||||
简而言之,`dust` 是一个提供文件类型和元数据的工具。如果你在一个目录中触发了 `dust`,它将以几种方式报告该目录的磁盘利用率。它提供了一个信息量很大的图表,告诉你哪个文件夹使用的磁盘空间最大。如果有一个嵌套的文件夹,你可以看到每个文件夹使用的空间百分比。
|
||||
|
||||
### 安装 dust
|
||||
|
||||
你可以使用 Rust 的 Cargo 包管理器安装 `dust`:
|
||||
|
||||
|
||||
```
|
||||
`$ cargo install du-dust`
|
||||
```
|
||||
|
||||
另外,你可以在 Linux 上的软件库中找到它,在 macOS 上,使用 [MacPorts][3] 或 [Homebrew][4]。
|
||||
|
||||
### 探索 dust
|
||||
|
||||
在一个目录中执行 `dust` 命令,会返回一个图表,以树状格式显示其内容和每个项目所占的百分比。
|
||||
|
||||
|
||||
```
|
||||
$ dust
|
||||
5.7M ┌── exa │ ██ │ 2%
|
||||
5.9M ├── tokei │ ██ │ 2%
|
||||
6.1M ├── dust │ ██ │ 2%
|
||||
6.2M ├── tldr │ ██ │ 2%
|
||||
9.4M ├── fd │ ██ │ 4%
|
||||
2.9M │ ┌── exa │ ░░░█ │ 1%
|
||||
15M │ ├── rustdoc │ ░███ │ 6%
|
||||
18M ├─┴ bin │ ████ │ 7%
|
||||
27M ├── rg │ ██████ │ 11%
|
||||
1.3M │ ┌── libz-sys-1.1.3.crate │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
1.4M │ ├── libgit2-sys-0.12.19+1.1.0.crate │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 1%
|
||||
4.5M │ ┌─┴ github.com-1ecc6299db9ec823 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 2%
|
||||
4.5M │ ┌─┴ cache │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 2%
|
||||
1.0M │ │ ┌── git2-0.13.18 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 0%
|
||||
1.4M │ │ ├── exa-0.10.1 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
1.5M │ │ │ ┌── src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
2.2M │ │ ├─┴ idna-0.2.3 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
1.2M │ │ │ ┌── linux │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 0%
|
||||
1.6M │ │ │ ┌─┴ linux_like │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
2.6M │ │ │ ┌─┴ unix │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
3.1M │ │ │ ┌─┴ src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
3.1M │ │ ├─┴ libc-0.2.94 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
1.2M │ │ │ ┌── test │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 0%
|
||||
2.6M │ │ │ ┌─┴ zlib-ng │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
904K │ │ │ │ ┌── vstudio │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 0%
|
||||
2.0M │ │ │ │ ┌─┴ contrib │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
3.4M │ │ │ ├─┴ zlib │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
6.1M │ │ │ ┌─┴ src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓██ │ 2%
|
||||
6.1M │ │ ├─┴ libz-sys-1.1.3 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓██ │ 2%
|
||||
1.6M │ │ │ ┌── pcre │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
2.5M │ │ │ ┌─┴ deps │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
3.8M │ │ │ ├── src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓▓█ │ 1%
|
||||
7.4M │ │ │ ┌─┴ libgit2 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓██ │ 3%
|
||||
7.6M │ │ ├─┴ libgit2-sys-0.12.19+1.1.0 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▓▓██ │ 3%
|
||||
26M │ │ ┌─┴ github.com-1ecc6299db9ec823 │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██████ │ 10%
|
||||
26M │ ├─┴ src │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██████ │ 10%
|
||||
932K │ │ ┌── .cache │ ░░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓█ │ 0%
|
||||
11M │ │ │ ┌── pack-c3e3a51a17096a3078196f3f014e02e5da6285aa.idx │ ░░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓███ │ 4%
|
||||
135M │ │ │ ├── pack-c3e3a51a17096a3078196f3f014e02e5da6285aa.pack│ ░░░░░░▓▓███████████████████████████ │ 53%
|
||||
147M │ │ │ ┌─┴ pack │ ░░░░░░█████████████████████████████ │ 57%
|
||||
147M │ │ │ ┌─┴ objects │ ░░░░░░█████████████████████████████ │ 57%
|
||||
147M │ │ ├─┴ .git │ ░░░░░░█████████████████████████████ │ 57%
|
||||
147M │ │ ┌─┴ github.com-1ecc6299db9ec823 │ ░░░░░░█████████████████████████████ │ 57%
|
||||
147M │ ├─┴ index │ ░░░░░░█████████████████████████████ │ 57%
|
||||
178M ├─┴ registry │ ███████████████████████████████████ │ 69%
|
||||
257M ┌─┴ . │██████████████████████████████████████████████████ │ 100%
|
||||
$
|
||||
```
|
||||
|
||||
将 `dust` 应用于一个特定的目录:
|
||||
|
||||
|
||||
```
|
||||
`$ dust ~/Work/`
|
||||
```
|
||||
|
||||
![Dust output from a specific directory][5]
|
||||
|
||||
(Sudeshna Sur, [CC BY-SA 4.0][6])
|
||||
|
||||
`-r` 选项以相反的顺序显示输出,root 在底部:
|
||||
|
||||
|
||||
```
|
||||
`$ dust -r ~/Work/`
|
||||
```
|
||||
|
||||
使用 `dust -d 3` 会返回三层的子目录和它们的磁盘利用率:
|
||||
|
||||
|
||||
```
|
||||
`$ dust -d 3 ~/Work/wildfly/jaxrs/target/classes`[/code] [code]
|
||||
|
||||
$ dust -d 3 ~/Work/wildfly/jaxrs/target/classes
|
||||
4.0K ┌── jaxrs.xml │ █ │ 1%
|
||||
4.0K ┌─┴ subsystem-templates │ █ │ 1%
|
||||
4.0K │ ┌── org.jboss.as.controller.transform.ExtensionTransformerRegistration│ █ │ 1%
|
||||
4.0K │ ├── org.jboss.as.controller.Extension │ █ │ 1%
|
||||
8.0K │ ┌─┴ services │ █ │ 2%
|
||||
8.0K ├─┴ META-INF │ █ │ 2%
|
||||
4.0K │ ┌── jboss-as-jaxrs_1_0.xsd │ ░█ │ 1%
|
||||
8.0K │ ├── jboss-as-jaxrs_2_0.xsd │ ░█ │ 2%
|
||||
12K ├─┴ schema │ ██ │ 3%
|
||||
408K │ ┌── as │ ████████████████████████████████████████ │ 94%
|
||||
408K │ ┌─┴ jboss │ ████████████████████████████████████████ │ 94%
|
||||
408K ├─┴ org │ ████████████████████████████████████████ │ 94%
|
||||
432K ┌─┴ classes │██████████████████████████████████████████ │ 100%
|
||||
$
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
`dust` 的魅力在于它是一个小的、简单的、易于理解的命令。它使用一种颜色方案来表示最大的子目录,使你的目录易于可视化。这是一个受欢迎的项目,欢迎大家来贡献。
|
||||
|
||||
你是否使用或考虑使用 `dust`?如果是,请在下面的评论中告诉我们你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/6/dust-linux
|
||||
|
||||
作者:[Sudeshna Sur][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/sudeshna-sur
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/sand_dunes_desert_hills_landscape_nature.jpg?itok=wUByylBb
|
||||
[2]: https://github.com/bootandy/dust
|
||||
[3]: https://opensource.com/article/20/11/macports
|
||||
[4]: https://opensource.com/article/20/6/homebrew-mac
|
||||
[5]: https://opensource.com/sites/default/files/uploads/dust-work.png (Dust output from a specific directory)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
@ -7,32 +7,32 @@
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
Python 3.10 beta in Fedora Linux
|
||||
Fedora Linux 中的 Python 3.10 测试版
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
The Python developers have already released three beta versions of Python 3.10.0. You can try the latest one in Fedora Linux today! Test your Python code with 3.10 early to be ready for the final 3.10.0 release in October.
|
||||
Python 开发者已经发布了 Python 3.10.0 的三个测试版本。今天,你可以在 Fedora Linux 中试用最新的版本 尽早用 3.10 测试你的 Python 代码,为 10 月份的 3.10.0 最终版本做好准备。
|
||||
|
||||
### Install Python 3.10 on Fedora Linux
|
||||
### 在 Fedora Linux 上安装 Python 3.10
|
||||
|
||||
If you run Fedora Linux, you can install Python 3.10 from the official software repository with _dnf_:
|
||||
如果你运行 Fedora Linux,你可以用 _dnf_ 从官方仓库安装 Python 3.10:
|
||||
|
||||
```
|
||||
$ sudo dnf install python3.10
|
||||
```
|
||||
|
||||
You might need to enable the _updates-testing_ repository to get the very latest pre-release:
|
||||
你可能需要启用 _updates-testing_ 仓库来获得最新的预发布版本:
|
||||
|
||||
```
|
||||
$ sudo dnf install --enablerepo=updates-testing python3.10
|
||||
```
|
||||
|
||||
As more betas and release candidates [will be released][2], the Fedora package will receive updates. No need to compile your own development version of Python, just install it and have it up to date. The Python developers will add no new features starting with the first beta; you can already enjoy all the new things.
|
||||
随着更多的测试版和候选版[将被发布][2],Fedora 包将得到更新。不需要编译你自己的 Python 开发版本,只要安装它就可以获得最新。从第一个测试版开始,Python 开发者将不增加新的功能。你已经可以享受所有的新东西了。
|
||||
|
||||
### Test your projects with Python 3.10
|
||||
### 用 Python 3.10 测试你的项目
|
||||
|
||||
Run the _python3.10_ command to use Python 3.10 or create virtual environments with the [builtin _venv_ module, tox][3] or with [pipenv][4] and [poetry][5]. Here’s an example using _tox_:
|
||||
运行 _python3.10_ 命令来使用 Python 3.10,或者用[内置的 _venv_ 模块 tox][3] 或用 [pipenv][4] 和 [poetry][5] 创建虚拟环境。下面是一个使用 _tox_ 的例子:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/benjaminp/six.git
|
||||
@ -56,11 +56,11 @@ ________________________ summary _________________________
|
||||
congratulations :)
|
||||
```
|
||||
|
||||
If you find a problem with Python 3.10 on Fedora Linux, please do [file bug reports at Fedora’s bugzilla][6] or in the [Python’s issue tracker][7]. If you aren’t sure if it is a problem in Python, you can [contact the Fedora’s Python maintainers][8] directly via email or IRC.
|
||||
如果您在 Fedora Linux 上发现了 Python 3.10 的问题,请[在 Fedora 的 bugzilla 上提交 bug 报告][6]或在 [Python 的问题追踪][7]上提交。如果你不确定这是否是 Python 的问题,你可以[通过电子邮件或 IRC 直接联系 Fedora 的 Python 维护者][8] 。
|
||||
|
||||
### What’s new in Python 3.10
|
||||
### Python 3.10 中的新内容
|
||||
|
||||
See the [full list of news in Python 3.10][9]. You can, for example, try out [structural pattern matching][10]:
|
||||
参见 [Python 3.10 的全部新闻列表][9]。例如,你可以尝试一下[结构模式匹配][10]:
|
||||
|
||||
```
|
||||
$ python3.10
|
||||
@ -87,7 +87,7 @@ X=3, Y=10
|
||||
10
|
||||
```
|
||||
|
||||
And stay tuned for [Python 3.10 as _python3_ in Fedora Linux 35][11]!
|
||||
请继续关注 [Fedora Linux 35 中将采用 Python 3.10 作为 _python3_][11]!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -95,7 +95,7 @@ via: https://fedoramagazine.org/python-3-10-beta-in-fedora-linux/
|
||||
|
||||
作者:[Miro Hrončok][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
Loading…
Reference in New Issue
Block a user