github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/proxy/dokodemo/dokodemo.go (about) 1 package dokodemo 2 3 //go:generate go run github.com/xtls/xray-core/common/errors/errorgen 4 5 import ( 6 "context" 7 "sync/atomic" 8 "time" 9 10 "github.com/xtls/xray-core/common" 11 "github.com/xtls/xray-core/common/buf" 12 "github.com/xtls/xray-core/common/log" 13 "github.com/xtls/xray-core/common/net" 14 "github.com/xtls/xray-core/common/protocol" 15 "github.com/xtls/xray-core/common/session" 16 "github.com/xtls/xray-core/common/signal" 17 "github.com/xtls/xray-core/common/task" 18 "github.com/xtls/xray-core/core" 19 "github.com/xtls/xray-core/features/policy" 20 "github.com/xtls/xray-core/features/routing" 21 "github.com/xtls/xray-core/transport/internet/stat" 22 ) 23 24 func init() { 25 common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 26 d := new(DokodemoDoor) 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 34 type DokodemoDoor struct { 35 policyManager policy.Manager 36 config *Config 37 address net.Address 38 port net.Port 39 sockopt *session.Sockopt 40 } 41 42 // Init initializes the DokodemoDoor instance with necessary parameters. 43 func (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error { 44 if (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 { 45 return newError("no network specified") 46 } 47 d.config = config 48 d.address = config.GetPredefinedAddress() 49 d.port = net.Port(config.Port) 50 d.policyManager = pm 51 d.sockopt = sockopt 52 53 return nil 54 } 55 56 // Network implements proxy.Inbound. 57 func (d *DokodemoDoor) Network() []net.Network { 58 if len(d.config.Networks) > 0 { 59 return d.config.Networks 60 } 61 62 return d.config.NetworkList.Network 63 } 64 65 func (d *DokodemoDoor) policy() policy.Session { 66 config := d.config 67 p := d.policyManager.ForLevel(config.UserLevel) 68 if config.Timeout > 0 && config.UserLevel == 0 { 69 p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second 70 } 71 return p 72 } 73 74 type hasHandshakeAddressContext interface { 75 HandshakeAddressContext(ctx context.Context) net.Address 76 } 77 78 // Process implements proxy.Inbound. 79 func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error { 80 newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog(session.ExportIDToError(ctx)) 81 dest := net.Destination{ 82 Network: network, 83 Address: d.address, 84 Port: d.port, 85 } 86 87 destinationOverridden := false 88 if d.config.FollowRedirect { 89 outbounds := session.OutboundsFromContext(ctx) 90 if len(outbounds) > 0 { 91 ob := outbounds[len(outbounds) - 1] 92 if ob.Target.IsValid() { 93 dest = ob.Target 94 destinationOverridden = true 95 } 96 } 97 if handshake, ok := conn.(hasHandshakeAddressContext); ok && !destinationOverridden { 98 addr := handshake.HandshakeAddressContext(ctx) 99 if addr != nil { 100 dest.Address = addr 101 destinationOverridden = true 102 } 103 } 104 } 105 if !dest.IsValid() || dest.Address == nil { 106 return newError("unable to get destination") 107 } 108 109 inbound := session.InboundFromContext(ctx) 110 inbound.Name = "dokodemo-door" 111 inbound.CanSpliceCopy = 1 112 inbound.User = &protocol.MemoryUser{ 113 Level: d.config.UserLevel, 114 } 115 116 ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ 117 From: conn.RemoteAddr(), 118 To: dest, 119 Status: log.AccessAccepted, 120 Reason: "", 121 }) 122 newError("received request for ", conn.RemoteAddr()).WriteToLog(session.ExportIDToError(ctx)) 123 124 plcy := d.policy() 125 ctx, cancel := context.WithCancel(ctx) 126 timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle) 127 128 if inbound != nil { 129 inbound.Timer = timer 130 } 131 132 ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer) 133 link, err := dispatcher.Dispatch(ctx, dest) 134 if err != nil { 135 return newError("failed to dispatch request").Base(err) 136 } 137 138 requestCount := int32(1) 139 requestDone := func() error { 140 defer func() { 141 if atomic.AddInt32(&requestCount, -1) == 0 { 142 timer.SetTimeout(plcy.Timeouts.DownlinkOnly) 143 } 144 }() 145 146 var reader buf.Reader 147 if dest.Network == net.Network_UDP { 148 reader = buf.NewPacketReader(conn) 149 } else { 150 reader = buf.NewReader(conn) 151 } 152 if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil { 153 return newError("failed to transport request").Base(err) 154 } 155 156 return nil 157 } 158 159 tproxyRequest := func() error { 160 return nil 161 } 162 163 var writer buf.Writer 164 if network == net.Network_TCP { 165 writer = buf.NewWriter(conn) 166 } else { 167 // if we are in TPROXY mode, use linux's udp forging functionality 168 if !destinationOverridden { 169 writer = &buf.SequentialWriter{Writer: conn} 170 } else { 171 back := conn.RemoteAddr().(*net.UDPAddr) 172 if !dest.Address.Family().IsIP() { 173 if len(back.IP) == 4 { 174 dest.Address = net.AnyIP 175 } else { 176 dest.Address = net.AnyIPv6 177 } 178 } 179 addr := &net.UDPAddr{ 180 IP: dest.Address.IP(), 181 Port: int(dest.Port), 182 } 183 var mark int 184 if d.sockopt != nil { 185 mark = int(d.sockopt.Mark) 186 } 187 pConn, err := FakeUDP(addr, mark) 188 if err != nil { 189 return err 190 } 191 writer = NewPacketWriter(pConn, &dest, mark, back) 192 defer writer.(*PacketWriter).Close() 193 /* 194 sockopt := &internet.SocketConfig{ 195 Tproxy: internet.SocketConfig_TProxy, 196 } 197 if dest.Address.Family().IsIP() { 198 sockopt.BindAddress = dest.Address.IP() 199 sockopt.BindPort = uint32(dest.Port) 200 } 201 if d.sockopt != nil { 202 sockopt.Mark = d.sockopt.Mark 203 } 204 tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt) 205 if err != nil { 206 return err 207 } 208 defer tConn.Close() 209 210 writer = &buf.SequentialWriter{Writer: tConn} 211 tReader := buf.NewPacketReader(tConn) 212 requestCount++ 213 tproxyRequest = func() error { 214 defer func() { 215 if atomic.AddInt32(&requestCount, -1) == 0 { 216 timer.SetTimeout(plcy.Timeouts.DownlinkOnly) 217 } 218 }() 219 if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil { 220 return newError("failed to transport request (TPROXY conn)").Base(err) 221 } 222 return nil 223 } 224 */ 225 } 226 } 227 228 responseDone := func() error { 229 defer timer.SetTimeout(plcy.Timeouts.UplinkOnly) 230 231 if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil { 232 return newError("failed to transport response").Base(err) 233 } 234 return nil 235 } 236 237 if err := task.Run(ctx, task.OnSuccess(func() error { 238 return task.Run(ctx, requestDone, tproxyRequest) 239 }, task.Close(link.Writer)), responseDone); err != nil { 240 common.Interrupt(link.Reader) 241 common.Interrupt(link.Writer) 242 return newError("connection ends").Base(err) 243 } 244 245 return nil 246 } 247 248 func NewPacketWriter(conn net.PacketConn, d *net.Destination, mark int, back *net.UDPAddr) buf.Writer { 249 writer := &PacketWriter{ 250 conn: conn, 251 conns: make(map[net.Destination]net.PacketConn), 252 mark: mark, 253 back: back, 254 } 255 writer.conns[*d] = conn 256 return writer 257 } 258 259 type PacketWriter struct { 260 conn net.PacketConn 261 conns map[net.Destination]net.PacketConn 262 mark int 263 back *net.UDPAddr 264 } 265 266 func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error { 267 for { 268 mb2, b := buf.SplitFirst(mb) 269 mb = mb2 270 if b == nil { 271 break 272 } 273 var err error 274 if b.UDP != nil && b.UDP.Address.Family().IsIP() { 275 conn := w.conns[*b.UDP] 276 if conn == nil { 277 conn, err = FakeUDP( 278 &net.UDPAddr{ 279 IP: b.UDP.Address.IP(), 280 Port: int(b.UDP.Port), 281 }, 282 w.mark, 283 ) 284 if err != nil { 285 newError(err).WriteToLog() 286 b.Release() 287 continue 288 } 289 w.conns[*b.UDP] = conn 290 } 291 _, err = conn.WriteTo(b.Bytes(), w.back) 292 if err != nil { 293 newError(err).WriteToLog() 294 w.conns[*b.UDP] = nil 295 conn.Close() 296 } 297 b.Release() 298 } else { 299 _, err = w.conn.WriteTo(b.Bytes(), w.back) 300 b.Release() 301 if err != nil { 302 buf.ReleaseMulti(mb) 303 return err 304 } 305 } 306 } 307 return nil 308 } 309 310 func (w *PacketWriter) Close() error { 311 for _, conn := range w.conns { 312 if conn != nil { 313 conn.Close() 314 } 315 } 316 return nil 317 }