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