我有服务器 A,其 IP 为 192.0.2.2,它没有连接到互联网,因此它必须将所有互联网 http 流量传递到服务器 B 上的 squid 代理,其 IP 为 192.0.2.3,监听端口 8080。
我使用了以下规则来建立与 squid 代理的连接,但是当我启动 wget 时却收到 400 错误请求错误:
iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination IP:8080
wget:
wget external.example.net/v4/Picture/pic1.jpg
--2015-09-05 18:42:01-- http://external.example.net/v4/Picture/pic1.jpg
Resolving external.example.net... 60.192.194.32, 61.54.192.95, 77.36.14.19, ...
Connecting to external.example.net|60.192.194.32|:80... connected.
HTTP request sent, awaiting response... 400 Bad Request
2015-09-05 18:42:01 ERROR 400: Bad Request.
当我检查 squid 日志时,我发现 URL 中缺少域名。
1 192.0.2.2 NONE/400 1186 GET /v4/Picture/pic1.jpg - NONE/- -
如果我使用 bash http_proxy 代替 iptables 规则,我可以成功下载图像,并且 squid 会记录完整的 url
export http_proxy=http://192.0.2.3:8080
wget external.example.net/v4/Picture/pic1.jpg
wget:
2015-09-05 18:55:48-- http://external.example.net/v4/Picture/pic1.jpg
Connecting to 192.0.2.3:8080... connected.
Proxy request sent, awaiting response... 200 OK
Length: 83760 (82K) [image/jpeg]
Saving to: `pic1.jpg'
鱿鱼日志
7 1.2.3.4 TCP_HIT/200 84455 GET http://external.example.net/v4/Picture/pic1.jpg - NONE/- image/jpeg
为什么我的第一个请求不起作用?
答案1
这与代理的工作方式不完全一致。
当您通过 HTTP 代理发送请求时,它看起来像这样,其中 proxy.example.net 是代理,而 target.example.net 是您要获取的站点:
GET http://target.example.net/path/to/resource HTTP/1.1
Host: proxy.example.net
这是为了说明目的,因为您会注意到用于向代理发出 HTTP 请求的 URL 是这样的:
http://proxy.example.net/http://target.example.net/path/to/resource
当您使用 DNAT 简单地重定向流量时,wget 将解析 target.example.net 并将 URI 的路径部分作为请求正文而不是要代理的 URL 发送,因此它只发送以下内容:
GET /path/to/resource HTTP/1.1
Host: target.example.net
squid 服务器对此感到困惑,因为它不是 target.example.net,也没有在 /path/to/resource 提供文档。
如果将 squid 配置为透明代理,您实际上可以使用以下指令来执行此操作(对于 2.6 版之前的 squid):
httpd_accel_host virtual
httpd_accel_port 8080
httpd_accel_with_proxy on
httpd_accel_uses_host_header on
最后一个,httpd_accel_uses_host_header on
告诉 squid 使用Host:
我上面示例中的标头(需要 HTTP 1.1)来确定从哪里获取资源,而不是使用我上面提到的显式代理请求。请参阅http://squidconfiguration.com/config-manual-2-4/httpd-accelerator-options/httpd_accel_uses_host_header/。
对于较新版本的 squid(3.1 及更高版本),请使用以下 listen 指令:
http_port 8080 intercept
看这里:http://www.squid-cache.org/Doc/config/http_port/
对于一些老版本的squid来说,是“透明”而不是“拦截”。
squid wiki 上有一个很好的教程:http://wiki.squid-cache.org/ConfigExamples/Intercept/LinuxRedirect