Refine unix domain socket (#367)

This commit is contained in:
lucifer 2020-10-29 15:30:38 +08:00 committed by GitHub
parent f17063a08a
commit 770b994337
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 542 additions and 195 deletions

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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()
}

View File

@ -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 {

View File

@ -6,6 +6,8 @@ func (n Network) SystemString() string {
return "tcp"
case Network_UDP:
return "udp"
case Network_UNIX:
return "unix"
default:
return "unknown"
}

View File

@ -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 (

View File

@ -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; }

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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" {

View File

@ -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)
}

View File

@ -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 {

View File

@ -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().

View File

@ -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().

View File

@ -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 {

View File

@ -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 (

View File

@ -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;
}

View File

@ -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 (

View File

@ -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;
}

View File

@ -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 {

View File

@ -0,0 +1,11 @@
package internet
import (
"os"
)
// FileLocker is UDS access lock
type FileLocker struct {
path string
file *os.File
}

View File

@ -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()
}
}

View File

@ -0,0 +1,11 @@
package internet
// Acquire lock
func (fl *FileLocker) Acquire() error {
return nil
}
// Release lock
func (fl *FileLocker) Release() {
return
}

View File

@ -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))
}

View File

@ -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) {

View File

@ -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()
}

View File

@ -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)

View File

@ -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()
}