用goproxy实现基于VPN的本地HTTP代理

我最近用VPN的时候觉得有些地方不太好用,比如说用HTTP代理的时候可以用Chrome的proxy-switchysharp插件做自动切换,这样访问国内资源时和访问国外资源时都很快。因此我用goproxy写了几行代码做了个可以指定本地出口IP的http proxy,连VPN时去掉“Send all traffic over VPN connection“选项,然后用proxy-switchysharp自动切换出口。

不过现在程序还有一些问题,我尝试去访问facebook和twitter都失败了,不知道为什么,同样是https,google和stackoverflow都是正常的,求高手指点。

#########

好了,我知道为什么脸书和推推不能访问了,因为DNS墙了。。。解析出来的地址就不对。

不知道有没有办法在go里面指定ResolveTCPAddr的dns服务器,我现在只能在hosts里面加上正确的IP地址来访问。

#########

代码如下:

package main

import (
    "github.com/elazarl/goproxy"
    "log"
    "net"
    "flag"
    "net/http"
)

var (
    listen = flag.String("listen", "localhost:8080", "listen on address")
    ip = flag.String("ip", "", "listen on address")
    verbose = flag.Bool("verbose", false, "verbose output")
)

func main() {
    flag.Parse()

    if *ip == "" {
        log.Fatal("IP address must be speicified")
    }

    proxy := goproxy.NewProxyHttpServer()
    proxy.Verbose = *verbose
    proxy.Tr.Dial = func (network, addr string) (c net.Conn, err error) {
        if network == "tcp" {
            localAddr, err := net.ResolveTCPAddr(network, *ip + ":0");
            if err != nil {
                return nil, err;
            }
            remoteAddr, err := net.ResolveTCPAddr(network, addr);
            if err != nil {
                return nil, err;
            }
            return net.DialTCP(network, localAddr, remoteAddr);
        }

        return net.Dial(network, addr);
    }
    log.Fatal(http.ListenAndServe(*listen, proxy))
}

使用方法

go run proxy.go -ip VPN虚拟网卡的IP地址

启动代理之后就可以像普通http代理一样在浏览器中使用他咯,非常方便。

 

另外看到一个也是基于goproxy的项目功能也挺有意思,主要是为开发者解决切换开发、生产环境麻烦的问题。有时间的话想整合一下这些功能,但是好像作者已经不更新了,而且是发布在bitbucket的。。。

http://rongmayisheng.com/post/goproxy-灵活的反向代理和静态资源代理

服务器挪到阿里云了

服务器从linode挪到阿里云了,为了备案被迫换了个域名。。。

google的蜘蛛也爬不了新站,连sitemap都抓不了。太惨了。。。难道要我整个双语版BLog?

对了。。。备案的时候不让用博客备案,我想了个新名字叫“海塞工坊”,这回头还得换个Logo。。。哎我了个去。。。管局这帮不干人事的,备个案硬是用了我小一个月。。。

 

好吧,好处还是有,至少访问速度快了不少,而且终于可以用又拍云的CDN了。。。速度是不是爆快?

一个Go语言SSH客户端的例子

an example of ssh client in golang

Google搜了好几个例子都用不了,好像是因为ssh库更新了,没办法只好自己摸索了。

这里用的是RSA Private Key来连接,要改成用密码连接也很容易。

参考文档:https://godoc.org/code.google.com/p/go.crypto/ssh

// 运行前得先安装ssh支持库: go get code.google.com/p/go.crypto/ssh

package main

import (
    "code.google.com/p/go.crypto/ssh"
    "io"
    "log"
)

var (
    pemBytes = `-----BEGIN RSA PRIVATE KEY-----
.......
.......
.......
-----END RSA PRIVATE KEY-----`
)

type keychain struct {
    signer ssh.Signer
}

func (k *keychain) Key(i int) (ssh.PublicKey, error) {
    if i != 0 {
        return nil, nil
    }
    pk := k.signer.PublicKey()
    return pk, nil
}

func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
    return k.signer.Sign(rand, data)
}

func main() {
    signer, err := ssh.ParsePrivateKey([]byte(pemBytes))
    if err != nil {
        panic(err)
    }

    clientKey := &keychain{signer}

    config := &ssh.ClientConfig{
        User: "Hessian",
        Auth: []ssh.ClientAuth{
            ssh.ClientAuthKeyring(clientKey),
        },
    }
    c, err := ssh.Dial("tcp", "YOUR_HOST:22", config)
    if err != nil {
        log.Println("unable to dial remote side:", err)
    }
    defer c.Close()

    // Create a session
    session, err := c.NewSession()
    if err != nil {
        log.Fatalf("unable to create session: %s", err)
    }
    defer session.Close()

    b, err := session.Output("ls -l")
    if err != nil {
        log.Fatalf("failed to execute: %s", err)
    }
    log.Println("Output: ", string(b))

    return
}