TIL:无需 curl,使用 Bash /dev/tcp 发出 HTTP 请求
摘要
了解如何使用 Bash 内置的 /dev/tcp 功能从容器中发出 HTTP 请求而无需 curl 或 wget,适用于受限环境下的轻量级调试。
暂无内容
查看缓存全文
缓存时间: 2026/06/16 17:34
# 在没有 curl 的容器中,使用 bash 的 /dev/tcp 发起 HTTP 请求
来源:https://mareksuppa.com/til/bash-dev-tcp-http-without-curl/
我需要检查一个容器能否通过内部 Docker 网络访问另一个容器:只需对共享网络上的服务发起一个简单的 `GET /health` 请求。明显的方法是 `curl http://service:8642/health`。但这个应用镜像非常精简,没有 `curl` 或 `wget`,也没有其他可以用来打开套接字的工具。
结果发现,`bash` 自己就能处理 HTTP。手动打开到主机和端口的连接,然后写入请求,只需要已有的 shell 即可:
bash
``
exec 3<>/dev/tcp/service/8642
printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3
cat <&3
``
这里的 `service` 只是你要连接的主机名。它必须能够解析,并且从运行命令的位置能够到达,因此需要事先配置好:可以是 Docker 网络中的容器名或服务名,也可以是任何可解析的 DNS 名称。请替换为你自己的主机和端口。
这会打印出完整的响应:状态行、头、空行以及主体。要添加一个头(例如 `Authorization: Bearer` 令牌),只需要在终止请求的空行之前再添加一行以 `\r\n` 结尾的行即可:
bash
``
exec 3<>/dev/tcp/service/8642
printf 'GET /v1/models HTTP/1.1\r\nHost: service\r\nAuthorization: Bearer %s\r\nConnection: close\r\n\r\n' "$API_KEY" >&3
cat <&3
``
我第一次使用时遇到的问题是 `/dev/tcp` 并不是真正的设备文件。磁盘上没有这样的路径;`ls /dev/tcp` 什么都找不到,从另一个 shell 执行 `cat /dev/tcp/...` 只会报错。这是 `bash` 内部处理的一种重定向。来自 [Bash 手册](https://www.gnu.org/software/bash/manual/bash.html#Redirections):
> `/dev/tcp/host/port` – 如果 host 是有效的主机名或互联网地址,且 port 是整数端口号或服务名,bash 会尝试打开对应的 TCP 套接字。
之所以选择这个名字,是因为(根据 https://www.gnu.org/software/bash/manual/bash.html#Redirections)没有真正的 Unix 系统存在 `/dev/tcp` 或 `/dev/udp` 目录结构,因此不会发生冲突。Bash 会为你进行 DNS 查找和 `connect(2)` 调用,`exec 3<>` 将套接字分配为文件描述符(`3`),你可以像读写其他文件描述符一样读写它。
几点需要注意:
- `Connection: close` 头部很重要。如果没有它,服务器会在响应后保持连接打开(这是 HTTP/1.1 的默认行为),`cat <&3` 会永远等待永远不会到来的字节。请求服务器关闭连接意味着 `cat` 会读到文件结尾并返回。将调用包装在 `timeout 6 bash -c '...'` 中可以应对两种情况。
- 没有 TLS。`/dev/tcp` 打开的是原始套接字,因此这只适用于明文 HTTP。对于 `https`,你需要 `openssl s_client`,既然如此,倒不如直接用合适的工具了。
- 这是 `bash` 的特性,不是 POSIX 标准。`dash`(Debian 的 `/bin/sh`)和 `zsh` 没有这个功能,所以 `#!/bin/sh` 脚本无法使用。请直接调用 `bash`。
- 这是一个编译时选项,当 `bash` 编译时启用了 `--enable-net-redirections` 才生效。大多数主流构建都启用了它,在我使用的基于 Debian 的镜像中它也能正常工作,但 Debian 曾多年禁用它(参见 https://bugs.launchpad.net/ubuntu/+source/bash/+bug/215034),因此在旧版或非常精简的系统上,最好先确认一下。
对于日常工作,`curl` 仍然是正确的工具。但在一个故意设计得非常小巧、无法安装任何东西的容器中,这个方法可以在不添加包的情况下快速完成检查。
相似文章
Show HN: Mezz, 一个可通过curl使用的WiFi沙箱,用于物联网渗透测试
Mezz 是一个自包含的WiFi沙箱工具,用于检查物联网设备流量,提供一个隔离网络,带有DNS日志记录和可选的MITM代理,全部可通过Docker部署在具有AP功能的WiFi的Linux主机上。
使用 systemfd 将终端输出管道传输到浏览器
本文演示了一种 Bash 脚本技巧,利用 systemfd、watchexec 和 socat,在 Rust Web 服务器开发期间将终端编译日志直接管道传输到浏览器。
通过SSH实时查看CI日志
本文介绍了一项新功能,用户可以通过终端用户界面通过SSH实时查看CI日志,无需安装,并能正确处理ANSI代码。
使用 Go 的 net/http/httptrace 追踪 HTTP 请求
本文介绍了如何使用 Go 的 net/http/httptrace 包通过基于上下文的钩子追踪 HTTP 请求阶段(DNS、连接、TLS 等),并演示了构建 CLI 追踪工具和 RoundTripper 日志记录器。
@avrldotdev: 最佳指南,适合任何人深入了解HTTP服务器工作原理并亲手构建一个。本文将帮助你学习:0. 网络…
一份全面的指南,介绍HTTP服务器的工作原理,涵盖网络协议、分块编码、状态机、解析器编写和并发基础知识,并附有亲手构建的说明。