github.com/v2fly/v2ray-core/v4@v4.45.2/proxy/dokodemo/dokodemo.go (about) 1 //go:build !confonly 2 // +build !confonly 3 4 package dokodemo 5 6 //go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen 7 8 import ( 9 "context" 10 "sync/atomic" 11 "time" 12 13 core "github.com/v2fly/v2ray-core/v4" 14 "github.com/v2fly/v2ray-core/v4/common" 15 "github.com/v2fly/v2ray-core/v4/common/buf" 16 "github.com/v2fly/v2ray-core/v4/common/log" 17 "github.com/v2fly/v2ray-core/v4/common/net" 18 "github.com/v2fly/v2ray-core/v4/common/protocol" 19 "github.com/v2fly/v2ray-core/v4/common/session" 20 "github.com/v2fly/v2ray-core/v4/common/signal" 21 "github.com/v2fly/v2ray-core/v4/common/task" 22 "github.com/v2fly/v2ray-core/v4/features/policy" 23 "github.com/v2fly/v2ray-core/v4/features/routing" 24 "github.com/v2fly/v2ray-core/v4/transport/internet" 25 ) 26 27 func init() { 28 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 29 d := new(Door) 30 err := core.RequireFeatures(ctx, func(pm policy.Manager) error { 31 return d.Init(config.(*Config), pm, session.SockoptFromContext(ctx)) 32 }) 33 return d, err 34 })) 35 } 36 37 type Door struct { 38 policyManager policy.Manager 39 config *Config 40 address net.Address 41 port net.Port 42 sockopt *session.Sockopt 43 } 44 45 // Init initializes the Door instance with necessary parameters. 46 func (d *Door) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error { 47 if (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 { 48 return newError("no network specified") 49 } 50 d.config = config 51 d.address = config.GetPredefinedAddress() 52 d.port = net.Port(config.Port) 53 d.policyManager = pm 54 d.sockopt = sockopt 55 56 return nil 57 } 58 59 // Network implements proxy.Inbound. 60 func (d *Door) Network() []net.Network { 61 if len(d.config.Networks) > 0 { 62 return d.config.Networks 63 } 64 65 return d.config.NetworkList.Network 66 } 67 68 func (d *Door) policy() policy.Session { 69 config := d.config 70 p := d.policyManager.ForLevel(config.UserLevel) 71 if config.Timeout > 0 && config.UserLevel == 0 { 72 p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second 73 } 74 return p 75 } 76 77 type hasHandshakeAddress interface { 78 HandshakeAddress() net.Address 79 } 80 81 // Process implements proxy.Inbound. 82 func (d *Door) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error { 83 newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog(session.ExportIDToError(ctx)) 84 dest := net.Destination{ 85 Network: network, 86 Address: d.address, 87 Port: d.port, 88 } 89 90 destinationOverridden := false 91 if d.config.FollowRedirect { 92 if outbound := session.OutboundFromContext(ctx); outbound != nil && outbound.Target.IsValid() { 93 dest = outbound.Target 94 destinationOverridden = true 95 } else if handshake, ok := conn.(hasHandshakeAddress); ok { 96 addr := handshake.HandshakeAddress() 97 if addr != nil { 98 dest.Address = addr 99 destinationOverridden = true 100 } 101 } 102 } 103 if !dest.IsValid() || dest.Address == nil { 104 return newError("unable to get destination") 105 } 106 107 if inbound := session.InboundFromContext(ctx); inbound != nil { 108 inbound.User = &protocol.MemoryUser{ 109 Level: d.config.UserLevel, 110 } 111 } 112 113 ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ 114 From: conn.RemoteAddr(), 115 To: dest, 116 Status: log.AccessAccepted, 117 Reason: "", 118 }) 119 newError("received request for ", conn.RemoteAddr()).WriteToLog(session.ExportIDToError(ctx)) 120 121 plcy := d.policy() 122 ctx, cancel := context.WithCancel(ctx) 123 timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle) 124 125 ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer) 126 link, err := dispatcher.Dispatch(ctx, dest) 127 if err != nil { 128 return newError("failed to dispatch request").Base(err) 129 } 130 131 requestCount := int32(1) 132 requestDone := func() error { 133 defer func() { 134 if atomic.AddInt32(&requestCount, -1) == 0 { 135 timer.SetTimeout(plcy.Timeouts.DownlinkOnly) 136 } 137 }() 138 139 var reader buf.Reader 140 if dest.Network == net.Network_UDP { 141 reader = buf.NewPacketReader(conn) 142 } else { 143 reader = buf.NewReader(conn) 144 } 145 if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil { 146 return newError("failed to transport request").Base(err) 147 } 148 149 return nil 150 } 151 152 tproxyRequest := func() error { 153 return nil 154 } 155 156 var writer buf.Writer 157 if network == net.Network_TCP { 158 writer = buf.NewWriter(conn) 159 } else { 160 // if we are in TPROXY mode, use linux's udp forging functionality 161 if !destinationOverridden { 162 writer = &buf.SequentialWriter{Writer: conn} 163 } else { 164 sockopt := &internet.SocketConfig{ 165 Tproxy: internet.SocketConfig_TProxy, 166 } 167 if dest.Address.Family().IsIP() { 168 sockopt.BindAddress = dest.Address.IP() 169 sockopt.BindPort = uint32(dest.Port) 170 } 171 if d.sockopt != nil { 172 sockopt.Mark = d.sockopt.Mark 173 } 174 tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt) 175 if err != nil { 176 return err 177 } 178 defer tConn.Close() 179 180 writer = &buf.SequentialWriter{Writer: tConn} 181 tReader := buf.NewPacketReader(tConn) 182 requestCount++ 183 tproxyRequest = func() error { 184 defer func() { 185 if atomic.AddInt32(&requestCount, -1) == 0 { 186 timer.SetTimeout(plcy.Timeouts.DownlinkOnly) 187 } 188 }() 189 if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil { 190 return newError("failed to transport request (TPROXY conn)").Base(err) 191 } 192 return nil 193 } 194 } 195 } 196 197 responseDone := func() error { 198 defer timer.SetTimeout(plcy.Timeouts.UplinkOnly) 199 200 if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil { 201 return newError("failed to transport response").Base(err) 202 } 203 return nil 204 } 205 206 if err := task.Run(ctx, task.OnSuccess(func() error { 207 return task.Run(ctx, requestDone, tproxyRequest) 208 }, task.Close(link.Writer)), responseDone); err != nil { 209 common.Interrupt(link.Reader) 210 common.Interrupt(link.Writer) 211 return newError("connection ends").Base(err) 212 } 213 214 return nil 215 }