1// +build !confonly 2 3package shadowsocks 4 5import ( 6 "context" 7 "time" 8 9 core "github.com/v2fly/v2ray-core/v4" 10 "github.com/v2fly/v2ray-core/v4/common" 11 "github.com/v2fly/v2ray-core/v4/common/buf" 12 "github.com/v2fly/v2ray-core/v4/common/log" 13 "github.com/v2fly/v2ray-core/v4/common/net" 14 "github.com/v2fly/v2ray-core/v4/common/protocol" 15 udp_proto "github.com/v2fly/v2ray-core/v4/common/protocol/udp" 16 "github.com/v2fly/v2ray-core/v4/common/session" 17 "github.com/v2fly/v2ray-core/v4/common/signal" 18 "github.com/v2fly/v2ray-core/v4/common/task" 19 "github.com/v2fly/v2ray-core/v4/features/policy" 20 "github.com/v2fly/v2ray-core/v4/features/routing" 21 "github.com/v2fly/v2ray-core/v4/transport/internet" 22 "github.com/v2fly/v2ray-core/v4/transport/internet/udp" 23) 24 25type Server struct { 26 config *ServerConfig 27 user *protocol.MemoryUser 28 policyManager policy.Manager 29} 30 31// NewServer create a new Shadowsocks server. 32func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { 33 if config.GetUser() == nil { 34 return nil, newError("user is not specified") 35 } 36 37 mUser, err := config.User.ToMemoryUser() 38 if err != nil { 39 return nil, newError("failed to parse user account").Base(err) 40 } 41 42 v := core.MustFromContext(ctx) 43 s := &Server{ 44 config: config, 45 user: mUser, 46 policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager), 47 } 48 49 return s, nil 50} 51 52func (s *Server) Network() []net.Network { 53 list := s.config.Network 54 if len(list) == 0 { 55 list = append(list, net.Network_TCP) 56 } 57 if s.config.UdpEnabled { 58 list = append(list, net.Network_UDP) 59 } 60 return list 61} 62 63func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error { 64 switch network { 65 case net.Network_TCP: 66 return s.handleConnection(ctx, conn, dispatcher) 67 case net.Network_UDP: 68 return s.handlerUDPPayload(ctx, conn, dispatcher) 69 default: 70 return newError("unknown network: ", network) 71 } 72} 73 74func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error { 75 udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) { 76 request := protocol.RequestHeaderFromContext(ctx) 77 if request == nil { 78 return 79 } 80 81 payload := packet.Payload 82 data, err := EncodeUDPPacket(request, payload.Bytes()) 83 payload.Release() 84 if err != nil { 85 newError("failed to encode UDP packet").Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx)) 86 return 87 } 88 defer data.Release() 89 90 conn.Write(data.Bytes()) 91 }) 92 93 inbound := session.InboundFromContext(ctx) 94 if inbound == nil { 95 panic("no inbound metadata") 96 } 97 inbound.User = s.user 98 99 reader := buf.NewPacketReader(conn) 100 for { 101 mpayload, err := reader.ReadMultiBuffer() 102 if err != nil { 103 break 104 } 105 106 for _, payload := range mpayload { 107 request, data, err := DecodeUDPPacket(s.user, payload) 108 if err != nil { 109 if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() { 110 newError("dropping invalid UDP packet from: ", inbound.Source).Base(err).WriteToLog(session.ExportIDToError(ctx)) 111 log.Record(&log.AccessMessage{ 112 From: inbound.Source, 113 To: "", 114 Status: log.AccessRejected, 115 Reason: err, 116 }) 117 } 118 payload.Release() 119 continue 120 } 121 122 currentPacketCtx := ctx 123 dest := request.Destination() 124 if inbound.Source.IsValid() { 125 currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ 126 From: inbound.Source, 127 To: dest, 128 Status: log.AccessAccepted, 129 Reason: "", 130 Email: request.User.Email, 131 }) 132 } 133 newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(currentPacketCtx)) 134 135 currentPacketCtx = protocol.ContextWithRequestHeader(currentPacketCtx, request) 136 udpServer.Dispatch(currentPacketCtx, dest, data) 137 } 138 } 139 140 return nil 141} 142 143func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher routing.Dispatcher) error { 144 sessionPolicy := s.policyManager.ForLevel(s.user.Level) 145 conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)) 146 147 bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)} 148 request, bodyReader, err := ReadTCPSession(s.user, &bufferedReader) 149 if err != nil { 150 log.Record(&log.AccessMessage{ 151 From: conn.RemoteAddr(), 152 To: "", 153 Status: log.AccessRejected, 154 Reason: err, 155 }) 156 return newError("failed to create request from: ", conn.RemoteAddr()).Base(err) 157 } 158 conn.SetReadDeadline(time.Time{}) 159 160 inbound := session.InboundFromContext(ctx) 161 if inbound == nil { 162 panic("no inbound metadata") 163 } 164 inbound.User = s.user 165 166 dest := request.Destination() 167 ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{ 168 From: conn.RemoteAddr(), 169 To: dest, 170 Status: log.AccessAccepted, 171 Reason: "", 172 Email: request.User.Email, 173 }) 174 newError("tunnelling request to ", dest).WriteToLog(session.ExportIDToError(ctx)) 175 176 ctx, cancel := context.WithCancel(ctx) 177 timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle) 178 179 ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer) 180 link, err := dispatcher.Dispatch(ctx, dest) 181 if err != nil { 182 return err 183 } 184 185 responseDone := func() error { 186 defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly) 187 188 bufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn)) 189 responseWriter, err := WriteTCPResponse(request, bufferedWriter) 190 if err != nil { 191 return newError("failed to write response").Base(err) 192 } 193 194 { 195 payload, err := link.Reader.ReadMultiBuffer() 196 if err != nil { 197 return err 198 } 199 if err := responseWriter.WriteMultiBuffer(payload); err != nil { 200 return err 201 } 202 } 203 204 if err := bufferedWriter.SetBuffered(false); err != nil { 205 return err 206 } 207 208 if err := buf.Copy(link.Reader, responseWriter, buf.UpdateActivity(timer)); err != nil { 209 return newError("failed to transport all TCP response").Base(err) 210 } 211 212 return nil 213 } 214 215 requestDone := func() error { 216 defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) 217 218 if err := buf.Copy(bodyReader, link.Writer, buf.UpdateActivity(timer)); err != nil { 219 return newError("failed to transport all TCP request").Base(err) 220 } 221 222 return nil 223 } 224 225 var requestDoneAndCloseWriter = task.OnSuccess(requestDone, task.Close(link.Writer)) 226 if err := task.Run(ctx, requestDoneAndCloseWriter, responseDone); err != nil { 227 common.Interrupt(link.Reader) 228 common.Interrupt(link.Writer) 229 return newError("connection ends").Base(err) 230 } 231 232 return nil 233} 234 235func init() { 236 common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 237 return NewServer(ctx, config.(*ServerConfig)) 238 })) 239} 240