瀏覽代碼

Merge pull request #1 from v2ray/master

Update
sunshineplan 8 年之前
父節點
當前提交
6a21f93be0

+ 1 - 1
common/buf/copy.go

@@ -54,7 +54,7 @@ func IgnoreWriterError() CopyOption {
 	}
 }
 
-func UpdateActivity(timer signal.ActivityTimer) CopyOption {
+func UpdateActivity(timer signal.ActivityUpdater) CopyOption {
 	return func(handler *copyHandler) {
 		handler.onData = append(handler.onData, func(MultiBuffer) {
 			timer.Update()

+ 6 - 0
common/common.go

@@ -10,3 +10,9 @@ func Must(err error) {
 		panic(err)
 	}
 }
+
+func Must2(v interface{}, err error) {
+	if err != nil {
+		panic(err)
+	}
+}

+ 29 - 23
common/net/address.go

@@ -35,25 +35,29 @@ const (
 	AddressFamilyDomain = AddressFamily(2)
 )
 
-func (v AddressFamily) Either(fs ...AddressFamily) bool {
+// Either returns true if current AddressFamily matches any of the AddressFamilys provided.
+func (af AddressFamily) Either(fs ...AddressFamily) bool {
 	for _, f := range fs {
-		if v == f {
+		if af == f {
 			return true
 		}
 	}
 	return false
 }
 
-func (v AddressFamily) IsIPv4() bool {
-	return v == AddressFamilyIPv4
+// IsIPv4 returns true if current AddressFamily is IPv4.
+func (af AddressFamily) IsIPv4() bool {
+	return af == AddressFamilyIPv4
 }
 
-func (v AddressFamily) IsIPv6() bool {
-	return v == AddressFamilyIPv6
+// IsIPv6 returns true if current AddressFamily is IPv6.
+func (af AddressFamily) IsIPv6() bool {
+	return af == AddressFamilyIPv6
 }
 
-func (v AddressFamily) IsDomain() bool {
-	return v == AddressFamilyDomain
+// IsDomain returns true if current AddressFamily is Domain.
+func (af AddressFamily) IsDomain() bool {
+	return af == AddressFamilyDomain
 }
 
 // Address represents a network address to be communicated with. It may be an IP address or domain
@@ -106,8 +110,8 @@ func DomainAddress(domain string) Address {
 
 type ipv4Address [4]byte
 
-func (v ipv4Address) IP() net.IP {
-	return net.IP(v[:])
+func (a ipv4Address) IP() net.IP {
+	return net.IP(a[:])
 }
 
 func (ipv4Address) Domain() string {
@@ -118,14 +122,14 @@ func (ipv4Address) Family() AddressFamily {
 	return AddressFamilyIPv4
 }
 
-func (v ipv4Address) String() string {
-	return v.IP().String()
+func (a ipv4Address) String() string {
+	return a.IP().String()
 }
 
 type ipv6Address [16]byte
 
-func (v ipv6Address) IP() net.IP {
-	return net.IP(v[:])
+func (a ipv6Address) IP() net.IP {
+	return net.IP(a[:])
 }
 
 func (ipv6Address) Domain() string {
@@ -136,8 +140,8 @@ func (ipv6Address) Family() AddressFamily {
 	return AddressFamilyIPv6
 }
 
-func (v ipv6Address) String() string {
-	return "[" + v.IP().String() + "]"
+func (a ipv6Address) String() string {
+	return "[" + a.IP().String() + "]"
 }
 
 type domainAddress string
@@ -146,23 +150,24 @@ func (domainAddress) IP() net.IP {
 	panic("Calling IP() on a DomainAddress.")
 }
 
-func (v domainAddress) Domain() string {
-	return string(v)
+func (a domainAddress) Domain() string {
+	return string(a)
 }
 
 func (domainAddress) Family() AddressFamily {
 	return AddressFamilyDomain
 }
 
-func (v domainAddress) String() string {
-	return v.Domain()
+func (a domainAddress) String() string {
+	return a.Domain()
 }
 
-func (v *IPOrDomain) AsAddress() Address {
-	if v == nil {
+// AsAddress translates IPOrDomain to Address.
+func (d *IPOrDomain) AsAddress() Address {
+	if d == nil {
 		return nil
 	}
-	switch addr := v.Address.(type) {
+	switch addr := d.Address.(type) {
 	case *IPOrDomain_Ip:
 		return IPAddress(addr.Ip)
 	case *IPOrDomain_Domain:
@@ -171,6 +176,7 @@ func (v *IPOrDomain) AsAddress() Address {
 	panic("Common|Net: Invalid address.")
 }
 
+// NewIPOrDomain translates Address to IPOrDomain
 func NewIPOrDomain(addr Address) *IPOrDomain {
 	switch addr.Family() {
 	case AddressFamilyDomain:

+ 14 - 12
common/protocol/id.go

@@ -5,6 +5,7 @@ import (
 	"crypto/md5"
 	"hash"
 
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/uuid"
 )
 
@@ -25,31 +26,32 @@ type ID struct {
 }
 
 // Equals returns true if this ID equals to the other one.
-func (v *ID) Equals(another *ID) bool {
-	return v.uuid.Equals(another.uuid)
+func (id *ID) Equals(another *ID) bool {
+	return id.uuid.Equals(another.uuid)
 }
 
-func (v *ID) Bytes() []byte {
-	return v.uuid.Bytes()
+func (id *ID) Bytes() []byte {
+	return id.uuid.Bytes()
 }
 
-func (v *ID) String() string {
-	return v.uuid.String()
+func (id *ID) String() string {
+	return id.uuid.String()
 }
 
-func (v *ID) UUID() *uuid.UUID {
-	return v.uuid
+func (id *ID) UUID() *uuid.UUID {
+	return id.uuid
 }
 
-func (v ID) CmdKey() []byte {
-	return v.cmdKey[:]
+func (id ID) CmdKey() []byte {
+	return id.cmdKey[:]
 }
 
+// NewID returns an ID with given UUID.
 func NewID(uuid *uuid.UUID) *ID {
 	id := &ID{uuid: uuid}
 	md5hash := md5.New()
-	md5hash.Write(uuid.Bytes())
-	md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21"))
+	common.Must2(md5hash.Write(uuid.Bytes()))
+	common.Must2(md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21")))
 	md5hash.Sum(id.cmdKey[:0])
 	return id
 }

+ 1 - 1
common/serial/typed_message.pb.go

@@ -15,7 +15,7 @@ var _ = math.Inf
 // proto package needs to be updated.
 const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
 
-// Serialized proto message along with its type name.
+// TypedMessage is a serialized proto message along with its type name.
 type TypedMessage struct {
 	// The name of the message type, retrieved from protobuf API.
 	Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"`

+ 20 - 10
common/signal/timer.go

@@ -5,33 +5,42 @@ import (
 	"time"
 )
 
-type ActivityTimer interface {
+type ActivityUpdater interface {
 	Update()
 }
 
-type realActivityTimer struct {
+type ActivityTimer struct {
 	updated chan bool
-	timeout time.Duration
+	timeout chan time.Duration
 	ctx     context.Context
 	cancel  context.CancelFunc
 }
 
-func (t *realActivityTimer) Update() {
+func (t *ActivityTimer) Update() {
 	select {
 	case t.updated <- true:
 	default:
 	}
 }
 
-func (t *realActivityTimer) run() {
-	ticker := time.NewTicker(t.timeout)
-	defer ticker.Stop()
+func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
+	t.timeout <- timeout
+}
+
+func (t *ActivityTimer) run() {
+	ticker := time.NewTicker(<-t.timeout)
+	defer func() {
+		ticker.Stop()
+	}()
 
 	for {
 		select {
 		case <-ticker.C:
 		case <-t.ctx.Done():
 			return
+		case timeout := <-t.timeout:
+			ticker.Stop()
+			ticker = time.NewTicker(timeout)
 		}
 
 		select {
@@ -44,14 +53,15 @@ func (t *realActivityTimer) run() {
 	}
 }
 
-func CancelAfterInactivity(ctx context.Context, timeout time.Duration) (context.Context, ActivityTimer) {
+func CancelAfterInactivity(ctx context.Context, timeout time.Duration) (context.Context, *ActivityTimer) {
 	ctx, cancel := context.WithCancel(ctx)
-	timer := &realActivityTimer{
+	timer := &ActivityTimer{
 		ctx:     ctx,
 		cancel:  cancel,
-		timeout: timeout,
+		timeout: make(chan time.Duration, 1),
 		updated: make(chan bool, 1),
 	}
+	timer.timeout <- timeout
 	go timer.run()
 	return ctx, timer
 }

+ 32 - 0
common/signal/timer_test.go

@@ -0,0 +1,32 @@
+package signal_test
+
+import (
+	"context"
+	"runtime"
+	"testing"
+	"time"
+
+	. "v2ray.com/core/common/signal"
+	"v2ray.com/core/testing/assert"
+)
+
+func TestActivityTimer(t *testing.T) {
+	assert := assert.On(t)
+
+	ctx, timer := CancelAfterInactivity(context.Background(), time.Second*5)
+	time.Sleep(time.Second * 6)
+	assert.Error(ctx.Err()).IsNotNil()
+	runtime.KeepAlive(timer)
+}
+
+func TestActivityTimerUpdate(t *testing.T) {
+	assert := assert.On(t)
+
+	ctx, timer := CancelAfterInactivity(context.Background(), time.Second*10)
+	time.Sleep(time.Second * 3)
+	assert.Error(ctx.Err()).IsNil()
+	timer.SetTimeout(time.Second * 1)
+	time.Sleep(time.Second * 2)
+	assert.Error(ctx.Err()).IsNotNil()
+	runtime.KeepAlive(timer)
+}

+ 1 - 1
core.go

@@ -18,7 +18,7 @@ import (
 )
 
 var (
-	version  = "2.38"
+	version  = "2.41"
 	build    = "Custom"
 	codename = "One for all"
 	intro    = "An unified platform for anti-censorship."

+ 4 - 1
proxy/dokodemo/dokodemo.go

@@ -62,7 +62,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
 
 	timeout := time.Second * time.Duration(d.config.Timeout)
 	if timeout == 0 {
-		timeout = time.Minute * 2
+		timeout = time.Minute * 5
 	}
 	ctx, timer := signal.CancelAfterInactivity(ctx, timeout)
 
@@ -94,6 +94,9 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
 		if err := buf.Copy(inboundRay.InboundOutput(), writer, buf.UpdateActivity(timer)); err != nil {
 			return newError("failed to transport response").Base(err)
 		}
+
+		timer.SetTimeout(time.Second * 2)
+
 		return nil
 	})
 

+ 4 - 5
proxy/freedom/freedom.go

@@ -62,11 +62,10 @@ func (v *Handler) ResolveIP(destination net.Destination) net.Destination {
 	}
 
 	ip := ips[dice.Roll(len(ips))]
-	var newDest net.Destination
-	if destination.Network == net.Network_TCP {
-		newDest = net.TCPDestination(net.IPAddress(ip), destination.Port)
-	} else {
-		newDest = net.UDPDestination(net.IPAddress(ip), destination.Port)
+	newDest := net.Destination{
+		Network: destination.Network,
+		Address: net.IPAddress(ip),
+		Port:    destination.Port,
 	}
 	log.Trace(newError("changing destination from ", destination, " to ", newDest))
 	return newDest

+ 2 - 1
proxy/http/server.go

@@ -125,7 +125,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
 
 	timeout := time.Second * time.Duration(s.config.Timeout)
 	if timeout == 0 {
-		timeout = time.Minute * 2
+		timeout = time.Minute * 5
 	}
 	ctx, timer := signal.CancelAfterInactivity(ctx, timeout)
 	ray, err := dispatcher.Dispatch(ctx, dest)
@@ -148,6 +148,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
 		if err := buf.Copy(ray.InboundOutput(), v2writer, buf.UpdateActivity(timer)); err != nil {
 			return err
 		}
+		timer.SetTimeout(time.Second * 2)
 		return nil
 	})
 

+ 1 - 1
proxy/shadowsocks/client.go

@@ -91,7 +91,7 @@ func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, diale
 		request.Option |= RequestOptionOneTimeAuth
 	}
 
-	ctx, timer := signal.CancelAfterInactivity(ctx, time.Minute*2)
+	ctx, timer := signal.CancelAfterInactivity(ctx, time.Minute*5)
 
 	if request.Command == protocol.RequestCommandTCP {
 		bufferedWriter := buf.NewBufferedWriter(conn)

+ 6 - 4
proxy/shadowsocks/server.go

@@ -70,7 +70,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
 	}
 }
 
-func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher dispatcher.Interface) error {
+func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher dispatcher.Interface) error {
 	udpServer := udp.NewDispatcher(dispatcher)
 
 	reader := buf.NewReader(conn)
@@ -81,7 +81,7 @@ func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
 		}
 
 		for _, payload := range mpayload {
-			request, data, err := DecodeUDPPacket(v.user, payload)
+			request, data, err := DecodeUDPPacket(s.user, payload)
 			if err != nil {
 				if source, ok := proxy.SourceFromContext(ctx); ok {
 					log.Trace(newError("dropping invalid UDP packet from: ", source).Base(err))
@@ -91,13 +91,13 @@ func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
 				continue
 			}
 
-			if request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Disabled {
+			if request.Option.Has(RequestOptionOneTimeAuth) && s.account.OneTimeAuth == Account_Disabled {
 				log.Trace(newError("client payload enables OTA but server doesn't allow it"))
 				payload.Release()
 				continue
 			}
 
-			if !request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Enabled {
+			if !request.Option.Has(RequestOptionOneTimeAuth) && s.account.OneTimeAuth == Account_Enabled {
 				log.Trace(newError("client payload disables OTA but server forces it"))
 				payload.Release()
 				continue
@@ -177,6 +177,8 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
 			return newError("failed to transport all TCP response").Base(err)
 		}
 
+		timer.SetTimeout(time.Second * 2)
+
 		return nil
 	})
 

+ 1 - 1
proxy/socks/client.go

@@ -84,7 +84,7 @@ func (c *Client) Process(ctx context.Context, ray ray.OutboundRay, dialer proxy.
 		return newError("failed to establish connection to server").AtWarning().Base(err)
 	}
 
-	ctx, timer := signal.CancelAfterInactivity(ctx, time.Minute*2)
+	ctx, timer := signal.CancelAfterInactivity(ctx, time.Minute*5)
 
 	var requestFunc func() error
 	var responseFunc func() error

+ 18 - 6
proxy/socks/protocol.go

@@ -244,7 +244,7 @@ func writeSocks5AuthenticationResponse(writer io.Writer, version byte, auth byte
 	return err
 }
 
-func appendAddress(buffer *buf.Buffer, address net.Address, port net.Port) {
+func appendAddress(buffer *buf.Buffer, address net.Address, port net.Port) error {
 	switch address.Family() {
 	case net.AddressFamilyIPv4:
 		buffer.AppendBytes(0x01)
@@ -253,16 +253,23 @@ func appendAddress(buffer *buf.Buffer, address net.Address, port net.Port) {
 		buffer.AppendBytes(0x04)
 		buffer.Append(address.IP())
 	case net.AddressFamilyDomain:
+		n := byte(len(address.Domain()))
+		if int(n) != len(address.Domain()) {
+			return newError("Super long domain is not supported in Socks protocol. ", address.Domain())
+		}
 		buffer.AppendBytes(0x03, byte(len(address.Domain())))
 		buffer.AppendSupplier(serial.WriteString(address.Domain()))
 	}
 	buffer.AppendSupplier(serial.WriteUint16(port.Value()))
+	return nil
 }
 
 func writeSocks5Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error {
 	buffer := buf.NewLocal(64)
 	buffer.AppendBytes(socks5Version, errCode, 0x00 /* reserved */)
-	appendAddress(buffer, address, port)
+	if err := appendAddress(buffer, address, port); err != nil {
+		return err
+	}
 
 	_, err := writer.Write(buffer.Bytes())
 	return err
@@ -327,12 +334,14 @@ func DecodeUDPPacket(packet []byte) (*protocol.RequestHeader, []byte, error) {
 	return request, packet[dataBegin:], nil
 }
 
-func EncodeUDPPacket(request *protocol.RequestHeader, data []byte) *buf.Buffer {
+func EncodeUDPPacket(request *protocol.RequestHeader, data []byte) (*buf.Buffer, error) {
 	b := buf.New()
 	b.AppendBytes(0, 0, 0 /* Fragment */)
-	appendAddress(b, request.Address, request.Port)
+	if err := appendAddress(b, request.Address, request.Port); err != nil {
+		return nil, err
+	}
 	b.Append(data)
-	return b
+	return b, nil
 }
 
 type UDPReader struct {
@@ -371,7 +380,10 @@ func NewUDPWriter(request *protocol.RequestHeader, writer io.Writer) *UDPWriter
 
 // Write implements io.Writer.
 func (w *UDPWriter) Write(b []byte) (int, error) {
-	eb := EncodeUDPPacket(w.request, b)
+	eb, err := EncodeUDPPacket(w.request, b)
+	if err != nil {
+		return 0, err
+	}
 	defer eb.Release()
 	if _, err := w.writer.Write(eb.Bytes()); err != nil {
 		return 0, err

+ 6 - 2
proxy/socks/server.go

@@ -108,7 +108,7 @@ func (*Server) handleUDP() error {
 func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
 	timeout := time.Second * time.Duration(v.config.Timeout)
 	if timeout == 0 {
-		timeout = time.Minute * 2
+		timeout = time.Minute * 5
 	}
 	ctx, timer := signal.CancelAfterInactivity(ctx, timeout)
 
@@ -135,6 +135,7 @@ func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
 		if err := buf.Copy(output, v2writer, buf.UpdateActivity(timer)); err != nil {
 			return newError("failed to transport all TCP response").Base(err)
 		}
+		timer.SetTimeout(time.Second * 2)
 		return nil
 	})
 
@@ -187,8 +188,11 @@ func (v *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
 
 				log.Trace(newError("writing back UDP response with ", payload.Len(), " bytes").AtDebug())
 
-				udpMessage := EncodeUDPPacket(request, payload.Bytes())
+				udpMessage, err := EncodeUDPPacket(request, payload.Bytes())
 				defer udpMessage.Release()
+				if err != nil {
+					log.Trace(newError("failed to write UDP response").AtWarning().Base(err))
+				}
 
 				conn.Write(udpMessage.Bytes())
 			})

+ 10 - 10
proxy/vmess/account.go

@@ -13,24 +13,24 @@ type InternalAccount struct {
 	Security protocol.Security
 }
 
-func (v *InternalAccount) AnyValidID() *protocol.ID {
-	if len(v.AlterIDs) == 0 {
-		return v.ID
+func (a *InternalAccount) AnyValidID() *protocol.ID {
+	if len(a.AlterIDs) == 0 {
+		return a.ID
 	}
-	return v.AlterIDs[dice.Roll(len(v.AlterIDs))]
+	return a.AlterIDs[dice.Roll(len(a.AlterIDs))]
 }
 
-func (v *InternalAccount) Equals(account protocol.Account) bool {
+func (a *InternalAccount) Equals(account protocol.Account) bool {
 	vmessAccount, ok := account.(*InternalAccount)
 	if !ok {
 		return false
 	}
 	// TODO: handle AlterIds difference
-	return v.ID.Equals(vmessAccount.ID)
+	return a.ID.Equals(vmessAccount.ID)
 }
 
-func (v *Account) AsAccount() (protocol.Account, error) {
-	id, err := uuid.ParseString(v.Id)
+func (a *Account) AsAccount() (protocol.Account, error) {
+	id, err := uuid.ParseString(a.Id)
 	if err != nil {
 		log.Trace(newError("failed to parse ID").Base(err).AtError())
 		return nil, err
@@ -38,7 +38,7 @@ func (v *Account) AsAccount() (protocol.Account, error) {
 	protoID := protocol.NewID(id)
 	return &InternalAccount{
 		ID:       protoID,
-		AlterIDs: protocol.NewAlterIDs(protoID, uint16(v.AlterId)),
-		Security: v.SecuritySettings.AsSecurity(),
+		AlterIDs: protocol.NewAlterIDs(protoID, uint16(a.AlterId)),
+		Security: a.SecuritySettings.AsSecurity(),
 	}, nil
 }

+ 6 - 5
proxy/vmess/encoding/auth.go

@@ -4,15 +4,16 @@ import (
 	"crypto/md5"
 	"hash/fnv"
 
-	"golang.org/x/crypto/sha3"
-
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/serial"
+
+	"golang.org/x/crypto/sha3"
 )
 
 // Authenticate authenticates a byte array using Fnv hash.
 func Authenticate(b []byte) uint32 {
 	fnv1hash := fnv.New32a()
-	fnv1hash.Write(b)
+	common.Must2(fnv1hash.Write(b))
 	return fnv1hash.Sum32()
 }
 
@@ -81,7 +82,7 @@ type ShakeSizeParser struct {
 
 func NewShakeSizeParser(nonce []byte) *ShakeSizeParser {
 	shake := sha3.NewShake128()
-	shake.Write(nonce)
+	common.Must2(shake.Write(nonce))
 	return &ShakeSizeParser{
 		shake: shake,
 	}
@@ -92,7 +93,7 @@ func (*ShakeSizeParser) SizeBytes() int {
 }
 
 func (s *ShakeSizeParser) next() uint16 {
-	s.shake.Read(s.buffer[:])
+	common.Must2(s.shake.Read(s.buffer[:]))
 	return serial.BytesToUint16(s.buffer[:])
 }
 

+ 24 - 25
proxy/vmess/encoding/client.go

@@ -11,6 +11,7 @@ import (
 	"golang.org/x/crypto/chacha20poly1305"
 
 	"v2ray.com/core/app/log"
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/crypto"
 	"v2ray.com/core/common/dice"
@@ -43,7 +44,7 @@ type ClientSession struct {
 // NewClientSession creates a new ClientSession.
 func NewClientSession(idHash protocol.IDHash) *ClientSession {
 	randomBytes := make([]byte, 33) // 16 + 16 + 1
-	rand.Read(randomBytes)
+	common.Must2(rand.Read(randomBytes))
 
 	session := &ClientSession{}
 	session.requestBodyKey = randomBytes[:16]
@@ -58,22 +59,22 @@ func NewClientSession(idHash protocol.IDHash) *ClientSession {
 	return session
 }
 
-func (v *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) {
+func (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) {
 	timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)()
 	account, err := header.User.GetTypedAccount()
 	if err != nil {
 		log.Trace(newError("failed to get user account: ", err).AtError())
 		return
 	}
-	idHash := v.idHash(account.(*vmess.InternalAccount).AnyValidID().Bytes())
-	idHash.Write(timestamp.Bytes(nil))
-	writer.Write(idHash.Sum(nil))
+	idHash := c.idHash(account.(*vmess.InternalAccount).AnyValidID().Bytes())
+	common.Must2(idHash.Write(timestamp.Bytes(nil)))
+	common.Must2(writer.Write(idHash.Sum(nil)))
 
 	buffer := make([]byte, 0, 512)
 	buffer = append(buffer, Version)
-	buffer = append(buffer, v.requestBodyIV...)
-	buffer = append(buffer, v.requestBodyKey...)
-	buffer = append(buffer, v.responseHeader, byte(header.Option))
+	buffer = append(buffer, c.requestBodyIV...)
+	buffer = append(buffer, c.requestBodyKey...)
+	buffer = append(buffer, c.responseHeader, byte(header.Option))
 	padingLen := dice.Roll(16)
 	if header.Security.Is(protocol.SecurityType_LEGACY) {
 		// Disable padding in legacy mode for a smooth transition.
@@ -100,29 +101,27 @@ func (v *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writ
 
 	if padingLen > 0 {
 		pading := make([]byte, padingLen)
-		rand.Read(pading)
+		common.Must2(rand.Read(pading))
 		buffer = append(buffer, pading...)
 	}
 
 	fnv1a := fnv.New32a()
-	fnv1a.Write(buffer)
+	common.Must2(fnv1a.Write(buffer))
 
 	buffer = fnv1a.Sum(buffer)
 
 	timestampHash := md5.New()
-	timestampHash.Write(hashTimestamp(timestamp))
+	common.Must2(timestampHash.Write(hashTimestamp(timestamp)))
 	iv := timestampHash.Sum(nil)
 	aesStream := crypto.NewAesEncryptionStream(account.(*vmess.InternalAccount).ID.CmdKey(), iv)
 	aesStream.XORKeyStream(buffer, buffer)
-	writer.Write(buffer)
-
-	return
+	common.Must2(writer.Write(buffer))
 }
 
-func (v *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {
+func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {
 	var sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{}
 	if request.Option.Has(protocol.RequestOptionChunkMasking) {
-		sizeParser = NewShakeSizeParser(v.requestBodyIV)
+		sizeParser = NewShakeSizeParser(c.requestBodyIV)
 	}
 	if request.Security.Is(protocol.SecurityType_NONE) {
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
@@ -141,7 +140,7 @@ func (v *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 	}
 
 	if request.Security.Is(protocol.SecurityType_LEGACY) {
-		aesStream := crypto.NewAesEncryptionStream(v.requestBodyKey, v.requestBodyIV)
+		aesStream := crypto.NewAesEncryptionStream(c.requestBodyKey, c.requestBodyIV)
 		cryptionWriter := crypto.NewCryptionWriter(aesStream, writer)
 		if request.Option.Has(protocol.RequestOptionChunkStream) {
 			auth := &crypto.AEADAuthenticator{
@@ -156,13 +155,13 @@ func (v *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 	}
 
 	if request.Security.Is(protocol.SecurityType_AES128_GCM) {
-		block, _ := aes.NewCipher(v.requestBodyKey)
+		block, _ := aes.NewCipher(c.requestBodyKey)
 		aead, _ := cipher.NewGCM(block)
 
 		auth := &crypto.AEADAuthenticator{
 			AEAD: aead,
 			NonceGenerator: &ChunkNonceGenerator{
-				Nonce: append([]byte(nil), v.requestBodyIV...),
+				Nonce: append([]byte(nil), c.requestBodyIV...),
 				Size:  aead.NonceSize(),
 			},
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
@@ -171,12 +170,12 @@ func (v *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 	}
 
 	if request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
-		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(v.requestBodyKey))
+		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey))
 
 		auth := &crypto.AEADAuthenticator{
 			AEAD: aead,
 			NonceGenerator: &ChunkNonceGenerator{
-				Nonce: append([]byte(nil), v.requestBodyIV...),
+				Nonce: append([]byte(nil), c.requestBodyIV...),
 				Size:  aead.NonceSize(),
 			},
 			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
@@ -299,8 +298,8 @@ type ChunkNonceGenerator struct {
 	count uint16
 }
 
-func (v *ChunkNonceGenerator) Next() []byte {
-	serial.Uint16ToBytes(v.count, v.Nonce[:0])
-	v.count++
-	return v.Nonce[:v.Size]
+func (g *ChunkNonceGenerator) Next() []byte {
+	serial.Uint16ToBytes(g.count, g.Nonce[:0])
+	g.count++
+	return g.Nonce[:g.Size]
 }

+ 12 - 11
proxy/vmess/encoding/commands.go

@@ -3,6 +3,7 @@ package encoding
 import (
 	"io"
 
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
@@ -45,8 +46,8 @@ func MarshalCommand(command interface{}, writer io.Writer) error {
 		return ErrCommandTooLarge
 	}
 
-	writer.Write([]byte{cmdID, byte(len), byte(auth >> 24), byte(auth >> 16), byte(auth >> 8), byte(auth)})
-	writer.Write(buffer.Bytes())
+	common.Must2(writer.Write([]byte{cmdID, byte(len), byte(auth >> 24), byte(auth >> 16), byte(auth >> 8), byte(auth)}))
+	common.Must2(writer.Write(buffer.Bytes()))
 	return nil
 }
 
@@ -78,7 +79,7 @@ type CommandFactory interface {
 type CommandSwitchAccountFactory struct {
 }
 
-func (v *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Writer) error {
+func (f *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Writer) error {
 	cmd, ok := command.(*protocol.CommandSwitchAccount)
 	if !ok {
 		return ErrCommandTypeMismatch
@@ -88,25 +89,25 @@ func (v *CommandSwitchAccountFactory) Marshal(command interface{}, writer io.Wri
 	if cmd.Host != nil {
 		hostStr = cmd.Host.String()
 	}
-	writer.Write([]byte{byte(len(hostStr))})
+	common.Must2(writer.Write([]byte{byte(len(hostStr))}))
 
 	if len(hostStr) > 0 {
-		writer.Write([]byte(hostStr))
+		common.Must2(writer.Write([]byte(hostStr)))
 	}
 
-	writer.Write(cmd.Port.Bytes(nil))
+	common.Must2(writer.Write(cmd.Port.Bytes(nil)))
 
 	idBytes := cmd.ID.Bytes()
-	writer.Write(idBytes)
+	common.Must2(writer.Write(idBytes))
 
-	writer.Write(serial.Uint16ToBytes(cmd.AlterIds, nil))
-	writer.Write([]byte{byte(cmd.Level)})
+	common.Must2(writer.Write(serial.Uint16ToBytes(cmd.AlterIds, nil)))
+	common.Must2(writer.Write([]byte{byte(cmd.Level)}))
 
-	writer.Write([]byte{cmd.ValidMin})
+	common.Must2(writer.Write([]byte{cmd.ValidMin}))
 	return nil
 }
 
-func (v *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error) {
+func (f *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, error) {
 	cmd := new(protocol.CommandSwitchAccount)
 	if len(data) == 0 {
 		return nil, newError("insufficient length.")

+ 5 - 4
proxy/vmess/encoding/server.go

@@ -11,6 +11,7 @@ import (
 	"time"
 
 	"golang.org/x/crypto/chacha20poly1305"
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/crypto"
 	"v2ray.com/core/common/net"
@@ -126,7 +127,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 	}
 
 	timestampHash := md5.New()
-	timestampHash.Write(hashTimestamp(timestamp))
+	common.Must2(timestampHash.Write(hashTimestamp(timestamp)))
 	iv := timestampHash.Sum(nil)
 	account, err := user.GetTypedAccount()
 	if err != nil {
@@ -220,7 +221,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
 	}
 
 	fnv1a := fnv.New32a()
-	fnv1a.Write(buffer[:bufferLen])
+	common.Must2(fnv1a.Write(buffer[:bufferLen]))
 	actualHash := fnv1a.Sum32()
 	expectedHash := serial.BytesToUint32(buffer[bufferLen : bufferLen+4])
 
@@ -314,10 +315,10 @@ func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, wr
 	encryptionWriter := crypto.NewCryptionWriter(aesStream, writer)
 	s.responseWriter = encryptionWriter
 
-	encryptionWriter.Write([]byte{s.responseHeader, byte(header.Option)})
+	common.Must2(encryptionWriter.Write([]byte{s.responseHeader, byte(header.Option)}))
 	err := MarshalCommand(header.Command, encryptionWriter)
 	if err != nil {
-		encryptionWriter.Write([]byte{0x00, 0x00})
+		common.Must2(encryptionWriter.Write([]byte{0x00, 0x00}))
 	}
 }
 

+ 3 - 3
proxy/vmess/inbound/inbound.go

@@ -127,17 +127,17 @@ func (v *Handler) GetUser(email string) *protocol.User {
 	return user
 }
 
-func transferRequest(timer signal.ActivityTimer, session *encoding.ServerSession, request *protocol.RequestHeader, input io.Reader, output ray.OutputStream) error {
+func transferRequest(timer signal.ActivityUpdater, session *encoding.ServerSession, request *protocol.RequestHeader, input io.Reader, output ray.OutputStream) error {
 	defer output.Close()
 
 	bodyReader := session.DecodeRequestBody(request, input)
 	if err := buf.Copy(bodyReader, output, buf.UpdateActivity(timer)); err != nil {
-		return err
+		return newError("failed to transfer request").Base(err)
 	}
 	return nil
 }
 
-func transferResponse(timer signal.ActivityTimer, session *encoding.ServerSession, request *protocol.RequestHeader, response *protocol.ResponseHeader, input buf.Reader, output io.Writer) error {
+func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSession, request *protocol.RequestHeader, response *protocol.ResponseHeader, input buf.Reader, output io.Writer) error {
 	session.EncodeResponseHeader(response, output)
 
 	bodyWriter := session.EncodeResponseBody(request, output)

+ 4 - 4
proxy/vmess/outbound/command.go

@@ -9,7 +9,7 @@ import (
 	"v2ray.com/core/proxy/vmess"
 )
 
-func (v *Handler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) {
+func (h *Handler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) {
 	account := &vmess.Account{
 		Id:      cmd.ID.String(),
 		AlterId: uint32(cmd.AlterIds),
@@ -25,16 +25,16 @@ func (v *Handler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) {
 	}
 	dest := net.TCPDestination(cmd.Host, cmd.Port)
 	until := time.Now().Add(time.Duration(cmd.ValidMin) * time.Minute)
-	v.serverList.AddServer(protocol.NewServerSpec(dest, protocol.BeforeTime(until), user))
+	h.serverList.AddServer(protocol.NewServerSpec(dest, protocol.BeforeTime(until), user))
 }
 
-func (v *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) {
+func (h *Handler) handleCommand(dest net.Destination, cmd protocol.ResponseCommand) {
 	switch typedCommand := cmd.(type) {
 	case *protocol.CommandSwitchAccount:
 		if typedCommand.Host == nil {
 			typedCommand.Host = dest.Address
 		}
-		v.handleSwitchAccount(typedCommand)
+		h.handleSwitchAccount(typedCommand)
 	default:
 	}
 }

+ 1 - 1
proxy/vmess/outbound/outbound.go

@@ -104,7 +104,7 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
 
 	session := encoding.NewClientSession(protocol.DefaultIDHash)
 
-	ctx, timer := signal.CancelAfterInactivity(ctx, time.Minute*2)
+	ctx, timer := signal.CancelAfterInactivity(ctx, time.Minute*5)
 
 	requestDone := signal.ExecuteAsync(func() error {
 		writer := buf.NewBufferedWriter(conn)

+ 3 - 2
proxy/vmess/vmess.go

@@ -12,6 +12,7 @@ import (
 	"sync"
 	"time"
 
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/protocol"
 )
 
@@ -60,11 +61,11 @@ func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, idx in
 	var hashValueRemoval [16]byte
 	idHash := v.hasher(entry.id.Bytes())
 	for entry.lastSec <= nowSec {
-		idHash.Write(entry.lastSec.Bytes(nil))
+		common.Must2(idHash.Write(entry.lastSec.Bytes(nil)))
 		idHash.Sum(hashValue[:0])
 		idHash.Reset()
 
-		idHash.Write(entry.lastSecRemoval.Bytes(nil))
+		common.Must2(idHash.Write(entry.lastSecRemoval.Bytes(nil)))
 		idHash.Sum(hashValueRemoval[:0])
 		idHash.Reset()
 

File diff suppressed because it is too large
+ 0 - 0
tools/geoip/geoip.generated.go


+ 1 - 1
transport/internet/kcp/connection.go

@@ -214,7 +214,7 @@ func NewConnection(conv uint16, sysConn SystemConnection, config *Config) *Conne
 		dataInput:  make(chan bool, 1),
 		dataOutput: make(chan bool, 1),
 		Config:     config,
-		output:     NewSegmentWriter(sysConn),
+		output:     NewRetryableWriter(NewSegmentWriter(sysConn)),
 		mss:        config.GetMTUValue() - uint32(sysConn.Overhead()) - DataSegmentOverhead,
 		roundTrip: &RoundTripInfo{
 			rto:    100,

+ 3 - 2
transport/internet/kcp/crypt.go

@@ -4,6 +4,7 @@ import (
 	"crypto/cipher"
 	"hash/fnv"
 
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/serial"
 )
 
@@ -32,7 +33,7 @@ func (a *SimpleAuthenticator) Seal(dst, nonce, plain, extra []byte) []byte {
 	dst = append(dst, plain...)
 
 	fnvHash := fnv.New32a()
-	fnvHash.Write(dst[4:])
+	common.Must2(fnvHash.Write(dst[4:]))
 	fnvHash.Sum(dst[:0])
 
 	len := len(dst)
@@ -61,7 +62,7 @@ func (a *SimpleAuthenticator) Open(dst, nonce, cipherText, extra []byte) ([]byte
 	}
 
 	fnvHash := fnv.New32a()
-	fnvHash.Write(dst[4:])
+	common.Must2(fnvHash.Write(dst[4:]))
 	if serial.BytesToUint32(dst[:4]) != fnvHash.Sum32() {
 		return nil, newError("invalid auth")
 	}

+ 24 - 5
transport/internet/kcp/output.go

@@ -4,6 +4,9 @@ import (
 	"io"
 	"sync"
 
+	"v2ray.com/core/common/retry"
+
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 )
 
@@ -24,11 +27,27 @@ func NewSegmentWriter(writer io.Writer) SegmentWriter {
 	}
 }
 
-func (v *SimpleSegmentWriter) Write(seg Segment) error {
-	v.Lock()
-	defer v.Unlock()
+func (w *SimpleSegmentWriter) Write(seg Segment) error {
+	w.Lock()
+	defer w.Unlock()
 
-	v.buffer.Reset(seg.Bytes())
-	_, err := v.writer.Write(v.buffer.Bytes())
+	common.Must(w.buffer.Reset(seg.Bytes()))
+	_, err := w.writer.Write(w.buffer.Bytes())
 	return err
 }
+
+type RetryableWriter struct {
+	writer SegmentWriter
+}
+
+func NewRetryableWriter(writer SegmentWriter) SegmentWriter {
+	return &RetryableWriter{
+		writer: writer,
+	}
+}
+
+func (w *RetryableWriter) Write(seg Segment) error {
+	return retry.Timed(5, 100).On(func() error {
+		return w.writer.Write(seg)
+	})
+}

+ 1 - 1
transport/internet/websocket/dialer.go

@@ -17,7 +17,7 @@ func Dial(ctx context.Context, dest net.Destination) (internet.Connection, error
 
 	conn, err := dialWebsocket(ctx, dest)
 	if err != nil {
-		return nil, newError("failed to dial WebSocket")
+		return nil, newError("failed to dial WebSocket").Base(err)
 	}
 	return internet.Connection(conn), nil
 }

Some files were not shown because too many files changed in this diff