func DecodeUDPPacket(user *protocol.User, payload *buf.Buffer) (*protocol.RequestHeader, *buf.Buffer, error) { rawAccount, err := user.GetTypedAccount() if err != nil { return nil, nil, errors.Base(err).Message("Shadowsocks|UDP: Failed to parse account.") } account := rawAccount.(*ShadowsocksAccount) ivLen := account.Cipher.IVSize() iv := payload.BytesTo(ivLen) payload.SliceFrom(ivLen) stream, err := account.Cipher.NewDecodingStream(account.Key, iv) if err != nil { return nil, nil, errors.Base(err).Message("Shadowsocks|UDP: Failed to initialize decoding stream.") } stream.XORKeyStream(payload.Bytes(), payload.Bytes()) authenticator := NewAuthenticator(HeaderKeyGenerator(account.Key, iv)) request := &protocol.RequestHeader{ Version: Version, User: user, Command: protocol.RequestCommandUDP, } addrType := (payload.Byte(0) & 0x0F) if (payload.Byte(0) & 0x10) == 0x10 { request.Option |= RequestOptionOneTimeAuth } if request.Option.Has(RequestOptionOneTimeAuth) && account.OneTimeAuth == Account_Disabled { return nil, nil, errors.New("Shadowsocks|UDP: Rejecting packet with OTA enabled, while server disables OTA.") } if !request.Option.Has(RequestOptionOneTimeAuth) && account.OneTimeAuth == Account_Enabled { return nil, nil, errors.New("Shadowsocks|UDP: Rejecting packet with OTA disabled, while server enables OTA.") } if request.Option.Has(RequestOptionOneTimeAuth) { payloadLen := payload.Len() - AuthSize authBytes := payload.BytesFrom(payloadLen) actualAuth := make([]byte, AuthSize) authenticator.Authenticate(payload.BytesTo(payloadLen))(actualAuth) if !bytes.Equal(actualAuth, authBytes) { return nil, nil, errors.New("Shadowsocks|UDP: Invalid OTA.") } payload.Slice(0, payloadLen) } payload.SliceFrom(1) switch addrType { case AddrTypeIPv4: request.Address = v2net.IPAddress(payload.BytesTo(4)) payload.SliceFrom(4) case AddrTypeIPv6: request.Address = v2net.IPAddress(payload.BytesTo(16)) payload.SliceFrom(16) case AddrTypeDomain: domainLength := int(payload.Byte(0)) request.Address = v2net.DomainAddress(string(payload.BytesRange(1, 1+domainLength))) payload.SliceFrom(1 + domainLength) default: return nil, nil, errors.New("Shadowsocks|UDP: Unknown address type: ", addrType) } request.Port = v2net.PortFromBytes(payload.BytesTo(2)) payload.SliceFrom(2) return request, payload, nil }