Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c3774d05ad | |||
| 528b50dbb8 | |||
| 940de4a789 | |||
| 505fa325e4 | |||
| 6dbcc3d1e2 |
@@ -73,6 +73,7 @@
|
||||
- [Xray_bash_onekey](https://github.com/hello-yunshu/Xray_bash_onekey), [XTool](https://github.com/LordPenguin666/XTool), [VPainLess](https://github.com/vpainless/vpainless)
|
||||
- [v2ray-agent](https://github.com/mack-a/v2ray-agent), [Xray_onekey](https://github.com/wulabing/Xray_onekey), [ProxySU](https://github.com/proxysu/ProxySU)
|
||||
- Magisk
|
||||
- [NetProxy-Magisk](https://github.com/Fanju6/NetProxy-Magisk)
|
||||
- [Xray4Magisk](https://github.com/Asterisk4Magisk/Xray4Magisk)
|
||||
- [Xray_For_Magisk](https://github.com/E7KMbb/Xray_For_Magisk)
|
||||
- Homebrew
|
||||
@@ -119,6 +120,7 @@
|
||||
- [SimpleXray](https://github.com/lhear/SimpleXray)
|
||||
- [XrayFA](https://github.com/Q7DF1/XrayFA)
|
||||
- [AnyPortal](https://github.com/AnyPortal/AnyPortal)
|
||||
- [NetProxy-Magisk](https://github.com/Fanju6/NetProxy-Magisk)
|
||||
- [OneXray](https://github.com/OneXray/OneXray)
|
||||
- iOS & macOS arm64 & tvOS
|
||||
- [Happ](https://apps.apple.com/app/happ-proxy-utility/id6504287215) | [Happ RU](https://apps.apple.com/ru/app/happ-proxy-utility-plus/id6746188973) | [Happ tvOS](https://apps.apple.com/us/app/happ-proxy-utility-for-tv/id6748297274)
|
||||
|
||||
@@ -267,6 +267,20 @@ func (h *Handler) DestIpAddress() net.IP {
|
||||
return internet.DestIpAddress()
|
||||
}
|
||||
|
||||
func (h *Handler) SocketSettings() *internet.SocketConfig {
|
||||
if h.streamSettings == nil {
|
||||
return nil
|
||||
}
|
||||
return h.streamSettings.SocketSettings
|
||||
}
|
||||
|
||||
func (h *Handler) UsesProxySettings() bool {
|
||||
if h.senderSettings != nil && h.senderSettings.ProxySettings.HasTag() {
|
||||
return true
|
||||
}
|
||||
return h.streamSettings != nil && h.streamSettings.SocketSettings != nil && len(h.streamSettings.SocketSettings.DialerProxy) > 0
|
||||
}
|
||||
|
||||
// Dial implements internet.Dialer.
|
||||
func (h *Handler) Dial(ctx context.Context, dest net.Destination) (stat.Connection, error) {
|
||||
if h.senderSettings != nil {
|
||||
|
||||
@@ -3,7 +3,6 @@ package singbridge
|
||||
import (
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
)
|
||||
|
||||
@@ -18,14 +17,14 @@ func ToNetwork(network string) net.Network {
|
||||
}
|
||||
}
|
||||
|
||||
func ToDestination(socksaddr M.Socksaddr, network net.Network) (net.Destination, error) {
|
||||
func ToDestination(socksaddr M.Socksaddr, network net.Network) net.Destination {
|
||||
// IsFqdn() implicitly checks if the domain name is valid
|
||||
if socksaddr.IsFqdn() {
|
||||
return net.Destination{
|
||||
Network: network,
|
||||
Address: net.DomainAddress(socksaddr.Fqdn),
|
||||
Port: net.Port(socksaddr.Port),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// IsIP() implicitly checks if the IP address is valid
|
||||
@@ -34,10 +33,10 @@ func ToDestination(socksaddr M.Socksaddr, network net.Network) (net.Destination,
|
||||
Network: network,
|
||||
Address: net.IPAddress(socksaddr.Addr.AsSlice()),
|
||||
Port: net.Port(socksaddr.Port),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return net.Destination{}, errors.New("invalid socks address: ", socksaddr)
|
||||
return net.Destination{}
|
||||
}
|
||||
|
||||
func ToSocksaddr(destination net.Destination) M.Socksaddr {
|
||||
|
||||
@@ -26,11 +26,7 @@ func NewDialer(dialer internet.Dialer) *XrayDialer {
|
||||
}
|
||||
|
||||
func (d *XrayDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
dest, err := ToDestination(destination, ToNetwork(network))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.Dialer.Dial(ctx, dest)
|
||||
return d.Dialer.Dial(ctx, ToDestination(destination, ToNetwork(network)))
|
||||
}
|
||||
|
||||
func (d *XrayDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
@@ -47,17 +43,13 @@ func NewOutboundDialer(outbound proxy.Outbound, dialer internet.Dialer) *XrayOut
|
||||
}
|
||||
|
||||
func (d *XrayOutboundDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
dest, err := ToDestination(destination, ToNetwork(network))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbounds := session.OutboundsFromContext(ctx)
|
||||
if len(outbounds) == 0 {
|
||||
outbounds = []*session.Outbound{{}}
|
||||
ctx = session.ContextWithOutbounds(ctx, outbounds)
|
||||
}
|
||||
ob := outbounds[len(outbounds)-1]
|
||||
ob.Target = dest
|
||||
ob.Target = ToDestination(destination, ToNetwork(network))
|
||||
|
||||
opts := []pipe.Option{pipe.WithSizeLimit(64 * 1024)}
|
||||
uplinkReader, uplinkWriter := pipe.New(opts...)
|
||||
|
||||
@@ -31,23 +31,15 @@ func NewDispatcher(dispatcher routing.Dispatcher, newErrorFunc func(values ...an
|
||||
}
|
||||
|
||||
func (d *Dispatcher) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
|
||||
dest, err := ToDestination(metadata.Destination, net.Network_TCP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
xConn := NewConn(conn)
|
||||
return d.upstream.DispatchLink(ctx, dest, &transport.Link{
|
||||
return d.upstream.DispatchLink(ctx, ToDestination(metadata.Destination, net.Network_TCP), &transport.Link{
|
||||
Reader: xConn,
|
||||
Writer: xConn,
|
||||
})
|
||||
}
|
||||
|
||||
func (d *Dispatcher) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
|
||||
dest, err := ToDestination(metadata.Destination, net.Network_UDP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return d.upstream.DispatchLink(ctx, dest, &transport.Link{
|
||||
return d.upstream.DispatchLink(ctx, ToDestination(metadata.Destination, net.Network_UDP), &transport.Link{
|
||||
Reader: buf.NewPacketReader(conn.(io.Reader)),
|
||||
Writer: buf.NewWriter(conn.(io.Writer)),
|
||||
})
|
||||
|
||||
+26
-22
@@ -10,21 +10,15 @@ import (
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
)
|
||||
|
||||
func CopyPacketConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, destination net.Destination, serverConn net.PacketConn) error {
|
||||
cancel := func() {
|
||||
common.Interrupt(link.Reader)
|
||||
common.Interrupt(serverConn)
|
||||
}
|
||||
conn := &PacketConnWrapper{
|
||||
Reader: link.Reader,
|
||||
Writer: link.Writer,
|
||||
Dest: destination,
|
||||
Conn: inboundConn,
|
||||
T: signal.CancelAfterInactivity(ctx, cancel, 300*time.Second),
|
||||
}
|
||||
return ReturnError(bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(serverConn)))
|
||||
}
|
||||
@@ -35,13 +29,11 @@ type PacketConnWrapper struct {
|
||||
net.Conn
|
||||
Dest net.Destination
|
||||
cached buf.MultiBuffer
|
||||
|
||||
// A simple patch to avoid goroutine leak since sing infra cannot awake read block by write err
|
||||
T *signal.ActivityTimer
|
||||
}
|
||||
|
||||
// This ReadPacket implemented a timeout to avoid goroutine leak like PipeConnWrapper.Read()
|
||||
// as a temporarily solution
|
||||
func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
|
||||
w.T.Update()
|
||||
if w.cached != nil {
|
||||
mb, bb := buf.SplitFirst(w.cached)
|
||||
if bb == nil {
|
||||
@@ -59,12 +51,30 @@ func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
|
||||
return ToSocksaddr(destination), nil
|
||||
}
|
||||
}
|
||||
mb, err := w.ReadMultiBuffer()
|
||||
if err != nil {
|
||||
// uplinkonly
|
||||
w.T.SetTimeout(3 * time.Second)
|
||||
return M.Socksaddr{}, err
|
||||
|
||||
// timeout
|
||||
type readResult struct {
|
||||
mb buf.MultiBuffer
|
||||
err error
|
||||
}
|
||||
c := make(chan readResult, 1)
|
||||
go func() {
|
||||
mb, err := w.ReadMultiBuffer()
|
||||
c <- readResult{mb: mb, err: err}
|
||||
}()
|
||||
var mb buf.MultiBuffer
|
||||
select {
|
||||
case <-time.After(60 * time.Second):
|
||||
common.Close(w.Reader)
|
||||
common.Interrupt(w.Reader)
|
||||
return M.Socksaddr{}, buf.ErrReadTimeout
|
||||
case result := <-c:
|
||||
if result.err != nil {
|
||||
return M.Socksaddr{}, result.err
|
||||
}
|
||||
mb = result.mb
|
||||
}
|
||||
|
||||
nb, bb := buf.SplitFirst(mb)
|
||||
if bb == nil {
|
||||
return M.Socksaddr{}, nil
|
||||
@@ -83,15 +93,9 @@ func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) {
|
||||
}
|
||||
|
||||
func (w *PacketConnWrapper) WritePacket(buffer *B.Buffer, destination M.Socksaddr) error {
|
||||
w.T.Update()
|
||||
endpoint, err := ToDestination(destination, net.Network_UDP)
|
||||
if err != nil {
|
||||
// uplinkonly
|
||||
w.T.SetTimeout(3 * time.Second)
|
||||
return err
|
||||
}
|
||||
vBuf := buf.New()
|
||||
vBuf.Write(buffer.Bytes())
|
||||
endpoint := ToDestination(destination, net.Network_UDP)
|
||||
vBuf.UDP = &endpoint
|
||||
return w.Writer.WriteMultiBuffer(buf.MultiBuffer{vBuf})
|
||||
}
|
||||
|
||||
+18
-18
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
"github.com/xtls/xray-core/common"
|
||||
"github.com/xtls/xray-core/common/buf"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
)
|
||||
|
||||
@@ -23,11 +22,6 @@ func CopyConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, s
|
||||
} else {
|
||||
conn.R = &buf.BufferedReader{Reader: link.Reader}
|
||||
}
|
||||
cancel := func() {
|
||||
common.Interrupt(link.Reader)
|
||||
common.Interrupt(serverConn)
|
||||
}
|
||||
conn.T = signal.CancelAfterInactivity(ctx, cancel, 300*time.Second)
|
||||
return ReturnError(bufio.CopyConn(ctx, conn, serverConn))
|
||||
}
|
||||
|
||||
@@ -35,27 +29,35 @@ type PipeConnWrapper struct {
|
||||
R io.Reader
|
||||
W buf.Writer
|
||||
net.Conn
|
||||
|
||||
// A simple patch to avoid goroutine leak since sing infra cannot awake read block by write err
|
||||
T *signal.ActivityTimer
|
||||
}
|
||||
|
||||
func (w *PipeConnWrapper) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// This Read implemented a timeout to avoid goroutine leak.
|
||||
// as a temporarily solution
|
||||
func (w *PipeConnWrapper) Read(b []byte) (n int, err error) {
|
||||
w.T.Update()
|
||||
n, err = w.R.Read(b)
|
||||
if err != nil {
|
||||
// uplinkonly
|
||||
w.T.SetTimeout(3 * time.Second)
|
||||
type readResult struct {
|
||||
n int
|
||||
err error
|
||||
}
|
||||
c := make(chan readResult, 1)
|
||||
go func() {
|
||||
n, err := w.R.Read(b)
|
||||
c <- readResult{n: n, err: err}
|
||||
}()
|
||||
select {
|
||||
case result := <-c:
|
||||
return result.n, result.err
|
||||
case <-time.After(300 * time.Second):
|
||||
common.Close(w.R)
|
||||
common.Interrupt(w.R)
|
||||
return 0, buf.ErrReadTimeout
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *PipeConnWrapper) Write(p []byte) (n int, err error) {
|
||||
w.T.Update()
|
||||
n = len(p)
|
||||
var mb buf.MultiBuffer
|
||||
pLen := len(p)
|
||||
@@ -74,8 +76,6 @@ func (w *PipeConnWrapper) Write(p []byte) (n int, err error) {
|
||||
if err != nil {
|
||||
n = 0
|
||||
buf.ReleaseMulti(mb)
|
||||
// downlinkonly
|
||||
w.T.SetTimeout(3 * time.Second)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@ import (
|
||||
|
||||
var (
|
||||
Version_x byte = 26
|
||||
Version_y byte = 5
|
||||
Version_z byte = 3
|
||||
Version_y byte = 4
|
||||
Version_z byte = 25
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -497,8 +497,8 @@ func (b Bandwidth) Bps() (uint64, error) {
|
||||
}
|
||||
|
||||
type UdpHop struct {
|
||||
PortList PortList `json:"ports"`
|
||||
Interval Int32Range `json:"interval"`
|
||||
PortList json.RawMessage `json:"ports"`
|
||||
Interval *Int32Range `json:"interval"`
|
||||
}
|
||||
|
||||
type Masquerade struct {
|
||||
@@ -2142,7 +2142,18 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
||||
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
|
||||
}
|
||||
|
||||
if (c.FinalMask.QuicParams.UdpHop.Interval.From != 0 && c.FinalMask.QuicParams.UdpHop.Interval.From < 5) || (c.FinalMask.QuicParams.UdpHop.Interval.To != 0 && c.FinalMask.QuicParams.UdpHop.Interval.To < 5) {
|
||||
var hop *PortList
|
||||
if err := json.Unmarshal(c.FinalMask.QuicParams.UdpHop.PortList, &hop); err != nil {
|
||||
hop = &PortList{}
|
||||
}
|
||||
|
||||
var inertvalMin, inertvalMax int64
|
||||
if c.FinalMask.QuicParams.UdpHop.Interval != nil {
|
||||
inertvalMin = int64(c.FinalMask.QuicParams.UdpHop.Interval.From)
|
||||
inertvalMax = int64(c.FinalMask.QuicParams.UdpHop.Interval.To)
|
||||
}
|
||||
|
||||
if (inertvalMin != 0 && inertvalMin < 5) || (inertvalMax != 0 && inertvalMax < 5) {
|
||||
return nil, errors.New("Interval must be at least 5")
|
||||
}
|
||||
|
||||
@@ -2179,9 +2190,9 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
||||
BrutalUp: up,
|
||||
BrutalDown: down,
|
||||
UdpHop: &internet.UdpHop{
|
||||
Ports: c.FinalMask.QuicParams.UdpHop.PortList.Build().Ports(),
|
||||
IntervalMin: int64(c.FinalMask.QuicParams.UdpHop.Interval.From),
|
||||
IntervalMax: int64(c.FinalMask.QuicParams.UdpHop.Interval.To),
|
||||
Ports: hop.Build().Ports(),
|
||||
IntervalMin: inertvalMin,
|
||||
IntervalMax: inertvalMax,
|
||||
},
|
||||
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
|
||||
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
|
||||
|
||||
+134
-89
@@ -38,6 +38,14 @@ var defaultBlockAllRule *FinalRule
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
h := new(Handler)
|
||||
if handler, ok := session.FullHandlerFromContext(ctx).(handlerWithSocketSettings); ok {
|
||||
if sockopt := handler.SocketSettings(); sockopt != nil {
|
||||
h.socketStrategy = sockopt.DomainStrategy
|
||||
}
|
||||
}
|
||||
if handler, ok := session.FullHandlerFromContext(ctx).(handlerWithProxySettings); ok {
|
||||
h.usesProxySettings = handler.UsesProxySettings()
|
||||
}
|
||||
if err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
|
||||
return h.Init(config.(*Config), pm)
|
||||
}); err != nil {
|
||||
@@ -88,6 +96,14 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
type handlerWithSocketSettings interface {
|
||||
SocketSettings() *internet.SocketConfig
|
||||
}
|
||||
|
||||
type handlerWithProxySettings interface {
|
||||
UsesProxySettings() bool
|
||||
}
|
||||
|
||||
type FinalRule struct {
|
||||
action RuleAction
|
||||
network [8]bool
|
||||
@@ -98,9 +114,11 @@ type FinalRule struct {
|
||||
|
||||
// Handler handles Freedom connections.
|
||||
type Handler struct {
|
||||
policyManager policy.Manager
|
||||
config *Config
|
||||
finalRules []*FinalRule
|
||||
policyManager policy.Manager
|
||||
config *Config
|
||||
finalRules []*FinalRule
|
||||
socketStrategy internet.DomainStrategy
|
||||
usesProxySettings bool
|
||||
}
|
||||
|
||||
func buildFinalRule(config *FinalRuleConfig) (*FinalRule, error) {
|
||||
@@ -177,22 +195,6 @@ func getDefaultFinalRule(inbound *session.Inbound) *FinalRule {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) shouldResolveDomainBeforeFinalRules(dialDest net.Destination, defaultRule *FinalRule) bool {
|
||||
if !dialDest.Address.Family().IsDomain() {
|
||||
return false
|
||||
}
|
||||
if len(h.finalRules) > 0 {
|
||||
rule := h.finalRules[0]
|
||||
if rule.action == RuleAction_Allow && rule.network[dialDest.Network] && len(rule.port) == 0 && rule.ip == nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if defaultRule != nil || len(h.finalRules) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *Handler) matchFinalRule(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) *FinalRule {
|
||||
for _, rule := range h.finalRules {
|
||||
if rule.Apply(network, address, port) {
|
||||
@@ -205,13 +207,6 @@ func (h *Handler) matchFinalRule(network net.Network, address net.Address, port
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) applyFinalRules(network net.Network, address net.Address, port net.Port, defaultRule *FinalRule) RuleAction {
|
||||
if rule := h.matchFinalRule(network, address, port, defaultRule); rule != nil {
|
||||
return rule.action
|
||||
}
|
||||
return RuleAction_Allow
|
||||
}
|
||||
|
||||
// Init initializes the Handler with necessary parameters.
|
||||
func (h *Handler) Init(config *Config, pm policy.Manager) error {
|
||||
h.config = config
|
||||
@@ -239,11 +234,32 @@ func (h *Handler) blockDelay(rule *FinalRule) time.Duration {
|
||||
min = rule.blockDelay.Min
|
||||
max = rule.blockDelay.Max
|
||||
}
|
||||
abs := max - min
|
||||
span := max - min
|
||||
if max < min {
|
||||
abs = min - max
|
||||
span = min - max
|
||||
}
|
||||
return time.Duration(min+uint64(dice.Roll(int(abs+1)))) * time.Second
|
||||
return time.Duration(min+uint64(dice.Roll(int(span+1)))) * time.Second
|
||||
}
|
||||
|
||||
func (h *Handler) blackhole(ctx context.Context, input buf.Reader, output buf.Writer, rule *FinalRule, dest *net.Destination) error {
|
||||
delay := h.blockDelay(rule)
|
||||
errors.LogInfo(ctx, "blocked target: ", *dest, ", blackholing connection for ", delay)
|
||||
timer := time.AfterFunc(delay, func() {
|
||||
common.Interrupt(input)
|
||||
common.Interrupt(output)
|
||||
errors.LogInfo(ctx, "closed blackholed connection to blocked target: ", *dest)
|
||||
})
|
||||
defer timer.Stop()
|
||||
defer common.Close(output)
|
||||
_ = buf.Copy(input, buf.Discard)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) udpDomainStrategy() internet.DomainStrategy {
|
||||
if h.config.DomainStrategy.HasStrategy() {
|
||||
return h.config.DomainStrategy
|
||||
}
|
||||
return h.socketStrategy
|
||||
}
|
||||
|
||||
func isValidAddress(addr *net.IPOrDomain) bool {
|
||||
@@ -295,40 +311,73 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
var blockedRule *FinalRule
|
||||
err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||
dialDest := destination
|
||||
if h.config.DomainStrategy.HasStrategy() && dialDest.Address.Family().IsDomain() {
|
||||
strategy := h.config.DomainStrategy
|
||||
if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil {
|
||||
strategy = strategy.GetDynamicStrategy(origTargetAddr.Family())
|
||||
}
|
||||
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
||||
if h.config.DomainStrategy.ForceIP() {
|
||||
return err
|
||||
|
||||
if dialDest.Address.Family().IsDomain() {
|
||||
if strategy := h.config.DomainStrategy; strategy.HasStrategy() {
|
||||
if destination.Network == net.Network_UDP && origTargetAddr != nil && outGateway == nil {
|
||||
strategy = strategy.GetDynamicStrategy(origTargetAddr.Family())
|
||||
}
|
||||
} else {
|
||||
dialDest = net.Destination{
|
||||
Network: dialDest.Network,
|
||||
Address: net.IPAddress(ips[dice.Roll(len(ips))]),
|
||||
Port: dialDest.Port,
|
||||
}
|
||||
errors.LogInfo(ctx, "dialing to ", dialDest)
|
||||
}
|
||||
} else if h.shouldResolveDomainBeforeFinalRules(dialDest, defaultRule) { // asis + domain + hasrules
|
||||
addrs, err := net.DefaultResolver.LookupIPAddr(ctx, dialDest.Address.Domain())
|
||||
if err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
||||
} else if len(addrs) > 0 {
|
||||
if addr := net.IPAddress(addrs[dice.Roll(len(addrs))].IP); addr != nil {
|
||||
dialDest.Address = addr
|
||||
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
|
||||
if err != nil { // SRV/TXT
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
||||
if h.config.DomainStrategy.ForceIP() || defaultRule != nil || len(h.finalRules) > 0 {
|
||||
return err // retry
|
||||
}
|
||||
} else { // to ip
|
||||
dialDest = net.Destination{
|
||||
Network: dialDest.Network,
|
||||
Address: net.IPAddress(ips[dice.Roll(len(ips))]),
|
||||
Port: dialDest.Port,
|
||||
}
|
||||
errors.LogInfo(ctx, "dialing to ", dialDest)
|
||||
if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||
blockedDest = &dialDest
|
||||
blockedRule = rule
|
||||
return nil
|
||||
}
|
||||
}
|
||||
} else if defaultRule != nil || len(h.finalRules) > 0 { // freedom asis + hasrules
|
||||
if strategy := h.socketStrategy; strategy.HasStrategy() {
|
||||
ips, err := internet.LookupForIP(dialDest.Address.Domain(), strategy, outGateway)
|
||||
if err != nil { // SRV/TXT
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
||||
if strategy.ForceIP() {
|
||||
return err // retry
|
||||
}
|
||||
}
|
||||
for _, ip := range ips {
|
||||
if addr := net.IPAddress(ip); addr != nil {
|
||||
if rule := h.matchFinalRule(dialDest.Network, addr, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||
blockedDest = &dialDest
|
||||
blockedDest.Address = addr
|
||||
blockedRule = rule
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // sockopt asis
|
||||
addrs, err := net.DefaultResolver.LookupIPAddr(ctx, dialDest.Address.Domain())
|
||||
if err != nil { // SRV/TXT
|
||||
errors.LogInfoInner(ctx, err, "failed to get IP address for domain ", dialDest.Address.Domain())
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if ipAddr := net.IPAddress(addr.IP); ipAddr != nil {
|
||||
if rule := h.matchFinalRule(dialDest.Network, ipAddr, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||
blockedDest = &dialDest
|
||||
blockedDest.Address = ipAddr
|
||||
blockedRule = rule
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||
blockedDest = &dialDest
|
||||
blockedRule = rule
|
||||
return nil
|
||||
} else {
|
||||
if rule := h.matchFinalRule(dialDest.Network, dialDest.Address, dialDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||
blockedDest = &dialDest
|
||||
blockedRule = rule
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
rawConn, err := dialer.Dial(ctx, dialDest)
|
||||
@@ -343,25 +392,21 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
return errors.New("failed to open connection to ", destination).Base(err)
|
||||
}
|
||||
if blockedDest != nil {
|
||||
delay := h.blockDelay(blockedRule)
|
||||
errors.LogInfo(ctx, "blocked target: ", *blockedDest, ", blackholing connection for ", delay)
|
||||
timer := time.AfterFunc(delay, func() {
|
||||
common.Interrupt(input)
|
||||
common.Interrupt(output)
|
||||
errors.LogInfo(ctx, "closed blackholed connection to blocked target: ", *blockedDest)
|
||||
})
|
||||
defer timer.Stop()
|
||||
defer common.Close(output)
|
||||
if err := buf.Copy(input, buf.Discard); err != nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
return h.blackhole(ctx, input, output, blockedRule, blockedDest)
|
||||
}
|
||||
// TODO: SRV/TXT
|
||||
// if remoteDest := net.DestinationFromAddr(conn.RemoteAddr()); h.applyFinalRules(remoteDest.Network, remoteDest.Address, remoteDest.Port, defaultRule) == RuleAction_Block {
|
||||
// conn.Close()
|
||||
// return blackhole(remoteDest)
|
||||
// }
|
||||
if defaultRule != nil || len(h.finalRules) > 0 {
|
||||
if h.usesProxySettings {
|
||||
errors.LogInfo(ctx, "skipping final rule check for proxied remote endpoint, original target: ", destination)
|
||||
} else {
|
||||
// SRV/TXT, lookup failed
|
||||
remoteDest := net.DestinationFromAddr(conn.RemoteAddr())
|
||||
if rule := h.matchFinalRule(remoteDest.Network, remoteDest.Address, remoteDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||
conn.Close()
|
||||
return h.blackhole(ctx, input, output, rule, &remoteDest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if h.config.ProxyProtocol > 0 && h.config.ProxyProtocol <= 2 {
|
||||
version := byte(h.config.ProxyProtocol)
|
||||
srcAddr := inbound.Source.RawNetAddr()
|
||||
@@ -406,7 +451,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
||||
writer = buf.NewWriter(conn)
|
||||
}
|
||||
} else {
|
||||
writer = NewPacketWriter(conn, h, defaultRule, UDPOverride, destination)
|
||||
writer = NewPacketWriter(conn, h, defaultRule, UDPOverride, destination, outGateway)
|
||||
if h.config.Noises != nil {
|
||||
errors.LogDebug(ctx, "NOISE", h.config.Noises)
|
||||
writer = &NoisePacketWriter{
|
||||
@@ -510,7 +555,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||
}
|
||||
udpAddr := d.(*net.UDPAddr)
|
||||
sourceAddr := net.IPAddress(udpAddr.IP)
|
||||
if r.Handler.applyFinalRules(net.Network_UDP, sourceAddr, net.Port(udpAddr.Port), r.DefaultRule) == RuleAction_Block {
|
||||
if rule := r.Handler.matchFinalRule(net.Network_UDP, sourceAddr, net.Port(udpAddr.Port), r.DefaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||
continue
|
||||
}
|
||||
b.Resize(0, int32(n))
|
||||
@@ -535,7 +580,7 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||
}
|
||||
|
||||
// DialDest means the dial target used in the dialer when creating conn
|
||||
func NewPacketWriter(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverride net.Destination, DialDest net.Destination) buf.Writer {
|
||||
func NewPacketWriter(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverride net.Destination, DialDest net.Destination, outGateway net.Address) buf.Writer {
|
||||
iConn := conn
|
||||
statConn, ok := iConn.(*stat.CounterConnection)
|
||||
if ok {
|
||||
@@ -559,7 +604,7 @@ func NewPacketWriter(conn net.Conn, h *Handler, defaultRule *FinalRule, UDPOverr
|
||||
DefaultRule: defaultRule,
|
||||
UDPOverride: UDPOverride,
|
||||
ResolvedUDPAddr: resolvedUDPAddr,
|
||||
LocalAddr: net.DestinationFromAddr(conn.LocalAddr()).Address,
|
||||
OutGateway: outGateway,
|
||||
}
|
||||
|
||||
}
|
||||
@@ -578,7 +623,7 @@ type PacketWriter struct {
|
||||
// Resulting in these packets being sent to many different IPs randomly
|
||||
// So, cache and keep the resolve result
|
||||
ResolvedUDPAddr *utils.TypedSyncMap[string, net.Address]
|
||||
LocalAddr net.Address
|
||||
OutGateway net.Address
|
||||
}
|
||||
|
||||
func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
@@ -601,21 +646,21 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
if ip, ok := w.ResolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
|
||||
b.UDP.Address = ip
|
||||
} else {
|
||||
ShouldUseSystemResolver := true
|
||||
if w.Handler.config.DomainStrategy.HasStrategy() {
|
||||
ips, err := internet.LookupForIP(b.UDP.Address.Domain(), w.Handler.config.DomainStrategy, w.LocalAddr)
|
||||
shouldUseSystemResolver := true
|
||||
if resolveStrategy := w.Handler.udpDomainStrategy(); resolveStrategy.HasStrategy() {
|
||||
ips, err := internet.LookupForIP(b.UDP.Address.Domain(), resolveStrategy, w.OutGateway)
|
||||
if err != nil {
|
||||
// drop packet if resolve failed when forceIP
|
||||
if w.Handler.config.DomainStrategy.ForceIP() {
|
||||
if resolveStrategy.ForceIP() {
|
||||
b.Release()
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
ip = net.IPAddress(ips[dice.Roll(len(ips))])
|
||||
ShouldUseSystemResolver = false
|
||||
shouldUseSystemResolver = false
|
||||
}
|
||||
}
|
||||
if ShouldUseSystemResolver {
|
||||
if shouldUseSystemResolver {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", b.UDP.NetAddr())
|
||||
if err != nil {
|
||||
b.Release()
|
||||
@@ -629,7 +674,7 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if w.applyFinalRules(net.Network_UDP, b.UDP.Address, b.UDP.Port, w.DefaultRule) == RuleAction_Block {
|
||||
if rule := w.matchFinalRule(net.Network_UDP, b.UDP.Address, b.UDP.Port, w.DefaultRule); rule != nil && rule.action == RuleAction_Block {
|
||||
b.Release()
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package shadowsocks_2022
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
shadowsocks "github.com/sagernet/sing-shadowsocks"
|
||||
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
||||
@@ -19,7 +18,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/singbridge"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
"github.com/xtls/xray-core/transport/internet/stat"
|
||||
@@ -117,11 +115,7 @@ func (i *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.M
|
||||
})
|
||||
errors.LogInfo(ctx, "tunnelling request to tcp:", metadata.Destination)
|
||||
dispatcher := session.DispatcherFromContext(ctx)
|
||||
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_TCP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
link, err := dispatcher.Dispatch(ctx, destination)
|
||||
link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -142,10 +136,7 @@ func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, me
|
||||
})
|
||||
errors.LogInfo(ctx, "tunnelling request to udp:", metadata.Destination)
|
||||
dispatcher := session.DispatcherFromContext(ctx)
|
||||
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
|
||||
link, err := dispatcher.Dispatch(ctx, destination)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -154,9 +145,6 @@ func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, me
|
||||
Reader: link.Reader,
|
||||
Writer: link.Writer,
|
||||
Dest: destination,
|
||||
T: signal.CancelAfterInactivity(ctx, func() {
|
||||
common.Interrupt(link.Reader)
|
||||
}, 300*time.Second),
|
||||
}
|
||||
return bufio.CopyPacketConn(ctx, conn, outConn)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
||||
C "github.com/sagernet/sing/common"
|
||||
@@ -23,7 +22,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/singbridge"
|
||||
"github.com/xtls/xray-core/common/uuid"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
@@ -239,10 +237,11 @@ func (i *MultiUserInbound) NewConnection(ctx context.Context, conn net.Conn, met
|
||||
})
|
||||
errors.LogInfo(ctx, "tunnelling request to tcp:", metadata.Destination)
|
||||
dispatcher := session.DispatcherFromContext(ctx)
|
||||
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_TCP)
|
||||
if err != nil {
|
||||
return err
|
||||
destination := singbridge.ToDestination(metadata.Destination, net.Network_TCP)
|
||||
if !destination.IsValid() {
|
||||
return errors.New("invalid destination")
|
||||
}
|
||||
|
||||
link, err := dispatcher.Dispatch(ctx, destination)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -263,10 +262,7 @@ func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.Packe
|
||||
})
|
||||
errors.LogInfo(ctx, "tunnelling request to udp:", metadata.Destination)
|
||||
dispatcher := session.DispatcherFromContext(ctx)
|
||||
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
|
||||
link, err := dispatcher.Dispatch(ctx, destination)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -275,9 +271,6 @@ func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.Packe
|
||||
Reader: link.Reader,
|
||||
Writer: link.Writer,
|
||||
Dest: destination,
|
||||
T: signal.CancelAfterInactivity(ctx, func() {
|
||||
common.Interrupt(link.Reader)
|
||||
}, 300*time.Second),
|
||||
}
|
||||
return bufio.CopyPacketConn(ctx, conn, outConn)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
|
||||
C "github.com/sagernet/sing/common"
|
||||
@@ -21,7 +20,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/protocol"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/singbridge"
|
||||
"github.com/xtls/xray-core/common/uuid"
|
||||
"github.com/xtls/xray-core/features/routing"
|
||||
@@ -140,11 +138,7 @@ func (i *RelayInbound) NewConnection(ctx context.Context, conn net.Conn, metadat
|
||||
})
|
||||
errors.LogInfo(ctx, "tunnelling request to tcp:", metadata.Destination)
|
||||
dispatcher := session.DispatcherFromContext(ctx)
|
||||
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_TCP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
link, err := dispatcher.Dispatch(ctx, destination)
|
||||
link, err := dispatcher.Dispatch(ctx, singbridge.ToDestination(metadata.Destination, net.Network_TCP))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -167,10 +161,7 @@ func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketCon
|
||||
})
|
||||
errors.LogInfo(ctx, "tunnelling request to udp:", metadata.Destination)
|
||||
dispatcher := session.DispatcherFromContext(ctx)
|
||||
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destination := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
|
||||
link, err := dispatcher.Dispatch(ctx, destination)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -179,9 +170,6 @@ func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketCon
|
||||
Reader: link.Reader,
|
||||
Writer: link.Writer,
|
||||
Dest: destination,
|
||||
T: signal.CancelAfterInactivity(ctx, func() {
|
||||
common.Interrupt(link.Reader)
|
||||
}, 300*time.Second),
|
||||
}
|
||||
return bufio.CopyPacketConn(ctx, conn, outConn)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"github.com/xtls/xray-core/common/session"
|
||||
"github.com/xtls/xray-core/common/signal"
|
||||
"github.com/xtls/xray-core/common/singbridge"
|
||||
"github.com/xtls/xray-core/transport"
|
||||
"github.com/xtls/xray-core/transport/internet"
|
||||
@@ -143,9 +142,6 @@ func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer int
|
||||
Writer: link.Writer,
|
||||
Conn: inboundConn,
|
||||
Dest: destination,
|
||||
T: signal.CancelAfterInactivity(ctx, func() {
|
||||
common.Interrupt(link.Reader)
|
||||
}, 300*time.Second),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ var (
|
||||
globalTransportConfigCreatorCache = make(map[string]ConfigCreator)
|
||||
)
|
||||
|
||||
var strategy = [][]byte{
|
||||
var strategy = [11][3]byte{
|
||||
// name strategy, prefer, fallback
|
||||
{0, 0, 0}, // AsIs none, /, /
|
||||
{1, 0, 0}, // UseIP use, both, none
|
||||
@@ -27,8 +27,6 @@ var strategy = [][]byte{
|
||||
{2, 6, 4}, // ForceIPv6v4 force, 6, 4
|
||||
}
|
||||
|
||||
const unknownProtocol = "unknown"
|
||||
|
||||
func RegisterProtocolConfigCreator(name string, creator ConfigCreator) error {
|
||||
if _, found := globalTransportConfigCreatorCache[name]; found {
|
||||
return errors.New("protocol ", name, " is already registered").AtError()
|
||||
|
||||
@@ -730,6 +730,8 @@ type SocketConfig struct {
|
||||
// ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket
|
||||
// option. This option is for UDP only.
|
||||
ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"`
|
||||
BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"`
|
||||
BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"`
|
||||
AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"`
|
||||
DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
||||
DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"`
|
||||
@@ -809,6 +811,20 @@ func (x *SocketConfig) GetReceiveOriginalDestAddress() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *SocketConfig) GetBindAddress() []byte {
|
||||
if x != nil {
|
||||
return x.BindAddress
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SocketConfig) GetBindPort() uint32 {
|
||||
if x != nil {
|
||||
return x.BindPort
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SocketConfig) GetAcceptProxyProtocol() bool {
|
||||
if x != nil {
|
||||
return x.AcceptProxyProtocol
|
||||
@@ -1050,12 +1066,14 @@ const file_transport_internet_config_proto_rawDesc = "" +
|
||||
"\x05level\x18\x03 \x01(\tR\x05level\x12\x10\n" +
|
||||
"\x03opt\x18\x04 \x01(\tR\x03opt\x12\x14\n" +
|
||||
"\x05value\x18\x05 \x01(\tR\x05value\x12\x12\n" +
|
||||
"\x04type\x18\x06 \x01(\tR\x04type\"\xc9\b\n" +
|
||||
"\x04type\x18\x06 \x01(\tR\x04type\"\x89\t\n" +
|
||||
"\fSocketConfig\x12\x12\n" +
|
||||
"\x04mark\x18\x01 \x01(\x05R\x04mark\x12\x10\n" +
|
||||
"\x03tfo\x18\x02 \x01(\x05R\x03tfo\x12H\n" +
|
||||
"\x06tproxy\x18\x03 \x01(\x0e20.xray.transport.internet.SocketConfig.TProxyModeR\x06tproxy\x12A\n" +
|
||||
"\x1dreceive_original_dest_address\x18\x04 \x01(\bR\x1areceiveOriginalDestAddress\x122\n" +
|
||||
"\x1dreceive_original_dest_address\x18\x04 \x01(\bR\x1areceiveOriginalDestAddress\x12!\n" +
|
||||
"\fbind_address\x18\x05 \x01(\fR\vbindAddress\x12\x1b\n" +
|
||||
"\tbind_port\x18\x06 \x01(\rR\bbindPort\x122\n" +
|
||||
"\x15accept_proxy_protocol\x18\a \x01(\bR\x13acceptProxyProtocol\x12P\n" +
|
||||
"\x0fdomain_strategy\x18\b \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0edomainStrategy\x12!\n" +
|
||||
"\fdialer_proxy\x18\t \x01(\tR\vdialerProxy\x125\n" +
|
||||
|
||||
@@ -124,6 +124,10 @@ message SocketConfig {
|
||||
// option. This option is for UDP only.
|
||||
bool receive_original_dest_address = 4;
|
||||
|
||||
bytes bind_address = 5;
|
||||
|
||||
uint32 bind_port = 6;
|
||||
|
||||
bool accept_proxy_protocol = 7;
|
||||
|
||||
DomainStrategy domain_strategy = 8;
|
||||
|
||||
@@ -3,7 +3,6 @@ package hysteria
|
||||
import (
|
||||
"context"
|
||||
go_tls "crypto/tls"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
@@ -65,7 +64,7 @@ func (c *client) close() {
|
||||
c.udpSM = nil
|
||||
}
|
||||
|
||||
func (c *client) dial(ctx context.Context) error {
|
||||
func (c *client) dial() error {
|
||||
status := c.status()
|
||||
if status == StatusActive {
|
||||
return nil
|
||||
@@ -114,54 +113,30 @@ func (c *client) dial(ctx context.Context) error {
|
||||
// quicConfig.KeepAlivePeriod = 10 * time.Second
|
||||
// }
|
||||
|
||||
udpHopDialer := func(addr *net.UDPAddr) (net.PacketConn, error) {
|
||||
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
||||
return nil, errors.New("")
|
||||
}
|
||||
|
||||
var pktConn net.PacketConn
|
||||
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
default:
|
||||
panic(reflect.TypeOf(c))
|
||||
}
|
||||
|
||||
return pktConn, nil
|
||||
}
|
||||
|
||||
var pktConn net.PacketConn
|
||||
var udpAddr *net.UDPAddr
|
||||
var err error
|
||||
udpAddr, err = net.ResolveUDPAddr("udp", c.dest.NetAddr())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(quicParams.UdpHop.Ports) > 0 {
|
||||
index := rand.Intn(len(quicParams.UdpHop.Ports))
|
||||
c.dest.Port = net.Port(quicParams.UdpHop.Ports[index])
|
||||
conn, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
|
||||
pktConn, err = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, c.udpHopDialer)
|
||||
if err != nil {
|
||||
return errors.New("failed to dial to dest").Base(err)
|
||||
return err
|
||||
}
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
||||
default:
|
||||
panic(reflect.TypeOf(c))
|
||||
}
|
||||
pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index)
|
||||
} else {
|
||||
conn, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
|
||||
conn, err := internet.DialSystem(context.Background(), c.dest, c.socketConfig)
|
||||
if err != nil {
|
||||
return errors.New("failed to dial to dest").Base(err)
|
||||
return err
|
||||
}
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
udpAddr = c.RemoteAddr().(*net.UDPAddr)
|
||||
case *net.UDPConn:
|
||||
pktConn = c
|
||||
case *cnc.Connection:
|
||||
pktConn = &internet.FakePacketConn{Conn: c}
|
||||
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||
default:
|
||||
panic(reflect.TypeOf(c))
|
||||
}
|
||||
@@ -253,11 +228,11 @@ func (c *client) dial(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) tcp(ctx context.Context) (stat.Connection, error) {
|
||||
func (c *client) tcp() (stat.Connection, error) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
err := c.dial(ctx)
|
||||
err := c.dial()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -276,11 +251,11 @@ func (c *client) tcp(ctx context.Context) (stat.Connection, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *client) udp(ctx context.Context) (stat.Connection, error) {
|
||||
func (c *client) udp() (stat.Connection, error) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
err := c.dial(ctx)
|
||||
err := c.dial()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -296,6 +271,29 @@ func (c *client) clean() {
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
func (c *client) udpHopDialer(addr *net.UDPAddr) (net.PacketConn, error) {
|
||||
conn, err := internet.DialSystem(context.Background(), net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
||||
return nil, errors.New("failed to dial to dest").Base(err)
|
||||
}
|
||||
|
||||
var pktConn net.PacketConn
|
||||
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
case *net.UDPConn:
|
||||
pktConn = c
|
||||
default:
|
||||
errors.LogInfo(context.Background(), "skip hop: invalid conn ", reflect.TypeOf(c))
|
||||
conn.Close()
|
||||
return nil, errors.New("invalid conn ", reflect.TypeOf(c))
|
||||
}
|
||||
|
||||
return pktConn, nil
|
||||
}
|
||||
|
||||
type dialerConf struct {
|
||||
net.Destination
|
||||
*internet.MemoryStreamConfig
|
||||
@@ -358,9 +356,9 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
||||
}
|
||||
|
||||
if datagram {
|
||||
return c.udp(ctx)
|
||||
return c.udp()
|
||||
}
|
||||
return c.tcp(ctx)
|
||||
return c.tcp()
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -47,7 +47,7 @@ type udpPacket struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopIntervalMax time.Duration, listenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error), currentConn net.PacketConn, addrIndex int) net.PacketConn {
|
||||
func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopIntervalMax time.Duration, listenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error)) (net.PacketConn, error) {
|
||||
if len(addrs) == 0 {
|
||||
panic("len(addrs) == 0")
|
||||
}
|
||||
@@ -75,8 +75,8 @@ func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopInte
|
||||
HopIntervalMax: hopIntervalMax,
|
||||
ListenUDPFunc: listenUDPFunc,
|
||||
prevConn: nil,
|
||||
currentConn: currentConn,
|
||||
addrIndex: addrIndex,
|
||||
currentConn: nil,
|
||||
addrIndex: rand.Intn(len(addrs)),
|
||||
recvQueue: make(chan *udpPacket, packetQueueSize),
|
||||
closeChan: make(chan struct{}),
|
||||
bufPool: sync.Pool{
|
||||
@@ -85,9 +85,14 @@ func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopInte
|
||||
},
|
||||
},
|
||||
}
|
||||
var err error
|
||||
hConn.currentConn, err = listenUDPFunc(hConn.Addrs[hConn.addrIndex].(*net.UDPAddr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go hConn.recvLoop(hConn.currentConn)
|
||||
go hConn.hopLoop()
|
||||
return hConn
|
||||
return hConn, nil
|
||||
}
|
||||
|
||||
func (u *UdpHopPacketConn) recvLoop(conn net.PacketConn) {
|
||||
|
||||
@@ -58,14 +58,14 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
|
||||
|
||||
if streamSettings.UdpmaskManager != nil {
|
||||
var pktConn net.PacketConn
|
||||
var udpAddr *net.UDPAddr
|
||||
var udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
udpAddr = c.RemoteAddr().(*net.UDPAddr)
|
||||
case *net.UDPConn:
|
||||
pktConn = c
|
||||
case *cnc.Connection:
|
||||
pktConn = &internet.FakePacketConn{Conn: c}
|
||||
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||
default:
|
||||
panic(reflect.TypeOf(c))
|
||||
}
|
||||
|
||||
@@ -288,6 +288,32 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
func bindAddr(fd uintptr, address []byte, port uint32) error {
|
||||
setReuseAddr(fd)
|
||||
setReusePort(fd)
|
||||
|
||||
var sockaddr unix.Sockaddr
|
||||
|
||||
switch len(address) {
|
||||
case net.IPv4len:
|
||||
a4 := &unix.SockaddrInet4{
|
||||
Port: int(port),
|
||||
}
|
||||
copy(a4.Addr[:], address)
|
||||
sockaddr = a4
|
||||
case net.IPv6len:
|
||||
a6 := &unix.SockaddrInet6{
|
||||
Port: int(port),
|
||||
}
|
||||
copy(a6.Addr[:], address)
|
||||
sockaddr = a6
|
||||
default:
|
||||
return errors.New("unexpected length of ip")
|
||||
}
|
||||
|
||||
return unix.Bind(int(fd), sockaddr)
|
||||
}
|
||||
|
||||
func setReuseAddr(fd uintptr) error {
|
||||
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
|
||||
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
||||
|
||||
@@ -222,6 +222,32 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
||||
setReuseAddr(fd)
|
||||
setReusePort(fd)
|
||||
|
||||
var sockaddr syscall.Sockaddr
|
||||
|
||||
switch len(ip) {
|
||||
case net.IPv4len:
|
||||
a4 := &syscall.SockaddrInet4{
|
||||
Port: int(port),
|
||||
}
|
||||
copy(a4.Addr[:], ip)
|
||||
sockaddr = a4
|
||||
case net.IPv6len:
|
||||
a6 := &syscall.SockaddrInet6{
|
||||
Port: int(port),
|
||||
}
|
||||
copy(a6.Addr[:], ip)
|
||||
sockaddr = a6
|
||||
default:
|
||||
return errors.New("unexpected length of ip")
|
||||
}
|
||||
|
||||
return syscall.Bind(int(fd), sockaddr)
|
||||
}
|
||||
|
||||
func setReuseAddr(fd uintptr) error {
|
||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
||||
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
||||
|
||||
@@ -2,6 +2,7 @@ package internet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -11,6 +12,32 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
||||
setReuseAddr(fd)
|
||||
setReusePort(fd)
|
||||
|
||||
var sockaddr syscall.Sockaddr
|
||||
|
||||
switch len(ip) {
|
||||
case net.IPv4len:
|
||||
a4 := &syscall.SockaddrInet4{
|
||||
Port: int(port),
|
||||
}
|
||||
copy(a4.Addr[:], ip)
|
||||
sockaddr = a4
|
||||
case net.IPv6len:
|
||||
a6 := &syscall.SockaddrInet6{
|
||||
Port: int(port),
|
||||
}
|
||||
copy(a6.Addr[:], ip)
|
||||
sockaddr = a6
|
||||
default:
|
||||
return errors.New("unexpected length of ip")
|
||||
}
|
||||
|
||||
return syscall.Bind(int(fd), sockaddr)
|
||||
}
|
||||
|
||||
// applyOutboundSocketOptions applies socket options for outbound connection.
|
||||
// note that unlike other part of Xray, this function needs network with speified network stack(tcp4/tcp6/udp4/udp6)
|
||||
func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
|
||||
|
||||
@@ -11,6 +11,10 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setReuseAddr(fd uintptr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -181,6 +181,10 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
||||
return nil
|
||||
}
|
||||
|
||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setReuseAddr(fd uintptr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
gotls "crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
"net/url"
|
||||
@@ -200,7 +199,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
||||
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), streamSettings.SocketSettings)
|
||||
if err != nil {
|
||||
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
||||
return nil, errors.New("")
|
||||
return nil, errors.New("failed to dial to dest").Base(err)
|
||||
}
|
||||
|
||||
var pktConn net.PacketConn
|
||||
@@ -208,8 +207,12 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
case *net.UDPConn:
|
||||
pktConn = c
|
||||
default:
|
||||
panic(reflect.TypeOf(c))
|
||||
errors.LogInfo(context.Background(), "skip hop: invalid conn ", reflect.TypeOf(c))
|
||||
conn.Close()
|
||||
return nil, errors.New("invalid conn ", reflect.TypeOf(c))
|
||||
}
|
||||
|
||||
return pktConn, nil
|
||||
@@ -217,33 +220,28 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
||||
|
||||
var pktConn net.PacketConn
|
||||
var udpAddr *net.UDPAddr
|
||||
var err error
|
||||
udpAddr, err = net.ResolveUDPAddr("udp", dest.NetAddr())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(quicParams.UdpHop.Ports) > 0 {
|
||||
index := rand.Intn(len(quicParams.UdpHop.Ports))
|
||||
dest.Port = net.Port(quicParams.UdpHop.Ports[index])
|
||||
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
|
||||
pktConn, err = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to dial to dest").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
||||
default:
|
||||
panic(reflect.TypeOf(c))
|
||||
}
|
||||
pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index)
|
||||
} else {
|
||||
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to dial to dest").Base(err)
|
||||
return nil, err
|
||||
}
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
udpAddr = c.RemoteAddr().(*net.UDPAddr)
|
||||
case *net.UDPConn:
|
||||
pktConn = c
|
||||
case *cnc.Connection:
|
||||
pktConn = &internet.FakePacketConn{Conn: c}
|
||||
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||
default:
|
||||
panic(reflect.TypeOf(c))
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ type Listener struct {
|
||||
server http.Server
|
||||
h3server *http3.Server
|
||||
listener net.Listener
|
||||
h3listener http3.QUICListener
|
||||
h3listener Qface
|
||||
config *Config
|
||||
addConn internet.ConnHandler
|
||||
isH3 bool
|
||||
@@ -519,8 +519,8 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
|
||||
return nil, errors.New("failed to listen QUIC for XHTTP/3 on ", address, ":", port).Base(err)
|
||||
}
|
||||
l.h3listener = &QListener{
|
||||
QUICListener: l.h3listener,
|
||||
quicParams: quicParams,
|
||||
Qface: l.h3listener,
|
||||
quicParams: quicParams,
|
||||
}
|
||||
errors.LogInfo(ctx, "listening QUIC for XHTTP/3 on ", address, ":", port)
|
||||
|
||||
@@ -615,13 +615,21 @@ func init() {
|
||||
common.Must(internet.RegisterTransportListener(protocolName, ListenXH))
|
||||
}
|
||||
|
||||
type Qface interface {
|
||||
Accept(ctx context.Context) (*quic.Conn, error)
|
||||
Addr() net.Addr
|
||||
Close() error
|
||||
}
|
||||
|
||||
var _ Qface = (*quic.EarlyListener)(nil)
|
||||
|
||||
type QListener struct {
|
||||
http3.QUICListener
|
||||
Qface
|
||||
quicParams *internet.QuicParams
|
||||
}
|
||||
|
||||
func (l *QListener) Accept(ctx context.Context) (*quic.Conn, error) {
|
||||
conn, err := l.QUICListener.Accept(ctx)
|
||||
conn, err := l.Qface.Accept(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -44,10 +44,14 @@ func resolveSrcAddr(network net.Network, src net.Address) net.Addr {
|
||||
}
|
||||
}
|
||||
|
||||
func hasBindAddr(sockopt *SocketConfig) bool {
|
||||
return sockopt != nil && len(sockopt.BindAddress) > 0 && sockopt.BindPort > 0
|
||||
}
|
||||
|
||||
func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
|
||||
errors.LogDebug(ctx, "dialing to "+dest.String())
|
||||
|
||||
if dest.Network == net.Network_UDP {
|
||||
if dest.Network == net.Network_UDP && !hasBindAddr(sockopt) {
|
||||
srcAddr := resolveSrcAddr(net.Network_UDP, src)
|
||||
if srcAddr == nil {
|
||||
srcAddr = &net.UDPAddr{
|
||||
@@ -128,6 +132,11 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
|
||||
if err := applyOutboundSocketOptions(network, address, fd, sockopt); err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to apply socket options")
|
||||
}
|
||||
if dest.Network == net.Network_UDP && hasBindAddr(sockopt) {
|
||||
if err := bindAddr(fd, sockopt.BindAddress, sockopt.BindPort); err != nil {
|
||||
errors.LogInfoInner(ctx, err, "failed to bind source address to ", sockopt.BindAddress)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -219,7 +228,7 @@ type FakePacketConn struct {
|
||||
|
||||
func (c *FakePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
n, err = c.Read(p)
|
||||
return n, &net.UDPAddr{IP: c.Conn.RemoteAddr().(*net.TCPAddr).IP, Port: c.Conn.RemoteAddr().(*net.TCPAddr).Port}, err
|
||||
return n, c.RemoteAddr(), err
|
||||
}
|
||||
|
||||
func (c *FakePacketConn) WriteTo(p []byte, _ net.Addr) (n int, err error) {
|
||||
@@ -227,5 +236,15 @@ func (c *FakePacketConn) WriteTo(p []byte, _ net.Addr) (n int, err error) {
|
||||
}
|
||||
|
||||
func (c *FakePacketConn) LocalAddr() net.Addr {
|
||||
return &net.UDPAddr{IP: c.Conn.LocalAddr().(*net.TCPAddr).IP, Port: c.Conn.LocalAddr().(*net.TCPAddr).Port}
|
||||
return &net.UDPAddr{
|
||||
IP: []byte{0, 0, 0, 0},
|
||||
Port: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *FakePacketConn) RemoteAddr() net.Addr {
|
||||
return &net.UDPAddr{
|
||||
IP: []byte{0, 0, 0, 0},
|
||||
Port: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ func init() {
|
||||
|
||||
if streamSettings != nil && streamSettings.UdpmaskManager != nil {
|
||||
var pktConn net.PacketConn
|
||||
var udpAddr *net.UDPAddr
|
||||
var udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
||||
switch c := conn.(type) {
|
||||
case *internet.PacketConnWrapper:
|
||||
pktConn = c.PacketConn
|
||||
udpAddr = c.RemoteAddr().(*net.UDPAddr)
|
||||
case *net.UDPConn:
|
||||
pktConn = c
|
||||
case *cnc.Connection:
|
||||
pktConn = &internet.FakePacketConn{Conn: c}
|
||||
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||
default:
|
||||
panic(reflect.TypeOf(c))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user