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