圈圈套圈圈(5) 分发代理

不知道怎么取这个名字。
其本身的作用类似一个做负载均衡的反向圈圈。 这个圈圈的作用是根据请求的地址将请求发送到下一个(不同)的圈圈服务器。

在当前的测试中, 尚无法走推犆,脸数之流的https.

检查net/http的代码, 其中连接是通过http.Transport这个结构出去的.

type Transport struct {
    // ...省略
    // Proxy specifies a function to return a proxy for a given
    // Request. If the function returns a non-nil error, the
    // request is aborted with the provided error.
    //
    // The proxy type is determined by the URL scheme. "http"
    // and "socks5" are supported. If the scheme is empty,
    // "http" is assumed.
    //
    // If Proxy is nil or returns a nil *URL, no proxy is used.
    Proxy func(*Request) (*url.URL, error)
    // ...省略

通常设置圈圈的圈圈的代码如下:

   proxy.Tr.Proxy = http.ProxyURL(proxyUrl)

这个http.ProxyURL的代码如下:


// ProxyURL returns a proxy function (for use in a Transport)
// that always returns the same URL.
func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
    return func(*Request) (*url.URL, error) {
        return fixedURL, nil
    }
}

根据请求的request来给出圈圈的地址。 这正是我们想要的。


func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
    if port := treq.URL.Port(); !validPort(port) {
        return cm, fmt.Errorf("invalid URL port %q", port)
    }
    cm.targetScheme = treq.URL.Scheme
    cm.targetAddr = canonicalAddr(treq.URL)
    if t.Proxy != nil {
        cm.proxyURL, err = t.Proxy(treq.Request)
        if err == nil && cm.proxyURL != nil {
            if port := cm.proxyURL.Port(); !validPort(port) {
                return cm, fmt.Errorf("invalid proxy URL port %q", port)
            }
        }
    }
    return cm, err
}

如果cm.proxyURL非空才做圈圈的操作。 所以我们可以选择不使用圈圈。

所以完整代码如下, 非常简单:

package main

import (
    "flag"
    "log"
    "net/http"
    "net/url"
    "strings"

    "github.com/elazarl/goproxy"
)

var (
    addr    = flag.String("addr", ":8080", "proxy listen address")
    verbose = flag.Bool("v", false, "should every proxy request be logged to stdout")
    vvb2    = flag.Bool("mas", false, "verbose more")
)

const (
    NarrowProxyLink = "http://abc:xyz@myvnc:30000"
    WideProxyLink   = "http://mas:more@192.168.1.3:8080"
)

func init() {
    flag.Parse()
}

func makeBi(internal, external *url.URL) func(*http.Request) (*url.URL, error) {
    return func(req *http.Request) (*url.URL, error) {
        hostname := req.URL.Hostname()
        switch {
        case hostname == "localhost":
            if *vvb2 {
                log.Printf("no proxy for localhost")
            }
            return nil, nil
        case strings.HasSuffix(req.URL.Hostname(), "csdn.net"):
            if *vvb2 {
                log.Printf("using internal:<%v>", req.URL.Hostname())
            }
            return internal, nil
        default:
            if *vvb2 {
                log.Printf("using external for:<%v>", req.URL.Hostname())
            }
            return external, nil
        }
    }
}

func main() {
    log.SetFlags(log.Lshortfile)
    proxy := goproxy.NewProxyHttpServer()
    proxy.Verbose = *verbose

    proxyI, err := url.Parse(NarrowProxyLink)
    if err != nil {
        panic(err)
    }
    proxyE, err := url.Parse(WideProxyLink)
    if err != nil {
        panic(err)
    }

    //log.Printf("Using proxy <%v>", proxyUrl)
    //proxy.Tr.Proxy = http.ProxyURL(proxyUrl)
    proxy.Tr.Proxy = makeBi(proxyI, proxyE)
    log.Fatal(http.ListenAndServe(*addr, proxy))
}

要加上适当的证书才能让浏览器通过这样的代理。
现在暂时不知道如何设置这些证书以及如何正确导出导入。

    setCA(caCert(), caKey())
    proxy := goproxy.NewProxyHttpServer()
    proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)

参考链接(证书)
https://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl
https://github.com/yuanliangding/books/blob/master/%E8%AE%A1%E7%AE%97%E6%9C%BA%E2%97%8F%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%E2%97%8F%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE/HTTP%E6%9D%83%E5%A8%81%E6%8C%87%E5%8D%97%EF%BC%88%E4%B8%AD%E6%96%87%E7%89%88%EF%BC%89.pdf

(HTTP权威指南PDF版本)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值