diff --git a/common/protocol/headers.go b/common/protocol/headers.go index 2b6c538c64e..83a5fdd6df8 100644 --- a/common/protocol/headers.go +++ b/common/protocol/headers.go @@ -48,8 +48,6 @@ type RequestHeader struct { Port net.Port Address net.Address User *MemoryUser - MessName string - MessSeed []byte } func (h *RequestHeader) Destination() net.Destination { diff --git a/proxy/vless/encoding/addons.go b/proxy/vless/encoding/addons.go new file mode 100644 index 00000000000..6f06d6310ef --- /dev/null +++ b/proxy/vless/encoding/addons.go @@ -0,0 +1,127 @@ +// +build !confonly + +package encoding + +import ( + "crypto/rand" + "io" + + "v2ray.com/core/common" + "v2ray.com/core/common/buf" + "v2ray.com/core/common/crypto" + "v2ray.com/core/common/protocol" + + "github.com/golang/protobuf/proto" +) + +func EncodeAddonsHeader(addons *Addons, buffer *buf.Buffer) { + + switch addons.MessName { + case "shake": + + addons.MessSeed = make([]byte, 16) + rand.Read(addons.MessSeed) + + bytes := common.Must2(proto.Marshal(addons)).([]byte) + + common.Must(buffer.WriteByte(byte(len(bytes)))) + common.Must2(buffer.Write(bytes)) + + default: + + common.Must(buffer.WriteByte(0)) + + } + +} + +func DecodeAddonsHeader(reader io.Reader, buffer *buf.Buffer) (*Addons, error) { + + addons := &Addons{} + + buffer.Clear() + if _, err := buffer.ReadFullFrom(reader, 1); err != nil { + return nil, newError("failed to read addons length").Base(err) + } + + length := int32(buffer.Byte(0)) + if length != 0 { + + buffer.Clear() + if _, err := buffer.ReadFullFrom(reader, length); err != nil { + return nil, newError("failed to read addons bytes").Base(err) + } + + common.Must(proto.Unmarshal(buffer.Bytes(), addons)) + + // Verification + switch addons.MessName { + case "shake": + if len(addons.MessSeed) != 16 { + return nil, newError("mess: shake's seed length is not 16") + } + } + + } + + return addons, nil + +} + +// EncodeAddonsBody returns a Writer that auto-encrypt content written by caller. +func EncodeAddonsBody(request *protocol.RequestHeader, addons *Addons, writer io.Writer) buf.Writer { + + switch addons.MessName { + case "shake": + + var sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{} + sizeParser = NewShakeSizeParser(addons.MessSeed) + var padding crypto.PaddingLengthGenerator + //padding = sizeParser.(crypto.PaddingLengthGenerator) + + if request.Command.TransferType() == protocol.TransferTypeStream { + return crypto.NewChunkStreamWriter(sizeParser, writer) + } + auth := &crypto.AEADAuthenticator{ + AEAD: new(NoOpAuthenticator), + NonceGenerator: crypto.GenerateEmptyBytes(), + AdditionalDataGenerator: crypto.GenerateEmptyBytes(), + } + return crypto.NewAuthenticationWriter(auth, sizeParser, writer, protocol.TransferTypePacket, padding) + + default: + + return buf.NewWriter(writer) + + } + +} + +// DecodeAddonsBody returns a Reader from which caller can fetch decrypted body. +func DecodeAddonsBody(request *protocol.RequestHeader, addons *Addons, reader io.Reader) buf.Reader { + + switch addons.MessName { + case "shake": + + var sizeParser crypto.ChunkSizeDecoder = crypto.PlainChunkSizeParser{} + sizeParser = NewShakeSizeParser(addons.MessSeed) + var padding crypto.PaddingLengthGenerator + //padding = sizeParser.(crypto.PaddingLengthGenerator) + + if request.Command.TransferType() == protocol.TransferTypeStream { + return crypto.NewChunkStreamReader(sizeParser, reader) + } + auth := &crypto.AEADAuthenticator{ + AEAD: new(NoOpAuthenticator), + NonceGenerator: crypto.GenerateEmptyBytes(), + AdditionalDataGenerator: crypto.GenerateEmptyBytes(), + } + return crypto.NewAuthenticationReader(auth, sizeParser, reader, protocol.TransferTypePacket, padding) + + default: + + return buf.NewReader(reader) + + } + +} diff --git a/proxy/vless/encoding/addons.pb.go b/proxy/vless/encoding/addons.pb.go new file mode 100644 index 00000000000..bd78b4c9c64 --- /dev/null +++ b/proxy/vless/encoding/addons.pb.go @@ -0,0 +1,385 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: v2ray.com/core/proxy/vless/encoding/addons.proto + +package encoding + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Addons struct { + MessName string `protobuf:"bytes,1,opt,name=MessName,proto3" json:"MessName,omitempty"` + MessSeed []byte `protobuf:"bytes,2,opt,name=MessSeed,proto3" json:"MessSeed,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Addons) Reset() { *m = Addons{} } +func (m *Addons) String() string { return proto.CompactTextString(m) } +func (*Addons) ProtoMessage() {} +func (*Addons) Descriptor() ([]byte, []int) { + return fileDescriptor_d597c8244066ecf1, []int{0} +} +func (m *Addons) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Addons) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Addons.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Addons) XXX_Merge(src proto.Message) { + xxx_messageInfo_Addons.Merge(m, src) +} +func (m *Addons) XXX_Size() int { + return m.Size() +} +func (m *Addons) XXX_DiscardUnknown() { + xxx_messageInfo_Addons.DiscardUnknown(m) +} + +var xxx_messageInfo_Addons proto.InternalMessageInfo + +func (m *Addons) GetMessName() string { + if m != nil { + return m.MessName + } + return "" +} + +func (m *Addons) GetMessSeed() []byte { + if m != nil { + return m.MessSeed + } + return nil +} + +func init() { + proto.RegisterType((*Addons)(nil), "v2ray.core.proxy.vless.encoding.Addons") +} + +func init() { + proto.RegisterFile("v2ray.com/core/proxy/vless/encoding/addons.proto", fileDescriptor_d597c8244066ecf1) +} + +var fileDescriptor_d597c8244066ecf1 = []byte{ + // 191 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x28, 0x33, 0x2a, 0x4a, + 0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x28, 0xca, 0xaf, 0xa8, + 0xd4, 0x2f, 0xcb, 0x49, 0x2d, 0x2e, 0xd6, 0x4f, 0xcd, 0x4b, 0xce, 0x4f, 0xc9, 0xcc, 0x4b, 0xd7, + 0x4f, 0x4c, 0x49, 0xc9, 0xcf, 0x2b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x87, 0xe9, + 0x28, 0x4a, 0xd5, 0x03, 0xab, 0xd6, 0x03, 0xab, 0xd6, 0x83, 0xa9, 0x56, 0x72, 0xe0, 0x62, 0x73, + 0x04, 0x6b, 0x10, 0x92, 0xe2, 0xe2, 0xf0, 0x4d, 0x2d, 0x2e, 0xf6, 0x4b, 0xcc, 0x4d, 0x95, 0x60, + 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x82, 0xf3, 0x61, 0x72, 0xc1, 0xa9, 0xa9, 0x29, 0x12, 0x4c, 0x0a, + 0x8c, 0x1a, 0x3c, 0x41, 0x70, 0xbe, 0x53, 0xf2, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, + 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe3, 0xb1, 0x1c, 0x03, 0x97, 0x72, 0x72, 0x7e, 0xae, 0x1e, 0x01, + 0x8b, 0x03, 0x18, 0xa3, 0x38, 0x60, 0xec, 0x55, 0x4c, 0xf2, 0x61, 0x46, 0x41, 0x89, 0x95, 0x7a, + 0xce, 0x20, 0xd5, 0x01, 0x60, 0xd5, 0x61, 0x60, 0xd5, 0xae, 0x50, 0x15, 0x49, 0x6c, 0x60, 0xef, + 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x1b, 0xf5, 0xa1, 0x34, 0x02, 0x01, 0x00, 0x00, +} + +func (m *Addons) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Addons) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Addons) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.MessSeed) > 0 { + i -= len(m.MessSeed) + copy(dAtA[i:], m.MessSeed) + i = encodeVarintAddons(dAtA, i, uint64(len(m.MessSeed))) + i-- + dAtA[i] = 0x12 + } + if len(m.MessName) > 0 { + i -= len(m.MessName) + copy(dAtA[i:], m.MessName) + i = encodeVarintAddons(dAtA, i, uint64(len(m.MessName))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintAddons(dAtA []byte, offset int, v uint64) int { + offset -= sovAddons(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Addons) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.MessName) + if l > 0 { + n += 1 + l + sovAddons(uint64(l)) + } + l = len(m.MessSeed) + if l > 0 { + n += 1 + l + sovAddons(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovAddons(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAddons(x uint64) (n int) { + return sovAddons(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Addons) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAddons + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Addons: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Addons: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MessName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAddons + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAddons + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAddons + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MessName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MessSeed", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAddons + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAddons + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAddons + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MessSeed = append(m.MessSeed[:0], dAtA[iNdEx:postIndex]...) + if m.MessSeed == nil { + m.MessSeed = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAddons(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthAddons + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthAddons + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAddons(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAddons + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAddons + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAddons + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAddons + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAddons + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAddons + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAddons = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAddons = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAddons = fmt.Errorf("proto: unexpected end of group") +) diff --git a/proxy/vless/encoding/addons.proto b/proxy/vless/encoding/addons.proto new file mode 100644 index 00000000000..7530e2a73e1 --- /dev/null +++ b/proxy/vless/encoding/addons.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package v2ray.core.proxy.vless.encoding; +option csharp_namespace = "V2Ray.Core.Proxy.Vless.Encoding"; +option go_package = "encoding"; +option java_package = "com.v2ray.core.proxy.vless.encoding"; +option java_multiple_files = true; + +message Addons { + string MessName = 1; + bytes MessSeed = 2; +} diff --git a/proxy/vless/encoding/encoding.go b/proxy/vless/encoding/encoding.go index f6d04947673..59f95cc878c 100644 --- a/proxy/vless/encoding/encoding.go +++ b/proxy/vless/encoding/encoding.go @@ -1,14 +1,19 @@ package encoding import ( + "io" + + "v2ray.com/core/common" + "v2ray.com/core/common/buf" "v2ray.com/core/common/net" "v2ray.com/core/common/protocol" + "v2ray.com/core/proxy/vless" ) //go:generate errorgen const ( - Version = byte(1) + Version = byte(0) ) var addrParser = protocol.NewAddressParser( @@ -17,3 +22,128 @@ var addrParser = protocol.NewAddressParser( protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6), protocol.PortThenAddress(), ) + +// EncodeRequestHeader writes encoded request header into the given writer. +func EncodeRequestHeader(request *protocol.RequestHeader, addons *Addons, writer io.Writer) error { + + buffer := buf.StackNew() + defer buffer.Release() + + common.Must(buffer.WriteByte(request.Version)) + common.Must2(buffer.Write(request.User.Account.(*vless.MemoryAccount).ID.Bytes())) + + EncodeAddonsHeader(addons, &buffer) + + common.Must(buffer.WriteByte(byte(request.Command))) + if request.Command != protocol.RequestCommandMux { + if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil { + return newError("failed to write address and port").Base(err) + } + } + + common.Must2(writer.Write(buffer.Bytes())) + return nil +} + +// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream. +func DecodeRequestHeader(validator *vless.UserValidator, reader io.Reader) (*protocol.RequestHeader, *Addons, error) { + + buffer := buf.StackNew() + defer buffer.Release() + + if _, err := buffer.ReadFullFrom(reader, 1); err != nil { + return nil, nil, newError("failed to read request version").Base(err).AtWarning() + } + + request := &protocol.RequestHeader{ + Version: buffer.Byte(0), + } + + switch request.Version { + case 0: + + buffer.Clear() + if _, err := buffer.ReadFullFrom(reader, protocol.IDBytesLen); err != nil { + return nil, nil, newError("failed to read request user").Base(err) + } + + var id [16]byte + copy(id[:], buffer.Bytes()) + user, valid := validator.Get(id) + if !valid { + return nil, nil, newError("invalid request user") + } + request.User = user + + addons, err := DecodeAddonsHeader(reader, &buffer) + if err != nil { + return nil, nil, err + } + + buffer.Clear() + if _, err := buffer.ReadFullFrom(reader, 1); err != nil { + return nil, nil, newError("failed to read request command").Base(err) + } + + request.Command = protocol.RequestCommand(buffer.Byte(0)) + + switch request.Command { + case protocol.RequestCommandMux: + request.Address = net.DomainAddress("v1.mux.cool") + request.Port = 0 + case protocol.RequestCommandTCP, protocol.RequestCommandUDP: + if addr, port, err := addrParser.ReadAddressPort(&buffer, reader); err == nil { + request.Address = addr + request.Port = port + } + } + + if request.Address == nil { + return nil, nil, newError("invalid request address") + } + + return request, addons, nil + + default: + + return nil, nil, newError("unexpected request version") + + } + +} + +// EncodeResponseHeader writes encoded response header into the given writer. +func EncodeResponseHeader(request *protocol.RequestHeader, response *Addons, writer io.Writer) error { + + buffer := buf.StackNew() + defer buffer.Release() + + common.Must(buffer.WriteByte(request.Version)) + + EncodeAddonsHeader(response, &buffer) + + common.Must2(writer.Write(buffer.Bytes())) + return nil +} + +// DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream. +func DecodeResponseHeader(request *protocol.RequestHeader, reader io.Reader) (*Addons, error) { + + buffer := buf.StackNew() + defer buffer.Release() + + if _, err := buffer.ReadFullFrom(reader, 1); err != nil { + return nil, newError("failed to read response version").Base(err).AtWarning() + } + + if buffer.Byte(0) != request.Version { + return nil, newError("unexpected response version. Expecting ", int(request.Version), " but actually ", int(buffer.Byte(0))) + } + + response, err := DecodeAddonsHeader(reader, &buffer) + if err != nil { + return nil, err + } + + return response, nil +} diff --git a/proxy/vless/inbound/inbound.go b/proxy/vless/inbound/inbound.go index e745713d339..87d6c44b9d8 100644 --- a/proxy/vless/inbound/inbound.go +++ b/proxy/vless/inbound/inbound.go @@ -172,41 +172,6 @@ func (h *Handler) RemoveUser(ctx context.Context, email string) error { return nil } -func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSession, response *protocol.RequestHeader, input buf.Reader, output *buf.BufferedWriter) error { - - session.EncodeResponseHeader(response, output) - bodyWriter := session.EncodeResponseBody(response, output) - - { - // Optimize for small response packet - data, err := input.ReadMultiBuffer() - if err != nil { - return err - } - - if err := bodyWriter.WriteMultiBuffer(data); err != nil { - return err - } - } - - if err := output.SetBuffered(false); err != nil { - return err - } - - if err := buf.Copy(input, bodyWriter, buf.UpdateActivity(timer)); err != nil { - return err - } - - // Indicates the end of transmission - if response.MessName == "shake" { - if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil { - return err - } - } - - return nil -} - // Process implements proxy.Inbound.Process(). func (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher routing.Dispatcher) error { sessionPolicy := h.policyManager.ForLevel(0) @@ -215,8 +180,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i } reader := &buf.BufferedReader{Reader: buf.NewReader(connection)} - svrSession := encoding.NewServerSession(h.clients) - request, err := svrSession.DecodeRequestHeader(reader) + request, addons, err := encoding.DecodeRequestHeader(h.clients, reader) if err != nil { if errors.Cause(err) != io.EOF { log.Record(&log.AccessMessage{ @@ -266,10 +230,11 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i requestDone := func() error { defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) - bodyReader := svrSession.DecodeRequestBody(request, reader) + bodyReader := encoding.DecodeAddonsBody(request, addons, reader) if err := buf.Copy(bodyReader, link.Writer, buf.UpdateActivity(timer)); err != nil { return newError("failed to transfer request").Base(err) } + return nil } @@ -279,10 +244,43 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i writer := buf.NewBufferedWriter(buf.NewWriter(connection)) defer writer.Flush() - response := &protocol.RequestHeader{ - MessName: request.MessName, + response := &encoding.Addons{ + MessName: addons.MessName, + } + + if err := encoding.EncodeResponseHeader(request, response, writer); err != nil { + return newError("failed to encode response").Base(err).AtWarning() + } + bodyWriter := encoding.EncodeAddonsBody(request, response, writer) + + { + // Optimize for small response packet + data, err := link.Reader.ReadMultiBuffer() + if err != nil { + return err + } + + if err := bodyWriter.WriteMultiBuffer(data); err != nil { + return err + } + } + + if err := writer.SetBuffered(false); err != nil { + return err + } + + if err := buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil { + return err } - return transferResponse(timer, svrSession, response, link.Reader, writer) + + // Indicates the end of transmission + if response.MessName == "shake" { + if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil { + return err + } + } + + return nil } var requestDonePost = task.OnSuccess(requestDone, task.Close(link.Writer)) diff --git a/proxy/vless/outbound/config.go b/proxy/vless/outbound/config.go index a1e73e06682..35bf561b663 100644 --- a/proxy/vless/outbound/config.go +++ b/proxy/vless/outbound/config.go @@ -1 +1,3 @@ +// +build !confonly + package outbound diff --git a/proxy/vless/outbound/outbound.go b/proxy/vless/outbound/outbound.go index b5018772b36..5d842488cc7 100644 --- a/proxy/vless/outbound/outbound.go +++ b/proxy/vless/outbound/outbound.go @@ -6,7 +6,6 @@ package outbound import ( "context" - "math/rand" "time" "v2ray.com/core" @@ -29,8 +28,6 @@ func init() { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { return New(ctx, config.(*Config)) })) - - rand.Seed(time.Now().UnixNano()) } // Handler is an outbound connection handler for VLess protocol. @@ -98,20 +95,24 @@ func (v *Handler) Process(ctx context.Context, link *transport.Link, dialer inte } request := &protocol.RequestHeader{ + Version: encoding.Version, User: rec.PickUser(), Command: command, Address: target.Address, Port: target.Port, + //Option: protocol.RequestOptionChunkStream, } account := request.User.Account.(*vless.MemoryAccount) - request.MessName = account.Mess //request.Security = account.Security + addons := &encoding.Addons{ + MessName: account.Mess, + } + input := link.Reader output := link.Writer - session := encoding.NewClientSession() sessionPolicy := v.policyManager.ForLevel(request.User.Level) ctx, cancel := context.WithCancel(ctx) @@ -121,11 +122,11 @@ func (v *Handler) Process(ctx context.Context, link *transport.Link, dialer inte defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly) writer := buf.NewBufferedWriter(buf.NewWriter(conn)) - if err := session.EncodeRequestHeader(request, writer); err != nil { + if err := encoding.EncodeRequestHeader(request, addons, writer); err != nil { return newError("failed to encode request").Base(err).AtWarning() } - bodyWriter := session.EncodeRequestBody(request, writer) + bodyWriter := encoding.EncodeAddonsBody(request, addons, writer) if err := buf.CopyOnceTimeout(input, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout { return newError("failed to write first payload").Base(err) } @@ -139,7 +140,7 @@ func (v *Handler) Process(ctx context.Context, link *transport.Link, dialer inte } // Indicates the end of transmission - if request.MessName == "shake" { + if addons.MessName == "shake" { if err := bodyWriter.WriteMultiBuffer(buf.MultiBuffer{}); err != nil { return err } @@ -152,12 +153,12 @@ func (v *Handler) Process(ctx context.Context, link *transport.Link, dialer inte defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly) reader := &buf.BufferedReader{Reader: buf.NewReader(conn)} - response, err := session.DecodeResponseHeader(reader) + response, err := encoding.DecodeResponseHeader(request, reader) if err != nil { return newError("failed to read header").Base(err) } - bodyReader := session.DecodeResponseBody(response, reader) + bodyReader := encoding.DecodeAddonsBody(request, response, reader) return buf.Copy(bodyReader, output, buf.UpdateActivity(timer)) }