在上一篇文章（通过 SSH 实现 TCP / IP 隧道（端口转发）：使用 OpenSSH 可能的 8 种场景）中，我们看到了处理端口转发的所有可能情况，不过那只是静态端口转发。也就是说，我们只介绍了通过 SSH 连接来访问另一个系统的端口的情况。在那篇文章中，我们未涉及动态端口转发，此外一些读者没看过该文章，本篇文章中将尝试补充完整。当我们谈论使用 SSH 进行动态端口转发时，我们说的是将 SSH 服务器转换为 SOCKS 服务器。那么什么是 SOCKS 服务器？你知道 Web 代理是用来做什么的吗？答案可能是肯定的，因为很多公司都在使用它。它是一个直接连接到互联网的系统，允许没有互联网访问的内部网客户端让其浏览器通过代理来（尽管也有透明代理）浏览网页。Web 代理除了允许输出到 Internet 之外，还可以缓存页面、图像等。已经由某客户端下载的资源，另一个客户端不必再下载它们。此外，它还可以过滤内容并监视用户的活动。当然了，它的基本功能是转发 HTTP 和 HTTPS 流量。一个 SOCKS 服务器提供的服务类似于公司内部网络提供的代理服务器服务，但不限于 HTTP/HTTPS，它还允许转发任何 TCP/IP 流量（SOCKS 5 也支持 UDP）。例如，假设我们希望在一个没有直接连接到互联网的内部网上通过 Thunderbird 使用 POP3 、 ICMP 和 SMTP 的邮件服务。如果我们只有一个 web 代理可以用，我们可以使用的唯一的简单方式是使用某个 webmail（也可以使用 Thunderbird 的 Webmail 扩展）。我们还可以通过 HTTP 隧道)来起到代理的用途。但最简单的方式是在网络中设置一个 SOCKS 服务器，它可以让我们使用 POP3、ICMP 和 SMTP，而不会造成任何的不便。虽然有很多软件可以配置非常专业的 SOCKS 服务器，但用 OpenSSH 设置一个只需要简单的一条命令：Clientessh $ ssh -D 1080 user@servidorssh 或者我们可以改进一下：Clientessh $ ssh -fN -D 0.0.0.0:1080 user@servidorssh 其中：选项 -D 类似于选项为 -L 和 -R 的静态端口转发。像那些一样，我们可以让客户端只监听本地请求或从其他节点到达的请求，具体取决于我们将请求关联到哪个地址：-D [bind_address:] port 在静态端口转发中可以看到，我们使用选项 -R 进行反向端口转发，而动态转发是不可能的。我们只能在 SSH 客户端创建 SOCKS 服务器，而不能在 SSH 服务器端创建。1080 是 SOCKS 服务器的典型端口，正如 8080 是 Web 代理服务器的典型端口一样。选项 -N 防止实际启动远程 shell 交互式会话。当我们只用 ssh 来建立隧道时很有用。选项 -f 会使 ssh 停留在后台并将其与当前 shell 分离，以便使该进程成为守护进程。如果没有选项 -N（或不指定命令），则不起作用，否则交互式 shell 将与后台进程不兼容。使用 PuTTY 也可以非常简单地进行端口重定向。与 ssh -D 0.0.0.0:1080 相当的配置如下：对于通过 SOCKS 服务器访问另一个网络的应用程序，如果应用程序提供了对 SOCKS 服务器的特别支持，就会非常方便（虽然不是必需的），就像浏览器支持使用代理服务器一样。作为一个例子，如 Firefox 或 Internet Explorer 这样的浏览器使用 SOCKS 服务器访问另一个网络的应用程序：注意：上述截图来自 IE for Linux ：如果您需要在 Linux 上使用 Internet Explorer，强烈推荐！然而，最常见的浏览器并不要求 SOCKS 服务器，因为它们通常与代理服务器配合得更好。不过，Thunderbird 也支持 SOCKS，而且很有用：另一个例子：Spotify 客户端同样支持 SOCKS：需要关注一下名称解析。有时我们会发现，在目前的网络中，我们无法解析 SOCKS 服务器另一端所要访问的系统的名称。SOCKS 5 还允许我们通过隧道传播 DNS 请求（ 因为 SOCKS 5 允许我们使用 UDP）并将它们发送到另一端：可以指定是本地还是远程解析（或者也可以两者都试试）。支持此功能的应用程序也必须考虑到这一点。例如，Firefox 具有参数 network.proxy.socks_remote_dns（在 about:config 中），允许我们指定远程解析。而默认情况下，它在本地解析。Thunderbird 也支持参数 network.proxy.socks_remote_dns，但由于没有地址栏来放置 about:config，我们需要改变它，就像在 MozillaZine:about:config 中读到的，依次点击 工具 → 选项 → 高级 → 常规 → 配置编辑器（按钮）。没有对 SOCKS 特别支持的应用程序可以被 sock 化 socksified 。这对于使用 TCP/IP 的许多应用程序都没有问题，但并不是全部。“sock 化” 需要加载一个额外的库，它可以检测对 TCP/IP 堆栈的请求，并修改请求，以通过 SOCKS 服务器重定向，从而不需要特别编程来支持 SOCKS 便可以正常通信。在 Windows 和 Linux 上都有 “Sock 化工具”。对于 Windows，我们举个例子，SocksCap 是一种闭源，但对非商业使用免费的产品，我使用了很长时间都十分满意。SocksCap 由一家名为 Permeo 的公司开发，该公司是创建 SOCKS 参考技术的公司。Permeo 被 Blue Coat 买下后，它停止了 SocksCap 项目。现在你仍然可以在互联网上找到 sc32r240.exe 文件。FreeCap 也是面向 Windows 的免费代码项目，外观和使用都非常类似于 SocksCap。然而，它工作起来更加糟糕，多年来一直没有缺失维护。看起来，它的作者倾向于推出需要付款的新产品 WideCap。这是 SocksCap 的一个界面，可以看到我们 “sock 化” 了的几个应用程序。当我们从这里启动它们时，这些应用程序将通过 SOCKS 服务器访问网络：在配置对话框中可以看到，如果选择了协议 SOCKS 5，我们可以选择在本地或远程解析名称：在 Linux 上，如同往常一样，对某个远程命令我们都有许多替代方案。在 Debian/Ubuntu 中，命令行：$ Apt-cache search socks 的输出会告诉我们很多。最著名的是 tsocks 和 proxychains。它们的工作方式大致相同：只需用它们启动我们想要 “sock 化” 的应用程序就行。使用 proxychains 的 wget 的例子：$ Proxychains wget http://www.google.com ProxyChains-3.1 (http://proxychains.sf.net) --19: 13: 20-- http://www.google.com/ Resolving www.google.com ... DNS-request | Www.google.com | S-chain | - <- - 10.23.37.3:1080-<><>-4.2.2.2:53-<><>-OK | DNS-response | Www.google.com is 72.14.221.147 72.14.221.147 Connecting to www.google.com | 72.14.221.147 |: 80 ... | S-chain | - <- - 10.23.37.3:1080-<><>-72.14.221.147:80-<><>-OK Connected. HTTP request sent, awaiting response ... 200 OK Length: unspecified [text / html] Saving to: `index.html ' [<=>] 6,016 24.0K / s in 0.2s 19:13:21 (24.0 KB / s) - `index.html 'saved [6016] 要让它可以工作，我们必须在 /etc/proxychains.conf 中指定要使用的代理服务器：[ProxyList] Socks5 clientessh 1080 我们也设置远程进行 DNS 请求：# Proxy DNS requests - no leak for DNS data Proxy_dns 另外，在前面的输出中，我们已经看到了同一个 proxychains 的几条信息性的消息， 非 wget 的行是标有字符串 |DNS-request|、|S-chain| 或 |DNS-response| 的。如果我们不想看到它们，也可以在配置中进行调整：# Quiet mode (no output from library) Quiet_mode via: https://wesharethis.com/2017/07/15/dynamic-port-forwarding-mount-socks-server-ssh/作者：Ahmad 译者：firmianay 校对：jasminepeng本文由 LCTT 原创编译，Linux中国 荣誉推出
通过 SSH 实现 TCP / IP 隧道（端口转发）：使用 OpenSSH 可能的 8 种场景
对于 Secure Shell (SSH) 这样的网络协议来说，其主要职责就是在终端模式下访问一个远程系统。因为 SSH 协议对传输数据进行了加密，所以通过它在远端系统执行命令是安全的。此外，我们还可以在这种加密后的连接上通过创建隧道（端口转发）的方式，来实现两个不同终端间的互联。凭借这种方式，只要我们能通过 SSH 创建连接，就可以绕开防火墙或者端口禁用的限制。这个话题在网络领域有大量的应用和讨论：Wikipedia: SSH TunnelingO’Reilly: Using SSH TunnelingSsh.com: Tunneling ExplainedSsh.com: Port ForwardingSecurityFocus: SSH Port ForwardingRed Hat Magazine: SSH Port Forwarding我们在接下来的内容中并不讨论端口转发的细节，而是准备介绍一个如何使用 OpenSSH 来完成 TCP 端口转发的速查表，其中包含了八种常见的场景。有些 SSH 客户端，比如 PuTTY，也允许通过界面配置的方式来实现端口转发。而我们着重关注的是通过 OpenSSH 来实现的的方式。在下面的例子当中，我们假设环境中的网络划分为外部网络（network1）和内部网络（network2）两部分，并且这两个网络之间，只能在 externo1 与 interno1 之间通过 SSH 连接的方式来互相访问。外部网络的节点之间和内部网络的节点之间是完全联通的。场景 1在 externo1 节点访问由 interno1 节点提供的 TCP 服务（本地端口转发 / 绑定地址 = localhost / 主机 = localhost ）externo1 节点可以通过 OpenSSH 连接到 interno1 节点，之后我们想通过其访问运行在 5900 端口上的 VNC 服务。我们可以通过下面的命令来实现：externo1 $ ssh -L 7900:localhost:5900 user@interno1 现在，我们可以在 externo1 节点上确认下 7900 端口是否处于监听状态中：externo1 $ netstat -ltn Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State ... Tcp 0 0 127.0.0.1:7900 0.0.0.0:* LISTEN ... 我们只需要在 externo1 节点上执行如下命令即可访问 internal 节点的 VNC 服务：externo1 $ vncviewer localhost::7900 注意：在 vncviewer 的 man 手册中并未提及这种修改端口号的方式。在 About VNCViewer configuration of the output TCP port 中可以看到。这也是 the TightVNC vncviewer 所介绍的的。场景 2在 externo2 节点上访问由 interno1 节点提供的 TCP 服务（本地端口转发 / 绑定地址 = 0.0.0.0 / 主机 = localhost）这次的场景跟方案 1 的场景的类似，但是我们这次想从 externo2 节点来连接到 interno1 上的 VNC 服务：正确的命令如下：externo1 $ ssh -L 0.0.0.0:7900:localhost:5900 user@interno1 看起来跟方案 1 中的命令类似，但是让我们看看 netstat 命令的输出上的区别。7900 端口被绑定到了本地（127.0.0.1），所以只有本地进程可以访问。这次我们将端口关联到了 0.0.0.0，所以系统允许任何 IP 地址的机器访问 7900 这个端口。externo1 $ netstat -ltn Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State ... Tcp 0 0 0.0.0.0:7900 0.0.0.0:* LISTEN ... 所以现在在 externo2 节点上，我们可以执行：externo2 $ vncviewer externo1::7900 来连接到 interno1 节点上的 VNC 服务。除了将 IP 指定为 0.0.0.0 之外，我们还可以使用参数 -g（允许远程机器使用本地端口转发），完整命令如下：externo1 $ ssh -g -L 7900:localhost:5900 user@interno1 这条命令与前面的命令能实现相同效果：externo1 $ ssh -L 0.0.0.0:7900:localhost:5900 user@interno1 换句话说，如果我们想限制只能连接到系统上的某个 IP，可以像下面这样定义：externo1 $ ssh -L 192.168.24.80:7900:localhost:5900 user@interno1 externo1 $ netstat -ltn Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State ... Tcp 0 0 192.168.24.80:7900 0.0.0.0:* LISTEN ... 场景 3在 interno1 上访问由 externo1 提供的 TCP 服务（远程端口转发 / 绑定地址 = localhost / 主机 = localhost）在场景 1 中 SSH 服务器与 TCP 服务（VNC）提供者在同一个节点上。现在我们想在 SSH 客户端所在的节点上，提供一个 TCP 服务（VNC）供 SSH 服务端来访问：将方案 1 中的命令参数由 -L 替换为 -R。完整命令如下：externo1 $ ssh -R 7900:localhost:5900 user@interno1 然后我们就能看到 interno1 节点上对 7900 端口正在监听：interno1 $ netstat -lnt Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State ... Tcp 0 0 127.0.0.1:7900 0.0.0.0:* LISTEN ... 现在在 interno1 节点上，我们可以使用如下命令来访问 externo1 上的 VNC 服务：interno1 $ vncviewer localhost::7900 场景 4interno2 使用 externo1 上提供的 TCP 服务（远端端口转发 / 绑定地址 = 0.0.0.0 / 主机 = localhost）与场景 3 类似，但是现在我们尝试指定允许访问转发端口的 IP（就像场景 2 中做的一样）为 0.0.0.0，这样其他节点也可以访问 VNC 服务：正确的命令是：externo1 $ ssh -R 0.0.0.0:7900:localhost:5900 user@interno1 但是这里有个重点需要了解，出于安全的原因，如果我们直接执行该命令的话可能不会生效，因为我们需要修改 SSH 服务端的一个参数值 GatewayPorts，它的默认值是：no。GatewayPorts该参数指定了远程主机是否允许客户端访问转发端口。默认情况下，sshd(8) 只允许本机进程访问转发端口。这是为了阻止其他主机连接到该转发端口。GatewayPorts 参数可用于让 sshd 允许远程转发端口绑定到非回环地址上，从而可以让远程主机访问。当参数值设置为 “no” 的时候只有本机可以访问转发端口；“yes” 则表示允许远程转发端口绑定到通配地址上；或者设置为 “clientspecified” 则表示由客户端来选择哪些主机地址允许访问转发端口。默认值是 “no”。如果我们没有修改服务器配置的权限，我们将不能使用该方案来进行端口转发。这是因为如果没有其他的限制，用户可以开启一个端口（> 1024）来监听来自外部的请求并转发到 localhost:7900。参照这个案例：netcat ( Debian # 310431: sshd\_config should warn about the GatewayPorts workaround. )所以我们修改 /etc/ssh/sshd_config，添加如下内容：GatewayPorts clientspecified 然后，我们使用如下命令来重载修改后的配置文件（在 Debian 和 Ubuntu 上）。sudo /etc/init.d/ssh reload 我们确认一下现在 interno1 节点上存在 7900 端口的监听程序，监听来自不同 IP 的请求：interno1 $ netstat -ltn Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State ... Tcp 0 0 0.0.0.0:7900 0.0.0.0:* LISTEN ... 然后我们就可以在 interno2 节点上使用 VNC 服务了：interno2 $ internal vncviewer1::7900 场景 5在 externo1 上使用由 interno2 提供的 TCP 服务（本地端口转发 / 绑定地址 localhost / 主机 = interno2 ）在这种场景下我们使用如下命令：externo1 $ ssh -L 7900:interno2:5900 user@interno1 然后我们就能在 externo1 节点上，通过执行如下命令来使用 VNC 服务了：externo1 $ vncviewer localhost::7900 场景 6在 interno1 上使用由 externo2 提供的 TCP 服务（远程端口转发 / 绑定地址 = localhost / host = externo2）在这种场景下，我们使用如下命令：externo1 $ ssh -R 7900:externo2:5900 user@interno1 然后我们可以在 interno1 上通过执行如下命令来访问 VNC 服务：interno1 $ vncviewer localhost::7900 场景 7在 externo2 上使用由 interno2 提供的 TCP 服务（本地端口转发 / 绑定地址 = 0.0.0.0 / 主机 = interno2）本场景下，我们使用如下命令：externo1 $ ssh -L 0.0.0.0:7900:interno2:5900 user@interno1 或者：externo1 $ ssh -g -L 7900:interno2:5900 user@interno1 然后我们就可以在 externo2 上执行如下命令来访问 vnc 服务：externo2 $ vncviewer externo1::7900 场景 8在 interno2 上使用由 externo2 提供的 TCP 服务（远程端口转发 / 绑定地址 = 0.0.0.0 / 主机 = externo2）本场景下我们使用如下命令：externo1 $ ssh -R 0.0.0.0:7900:externo2:5900 user@interno1 SSH 服务器需要配置为：GatewayPorts clientspecified 就像我们在场景 4 中讲过的那样。然后我们可以在 interno2 节点上执行如下命令来访问 VNC 服务：interno2 $ internal vncviewer1::7900 如果我们需要一次性的创建多个隧道，使用配置文件的方式替代一个可能很长的命令是一个更好的选择。假设我们只能通过 SSH 的方式访问某个特定网络，同时又需要创建多个隧道来访问该网络内不同服务器上的服务，比如 VNC 或者 远程桌面。此时只需要创建一个如下的配置文件 $HOME/redirects 即可（在 SOCKS 服务器 上）。# SOCKS server DynamicForward 1080 # SSH redirects LocalForward 2221 serverlinux1: 22 LocalForward 2222 serverlinux2: 22 LocalForward 2223 172.16.23.45:22 LocalForward 2224 172.16.23.48:22 # RDP redirects for Windows systems LocalForward 3391 serverwindows1: 3389 LocalForward 3392 serverwindows2: 3389 # VNC redirects for systems with "vncserver" LocalForward 5902 serverlinux1: 5901 LocalForward 5903 172.16.23.45:5901 然后我们只需要执行如下命令：externo1 $ ssh -F $HOME/redirects user@interno1 via: https://wesharethis.com/2017/07/creating-tcp-ip-port-forwarding-tunnels-ssh-8-possible-scenarios-using-openssh/作者：Ahmad 译者：toutoudnf 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
本文主要聚焦在如何使用 Yocto 在 Ubuntu 上创建一个最小化的 Linux 发行版。Yocto 项目在嵌入式 Linux 的世界非常著名，这是因为它用起来非常灵活、方便。Yocto 的目标是为嵌入式软硬件开发商创建自己的 Linux 发行版。本文我们将会创建一个可以运行在 QEMU 上的最小化的 Linux，并且在 QEMU 上实际运行。开发机的基本条件最少 4-6 GB 内存最新版的 Ubuntu 系统（本文使用了 16.04 LTS）磁盘剩余空间至少 60-80 GB在创建 Linux 发行版之前先安装下面的软件包下载最新的 Yocto（Poky 是其最小开发环境）稳定分支apt-get update apt-get install wget git-core unzip make gcc g++ build-essential subversion sed autoconf automake texi2html texinfo coreutils diffstat python-pysqlite2 docbook-utils libsdl1.2-dev libxml-parser-perl libgl1-mesa-dev libglu1-mesa-dev xsltproc desktop-file-utils chrpath groff libtool xterm gawk fop 如下所示，开发环境要安装的软件包将近 1GB 大小。在这个教程中，系统上克隆的是 poky 的 morty 稳定分支。 git clone -b morty git://git.yoctoproject.org/poky.git 进入 poky 目录，然后运行下面的命令为 Yocto 开发环境设置（设置/导出）一些环境变量。source oe-init-build-env 如下所示，在运行了 open embedded (oe) 的构建环境脚本之后，终端里的路径会自动切换到 build 目录，以便进行之后行发行版的的配置和构建。上面的截屏展示了在 conf 目录下创建的文件 local.conf。这是 Yocto 用来设置目标机器细节和 SDK 的目标架构的配置文件。如下所示，这里设置的目标机器是 qemux86-64。如下面截图所示，在 local.conf 中取消下面参数的注释符号。DL_DIR ?= "${TOPDIR}/downloads" SSTATE_DIR ?= "${TOPDIR}/sstate-cache" TMPDIR ?= "${TOPDIR}/tmp" PACKAGE_CLASSES ?= "package_rpm" SDKMACHINE ?= "i686" 如下所示，在 local.conf 中为基于 Yocto 的 Linux 设置空密码和后续的一些参数。否则的话用户就不能登录进新的发行版。EXTRA_IMAGE_FEATURES ?= "debug-tweaks" 我们并不准备使用任何图形化工具来创建 Linux OS，比如 toaster （hob 已经不再支持了）。Yocto 编译构建过程现在运行下面的 bitbake 工具命令开始为选定的目标机器下载和编译软件包。bitbake core-image-minimal 非常重要的是要在普通 Linux 用户下运行上面的命令，而不是使用 root 用户。如下面截图所示，当你在 root 用户下运行 bitbake 命令会产生下面所示的错误。再一次运行导出环境变量的脚本（oe-init-build-env），重新执行相同的命令来启动下载和编译过程。如下所示，构建脚本组件的第一步工作是解析配置（recipe）。下面的截图展示了构建脚本的解析过程。同时也显示了用来构建你的新的基于 yocto 的发行版的构建系统的细节。在下载了 SDK 和必要的库之后，下一步工作是下载并编译软件包。如下截图展示了为构建新发行版而执行的任务。这一步将会执行 2-3 小时，因为首先要下载需要的软件包，然后还要为新的 Linux 发行版编译这些软件包。下面的截图表明了任务列表执行完毕。为目标机器类型 qemux86-64 编译好的新镜像位于 build/tmp/deploy/images/qemux86-64：如下所示，上面的命令如果运行在 Putty 上会产生一个错误。通过 rdp 在 Ubuntu 平台上再次运行上面的命令。为运行新的基于 Yocto 的 Linux 发行版的 qemu 打开一个新屏幕。下面展示了新发行版的登录界面，同时也显示了使用的 yocto 项目的版本号。默认的用户名是 root ，密码为空。最后使用 root 用户名和空密码登录新发行版。如下截图所示，在这个最小版本的 Linux 上运行了基本的命令（data 、 ifconfig 和 uname）。本文的目标是理解使用 Yocto 创建新的 Linux 发行版的过程。via: https://www.howtoforge.com/tutorial/how-to-create-your-own-linux-distribution-with-yocto-on-ubuntu/作者：Ahmad 译者：Ezio 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出