diff --git a/app/proxyman/inbound/always.go b/app/proxyman/inbound/always.go index f5fa108d2..f44747bd9 100644 --- a/app/proxyman/inbound/always.go +++ b/app/proxyman/inbound/always.go @@ -87,17 +87,14 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig * } mss.SocketSettings.ReceiveOriginalDestAddress = true } + if pr == nil { + if net.HasNetwork(nl, net.Network_UNIX) { + newError("creating unix domain socket worker on ", address).AtDebug().WriteToLog() - for port := pr.From; port <= pr.To; port++ { - if net.HasNetwork(nl, net.Network_TCP) { - newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog() - - worker := &tcpWorker{ + worker := &dsWorker{ address: address, - port: net.Port(port), proxy: p, stream: mss, - recvOrigDest: receiverConfig.ReceiveOriginalDestination, tag: tag, dispatcher: h.mux, sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), @@ -107,19 +104,41 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig * } h.workers = append(h.workers, worker) } + } + if pr != nil { + for port := pr.From; port <= pr.To; port++ { + if net.HasNetwork(nl, net.Network_TCP) { + newError("creating stream worker on ", address, ":", port).AtDebug().WriteToLog() - if net.HasNetwork(nl, net.Network_UDP) { - worker := &udpWorker{ - tag: tag, - proxy: p, - address: address, - port: net.Port(port), - dispatcher: h.mux, - uplinkCounter: uplinkCounter, - downlinkCounter: downlinkCounter, - stream: mss, + worker := &tcpWorker{ + address: address, + port: net.Port(port), + proxy: p, + stream: mss, + recvOrigDest: receiverConfig.ReceiveOriginalDestination, + tag: tag, + dispatcher: h.mux, + sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(), + uplinkCounter: uplinkCounter, + downlinkCounter: downlinkCounter, + ctx: ctx, + } + h.workers = append(h.workers, worker) + } + + if net.HasNetwork(nl, net.Network_UDP) { + worker := &udpWorker{ + tag: tag, + proxy: p, + address: address, + port: net.Port(port), + dispatcher: h.mux, + uplinkCounter: uplinkCounter, + downlinkCounter: downlinkCounter, + stream: mss, + } + h.workers = append(h.workers, worker) } - h.workers = append(h.workers, worker) } } diff --git a/app/proxyman/inbound/worker.go b/app/proxyman/inbound/worker.go index dc0677612..16e15aa8f 100644 --- a/app/proxyman/inbound/worker.go +++ b/app/proxyman/inbound/worker.go @@ -398,3 +398,86 @@ func (w *udpWorker) Port() net.Port { func (w *udpWorker) Proxy() proxy.Inbound { return w.proxy } + +type dsWorker struct { + address net.Address + proxy proxy.Inbound + stream *internet.MemoryStreamConfig + tag string + dispatcher routing.Dispatcher + sniffingConfig *proxyman.SniffingConfig + uplinkCounter stats.Counter + downlinkCounter stats.Counter + + hub internet.Listener + + ctx context.Context +} + +func (w *dsWorker) callback(conn internet.Connection) { + ctx, cancel := context.WithCancel(w.ctx) + sid := session.NewID() + ctx = session.ContextWithID(ctx, sid) + + ctx = session.ContextWithInbound(ctx, &session.Inbound{ + Source: net.DestinationFromAddr(conn.RemoteAddr()), + Gateway: net.UnixDestination(w.address), + Tag: w.tag, + }) + content := new(session.Content) + if w.sniffingConfig != nil { + content.SniffingRequest.Enabled = w.sniffingConfig.Enabled + content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride + } + ctx = session.ContextWithContent(ctx, content) + if w.uplinkCounter != nil || w.downlinkCounter != nil { + conn = &internet.StatCouterConnection{ + Connection: conn, + ReadCounter: w.uplinkCounter, + WriteCounter: w.downlinkCounter, + } + } + if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil { + newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx)) + } + cancel() + if err := conn.Close(); err != nil { + newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx)) + } +} + +func (w *dsWorker) Proxy() proxy.Inbound { + return w.proxy +} + +func (w *dsWorker) Port() net.Port { + return net.Port(0) +} +func (w *dsWorker) Start() error { + ctx := context.Background() + hub, err := internet.ListenUnix(ctx, w.address, w.stream, func(conn internet.Connection) { + go w.callback(conn) + }) + if err != nil { + return newError("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err) + } + w.hub = hub + return nil +} + +func (w *dsWorker) Close() error { + var errors []interface{} + if w.hub != nil { + if err := common.Close(w.hub); err != nil { + errors = append(errors, err) + } + if err := common.Close(w.proxy); err != nil { + errors = append(errors, err) + } + } + if len(errors) > 0 { + return newError("failed to close all resources").Base(newError(serial.Concat(errors...))) + } + + return nil +} diff --git a/common/net/destination.go b/common/net/destination.go index c7e1ecf09..055395e9d 100644 --- a/common/net/destination.go +++ b/common/net/destination.go @@ -20,8 +20,7 @@ func DestinationFromAddr(addr net.Addr) Destination { case *net.UDPAddr: return UDPDestination(IPAddress(addr.IP), Port(addr.Port)) case *net.UnixAddr: - // TODO: deal with Unix domain socket - return TCPDestination(LocalHostIP, Port(9)) + return UnixDestination(DomainAddress(addr.Name)) default: panic("Net: Unknown address type.") } @@ -39,6 +38,9 @@ func ParseDestination(dest string) (Destination, error) { } else if strings.HasPrefix(dest, "udp:") { d.Network = Network_UDP dest = dest[4:] + } else if strings.HasPrefix(dest, "unix:") { + d = UnixDestination(DomainAddress(dest[5:])) + return d, nil } hstr, pstr, err := SplitHostPort(dest) @@ -76,9 +78,23 @@ func UDPDestination(address Address, port Port) Destination { } } +// UnixDestination creates a Unix destination with given address +func UnixDestination(address Address) Destination { + return Destination{ + Network: Network_UNIX, + Address: address, + } +} + // NetAddr returns the network address in this Destination in string form. func (d Destination) NetAddr() string { - return d.Address.String() + ":" + d.Port.String() + addr := "" + if d.Network == Network_TCP || d.Network == Network_UDP { + addr = d.Address.String() + ":" + d.Port.String() + } else if d.Network == Network_UNIX { + addr = d.Address.String() + } + return addr } // String returns the strings form of this Destination. @@ -89,6 +105,8 @@ func (d Destination) String() string { prefix = "tcp:" case Network_UDP: prefix = "udp:" + case Network_UNIX: + prefix = "unix:" } return prefix + d.NetAddr() } diff --git a/common/net/destination_test.go b/common/net/destination_test.go index 1e160511d..5ba5d53ad 100644 --- a/common/net/destination_test.go +++ b/common/net/destination_test.go @@ -27,6 +27,12 @@ func TestDestinationProperty(t *testing.T) { String: "udp:[2001:4860:4860::8888]:53", NetString: "[2001:4860:4860::8888]:53", }, + { + Input: UnixDestination(DomainAddress("/tmp/test.sock")), + Network: Network_UNIX, + String: "unix:/tmp/test.sock", + NetString: "/tmp/test.sock", + }, } for _, testCase := range testCases { @@ -57,6 +63,10 @@ func TestDestinationParse(t *testing.T) { Input: "udp:8.8.8.8:53", Output: UDPDestination(IPAddress([]byte{8, 8, 8, 8}), Port(53)), }, + { + Input: "unix:/tmp/test.sock", + Output: UnixDestination(DomainAddress("/tmp/test.sock")), + }, { Input: "8.8.8.8:53", Output: Destination{ @@ -79,6 +89,10 @@ func TestDestinationParse(t *testing.T) { Input: "8.8.8.8:http", Error: true, }, + { + Input: "/tmp/test.sock", + Error: true, + }, } for _, testcase := range cases { diff --git a/common/net/network.go b/common/net/network.go index e6e79c705..f2e303b01 100644 --- a/common/net/network.go +++ b/common/net/network.go @@ -6,6 +6,8 @@ func (n Network) SystemString() string { return "tcp" case Network_UDP: return "udp" + case Network_UNIX: + return "unix" default: return "unknown" } diff --git a/common/net/network.pb.go b/common/net/network.pb.go index 28ab9ba66..665ef1073 100644 --- a/common/net/network.pb.go +++ b/common/net/network.pb.go @@ -33,6 +33,7 @@ const ( Network_RawTCP Network = 1 Network_TCP Network = 2 Network_UDP Network = 3 + Network_UNIX Network = 4 ) // Enum value maps for Network. @@ -42,12 +43,14 @@ var ( 1: "RawTCP", 2: "TCP", 3: "UDP", + 4: "UNIX", } Network_value = map[string]int32{ "Unknown": 0, "RawTCP": 1, "TCP": 2, "UDP": 3, + "UNIX": 4, } ) @@ -136,16 +139,17 @@ var file_common_net_network_proto_rawDesc = []byte{ 0x12, 0x38, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2a, 0x38, 0x0a, 0x07, 0x4e, 0x65, + 0x6b, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2a, 0x42, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x06, 0x52, 0x61, 0x77, 0x54, 0x43, 0x50, 0x10, 0x01, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x55, - 0x44, 0x50, 0x10, 0x03, 0x42, 0x50, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, - 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, - 0x74, 0x50, 0x01, 0x5a, 0x19, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, - 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, - 0x15, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x44, 0x50, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x4e, 0x49, 0x58, 0x10, 0x04, 0x42, 0x50, + 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x19, 0x76, + 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x15, 0x56, 0x32, 0x52, 0x61, 0x79, + 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4e, 0x65, 0x74, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/net/network.proto b/common/net/network.proto index adaca5fb1..87dbc05c9 100644 --- a/common/net/network.proto +++ b/common/net/network.proto @@ -12,9 +12,8 @@ enum Network { RawTCP = 1 [deprecated = true]; TCP = 2; UDP = 3; + UNIX = 4; } // NetworkList is a list of Networks. -message NetworkList { - repeated Network network = 1; -} +message NetworkList { repeated Network network = 1; } diff --git a/infra/conf/common.go b/infra/conf/common.go index 03ec6749a..cc8f01709 100644 --- a/infra/conf/common.go +++ b/infra/conf/common.go @@ -62,6 +62,8 @@ func (v Network) Build() net.Network { return net.Network_TCP case "udp": return net.Network_UDP + case "unix": + return net.Network_UNIX default: return net.Network_Unknown } diff --git a/infra/conf/transport_internet.go b/infra/conf/transport_internet.go index 38d16d203..c0bb27d67 100644 --- a/infra/conf/transport_internet.go +++ b/infra/conf/transport_internet.go @@ -222,19 +222,17 @@ func (c *QUICConfig) Build() (proto.Message, error) { } type DomainSocketConfig struct { - Path string `json:"path"` - Abstract bool `json:"abstract"` - Padding bool `json:"padding"` - AcceptProxyProtocol bool `json:"acceptProxyProtocol"` + Path string `json:"path"` + Abstract bool `json:"abstract"` + Padding bool `json:"padding"` } // Build implements Buildable. func (c *DomainSocketConfig) Build() (proto.Message, error) { return &domainsocket.Config{ - Path: c.Path, - Abstract: c.Abstract, - Padding: c.Padding, - AcceptProxyProtocol: c.AcceptProxyProtocol, + Path: c.Path, + Abstract: c.Abstract, + Padding: c.Padding, }, nil } @@ -421,9 +419,10 @@ func (p TransportProtocol) Build() (string, error) { } type SocketConfig struct { - Mark int32 `json:"mark"` - TFO *bool `json:"tcpFastOpen"` - TProxy string `json:"tproxy"` + Mark int32 `json:"mark"` + TFO *bool `json:"tcpFastOpen"` + TProxy string `json:"tproxy"` + AcceptProxyProtocol bool `json:"acceptProxyProtocol"` } // Build implements Buildable. @@ -447,9 +446,10 @@ func (c *SocketConfig) Build() (*internet.SocketConfig, error) { } return &internet.SocketConfig{ - Mark: c.Mark, - Tfo: tfoSettings, - Tproxy: tproxy, + Mark: c.Mark, + Tfo: tfoSettings, + Tproxy: tproxy, + AcceptProxyProtocol: c.AcceptProxyProtocol, }, nil } diff --git a/infra/conf/trojan.go b/infra/conf/trojan.go index 0929bb649..1eff0354d 100644 --- a/infra/conf/trojan.go +++ b/infra/conf/trojan.go @@ -149,7 +149,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) { case '@', '/': fb.Type = "unix" if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == "linux" { - fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work in front of haproxy + fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy copy(fullAddr, fb.Dest[1:]) fb.Dest = string(fullAddr) } diff --git a/infra/conf/v2ray.go b/infra/conf/v2ray.go index 992816490..2a90120b9 100644 --- a/infra/conf/v2ray.go +++ b/infra/conf/v2ray.go @@ -156,17 +156,34 @@ type InboundDetourConfig struct { func (c *InboundDetourConfig) Build() (*core.InboundHandlerConfig, error) { receiverSettings := &proxyman.ReceiverConfig{} - if c.PortRange == nil { - return nil, newError("port range not specified in InboundDetour.") - } - receiverSettings.PortRange = c.PortRange.Build() - - if c.ListenOn != nil { - if c.ListenOn.Family().IsDomain() { + if c.ListenOn == nil { + // Listen on anyip, must set PortRange + if c.PortRange == nil { + return nil, newError("Listen on AnyIP but no Port(s) set in InboundDetour.") + } + receiverSettings.PortRange = c.PortRange.Build() + } else { + // Listen on specific IP or Unix Domain Socket + receiverSettings.Listen = c.ListenOn.Build() + listenDS := c.ListenOn.Family().IsDomain() && (c.ListenOn.Domain()[0] == '/' || c.ListenOn.Domain()[0] == '@') + listenIP := c.ListenOn.Family().IsIP() || (c.ListenOn.Family().IsDomain() && c.ListenOn.Domain() == "localhost") + if listenIP { + // Listen on specific IP, must set PortRange + if c.PortRange == nil { + return nil, newError("Listen on specific ip without port in InboundDetour.") + } + // Listen on IP:Port + receiverSettings.PortRange = c.PortRange.Build() + } else if listenDS { + if c.PortRange != nil { + // Listen on Unix Domain Socket, PortRange should be nil + receiverSettings.PortRange = nil + } + } else { return nil, newError("unable to listen on domain address: ", c.ListenOn.Domain()) } - receiverSettings.Listen = c.ListenOn.Build() } + if c.Allocation != nil { concurrency := -1 if c.Allocation.Concurrency != nil && c.Allocation.Strategy == "random" { diff --git a/infra/conf/vless.go b/infra/conf/vless.go index 21fc0ae34..3d2dbfc3f 100644 --- a/infra/conf/vless.go +++ b/infra/conf/vless.go @@ -100,7 +100,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) { case '@', '/': fb.Type = "unix" if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == "linux" { - fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work in front of haproxy + fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy copy(fullAddr, fb.Dest[1:]) fb.Dest = string(fullAddr) } diff --git a/proxy/http/server.go b/proxy/http/server.go index 059ea310a..9f6b88590 100644 --- a/proxy/http/server.go +++ b/proxy/http/server.go @@ -55,7 +55,7 @@ func (s *Server) policy() policy.Session { // Network implements proxy.Inbound. func (*Server) Network() []net.Network { - return []net.Network{net.Network_TCP} + return []net.Network{net.Network_TCP, net.Network_UNIX} } func isTimeout(err error) bool { diff --git a/proxy/trojan/server.go b/proxy/trojan/server.go index c271e0321..747401d1a 100644 --- a/proxy/trojan/server.go +++ b/proxy/trojan/server.go @@ -97,7 +97,7 @@ func (s *Server) RemoveUser(ctx context.Context, e string) error { // Network implements proxy.Inbound.Network(). func (s *Server) Network() []net.Network { - return []net.Network{net.Network_TCP} + return []net.Network{net.Network_TCP, net.Network_UNIX} } // Process implements proxy.Inbound.Process(). diff --git a/proxy/vless/inbound/inbound.go b/proxy/vless/inbound/inbound.go index 5031ac0df..9b6eb8669 100644 --- a/proxy/vless/inbound/inbound.go +++ b/proxy/vless/inbound/inbound.go @@ -138,7 +138,7 @@ func (h *Handler) RemoveUser(ctx context.Context, e string) error { // Network implements proxy.Inbound.Network(). func (*Handler) Network() []net.Network { - return []net.Network{net.Network_TCP} + return []net.Network{net.Network_TCP, net.Network_UNIX} } // Process implements proxy.Inbound.Process(). diff --git a/proxy/vmess/inbound/inbound.go b/proxy/vmess/inbound/inbound.go index 9f385be96..12386b5fc 100644 --- a/proxy/vmess/inbound/inbound.go +++ b/proxy/vmess/inbound/inbound.go @@ -148,7 +148,7 @@ func (h *Handler) Close() error { // Network implements proxy.Inbound.Network(). func (*Handler) Network() []net.Network { - return []net.Network{net.Network_TCP} + return []net.Network{net.Network_TCP, net.Network_UNIX} } func (h *Handler) GetUser(email string) *protocol.MemoryUser { diff --git a/transport/internet/config.pb.go b/transport/internet/config.pb.go index 362a7364e..ccb9ed634 100644 --- a/transport/internet/config.pb.go +++ b/transport/internet/config.pb.go @@ -413,6 +413,7 @@ type SocketConfig struct { 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"` } func (x *SocketConfig) Reset() { @@ -489,6 +490,13 @@ func (x *SocketConfig) GetBindPort() uint32 { return 0 } +func (x *SocketConfig) GetAcceptProxyProtocol() bool { + if x != nil { + return x.AcceptProxyProtocol + } + return false +} + var File_transport_internet_config_proto protoreflect.FileDescriptor var file_transport_internet_config_proto_rawDesc = []byte{ @@ -540,7 +548,7 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x1f, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0xad, 0x03, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, + 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0xe1, 0x03, 0x0a, 0x0c, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x4e, 0x0a, 0x03, 0x74, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, @@ -560,27 +568,30 @@ var file_transport_internet_config_proto_rawDesc = []byte{ 0x0a, 0x0c, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x62, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x69, 0x6e, 0x64, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x35, - 0x0a, 0x10, 0x54, 0x43, 0x50, 0x46, 0x61, 0x73, 0x74, 0x4f, 0x70, 0x65, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, - 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x69, 0x73, 0x61, - 0x62, 0x6c, 0x65, 0x10, 0x02, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, - 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, - 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x5a, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x54, - 0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x08, 0x0a, - 0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x57, 0x65, 0x62, 0x53, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x04, - 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, - 0x10, 0x05, 0x42, 0x68, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, - 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x21, 0x76, 0x32, 0x72, 0x61, 0x79, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xaa, 0x02, 0x1d, 0x56, - 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x32, + 0x0a, 0x15, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61, + 0x63, 0x63, 0x65, 0x70, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x22, 0x35, 0x0a, 0x10, 0x54, 0x43, 0x50, 0x46, 0x61, 0x73, 0x74, 0x4f, 0x70, 0x65, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x73, 0x49, 0x73, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, + 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x10, 0x02, 0x22, 0x2f, 0x0a, 0x0a, 0x54, 0x50, 0x72, + 0x6f, 0x78, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x4f, 0x66, 0x66, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, + 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x10, 0x02, 0x2a, 0x5a, 0x0a, 0x11, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, + 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, + 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4b, 0x43, 0x50, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x57, + 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, + 0x54, 0x50, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, + 0x63, 0x6b, 0x65, 0x74, 0x10, 0x05, 0x42, 0x68, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, + 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x21, 0x76, + 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0xaa, 0x02, 0x1d, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/transport/internet/config.proto b/transport/internet/config.proto index f3b96a94e..abedd4ec7 100644 --- a/transport/internet/config.proto +++ b/transport/internet/config.proto @@ -31,7 +31,7 @@ message TransportConfig { message StreamConfig { // Effective network. Deprecated. Use the string form below. - TransportProtocol protocol = 1 [deprecated = true]; + TransportProtocol protocol = 1 [ deprecated = true ]; // Effective network. string protocol_name = 5; @@ -47,9 +47,7 @@ message StreamConfig { SocketConfig socket_settings = 6; } -message ProxyConfig { - string tag = 1; -} +message ProxyConfig { string tag = 1; } // SocketConfig is options to be applied on network sockets. message SocketConfig { @@ -87,4 +85,6 @@ message SocketConfig { bytes bind_address = 5; uint32 bind_port = 6; + + bool accept_proxy_protocol = 7; } diff --git a/transport/internet/domainsocket/config.pb.go b/transport/internet/domainsocket/config.pb.go index 76c61b15c..40f08fb12 100644 --- a/transport/internet/domainsocket/config.pb.go +++ b/transport/internet/domainsocket/config.pb.go @@ -39,8 +39,7 @@ type Config struct { Abstract bool `protobuf:"varint,2,opt,name=abstract,proto3" json:"abstract,omitempty"` // Some apps, eg. haproxy, use the full length of sockaddr_un.sun_path to // connect(2) or bind(2) when using abstract UDS. - Padding bool `protobuf:"varint,3,opt,name=padding,proto3" json:"padding,omitempty"` - AcceptProxyProtocol bool `protobuf:"varint,4,opt,name=acceptProxyProtocol,proto3" json:"acceptProxyProtocol,omitempty"` + Padding bool `protobuf:"varint,3,opt,name=padding,proto3" json:"padding,omitempty"` } func (x *Config) Reset() { @@ -96,13 +95,6 @@ func (x *Config) GetPadding() bool { return false } -func (x *Config) GetAcceptProxyProtocol() bool { - if x != nil { - return x.AcceptProxyProtocol - } - return false -} - var File_transport_internet_domainsocket_config_proto protoreflect.FileDescriptor var file_transport_internet_domainsocket_config_proto_rawDesc = []byte{ @@ -111,25 +103,22 @@ var file_transport_internet_domainsocket_config_proto_rawDesc = []byte{ 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x84, 0x01, 0x0a, 0x06, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x62, 0x73, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x62, 0x73, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, - 0x30, 0x0a, 0x13, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x42, 0x8f, 0x01, 0x0a, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, - 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x6f, - 0x63, 0x6b, 0x65, 0x74, 0x50, 0x01, 0x5a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, - 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0xaa, 0x02, 0x2a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, - 0x6f, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, - 0x6b, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x52, 0x0a, 0x06, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x62, 0x73, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x62, 0x73, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x8f, + 0x01, 0x0a, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, + 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x6f, 0x63, 0x6b, 0x65, + 0x74, 0x50, 0x01, 0x5a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x6f, 0x63, + 0x6b, 0x65, 0x74, 0xaa, 0x02, 0x2a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, + 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/transport/internet/domainsocket/config.proto b/transport/internet/domainsocket/config.proto index 5c1086d0d..b66c71e8b 100644 --- a/transport/internet/domainsocket/config.proto +++ b/transport/internet/domainsocket/config.proto @@ -17,5 +17,4 @@ message Config { // Some apps, eg. haproxy, use the full length of sockaddr_un.sun_path to // connect(2) or bind(2) when using abstract UDS. bool padding = 3; - bool acceptProxyProtocol = 4; } diff --git a/transport/internet/domainsocket/listener.go b/transport/internet/domainsocket/listener.go index 607dbbd09..72f57968e 100644 --- a/transport/internet/domainsocket/listener.go +++ b/transport/internet/domainsocket/listener.go @@ -10,13 +10,11 @@ import ( "os" "strings" - "github.com/pires/go-proxyproto" goxtls "github.com/xtls/go" "golang.org/x/sys/unix" "v2ray.com/core/common" "v2ray.com/core/common/net" - "v2ray.com/core/common/session" "v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet/tls" "v2ray.com/core/transport/internet/xtls" @@ -44,23 +42,11 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti return nil, newError("failed to listen domain socket").Base(err).AtWarning() } - var ln *Listener - if settings.AcceptProxyProtocol { - policyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil } - ln = &Listener{ - addr: addr, - ln: &proxyproto.Listener{Listener: unixListener, Policy: policyFunc}, - config: settings, - addConn: handler, - } - newError("accepting PROXY protocol").AtWarning().WriteToLog(session.ExportIDToError(ctx)) - } else { - ln = &Listener{ - addr: addr, - ln: unixListener, - config: settings, - addConn: handler, - } + ln := &Listener{ + addr: addr, + ln: unixListener, + config: settings, + addConn: handler, } if !settings.Abstract { diff --git a/transport/internet/filelocker.go b/transport/internet/filelocker.go new file mode 100644 index 000000000..33dec736d --- /dev/null +++ b/transport/internet/filelocker.go @@ -0,0 +1,11 @@ +package internet + +import ( + "os" +) + +// FileLocker is UDS access lock +type FileLocker struct { + path string + file *os.File +} diff --git a/transport/internet/filelocker_other.go b/transport/internet/filelocker_other.go new file mode 100644 index 000000000..347cd66cd --- /dev/null +++ b/transport/internet/filelocker_other.go @@ -0,0 +1,36 @@ +// +build !windows + +package internet + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// Acquire lock +func (fl *FileLocker) Acquire() error { + f, err := os.Create(fl.path) + if err != nil { + return err + } + if err := unix.Flock(int(f.Fd()), unix.LOCK_EX); err != nil { + f.Close() + return newError("failed to lock file: ", fl.path).Base(err) + } + fl.file = f + return nil +} + +// Release lock +func (fl *FileLocker) Release() { + if err := unix.Flock(int(fl.file.Fd()), unix.LOCK_UN); err != nil { + newError("failed to unlock file: ", fl.path).Base(err).WriteToLog() + } + if err := fl.file.Close(); err != nil { + newError("failed to close file: ", fl.path).Base(err).WriteToLog() + } + if err := os.Remove(fl.path); err != nil { + newError("failed to remove file: ", fl.path).Base(err).WriteToLog() + } +} diff --git a/transport/internet/filelocker_windows.go b/transport/internet/filelocker_windows.go new file mode 100644 index 000000000..adbe2e8ed --- /dev/null +++ b/transport/internet/filelocker_windows.go @@ -0,0 +1,11 @@ +package internet + +// Acquire lock +func (fl *FileLocker) Acquire() error { + return nil +} + +// Release lock +func (fl *FileLocker) Release() { + return +} diff --git a/transport/internet/http/hub.go b/transport/internet/http/hub.go index 4b75a1a28..645b9101b 100644 --- a/transport/internet/http/hub.go +++ b/transport/internet/http/hub.go @@ -4,8 +4,10 @@ package http import ( "context" + "fmt" "io" "net/http" + "os" "strings" "time" @@ -27,6 +29,7 @@ type Listener struct { handler internet.ConnHandler local net.Addr config *Config + locker *internet.FileLocker // for unix domain socket } func (l *Listener) Addr() net.Addr { @@ -34,6 +37,10 @@ func (l *Listener) Addr() net.Addr { } func (l *Listener) Close() error { + if l.locker != nil { + fmt.Fprintln(os.Stderr, "RELEASE LOCK") + l.locker.Release() + } return l.server.Close() } @@ -85,7 +92,10 @@ func (l *Listener) ServeHTTP(writer http.ResponseWriter, request *http.Request) forwardedAddrs := http_proto.ParseXForwardedFor(request.Header) if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() { - remoteAddr.(*net.TCPAddr).IP = forwardedAddrs[0].IP() + remoteAddr = &net.TCPAddr{ + IP: forwardedAddrs[0].IP(), + Port: int(0), + } } done := done.New() @@ -102,13 +112,25 @@ func (l *Listener) ServeHTTP(writer http.ResponseWriter, request *http.Request) func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) { httpSettings := streamSettings.ProtocolSettings.(*Config) - listener := &Listener{ - handler: handler, - local: &net.TCPAddr{ - IP: address.IP(), - Port: int(port), - }, - config: httpSettings, + var listener *Listener + if port == net.Port(0) { // unix + listener = &Listener{ + handler: handler, + local: &net.UnixAddr{ + Name: address.Domain(), + Net: "unix", + }, + config: httpSettings, + } + } else { // tcp + listener = &Listener{ + handler: handler, + local: &net.TCPAddr{ + IP: address.IP(), + Port: int(port), + }, + config: httpSettings, + } } var server *http.Server @@ -130,23 +152,45 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti } } + if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol { + newError("accepting PROXY protocol").AtWarning().WriteToLog(session.ExportIDToError(ctx)) + } + listener.server = server go func() { - tcpListener, err := internet.ListenSystem(ctx, &net.TCPAddr{ - IP: address.IP(), - Port: int(port), - }, streamSettings.SocketSettings) - if err != nil { - newError("failed to listen on", address, ":", port).Base(err).WriteToLog(session.ExportIDToError(ctx)) - return + var streamListener net.Listener + var err error + if port == net.Port(0) { // unix + streamListener, err = internet.ListenSystem(ctx, &net.UnixAddr{ + Name: address.Domain(), + Net: "unix", + }, streamSettings.SocketSettings) + if err != nil { + newError("failed to listen on ", address).Base(err).WriteToLog(session.ExportIDToError(ctx)) + return + } + locker := ctx.Value(address.Domain()) + if locker != nil { + listener.locker = locker.(*internet.FileLocker) + } + } else { // tcp + streamListener, err = internet.ListenSystem(ctx, &net.TCPAddr{ + IP: address.IP(), + Port: int(port), + }, streamSettings.SocketSettings) + if err != nil { + newError("failed to listen on ", address, ":", port).Base(err).WriteToLog(session.ExportIDToError(ctx)) + return + } } + if config == nil { - err = server.Serve(tcpListener) + err = server.Serve(streamListener) if err != nil { newError("stoping serving H2C").Base(err).WriteToLog(session.ExportIDToError(ctx)) } } else { - err = server.ServeTLS(tcpListener, "", "") + err = server.ServeTLS(streamListener, "", "") if err != nil { newError("stoping serving TLS").Base(err).WriteToLog(session.ExportIDToError(ctx)) } diff --git a/transport/internet/system_listener.go b/transport/internet/system_listener.go index b17cbbba5..d867914ea 100644 --- a/transport/internet/system_listener.go +++ b/transport/internet/system_listener.go @@ -2,8 +2,10 @@ package internet import ( "context" + "runtime" "syscall" + "github.com/pires/go-proxyproto" "v2ray.com/core/common/net" "v2ray.com/core/common/session" ) @@ -40,10 +42,45 @@ func getControlFunc(ctx context.Context, sockopt *SocketConfig, controllers []co func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.Listener, error) { var lc net.ListenConfig + var l net.Listener + var err error + var network, address string + switch addr := addr.(type) { + case *net.TCPAddr: + network = addr.Network() + address = addr.String() + lc.Control = getControlFunc(ctx, sockopt, dl.controllers) + case *net.UnixAddr: + lc.Control = nil + network = addr.Network() + address = addr.Name + if runtime.GOOS == "linux" && address[0] == '@' { + // linux abstract unix domain socket is lockfree + if len(address) > 1 && address[1] == '@' { + // but may need padding to work with haproxy + fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) + copy(fullAddr, address[1:]) + address = string(fullAddr) + } + } else { + // normal unix domain socket needs lock + locker := &FileLocker{ + path: address + ".lock", + } + err := locker.Acquire() + if err != nil { + return nil, err + } + ctx = context.WithValue(ctx, address, locker) + } + } - lc.Control = getControlFunc(ctx, sockopt, dl.controllers) - - return lc.Listen(ctx, addr.Network(), addr.String()) + l, err = lc.Listen(ctx, network, address) + if sockopt != nil && sockopt.AcceptProxyProtocol { + policyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil } + l = &proxyproto.Listener{Listener: l, Policy: policyFunc} + } + return l, err } func (dl *DefaultListener) ListenPacket(ctx context.Context, addr net.Addr, sockopt *SocketConfig) (net.PacketConn, error) { diff --git a/transport/internet/tcp/hub.go b/transport/internet/tcp/hub.go index de13e76f8..49a459f12 100644 --- a/transport/internet/tcp/hub.go +++ b/transport/internet/tcp/hub.go @@ -8,7 +8,6 @@ import ( "strings" "time" - "github.com/pires/go-proxyproto" goxtls "github.com/xtls/go" "v2ray.com/core/common" @@ -27,37 +26,53 @@ type Listener struct { authConfig internet.ConnectionAuthenticator config *Config addConn internet.ConnHandler + locker *internet.FileLocker // for unix domain socket } // ListenTCP creates a new Listener based on configurations. func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) { - listener, err := internet.ListenSystem(ctx, &net.TCPAddr{ - IP: address.IP(), - Port: int(port), - }, streamSettings.SocketSettings) - if err != nil { - return nil, newError("failed to listen TCP on", address, ":", port).Base(err) + l := &Listener{ + addConn: handler, } - newError("listening TCP on ", address, ":", port).WriteToLog(session.ExportIDToError(ctx)) - tcpSettings := streamSettings.ProtocolSettings.(*Config) - var l *Listener - - if tcpSettings.AcceptProxyProtocol { - policyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil } - l = &Listener{ - listener: &proxyproto.Listener{Listener: listener, Policy: policyFunc}, - config: tcpSettings, - addConn: handler, - } - newError("accepting PROXY protocol").AtWarning().WriteToLog(session.ExportIDToError(ctx)) - } else { - l = &Listener{ - listener: listener, - config: tcpSettings, - addConn: handler, + l.config = tcpSettings + if l.config != nil { + if streamSettings.SocketSettings == nil { + streamSettings.SocketSettings = &internet.SocketConfig{} } + streamSettings.SocketSettings.AcceptProxyProtocol = l.config.AcceptProxyProtocol } + var listener net.Listener + var err error + if port == net.Port(0) { //unix + listener, err = internet.ListenSystem(ctx, &net.UnixAddr{ + Name: address.Domain(), + Net: "unix", + }, streamSettings.SocketSettings) + if err != nil { + return nil, newError("failed to listen Unix Doman Socket on ", address).Base(err) + } + newError("listening Unix Domain Socket on ", address).WriteToLog(session.ExportIDToError(ctx)) + locker := ctx.Value(address.Domain()) + if locker != nil { + l.locker = locker.(*internet.FileLocker) + } + } else { + listener, err = internet.ListenSystem(ctx, &net.TCPAddr{ + IP: address.IP(), + Port: int(port), + }, streamSettings.SocketSettings) + if err != nil { + return nil, newError("failed to listen TCP on ", address, ":", port).Base(err) + } + newError("listening TCP on ", address, ":", port).WriteToLog(session.ExportIDToError(ctx)) + } + + if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol { + newError("accepting PROXY protocol").AtWarning().WriteToLog(session.ExportIDToError(ctx)) + } + + l.listener = listener if config := tls.ConfigFromStreamSettings(streamSettings); config != nil { l.tlsConfig = config.GetTLSConfig(tls.WithNextProto("h2")) @@ -117,6 +132,9 @@ func (v *Listener) Addr() net.Addr { // Close implements internet.Listener.Close. func (v *Listener) Close() error { + if v.locker != nil { + v.locker.Release() + } return v.listener.Close() } diff --git a/transport/internet/tcp_hub.go b/transport/internet/tcp_hub.go index efb72bfbb..310178445 100644 --- a/transport/internet/tcp_hub.go +++ b/transport/internet/tcp_hub.go @@ -27,6 +27,27 @@ type Listener interface { Addr() net.Addr } +// ListenUnix is the UDS version of ListenTCP +func ListenUnix(ctx context.Context, address net.Address, settings *MemoryStreamConfig, handler ConnHandler) (Listener, error) { + if settings == nil { + s, err := ToMemoryStreamConfig(nil) + if err != nil { + return nil, newError("failed to create default unix stream settings").Base(err) + } + settings = s + } + + protocol := settings.ProtocolName + listenFunc := transportListenerCache[protocol] + if listenFunc == nil { + return nil, newError(protocol, " unix istener not registered.").AtError() + } + listener, err := listenFunc(ctx, address, net.Port(0), settings, handler) + if err != nil { + return nil, newError("failed to listen on unix address: ", address).Base(err) + } + return listener, nil +} func ListenTCP(ctx context.Context, address net.Address, port net.Port, settings *MemoryStreamConfig, handler ConnHandler) (Listener, error) { if settings == nil { s, err := ToMemoryStreamConfig(nil) diff --git a/transport/internet/websocket/hub.go b/transport/internet/websocket/hub.go index e7e90d35d..834a9edb8 100644 --- a/transport/internet/websocket/hub.go +++ b/transport/internet/websocket/hub.go @@ -10,7 +10,6 @@ import ( "time" "github.com/gorilla/websocket" - "github.com/pires/go-proxyproto" "v2ray.com/core/common" "v2ray.com/core/common/net" @@ -48,7 +47,10 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req forwardedAddrs := http_proto.ParseXForwardedFor(request.Header) remoteAddr := conn.RemoteAddr() if len(forwardedAddrs) > 0 && forwardedAddrs[0].Family().IsIP() { - remoteAddr.(*net.TCPAddr).IP = forwardedAddrs[0].IP() + remoteAddr = &net.TCPAddr{ + IP: forwardedAddrs[0].IP(), + Port: int(0), + } } h.ln.addConn(newConnection(conn, remoteAddr)) @@ -60,23 +62,48 @@ type Listener struct { listener net.Listener config *Config addConn internet.ConnHandler + locker *internet.FileLocker // for unix domain socket } func ListenWS(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (internet.Listener, error) { - listener, err := internet.ListenSystem(ctx, &net.TCPAddr{ - IP: address.IP(), - Port: int(port), - }, streamSettings.SocketSettings) - if err != nil { - return nil, newError("failed to listen TCP(for WS) on", address, ":", port).Base(err) + l := &Listener{ + addConn: addConn, } - newError("listening TCP(for WS) on ", address, ":", port).WriteToLog(session.ExportIDToError(ctx)) - wsSettings := streamSettings.ProtocolSettings.(*Config) + l.config = wsSettings + if l.config != nil { + if streamSettings.SocketSettings == nil { + streamSettings.SocketSettings = &internet.SocketConfig{} + } + streamSettings.SocketSettings.AcceptProxyProtocol = l.config.AcceptProxyProtocol + } + var listener net.Listener + var err error + if port == net.Port(0) { //unix + listener, err = internet.ListenSystem(ctx, &net.UnixAddr{ + Name: address.Domain(), + Net: "unix", + }, streamSettings.SocketSettings) + if err != nil { + return nil, newError("failed to listen unix domain socket(for WS) on ", address).Base(err) + } + newError("listening unix domain socket(for WS) on ", address).WriteToLog(session.ExportIDToError(ctx)) + locker := ctx.Value(address.Domain()) + if locker != nil { + l.locker = locker.(*internet.FileLocker) + } + } else { //tcp + listener, err = internet.ListenSystem(ctx, &net.TCPAddr{ + IP: address.IP(), + Port: int(port), + }, streamSettings.SocketSettings) + if err != nil { + return nil, newError("failed to listen TCP(for WS) on ", address, ":", port).Base(err) + } + newError("listening TCP(for WS) on ", address, ":", port).WriteToLog(session.ExportIDToError(ctx)) + } - if wsSettings.AcceptProxyProtocol { - policyFunc := func(upstream net.Addr) (proxyproto.Policy, error) { return proxyproto.REQUIRE, nil } - listener = &proxyproto.Listener{Listener: listener, Policy: policyFunc} + if streamSettings.SocketSettings != nil && streamSettings.SocketSettings.AcceptProxyProtocol { newError("accepting PROXY protocol").AtWarning().WriteToLog(session.ExportIDToError(ctx)) } @@ -86,11 +113,7 @@ func ListenWS(ctx context.Context, address net.Address, port net.Port, streamSet } } - l := &Listener{ - config: wsSettings, - addConn: addConn, - listener: listener, - } + l.listener = listener l.server = http.Server{ Handler: &requestHandler{ @@ -117,6 +140,9 @@ func (ln *Listener) Addr() net.Addr { // Close implements net.Listener.Close(). func (ln *Listener) Close() error { + if ln.locker != nil { + ln.locker.Release() + } return ln.listener.Close() }