如何通过 WAN 进行 PXE 启动

如何通过 WAN 进行 PXE 启动

我目前在路由器后面的家庭网络上有一台 Debian PC 和一台 Raspbian Raspberry Pi。路由器为我打开了一个端口,当我不在时,我可以通过该端口 ssh 进入 rPi,然后一旦我进入网络,我就可以在家庭网络上做任何我想做的事情。

在旅行时,我的 Debian PC 的硬盘似乎坏了;至少它无法启动。

我没有留下任何启动 CD 供任何人插入,因为我一直通过 PXE 启动盒子,并将我的 Tomato 家用路由器配置为指向我笔记本电脑上的 VM,以提供启动任何 Linux 安装程序、系统救援 CD 或 Trinity 救援工具包所需的 BOOTP 和 TFTP 映像。

那台笔记本电脑现在陪我一起旅行。

当我连接到家里的 rPi 并临时将 IP 地址重新配置为 [我认为] 时,我可以从笔记本电脑设置 SSH 端口转发吗,dhcp-boot以便我的 Debian PC 可以通过 Internet 使用远程笔记本电脑 VM 进行 PXE 启动?

8月3日更新:遵循 Matt 的以下建议是一个好的开始,但仍然不完整。我仍然没有比以前更进一步。

TFTP 服务器监听 UDP 端口 69,但它似乎使用仅转发 TCP 的-R选项ssh

提供了一种方法,在隧道周围设置管道,翻译在隧道之前将 UDP 流量传输到 TCP,在隧道之后将 TCP 传输回 UDP,但评论指出这不是最好的方法。而且,这对我来说不起作用。

使用索卡特而不是管道似乎引起的争议较少,所以我想我会尝试一下,但这也没有用。

为了记录我到目前为止所做的事情,我尝试在我的笔记本电脑上本地复制该问题,如下所示。

我的虚拟机已经在端口 69 上运行 TFTP 服务器,它至少可以提供文件服务pxelinux.0

我创建了一个新的虚拟机,启动了 System Rescue CD ISO 映像。启动此虚拟机时,我将其设置为 DHCP 服务器:

# vi /etc/dhcp/dhcpd.conf

在该文件中,我指定了以下内容:

subnet 192.168.1.0 netmask 255.255.255.0 {
   range 192.168.1.251 192.168.1.253;
   option routers 192.168.1.1;
   filename "pxelinux.0";
   next-server 192.168.1.252;
}

然后,我重新启动了 DHCP 服务器:

# /etc/init.d/dhcpd restart

笔记:我现在在这个“外部”网络上有两个 DHCP 服务器——为我的笔记本电脑提供 IP 地址的路由器,以及现在这个 VM(直到它关闭)。这引入了竞争条件,因为我的 PXE 启动 VM 可能会收到来自任一 DHCP 服务器的响应;我希望我的 VM 的响应是第一个到达 PXE VM 的,这样它就可以获得next-server上述指令。

在实践中,由于我的练习有限,这似乎不是一个问题,但我不想让我的 VM 运行太久,这样就不会打扰这里的任何人。

如上所述,在 DHCP 服务器运行时,我启动了为 PXE 启动设置的第三个无盘 VM,以练习 PXE 启动过程。

.252 主机是我的 PXE 服务器,因此 PXE 启动 VM 能够访问它,通过 TFTP 获取所需的文件,并开始照常启动。

在正常情况下,我决定按照 Matt 的建议将 SSH 隧道引入到组合中。

# vi /etc/dhcp/dhcpd.conf

我将其修改next-server为系统救援 CD VM 本身的 IP 地址:

subnet 192.168.1.0 netmask 255.255.255.0 {
   range 192.168.1.251 192.168.1.253;
   option routers 192.168.1.1;
   filename "pxelinux.0";
   next-server 192.168.1.13;
}

然后,我重新启动了 DHCP 服务器:

# /etc/init.d/dhcpd restart

我还验证了这个盒子上没有运行TFTP服务器:

# netstat -an | grep 69

现在我的 PXE 启动 VM 无法启动。它从 DHCP 服务器接收到 IP 地址,但无法检索任何 TFTP 启动映像。

我带来了我的 PXE 服务器的公钥并将其放入根authorized_keys文件中。

我从 PXE 服务器 VM 创建了隧道:

$ ssh -R 69:localhost:69 -R 2049:localhost:2049 [email protected]

请注意,我目前不需要转发端口 2049,但稍后我需要为 NFS 执行此操作。

启动 PXE VM 时出现同样的问题:无法通过 TFTP 获取映像。

TFTP 服务器正在监听 UDP 端口 69:

udp        0      0 0.0.0.0:69              0.0.0.0:*

但是,转发的端口正在监听 TCP:

tcp        0      0 127.0.0.1:69            0.0.0.0:*               LISTEN
tcp6       0      0 ::1:69                  :::*                    LISTEN

尝试了使用管道的初始方法。在 System Rescue CD VM 上:

# mkfifo /tmp/fifo
# nc -v -l -u -p 6963 < /tmp/fifo | nc -v -u 127.0.0.1 6964 > /tmp/fifo

同时,在 PXE 服务器 VM 上:

$ ssh -R 6964:localhost:6965 [email protected]
$ nc -v -l -p 6965 < /tmp/fifo | nc -v -u localhost 69 > /tmp/fifo

从系统救援 CD VM,我尝试手动传输文件:

# tftp localhost 6963 -c get pxelinux.0
connect to [127.0.0.1] from sysresccd.gentoo [127.0.0.1] 51072
too many output retries : Broken pipe

这仍然不起作用,所以我再次尝试将隧道从等式中去掉。

系统救援 CD VM:

# nc -v -l -u -p 6963 < /tmp/fifo | nc -v -u 127.0.0.1 6965 > /tmp/fifo

PXE 服务器虚拟机:

$ nc -v -l -p 6965 < /tmp/fifo | nc -v -u localhost 69 > /tmp/fifo

在系统救援 CD VM 上传输:

# tftp localhost 6963 -c get pxelinux.0

这仍然不起作用,所以我清理了rm /tmp/fifo两个盒子。

接下来,我继续尝试socat,但结果相似。我也将 SSH 隧道从方程中剔除,结果相同。

这次,我无法使用系统救援 CD VM,因为它没有安装socat,所以我使用了不同的 VM。

首先,我想验证实际的 TFTP 服务器是否仍然可用:

$ tftp 192.168.1.252
tftp> get pxelinux.0
tftp> quit

果然,我下载了一个非零字节的文件。

当我使用一个没有任何东西监听 TFTP 端口的盒子时,这不起作用:

$ tftp localhost
tftp> get pxelinux.0
Transfer timed out.

tftp> quit
boots$ rm pxelinux.0

是时候加入socat混合了。

在 PXE 服务器上:

$ ssh -p 22 -R 6969:localhost:6968 192.168.1.7
$ sudo socat UDP4-LISTEN:69,fork TCP4:localhost:6969

在 PXE 服务器的另一个窗口中:

$ socat -T10 TCP4-LISTEN:6968,fork UDP4:localhost:69

这仍然不起作用:

$ tftp localhost
tftp> get pxelinux.0
Transfer timed out.

tftp> quit
boots$ rm pxelinux.0

8月4日更新:我想我已经找到了我的问题,但我不确定如何解决它。

我把我的设置变得更简单了。我完全取消了 SSH 隧道,只使用直接 UDP 端口。

在我的本地 TFTP 客户端上,只需这样做:

$ sudo socat -d -d -d -d udp4-recvfrom:69,reuseaddr,fork udp:192.168.1.252:69

提醒一下,.252 盒子是 TFTP 服务器。

这仍然不起作用:

$ tftp localhost
tftp> get pxelinux.0
Transfer timed out.

tftp> quit
boots$ rm pxelinux.0

因此我在 .7 和 .252 盒子上都运行了 Wireshark,查看了 UDP 流量,特别是 TFTP 流量。

以下是两个 Wireshark 实例上的捕获过滤器:

  • .7:udp 和主机 192.168.1.252 且端口不是 123
  • .252:udp 和主机 192.168.1.7 且端口不是 123

当我运行这个程序时,我看到 69 以外的端口上有大量 TFTP 流量。在这种情况下,数据包从源主机上的端口 60862 发送到目标上的端口 44792,并且确认从这些端口以另一种方式返回。

根据维基百科

传输请求始终以端口 69 为目标发起,但数据传输端口由发送方和接收方在传输初始化期间独立选择。端口是根据网络堆栈的参数随机选择的,通常来自临时端口范围。

如果我理解正确的话,我需要的隧道不只是端口 69。我需要哪些其他命令来转发这些端口?有没有简单的方法可以做到这一点?

8月5日更新:在此之前我可能还遇到了另一个问题。

关于上面列出的项目,我尝试使用 TFTP 进行更多操作,并在 Wireshark 中查看数据包。看起来我从随机源端口在端口 69 上获取了第一个数据包。在最后一种情况下,这是端口 48723。

事实证明,TFTP 服务器会从另一个端口通过此端口发送回 UDP 数据包。如果我可以监控到端口 69 的第一个数据包,我就可以看到这一点,并且我期望可以在超时之前快速在此端口上以类似的方式设置另一个隧道,因此该过程将有点手动,但我可能能够完成它。

现在我仔细一看,好像我根本没有收到第一个数据包socat

当我没有隧道时,我可以看到端口 69 上的初始数据包没有任何问题。

当我按照如下方式设置socat没有 SSH 隧道的直接隧道时,我看不到数据包。

窗口 1:

$ sudo socat -d -d -d -d udp4-recvfrom:69,reuseaddr,fork udp:192.168.1.252:69

窗口 2:

$ tftp localhost
tftp> get pxelinux.0
Transfer timed out.

以下是 的输出netcat

$ netstat -an | grep 69 | grep udp
udp        0      0 0.0.0.0:69              0.0.0.0:*

我在两端都运行了一个 Wireshark 实例;两者都什么都没显示。这是我在两端的捕获过滤器:

udp and not (port 123 or port 5353 or port 1900)

我打开了另一个问题对这个。

更新:向前迈出了一小步。我怀疑我的socat命令现在出了问题。

我仅在我的笔记本电脑上尝试了另一项简单的测试。

窗口 1:

$ sudo nc -v -l -u 69

Wireshark:

  • 监听接口 lo
  • 捕获过滤器:udp 和端口 69

窗口 2:

$ nc -u 127.0.0.1 69

当我在窗口 2 中输入内容时,我看到了窗口 1 中的输出,并且看到了在 Wireshark 中捕获的数据包。

然后,我用笔记本电脑的网卡重复了一遍:

窗口 1:

$ sudo nc -v -l -u 69

Wireshark:

  • 监听接口 wlan0
  • 捕获过滤器:udp 和端口 69

窗口 2:

$ nc -u 127.0.0.1 69

事实证明,尽管我在窗口 1 中看到了消息,但我并没有在 Wireshark 中捕获任何数据包。我记得我之前设置过 Docker,所以我有一个 docker0 桥;我还有几个虚拟化产品,所以也许它们妨碍了我。

我使用以下代码重新运行了 Wireshark 捕获:

  • 监听任意接口
  • 捕获过滤器:udp 和端口 69

这次,我得到了我想要的一切。也许我的问题一直出在 Wireshark 捕获界面上。

停止 netcat 窗口,现在后退一步:

$ sudo socat -d -d -d -d udp4-recvfrom:69,reuseaddr,fork udp:192.168.1.252:69

再次尝试TFTP测试:

$ tftp localhost
tftp> get pxelinux.0

就是这样!我现在正在用 Wireshark 捕获数据包!

我看到了捕获的读取请求消息,并且发现所有五次尝试/重试都来自同一源端口。

现在是时候看看我是否可以手动在这个源端口上设置一个额外的socat会话了。在 TFTP 服务器上,我还运行了:

$ for f in 52163; do socat -d -d -d -d udp4-recvfrom:${p},reuseaddr,fork udp:192.168.1.7:${p}; done

请注意,这有我的笔记本电脑的 IP 地址。(for 循环只是为了方便,所以我只需要在命令中指定一次端口号。)

事实证明,无论我运行 PXE 命令多少次,每个源端口都是相同的get pxelinux.0;当我退出 TFTP 并重新运行 TFTP 时,源端口号会发生变化。

我的笔记本电脑和 TFTP 盒上都运行着 Wireshark;现在我在笔记本电脑的 Wireshark 上可以看到数据包,但在 TFTP Wireshark 上却看不到。

我想我的命令有问题socat,但我不知道是什么问题:

$ sudo socat -d -d -d -d udp4-recvfrom:69,reuseaddr,fork udp:192.168.1.252:69

更新:所以现在我已经掌握了 netcat 的基础知识,我想更进一步引入socat混合,但仍然没有 ssh 隧道。

我有一台本地笔记本电脑,现在我们将 TFTP 服务器称为远程盒子,即使它只是我笔记本电脑上的一个虚拟机。

窗口 1:

local$ sudo socat udp4-recvfrom:69,reuseaddr,fork udp:192.168.1.13:69

窗口 2:

local$ nc -4u localhost 69

Wireshark 在远程机器上运行并捕获 UDP 流量。

在窗口 2 中,我输入了三行,每行后按 Enter 键:“one”、“two”和“three”。

在 Wireshark 中,我看到 TFTP 端口上有三个数据包,因此 TFTP 服务器肯定正在获取这些垃圾数据。有趣的是,这三个数据包的源端口各不相同。

接下来,我退出 netcat,并运行 TFTP 客户端,指定本地 IP 地址而不是“localhost”,因为我得到了烧毁今天:

local$ tftp 127.0.0.1
tftp> get pxelinux.0

现在我从本地笔记本电脑收到了 TFTP 读取请求包!!

(供您参考,在记录我的笔记之前,我运行了“tftp localhost”,但仍然没有得到任何结果。这看起来像是我在其他文章中提到的 IPv4/IPv6 问题问题

现在回到 SSH 隧道。

窗口 1:

remote$ socat tcp4-listen:6901,reuseaddr,fork udp:127.0.0.1:69

窗口 2:

local$ ssh -L 6901:127.0.0.1:6901 192.168.1.13

窗口 3:

local$ sudo socat udp4-recvfrom:69,reuseaddr,fork tcp:127.0.0.1:6901

我得到了 Wireshark 中捕获的读取请求数据包以及第一个数据包,由于没有通过源端口的隧道,该数据包无法到达任何地方,但至少我通过隧道获得了到达 TFTP 服务器的 UDP 数据包!

现在,这让我对那次回程有了些许思考。在socat这中间,看起来我从这个 TFTP 客户端获得了五次传输尝试,然后它就超时了;我不知道 NIC 固件中的 TFTP 客户端会如何表现。

对于每次尝试,我似乎都得到了不同的源端口,因为与 TFTP 服务器的连接来自socat而不是我的笔记本电脑的 TFTP 客户端。同样,我不知道 NIC 固件中内置的 TFTP 客户端将如何表现。

即使我确实监控了交通,并迅速建立了回程隧道看到Wireshark中的流量,我不确定是否太晚了。

我猜想如果我使用管道而不是,结果也会一样socat

更新:我想我已经准备放弃这个了,但只是为了好玩,我想我会回到原来的盒子并尝试捕获一些数据包,因为我现在有足够的数据包至少可以进行一次旅行。

我对“本地”和“远程”的概念现在已经颠倒了,因为我的 TFTP 服务器对我来说是本地的,而我坏掉的 PC 是远程的。

窗口 1:

laptop$ ssh [email protected]
local$ socat tcp4-listen:6901,reuseaddr,fork udp:127.0.0.1:69

窗口 2:

laptop$ ssh -R 6901:127.0.0.1:6901 [email protected]
remote$ ping -i 60 8.8.8.8

(ping 是为了在需要时保持连接有效。)

窗口 3:

laptop$ ssh [email protected]
remote$ sudo socat udp4-recvfrom:69,reuseaddr,fork tcp:127.0.0.1:6901

我一直担心源端口会随着 而改变socat,所以我很好奇想再次尝试管道。我回到了我的测试设置。

我保持本地和远程反转以与生产环境保持一致,即使对于我的测试环境来说是倒退的。

窗口 1:

laptop$ ssh 192.168.1.13
local$ mkfifo /tmp/fifo
local$ nc -lp 6901 < /tmp/fifo | nc -u 127.0.0.1 69 > /tmp/fifo

窗口 2:

laptop$ ssh 192.168.1.13
local$ ssh -R 6902:127.0.0.1:6901 192.168.1.7
remote$ ping -i 60 8.8.8.8

窗口 3:

remote$ mkfifo /tmp/fifo
remote$ sudo nc -lup 69 < /tmp/fifo | nc 127.0.0.1 6902 > /tmp/fifo

我再次尝试从 TFTP 客户端进行简单的 TFTP 获取。这次,我在 Wireshark 中注意到每个数据包的源端口都相同!也许还有希望!!

请记住,需要注意的是,UDP 数据包必须保持在 MTU 的大小以下,我相信我在某处读到过它们用于 TFTP。

我必须清理我的管道:

local$ rm /tmp/fifo
remote$ rm /tmp/fifo

我现在想在生产中尝试一下。

窗口 1:

laptop$ ssh [email protected]
local$ mkfifo /tmp/fifo
local$ nc -lp 6901 < /tmp/fifo | nc -u 127.0.0.1 69 > /tmp/fifo

窗口 2:

laptop$ ssh [email protected]
local$ ssh -R 6901:127.0.0.1:6901 [email protected]
remote$ ping -i 60 8.8.8.8

(ping 是为了在需要时保持连接有效。)

窗口 3:

laptop$ ssh [email protected]
remote$ mkfifo /tmp/fifo
remote$ sudo -i
remote$ nc -lup 69 < /tmp/fifo | nc 127.0.0.1 6901 > /tmp/fifo

当我启动 PC 时,根据 Wireshark,我收到一个 TFTP 数据包,该数据包一路传输到 PXE 服务器,但我没有收到任何重试。我希望也能收到重试,并且所有重试都具有相同的源端口。

我改变了nc管道左侧的 ,以指定-k保持活动,然后重新启动,但仍然只收到第一个数据包。

我必须清理我的管道:

local$ rm /tmp/fifo
remote$ sudo rm /tmp/fifo

答案1

应该工作,从ssh 文档

-R remote_socket:local_socket
指定将到远程(服务器)主机上给定 TCP 端口或 Unix 套接字的连接转发到给定的主机和端口

由于端口 69 是特权端口,因此您还必须知道:

仅当以 root 身份登录远程计算机时才可以转发特权端口。


首先修改 dnsmasq.conf 并更改您的 dhcp-boot 选项;目标端口将是树莓派。

从你的本地笔记本电脑上,

$ ssh [email protected] -R 69:69

一旦建立此端口转发,尝试重新启动 Debian 机器。

在 PXE 启动时,机器应该获得指向 pi 的 DHCP 启动选项。

通过端口 69 的 TFTP 请求将进入 SSH 隧道打开的端口,将该数据包发送到本地笔记本电脑上的 127.0.0.1:69。

假设您在端口 69 上运行 TFTP 服务器,则应该下载图像。

相关内容