github.com/sagernet/sing-box@v1.2.7/common/proxyproto/dialer.go (about) 1 package proxyproto 2 3 import ( 4 "context" 5 "net" 6 "net/netip" 7 8 "github.com/sagernet/sing-box/adapter" 9 E "github.com/sagernet/sing/common/exceptions" 10 M "github.com/sagernet/sing/common/metadata" 11 N "github.com/sagernet/sing/common/network" 12 13 "github.com/pires/go-proxyproto" 14 ) 15 16 var _ N.Dialer = (*Dialer)(nil) 17 18 type Dialer struct { 19 N.Dialer 20 } 21 22 func (d *Dialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { 23 switch N.NetworkName(network) { 24 case N.NetworkTCP: 25 conn, err := d.Dialer.DialContext(ctx, network, destination) 26 if err != nil { 27 return nil, err 28 } 29 var source M.Socksaddr 30 metadata := adapter.ContextFrom(ctx) 31 if metadata != nil { 32 source = metadata.Source 33 } 34 if !source.IsValid() { 35 source = M.SocksaddrFromNet(conn.LocalAddr()) 36 } 37 if destination.Addr.Is6() { 38 source = M.SocksaddrFrom(netip.AddrFrom16(source.Addr.As16()), source.Port) 39 } 40 h := proxyproto.HeaderProxyFromAddrs(1, source.TCPAddr(), destination.TCPAddr()) 41 _, err = h.WriteTo(conn) 42 if err != nil { 43 conn.Close() 44 return nil, E.Cause(err, "write proxy protocol header") 45 } 46 return conn, nil 47 default: 48 return d.Dialer.DialContext(ctx, network, destination) 49 } 50 }