基于golang的socks协议库
go的socks库挺多的,这里自销自己写的一个库,感觉使用起来还是挺方便的
项目地址(希望有靓仔光顾):https://github.com/peakedshout/go-socks
- 获取第三方库
go get github.com/peakedshout/go-socks
- socks协议目前主要是socks4和socks5,socks5比较主流,如果是socks5的客户端,可以直接使用proxy.SOCKS5去完成一个socks5的CONNECT连接
-
dr, _ := proxy.SOCKS5("tcp", "127.0.0.1:17999", nil, nil) c, _ := dr.Dial("tcp", ln.Addr().String()) defer c.Close() - 可以直接用在http.Transport{Proxy:}字段里面,起到一个代理的作用
- 但对于BIND/UDPASSOCIATE就没有支持了,可能是应用的比较少,得借助第三方来实现
-
- 使用 github.com/peakedshout/go-socks 起一个socks服务器
-
s, _ := socks.ListenSocksDefault(":12345") s.Wait() - 如果你只使用CONNECT而不需要身份验证,它是最快的,并且支持socks4和socks5的CONNECT,但如果想定制配置,得创建一个配置来填充需要的内容,像这样:
-
config := &server.SocksServerConfig{TlnAddr: ":23333",SocksAuthCb: server.SocksAuthCb{Socks5AuthPASSWORD: func(password share.Socks5AuthPassword) bool {return password.IsEqual("user", "password")},},RelayConfig: nil,VersionSwitch: share.SocksVersionSwitch{SwitchSocksVersion4: false,SwitchSocksVersion5: true,},CMDSwitch: share.SocksCMDSwitch{SwitchCMDCONNECT: true,SwitchCMDBIND: true,SwitchCMDUDPASSOCIATE: false,},ConnTimeout: 0,DialTimeout: 0,BindTimeout: 0,}s2, _ := socks.ListenSocks(config)s2.Close(nil) - 这样就配置好了一个支持CONNECT/BIND并且用户密码为user/password的配置,接着运行就完事了,如果需要其他配置,就在具体的选项上设置一下就行啦,这里RelayConfig是中继配置,这个后面再说
- 像socks5的Auth的一些认证方式,可以直接拿conn进行校验,这是就留用户去操作了
-
- 使用 github.com/peakedshout/go-socks 起一个socks客户端
- socks的客户端就多了,首先socks版本就有4和5,并且操作模式也分为CONNECT/BIND/UDPASSOCIATE,这里我们分操作模式来说
- 首先假定socks server在127.0.0.1:17999
-
CONNECT
-
sd, _ := socks.Socks4CONNECT("127.0.0.1:17999", share.Socks4UserId{123, 223}, nil)c, _ := sd.Dial("tcp", "123.45.67.89.10111")defer c.Close() - 这样就起好了一个socks4的CONNECT,其中的userid,如果socks服务设置了userid校验,那么这里也应该填上值
-
sd2, _ := socks.Socks5CONNECT("127.0.0.1:17999", &client.Socks5Auth{Socks5AuthNOAUTH: true,}, nil)c2, _ := sd2.Dial("tcp", "123.45.67.89.10111")c2.Close() - socks5的CONNECT也差不多,不过有点区别的是,填写的Socks5Auth是必填的,就算是无需校验的noauth,也得填写个bool值
- 如此CONNECT的方法就完成了,如果需要加入context,则使用对应的context方法就行了
-
-
BIND
- bind的方法有点绕,说通俗一点就是,客户端与服务端的角色互调,让服务端主动连接客户端,典型的就是ftp
-
sd, _ := socks.Socks4BIND("127.0.0.1:17999", share.Socks4UserId{123, 223}, nil, func(addr net.Addr) error {return nil})c, _ := sd.Dial("tcp", "123.45.67.89.10111")defer c.Close() - 和CONNECT差不多,但与之不同的是多了个bindCb的回调和dial的addr意义不同,这里的bindCb的作用是将socks服务监听的地址外带出去,让外部的用户获取到地址,通知服务端访问这个地址;dial的addr则是服务端的要连接的地址,socks服务会筛选这个地址的连接,这样就完成了从服务端连接客户端的流程
-
sd2, _ := socks.Socks5BIND("127.0.0.1:17999", &client.Socks5Auth{Socks5AuthNOAUTH: true,}, nil, func(addr net.Addr) error {return nil})c2, _ := sd2.Dial("tcp", "123.45.67.89.10111")defer c2.Close() - socks5的和socks4差不多,一样的工作模式
-
UDPASSOCIATE
- UDPASSOCIATE就只有socks5有了,UDPASSOCIATE的逻辑也挺有意思的,建议查阅一下具体的工作逻辑,这里简单说一下就是,通过一个tcp连接的去维系udp的生命,因为udp十分简单,没法像tcp那样能知道对方是否还使用,所以就借助了请求cmd的tcp连接作为udp监听的寿命,如果这个tcp连接断开了,那么这个udp也停止工作了。。。不过,我们不需要考虑那么复杂,这个库已经帮我们做完这些工作
-
sd, _ := socks.Socks5UDPASSOCIATE("127.0.0.1:17999", &client.Socks5Auth{Socks5AuthNOAUTH: true,}, nil, nil)c, _ := sd.DialUDP("udp", ":8888")defer c.Close() - 这里DialUDP的addr填写的是自己要使用udp地址,因为socks服务需要知道客户端的地址用于筛选出客户端的信息,不然无法哪些是外部的信息,哪些是客户端要解包的信息
- 最后用户拿到的是一个 net.PacketConn ,通过WriteTo和ReadFrom去完成udp的工作
- 这样三种工作模式就都有了,并且也支持了socks4和socks5,这里要多说一下的是,socks4虽然有socks4a去拓展了域名,但对于ipv6还是不支持的。
- 但显然,整篇看下来,这个socks的信道看起来变成了透明的,像是一些操作是可以进行加密信道,但这里就不多处理了。但相对的,多了个relay的选项,可以起到一个中续器的作用
-
rs, _ := socks.ListenRelayServerDefault("127.0.0.1:18000", key)defer rs.Close(nil) - 这里的addr填写的是中续服务监听地址,而key则是32位的byte,用于与socks服务的对称加密信道,同时,socks服务的配置的RelayConfig也填写上对应的内容
-
RelayConfig: &server.SocksRelayConfig{Addr: "127.0.0.1:18000",RawKey: k,KeepEncrypt: false, RelayTimeout: 0,}, - 这里的KeepEncrypt则是是否保持加密信道还是裸数据传输
- 填写好RelayConfig后,socks服务在发现有该配置后,就会任务交给中继服务去执行,这样就可以将socks服务和客户端放在本地,而中继服务在公网上,就实现了信道加密
- 最后提及一下,如果觉得多此一举或者是不信任这种方式,可以不使用该方式,这种方式主要加密了头先的socks请求,内容的加密可以由用户去实现
-
以上就是这个github.com/peakedshout/go-socks主要的功能了,如果觉得不错的话,欢迎来使用它!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
