如何用 Go 语言实现正向代理

正向代理是处理一组内网客户端发往外部机器的网络请求的一种代理方式。

实际上,正向代理是你的应用和你所要连接的服务器之间的中间人。它在 协议上起作用,并且被部署在网络设施的边缘。

你通常可以在大型组织或大学中见到正向代理,它被用来进行授权管理或网络安全方面的控制。

我发现在使用容器或者动态的云环境工作时,正向代理很有用,因为你会面临一组服务器和外部网络的通信问题。

如果你在 、 之类的动态环境下工作,你会拥有一批数量不定的服务器和一批数量不定的公网 。你把应用运行在 集群上时也是一样,容器可能遍布四处。

现在假设有客户让你提供一个公网 的范围,因为他需要设置防火墙。你如何提供这个特性呢?这个问题有些情况下很简单,有些情况下可能非常复杂。

2015 年 12 月 1 日,有一位用户在 论坛上提了这个问题,并且问题还未关闭。当然, 很棒。我只是举个例子,并非要埋怨他们。

解决这个问题的一种可行方法是使用正向代理。你可以让一组节点以同一静态IP运转,然后把清单提供给客户即可。

几乎所有云服务提供商都是这样做的,比如 的浮动 、 的弹性 等。

你可以通过配置自己的应用来把请求转发到这个(代理)池中。这样,终点的服务所取得的IP就是正向代理节点的,而不是内部。

正向代理可以成为你的网络设施的又一安全层,因为你可以在一个中心化的地方极其方便地扫描和控制内部网络发出来的数据包。

正向代理不会带来单点故障,因为你可以运行多个正向代理服务,他们具有很好的伸缩性。

在底层, 的 方法就是一种正向代理。

方法将请求连接转化为透明 通道,通常用于在未加密的 代理上进行 加密的通信。

很多用各种语言写成的 客户端已经以透明的方式支持这个功能了。在此,我以一个使用 语言和 的小例子来告诉大家,这很简单。

首先,我们创建一个名为 的应用。它是一个 服务器,功能是返回你的远程地址。

如果用 方法访问路径 ,你会得到一个类似下面的 格式的响应:,其中 就是你的公网地址。如果你使用的是笔记本电脑,那么在终端上发出请求后,你应该会得到 的结果。可以用 来试一下:

我写了另外一个程序,它用 在标准输出上打印响应。你可以在已经运行了 服务的前提下运行这个程序:

这是个很简单的例子,但是你可以将其运用在很多复杂场合。

为了让例子更清楚,我在 上创建了两台虚拟机:一台运行 ,另一台运行 。

whoyare: public ip 188.166.17.88

privoxy: public ip 167.99.41.79

是一个易用的正向代理。相比而言, 和 都不太适合在这种场景下使用,因为它们不支持方法。

我在 上创建了一个 镜像,你可以直接运行它,默认使用端口 。

第二步,编译并且把可执行文件用传送到服务器,可使用以下命令:

$ CGO_ENABLED=0 GOOS=linux go build -o bin/server_linux -a ./whoyare

应用运行起来之后,我们就可以用 来直接或者通过 发送请求了。

直接发送请求如下:

$ curl -v http://your-ip:8080/whoyare

使用环境变量来配置代理进行请求转发:

如你所见,我设置了 之后,响应不再包含我的公网 了,而是代理的 。

处应该会留下如下的请求日志:

2018-03-18 17:28:22.886 7fbbf41d5ae8 Request: 188.166.17.88:8080/whoyare

2018-03-18 17:32:29.495 7fbbf41d5ae8 Request: 188.166.17.88:8080/whoyare

你之前运行的客户端默认连接到,但可以通过设置环境变量来覆盖目标地址。运行以下命令可以直接到达。

$ URL=http://188.166.17.88:8080 ./bin/client_linux

2018/03/18 18:37:59 Target http://188.166.17.88:8080.

You are {"addr":"95.248.202.252:38620"}

语言的 包支持一组和代理相关的环境变量,设置这些环境变量可以对运行期间的服务立刻生效,十分灵活。

export HTTP_PROXY=http://http_proxy:port/

export HTTPS_PROXY=http://https_proxy:port/

export NO_PROXY=127.0.0.1, localhost

前两个环境变量很简单,一个是 代理,一个是 代理。 排除了一组主机名,当要访问的主机在这个清单里的时候,请求不经过代理。我这里配置的是 和 。

配置了环境变量的客户端将会通过代理访问,其他客户端将直接访问。

这个控制粒度很重要。你不仅可以按进程去控制是否经过代理,还可以按请求去控制,十分灵活。

$ HTTP_PROXY=http://167.99.41.79:8118 URL=http://188.166.17.88:8080

./bin/client_linux

2018/03/18 18:39:18 Target http://188.166.17.88:8080.

You are {"addr":"167.99.41.79:58922"}

可以看到,我们通过代理到达了,响应中的是代理的地址。

最后一个命令有些怪异,但它只是为了展示 是如何工作的。我们在设置访问代理的同时,排除了 的 。正如我们期望的那样,请求没有经过代理:

$ HTTP_PROXY=http://167.99.41.79:8118 URL=http://188.166.17.88:8080 NO_PROXY=188.166.17.88 ./bin/client_linux

2018/03/18 18:42:03 Target http://188.166.17.88:8080.

You are {"addr":"95.248.202.252:38712"}

本文应作为 语言和正向代理的实用介绍来阅读。你可以订阅我的 ,或者在 上关注我。兴许我以后还会介绍如何用 替代 以及如何在 集群上部署。所以,快告诉我先写哪部分吧!

via: https://gianarb.it/blog/golang-forwarding-proxy

作者:gianarb

译者:vincent08

校对:Unknwon

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

喜欢本文的朋友们,欢迎长按下图关注订阅哦!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181022B0H93400?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励