Skip to content
This repository has been archived by the owner on Mar 17, 2024. It is now read-only.

Commit

Permalink
close #141, 支持sendThrough配置
Browse files Browse the repository at this point in the history
  • Loading branch information
e1732a364fed committed Sep 15, 2022
1 parent 0fce08a commit 55ea3c6
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 17 deletions.
1 change: 1 addition & 0 deletions examples/multi.client.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ insecure = true
utls = true
advancedLayer = "ws"
path = "/ohmygod_verysimple_is_very_simple"
#sendThrough = "63.77.15.11" # dial可以设置 sendThrough为自己的某一个ip地址,来达到选择特定的ip来拨号的目的。常用与 服务器有ipv4和ipv6双栈,而因为某些原因需要单独使用 v4 或者v6 的情况。 (这里给出的示例ip是假的,请改为你自己的ip地址)


[[dial]]
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,7 @@ func dialClient(iics incomingInserverConnState, targetAddr netLayer.Addr,
}
}

clientConn, err = realTargetAddr.Dial(client.GetSockopt())
clientConn, err = realTargetAddr.Dial(client.GetSockopt(), client.LocalAddr())

if err != nil {
if err == netLayer.ErrMachineCantConnectToIpv6 {
Expand Down
19 changes: 19 additions & 0 deletions netLayer/addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,3 +633,22 @@ func V2rayGetAddrFrom(buf utils.ByteReader) (addr Addr, err error) {

return
}

func StrToNetAddr(network, s string) (net.Addr, error) {
if network == "" {
network = "tcp"
}
realNet := StrToTransportProtocol(network)
switch realNet {
case IP:
return net.ResolveIPAddr(network, s)
case TCP:
return net.ResolveTCPAddr(network, s)
case UDP:
return net.ResolveUDPAddr(network, s)
case UNIX:
return net.ResolveUnixAddr(network, s)
default:
return nil, utils.ErrWrongParameter
}
}
1 change: 1 addition & 0 deletions netLayer/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const (
TCP uint16 = 1 << iota
UDP
UNIX //unix domain socket
IP
Raw_socket
KCP
Quic //quic是一个横跨多个层的协议,这里也算一个,毕竟与kcp类似
Expand Down
33 changes: 20 additions & 13 deletions netLayer/dial.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
//Dial 可以拨号tcp、udp、unix domain socket、tls 这几种协议。
//如果不是这几种之一,则会尝试查询 CustomDialerMap 找出匹配的函数进行拨号。
//如果找不到,则会使用net包的方法进行拨号(其会返回错误)。
func (a *Addr) Dial(sockopt *Sockopt) (net.Conn, error) {
func (a *Addr) Dial(sockopt *Sockopt, localAddr net.Addr) (net.Conn, error) {
var istls bool
var resultConn net.Conn
var err error
Expand All @@ -38,13 +38,13 @@ func (a *Addr) Dial(sockopt *Sockopt) (net.Conn, error) {
case "udp", "udp4", "udp6":
ua := a.ToUDPAddr()

if sockopt == nil {
if sockopt == nil && localAddr == nil {

return DialUDP(ua)
} else {

var c net.Conn
c, err = a.DialWithOpt(sockopt)
c, err = a.DialWithOpt(sockopt, localAddr)
if err == nil {
uc := c.(*net.UDPConn)
return NewUDPConn(ua, uc, true), nil
Expand All @@ -71,14 +71,14 @@ tcp:

var tcpConn *net.TCPConn

if sockopt == nil {
if sockopt == nil && localAddr == nil {
tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{
IP: a.IP,
Port: a.Port,
})
} else {
var c net.Conn
c, err = a.DialWithOpt(sockopt)
c, err = a.DialWithOpt(sockopt, localAddr)
if err == nil {
tcpConn = c.(*net.TCPConn)
}
Expand All @@ -98,21 +98,21 @@ defaultPart:
if istls {
//若tls到达了这里,则说明a的ip没有给出,而只给出了域名,所以上面tcp部分没有直接拨号

if sockopt == nil {
if sockopt == nil && localAddr == nil {
resultConn, err = net.DialTimeout("tcp", a.String(), defaultDialTimeout)

} else {
newA := *a
newA.Network = "tcp"
resultConn, err = newA.DialWithOpt(sockopt)
resultConn, err = newA.DialWithOpt(sockopt, localAddr)
}

} else {
//一般情况下,unix domain socket 会到达这里,其他情况则都被前面代码捕获到了
if sockopt == nil {
resultConn, err = net.DialTimeout(a.Network, a.String(), defaultDialTimeout)
} else {
resultConn, err = a.DialWithOpt(sockopt)
resultConn, err = a.DialWithOpt(sockopt, localAddr)
}

}
Expand All @@ -136,16 +136,23 @@ dialedPart:

}

func (a Addr) DialWithOpt(sockopt *Sockopt) (net.Conn, error) {
//比Dial更低级的方法,专用于使用sockopt的情况。
//这里调用者要保证sockopt不为nil。a的Network只能为golang支持的那几种。
func (a Addr) DialWithOpt(sockopt *Sockopt, localAddr net.Addr) (net.Conn, error) {

dialer := &net.Dialer{
Timeout: defaultDialTimeout,
}
dialer.Control = func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
SetSockOpt(int(fd), sockopt, a.IsUDP(), a.IsIpv6())
if localAddr != nil {
dialer.LocalAddr = localAddr
}
if sockopt != nil {
dialer.Control = func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
SetSockOpt(int(fd), sockopt, a.IsUDP(), a.IsIpv6())

})
})
}
}

return dialer.Dial(a.Network, a.String())
Expand Down
2 changes: 1 addition & 1 deletion netLayer/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func DialDnsAddr(addr *Addr) (conn net.Conn, err error) {
if addr.IsUDP() {
conn, err = net.DialUDP("udp", nil, addr.ToUDPAddr())
} else {
conn, err = addr.Dial(nil)
conn, err = addr.Dial(nil, nil)

}
//todo: 以后支持DoH的话,要分离出https这个Network然后单独使用独特方法进行dial
Expand Down
6 changes: 6 additions & 0 deletions proxy/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package proxy
import (
"crypto/tls"
"io"
"net"
"strings"
"sync"

Expand Down Expand Up @@ -86,6 +87,7 @@ type Base struct {
DialConf *DialConf

Addr string
LA net.Addr //for client's LocalAddr
TLS bool
Tag string //可用于路由, 见 netLayer.route.go
TransportLayer string
Expand Down Expand Up @@ -122,6 +124,10 @@ func (b *Base) Network() string {
return b.TransportLayer
}

func (b *Base) LocalAddr() net.Addr {
return b.LA
}

func (b *Base) GetXver() int {
return b.Xver
}
Expand Down
3 changes: 3 additions & 0 deletions proxy/config_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ type ListenConf struct {
// CommonConf.Host , CommonConf.IP, CommonConf.Port is the addr and port for dialing.
type DialConf struct {
CommonConf

SendThrough string `toml:"sendThrough"` //可选,用于发送数据的 IP 地址

Utls bool `toml:"utls"` //是否使用 uTls 库 替换 go官方tls库

Mux bool `toml:"use_mux"` //是否使用内层mux。在某些支持mux命令的协议中(vless v1/trojan), 开启此开关会让 dial 使用 内层mux。
Expand Down
10 changes: 10 additions & 0 deletions proxy/creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ func newclient(creator ClientCreator, dc *DialConf, knownTls bool) (Client, erro
c.GetBase().TLS = true
e = prepareTLS_forClient(c, dc)
}
if dc.SendThrough != "" {
st, err := netLayer.StrToNetAddr(c.Network(), dc.SendThrough)
if err != nil {
return nil, utils.ErrInErr{ErrDesc: "parse sendthrough ip failed", ErrDetail: err}

} else {
c.GetBase().LA = st

}
}
return c, e

}
Expand Down
4 changes: 2 additions & 2 deletions proxy/direct.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ func (d *DirectClient) Handshake(underlay net.Conn, firstPayload []byte, target

if underlay == nil {
if d.Sockopt != nil {
result, err = target.DialWithOpt(d.Sockopt)
result, err = target.DialWithOpt(d.Sockopt, d.LA)
} else {
result, err = target.Dial(nil)
result, err = target.Dial(nil, d.LA)
}

} else {
Expand Down
2 changes: 2 additions & 0 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ type Client interface {
InnerMuxEstablished() bool
CloseInnerMuxSession()

LocalAddr() net.Addr //用于在拨号时选用一个特定的ip拨号。

sync.Locker //用于锁定 innerMux
}

Expand Down

0 comments on commit 55ea3c6

Please sign in to comment.