令所有proxy均支持fullcone配置.只有当listen和dial都为fullcone时,才真fullcone

This commit is contained in:
e1732a364fed
2000-01-01 00:00:00 +00:00
parent a3e4258dfc
commit 961bde8d6d
20 changed files with 68 additions and 40 deletions

View File

@@ -40,7 +40,7 @@ dns(udp/tls)/route(geoip/geosite,分流功能完全与v2ray等价)/fallback(path
tcp/udp(以及fullcone)/unix domain socket, tls(包括客户端证书验证), uTls,【tls lazy encrypt】, http伪装头,PROXY protocol v1/v2 监听,
cli(交互模式)/apiServer, Docker.
cli(交互模式)/apiServer, Docker, docker-compose.
为了不吓跑小白,本 README 把安装、使用方式 放在了前面,如果你要直接阅读本作的技术介绍部分,点击跳转 -> [创新点](#创新点)

View File

@@ -113,11 +113,8 @@ func RelayUDP(rc, lc MsgConn, downloadByteCount, uploadByteCount *uint64) uint64
count += uint64(len(bs))
}
if !rc.Fullcone() {
if !(rc.Fullcone() && lc.Fullcone()) {
rc.Close()
}
if !lc.Fullcone() {
lc.Close()
}
@@ -161,11 +158,8 @@ func relayUDP_rc_toLC(rc, lc MsgConn, downloadByteCount *uint64, mutex *sync.RWM
}
count += uint64(len(bs))
}
if !rc.Fullcone() {
if !(rc.Fullcone() && lc.Fullcone()) {
rc.Close()
}
if !lc.Fullcone() {
lc.Close()
}

View File

@@ -92,6 +92,8 @@ type Base struct {
Sockopt *netLayer.Sockopt
Xver int
IsFullcone bool
Tls_s *tlsLayer.Server
Tls_c *tlsLayer.Client
@@ -302,6 +304,7 @@ func (b *Base) ConfigCommon(cc *CommonConf) {
b.Xver = cc.Xver
b.Tag = cc.Tag
b.Sockopt = cc.Sockopt
b.IsFullcone = cc.Fullcone
if cc.HttpHeader != nil {
cc.HttpHeader.AssignDefaultValue()

View File

@@ -20,23 +20,16 @@ type DirectCreator struct{}
func (DirectCreator) NewClientFromURL(url *url.URL) (Client, error) {
d := &DirectClient{}
nStr := url.Query().Get("fullcone")
if nStr == "true" || nStr == "1" {
d.isfullcone = true
}
return d, nil
}
func (DirectCreator) NewClient(dc *DialConf) (Client, error) {
d := &DirectClient{}
d.isfullcone = dc.Fullcone
return d, nil
}
type DirectClient struct {
Base
isfullcone bool
}
func (*DirectClient) Name() string { return DirectName }
@@ -67,10 +60,10 @@ func (d *DirectClient) Handshake(underlay net.Conn, firstPayload []byte, target
//direct的Client的 EstablishUDPChannel 直接 监听一个udp端口无视传入的net.Conn.
func (d *DirectClient) EstablishUDPChannel(_ net.Conn, firstPayload []byte, target netLayer.Addr) (netLayer.MsgConn, error) {
if len(firstPayload) == 0 {
return netLayer.NewUDPMsgConn(nil, d.isfullcone, false)
return netLayer.NewUDPMsgConn(nil, d.IsFullcone, false)
} else {
mc, err := netLayer.NewUDPMsgConn(nil, d.isfullcone, false)
mc, err := netLayer.NewUDPMsgConn(nil, d.IsFullcone, false)
if err != nil {
return nil, err
}

View File

@@ -29,6 +29,8 @@ type CommonConf struct {
Xver int `toml:"xver"` //可选只能为0/1/2. 若不为0, 则使用 PROXY protocol 协议头.
Fullcone bool `toml:"fullcone"` //在direct会用到, fullcone的话因为不能关闭udp连接, 所以 时间长后, 可能会导致too many open files. fullcone 的话一般人是用不到的, 所以 有需要的人自行手动打开 即可
/////////////////// tls层 ///////////////////
TLS bool `toml:"tls"` //tls层; 可选. 如果不使用 's' 后缀法则还可以配置这一项来更清晰第标明使用tls
@@ -121,8 +123,7 @@ type ListenConf struct {
// CommonConf.Host , CommonConf.IP, CommonConf.Port is the addr and port for dialing.
type DialConf struct {
CommonConf
Utls bool `toml:"utls"` //是否使用 uTls 库 替换 go官方tls库
Fullcone bool `toml:"fullcone"` //在direct会用到, fullcone的话因为不能关闭udp连接, 所以可能会导致too many open files. fullcone 的话一般人是用不到的, 所以 有需要的人自行手动打开 即可
Utls bool `toml:"utls"` //是否使用 uTls 库 替换 go官方tls库
Mux bool `toml:"use_mux"` //是否使用内层mux。在某些支持mux命令的协议中vless v1/trojan, 开启此开关会让 dial 使用 内层mux。
}

View File

@@ -140,14 +140,22 @@ func configCommonURLQueryForServer(ser BaseInterface, u *url.URL) {
}
//SetAddrStr, setNetwork
func configCommonByURL(ser BaseInterface, u *url.URL) {
func configCommonByURL(baseI BaseInterface, u *url.URL) {
if u.Scheme != DirectName {
ser.SetAddrStr(u.Host) //若不给出port那就只有host名这样不好我们 默认 配置里肯定给了port
baseI.SetAddrStr(u.Host) //若不给出port那就只有host名这样不好我们 默认 配置里肯定给了port
}
serc := ser.GetBase()
if serc == nil {
base := baseI.GetBase()
if base == nil {
return
}
serc.setNetwork(u.Query().Get("network"))
base.setNetwork(u.Query().Get("network"))
base.IsFullcone = GetFullconeFromUrl(u)
}
func GetFullconeFromUrl(url *url.URL) bool {
nStr := url.Query().Get("fullcone")
return nStr == "true" || nStr == "1"
}

View File

@@ -91,6 +91,7 @@ func (c *Client) EstablishUDPChannel(underlay net.Conn, firstPayload []byte, tar
uc := NewUDPConn(underlay, nil)
uc.handshakeBuf = buf
uc.fullcone = c.IsFullcone
if len(firstPayload) == 0 {
return uc, nil

View File

@@ -99,7 +99,9 @@ realPart:
}
if isudp {
return nil, NewUDPConn(underlay, io.MultiReader(readbuf, underlay)), targetAddr, nil
x := NewUDPConn(underlay, io.MultiReader(readbuf, underlay))
x.fullcone = s.IsFullcone
return nil, x, targetAddr, nil
} else {
return &TCPConn{

View File

@@ -16,6 +16,7 @@ type UDPConn struct {
bufr *bufio.Reader
handshakeBuf *bytes.Buffer
fullcone bool
}
func NewUDPConn(conn net.Conn, optionalReader io.Reader) (uc *UDPConn) {
@@ -30,8 +31,8 @@ func NewUDPConn(conn net.Conn, optionalReader io.Reader) (uc *UDPConn) {
return
}
func (*UDPConn) Fullcone() bool {
return true
func (u *UDPConn) Fullcone() bool {
return u.fullcone
}
func (u *UDPConn) CloseConnWithRaddr(raddr netLayer.Addr) error {
return u.Close()

View File

@@ -159,6 +159,7 @@ func (c *Client) EstablishUDPChannel(underlay net.Conn, firstPayload []byte, tar
ServerAddr: &net.TCPAddr{
IP: ua.IP,
},
fullcone: c.IsFullcone,
}
cpc.UDPConn, err = net.DialUDP("udp", nil, ua)
if err != nil {

View File

@@ -19,6 +19,7 @@ type ClientUDPConn struct {
ServerUDPPort_forMe int //socks5服务会为每一个socks5客户端留一个专用的udp端口
WriteUDP_Target *net.UDPAddr
fullcone bool
}
func (cpc *ClientUDPConn) Associate() (err error) {
@@ -144,7 +145,7 @@ func (cpc *ClientUDPConn) CloseConnWithRaddr(raddr netLayer.Addr) error {
}
func (cpc *ClientUDPConn) Fullcone() bool {
return true
return cpc.fullcone
}
//传入 conn必须非nil否则panic

View File

@@ -44,6 +44,7 @@ func (ServerCreator) NewServerFromURL(u *url.URL) (proxy.Server, error) {
if userPass.InitWithUrl(u) {
s.AddUser(&userPass)
}
return s, nil
}
@@ -280,8 +281,13 @@ For:
// 更不用说这样 的 udp associate 会重复使用很多 随机udp端口特征很明显。
// 总之 udp associate 只能用于内网环境。
//旧代码每次遇到 associate都会返回一个新的随机端口而实际上这应该是有问题的
//如果一些不良的socks5客户端 每次 udp请求都使用 associate的话会造成端口数量无限增长最后产生 too many open files 错误。
if cmd == CmdUDPAssociate {
utils.Debug("socks5 got CmdUDPAssociate")
//这里我们serverAddr直接返回0.0.0.0即可,也实在想不到谁会返回 另一个ip地址出来。肯定应该和原ip相同的。
//随机生成一个端口专门用于处理该客户端。这是我的想法。
@@ -323,6 +329,7 @@ For:
uc := &ServerUDPConn{
clientSupposedAddr: clientFutureAddr.ToUDPAddr(), //这里为了解析域名, 就用了 netLayer.Addr 作为中介的方式
UDPConn: udpRC,
fullcone: s.IsFullcone,
}
return nil, uc, clientFutureAddr, nil
@@ -355,6 +362,7 @@ For:
type ServerUDPConn struct {
*net.UDPConn
clientSupposedAddr *net.UDPAddr //客户端指定的客户端自己未来将使用的公网UDP的Addr
fullcone bool
}
func (u *ServerUDPConn) CloseConnWithRaddr(raddr netLayer.Addr) error {
@@ -362,7 +370,7 @@ func (u *ServerUDPConn) CloseConnWithRaddr(raddr netLayer.Addr) error {
}
func (u *ServerUDPConn) Fullcone() bool {
return true
return u.fullcone
}
//将远程地址发来的响应 传给客户端

View File

@@ -9,12 +9,14 @@ import (
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/proxy/socks5"
"github.com/e1732a364fed/v2ray_simple/utils"
)
//tcp就不测了我们实践直接测试完全好使这里重点测试UDP
// 因为chrome也是无法通过 socks5去申请udp链接的所以没法自己用浏览器测试
func TestUDP(t *testing.T) {
utils.InitLog("")
s := socks5.NewServer()

View File

@@ -2,17 +2,23 @@
This package imports proxy/socks5 and proxy/http package.
Naming
socks5http 与 clash的 "mixed" 等价。之所以不用 "mixed"这个名称,是因为这容易在本作中引起歧义。
clash是一个客户端它没有服务端所以它的监听只是用于内网监听所以监听协议 只有http和socks5 两种,所以 它 叫 "mixed" 是没有歧义的;
而本作与v2ray一样是支持多种服务端协议的如果也叫 mixed 的话,会让人误以为,这是一个 "万能协议", 啥都能监听, 而这显然是误区。 命名为 socks5http, 则清晰地指出了 该协议的功能。
Password
为了避免混淆,本包不支持密码验证。你要是有这么高的密码要求 那你不妨用单独的协议,而不要用混合版。
实际上本包就是先经过http然后如果不是http代理请求就会回落到socks5.
所以你可以通过 设计回落的方式来达到 有密码 的 混合端口 的需求。
socks5http 与 clash的 "mixed" 等价。之所以不用 "mixed"这个名称,是因为这容易在本作中引起歧义。
clash是一个客户端它没有服务端所以它的监听只是用于内网监听所以监听协议 只有http和socks5 两种,所以 它 叫 "mixed" 是没有歧义的;
而本作与v2ray一样是支持多种服务端协议的如果也叫 mixed 的话,会让人误以为,这是一个 "万能协议", 啥都能监听, 而这显然是误区。 命名为 socks5http, 则清晰地指出了 该协议的功能。
*/
package socks5http

View File

@@ -137,7 +137,7 @@ func (c *Client) EstablishUDPChannel(underlay net.Conn, firstPayload []byte, tar
buf.WriteByte(CmdUDPAssociate)
WriteAddrToBuf(target, buf)
uc := NewUDPConn(underlay, nil)
uc := NewUDPConn(underlay, nil, c.IsFullcone)
uc.User = c.User
uc.handshakeBuf = buf
if len(firstPayload) == 0 {

View File

@@ -202,7 +202,7 @@ realPart:
}
if isudp {
uc := NewUDPConn(underlay, io.MultiReader(readbuf, underlay))
uc := NewUDPConn(underlay, io.MultiReader(readbuf, underlay), s.IsFullcone)
uc.User = theUser.(User)
return nil, uc, targetAddr, nil

View File

@@ -18,11 +18,14 @@ type UDPConn struct {
bufr *bufio.Reader
handshakeBuf *bytes.Buffer
isfullcone bool
}
func NewUDPConn(conn net.Conn, optionalReader io.Reader) (uc *UDPConn) {
func NewUDPConn(conn net.Conn, optionalReader io.Reader, fullcone bool) (uc *UDPConn) {
uc = new(UDPConn)
uc.Conn = conn
uc.isfullcone = fullcone
if optionalReader != nil {
uc.optionalReader = optionalReader
uc.bufr = bufio.NewReader(optionalReader)
@@ -32,8 +35,8 @@ func NewUDPConn(conn net.Conn, optionalReader io.Reader) (uc *UDPConn) {
return
}
func (*UDPConn) Fullcone() bool {
return true
func (u *UDPConn) Fullcone() bool {
return u.isfullcone
}
func (u *UDPConn) CloseConnWithRaddr(raddr netLayer.Addr) error {
return u.Close()

View File

@@ -211,6 +211,7 @@ func (c *Client) EstablishUDPChannel(underlay net.Conn, firstPayload []byte, tar
raddr: target,
udp_multi: c.udp_multi,
handshakeBuf: buf,
fullcone: c.IsFullcone,
}
if len(firstPayload) == 0 {
return uc, nil

View File

@@ -267,6 +267,7 @@ realPart:
raddr: targetAddr,
remainFirstBufLen: readbuf.Len(),
udp_multi: use_udp_multi,
fullcone: s.IsFullcone,
}, targetAddr, nil
} else {

View File

@@ -30,13 +30,15 @@ type UDPConn struct {
raddr netLayer.Addr
handshakeBuf *bytes.Buffer
fullcone bool
}
func (u *UDPConn) CloseConnWithRaddr(raddr netLayer.Addr) error {
return u.Close()
}
func (u *UDPConn) Fullcone() bool {
return u.version != 0
return u.fullcone && u.version != 0
}
func (u *UDPConn) GetProtocolVersion() int {