static void ParseErrorResponseUDP(KerberosData KerbData, TDSReader ByteReader)
        {
            int TagID = 0, TagLen = 0;

            do
            {
                TagID  = ByteReader.ReadByte() & (int)0x1F;
                TagLen = ReadAsnLen(ByteReader, false);

                switch (TagID)
                {
                case 4:     //skip Tag4->Stime,
                case 5:     //skip Tag5->SuSec
                {
                    ByteReader.ReadBytes(TagLen);
                    break;
                }

                case 6:
                {
                    ReadAsnLen(ByteReader);
                    KerbData.errorCode = ByteReader.ReadByte();
                    KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode);
                    return;
                }

                default:
                {
                    //throw new Exception("Unexpected Tag " + TagID + " found in  KERB UDP error response");
                    break;
                }
                }
            }while (TagID < 6); //Total 12 tags expected, but we are reading only 6 tags until error code
        }
 public void Read(TDSReader r)
 {
     PacketType = r.ReadByte();
     if (PacketType != (byte)TDSPacketType.SQLBATCH &&
         PacketType != (byte)TDSPacketType.LOGIN &&
         PacketType != (byte)TDSPacketType.RPC &&
         PacketType != (byte)TDSPacketType.RESPONSE &&
         PacketType != (byte)TDSPacketType.ATTENTION &&
         PacketType != (byte)TDSPacketType.BULKLOAD &&
         PacketType != (byte)TDSPacketType.DTC &&
         PacketType != (byte)TDSPacketType.LOGIN7 &&
         PacketType != (byte)TDSPacketType.SSPI &&
         PacketType != (byte)TDSPacketType.PRELOGIN &&
         PacketType != (byte)TDSPacketType.APPDATA)
     {
         throw new InvalidTDSException("Unknown token type: " + PacketType);
     }
     Status = r.ReadByte();
     if (Status > 31)
     {
         throw new InvalidTDSException("Unknown Status value: " + Status);               // supposed to ignore other flag fields
     }
     Length   = r.ReadBigEndianUInt16();
     SPID     = r.ReadBigEndianUInt16();
     PacketID = r.ReadByte();
     Window   = r.ReadByte();
     if (Window != 0)
     {
         throw new InvalidTDSException("Invalid TDS Window value: " + Window);              // supposed to ignore
     }
 }
Exemple #3
0
        public static TDSHeader Read(TDSReader r)   // TODo - not all token types have a TDS Header, like APPDATA or perhaps SSPI - needs more research
        {
            TDSHeader head = new TDSHeader();

            head.PacketType = r.ReadByte();
            if (head.PacketType != (byte)TDSPacketType.SQLBATCH &&
                head.PacketType != (byte)TDSPacketType.LOGIN &&
                head.PacketType != (byte)TDSPacketType.RPC &&
                head.PacketType != (byte)TDSPacketType.RESPONSE &&
                head.PacketType != (byte)TDSPacketType.ATTENTION &&
                head.PacketType != (byte)TDSPacketType.BULKLOAD &&
                head.PacketType != (byte)TDSPacketType.DTC &&
                head.PacketType != (byte)TDSPacketType.LOGIN7 &&
                head.PacketType != (byte)TDSPacketType.SSPI &&
                head.PacketType != (byte)TDSPacketType.PRELOGIN &&
                head.PacketType != (byte)TDSPacketType.APPDATA)
            {
                throw new InvalidTDSException("Unknown token type: " + head.PacketType);
            }
            head.Status = r.ReadByte();
            if (head.Status > 31)
            {
                throw new InvalidTDSException("Unknown Status value: " + head.Status);                    // supposed to ignore other flag fields
            }
            head.Length   = r.ReadBigEndianUInt16();
            head.SPID     = r.ReadBigEndianUInt16();
            head.PacketID = r.ReadByte();
            head.Window   = r.ReadByte();
            if (head.Window != 0)
            {
                throw new InvalidTDSException("Invalid TDS Window value: " + head.Window);                   // supposed to ignore
            }
            return(head);
        }
        public void Read(TDSReader r)
        {
            byte FeatureID = r.ReadByte();

            while (FeatureID != 0xFF)
            {
                FeatureExtAckData data = new FeatureExtAckData();
                data.FeatureID   = FeatureID;
                data.FeatureData = r.ReadBytes4();
                FeatureID        = r.ReadByte();
            }
        }
 public void Read(TDSReader r)
 {
     Length = r.ReadUInt16();
     r.TokenStart(Length);
     Number        = r.ReadUInt32();
     State         = r.ReadByte();
     Class         = r.ReadByte();
     Message       = r.ReadUnicodeString2();
     ServerName    = r.ReadUnicodeString1();
     ProcedureName = r.ReadUnicodeString1();
     LineNumber    = r.ReadUInt32();
     r.TokenDone();
 }
        static MessageTypes GetMessageType(KerberosData KerbData, TDSReader ByteReader)
        {
            int Len = ReadAsnLen(ByteReader);

            int MsgType = ByteReader.ReadByte();

            if (Len == 1)
            {
                if (MsgType == (int)MessageTypes.KRB_TGS_REQ)
                {
                    KerbData.RequestType = MessageTypes.KRB_TGS_REQ;
                }
                else if (MsgType == (int)MessageTypes.KRB_ERROR)
                {
                    KerbData.ResponseType = MessageTypes.KRB_ERROR;
                }
                else if (MsgType == (int)MessageTypes.KRB_TGS_REP)
                {
                    KerbData.ResponseType = MessageTypes.KRB_TGS_REP;
                }

                return((MessageTypes)MsgType);
            }
            else // bug in the code if we get here ...
            {
                throw new Exception("Invalid KERB Request length: " + Len);
            }
        }
        public void Read(TDSReader r)
        {
            byte   MajorVer;
            byte   MinorVer;
            ushort Build;

            Length = r.ReadUInt16();
            r.TokenStart(Length);
            Interface      = r.ReadByte();
            TDSVersion     = r.ReadUInt32();
            r.TDSVersion   = TDSVersion;
            ProgramName    = r.ReadUnicodeString1();
            MajorVer       = r.ReadByte();
            MinorVer       = r.ReadByte();
            Build          = r.ReadUInt16();
            ProgramVersion = MajorVer + "." + MinorVer + "." + Build;
            r.TokenDone();
        }
        static void ParseErrorResponseTCP(KerberosData KerbData, TDSReader ByteReader)
        {
            //Tag4-TagC
            int TagID = 0, TagLen = 0;

            do
            {
                TagID  = ByteReader.ReadByte();
                TagLen = ReadAsnLen(ByteReader, false);

                TagID = (TagID & (int)0x1F);
                switch (TagID)
                {
                case 4:
                case 5:
                case 9:
                case 10:
                case 12:
                {
                    ByteReader.ReadBytes(TagLen);         // Skip 'STime', 'SuSec', 'Realm'
                    break;
                }

                case 6:
                {
                    ReadAsnLen(ByteReader);
                    KerbData.errorCode = ByteReader.ReadByte();
                    KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode);
                    return;
                }

                default:
                {
                    break;
                    //return;
                    //throw new Exception("Unexpected Tag" + TagID + " found in  KERB TCP response");
                }
                }
            }while (TagID < 6); //Total 12 tags expected, but we are reading only 6 tags until error code
        }
        static Int32 ReadAsnLen(TDSReader ByteReader, bool IsReadFirstByte = true)
        {
            if (IsReadFirstByte)
            {
                ByteReader.ReadByte();
            }

            int Len = ByteReader.ReadByte();

            if ((Len & (int)0x80) == (int)0x80)
            {
                switch (Len & 0x7F)
                {
                case 1:
                {
                    Len = ByteReader.ReadByte();
                    break;
                }

                case 2:
                {
                    Len = ByteReader.ReadBigEndianUInt16();
                    break;
                }

                case 3:
                {
                    Len = (int)ByteReader.ReadUInt32();
                    break;
                }

                default:
                {
                    //throw new Exception("Unknown tag (" + Len + ") in kerberos packet.");
                    break;
                }
                }
            }
            return(Len);
        }
        static KerberosData ParseErrorResponseUDP(TDSReader ByteReader)
        {
            int TagID = 10, TagLen = 0, DataLen = 0;

            KerberosData KerbData = new KerberosData();

            ReadAsnLen(ByteReader); //Skip over 4 bytes 'ApplicationTag'
            ReadAsnLen(ByteReader); //Skip over 4 bytes 'SequenceHeader'
            do
            {
                TagID  = ByteReader.ReadByte();
                TagLen = ReadAsnLen(ByteReader, false);
                switch (TagID & 0x1F)
                {
                case 0:
                case 1:
                case 4:
                case 5:
                case 9:
                    break;

                case 6:
                {
                    DataLen = ReadAsnLen(ByteReader, false);
                    if (DataLen == 1)
                    {
                        KerbData.errorCode = ByteReader.ReadByte();
                        KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode);
                    }

                    return(KerbData);
                }
                } //Switch
            }while ((TagID & (int)0x1F) <= 9);


            return(KerbData);
        }
        static void GetVersion(KerberosData KerbData, TDSReader ByteReader)
        {
            int Length = ReadAsnLen(ByteReader);

            if (Length == 1)
            {
                KerbData.Version = ByteReader.ReadByte();
            }

            if ((Length != 1) || (KerbData.Version != 5))
            {
                throw new Exception("Invalid Kerberos version and unexpected version or unexpected number of bytes are used for storing the version ");
            }
        }
        public static KerberosData ProcessUDP(ConversationData c)
        {
            KerberosData KerbData = new KerberosData();

            KerbData.SourcePort = c.sourcePort;
            KerbData.convData   = c;

            int    Len2   = 0;
            int    TagLen = 0;
            string SPN    = null;
            int    TagID  = 0;

            bool IsContinueToNextFrame = false;

            foreach (FrameData fd in c.frames)
            {
                if (fd.payloadLength <= 1)
                {
                    continue;
                }


                TDSReader ByteReader = new TDSReader(fd.payload, 0, -1, fd.payloadLength);

                //Skip over 4 bytes 'ApplicationTag'
                ReadAsnLen(ByteReader);

                //Skip over 4 bytes 'KdcReq->SequenceHeader'
                ReadAsnLen(ByteReader);

                //Init vars after every frame processing

                Len2   = 0;
                TagLen = 0;
                SPN    = null;

                TagID = 0;

                do
                {
                    TagID  = ByteReader.ReadByte();
                    TagLen = ReadAsnLen(ByteReader, false);

                    TagID = TagID & 0x1F;
                    switch (TagID) //Lower 5 bits
                    {
                    case 0:        // version# in Tag 0 for KRB_TGS_REP (response)
                    case 1:
                    case 2:
                    {
                        if ((fd.isFromClient && TagID == 1) || (!fd.isFromClient && TagID == 0))
                        {
                            GetVersion(KerbData, ByteReader);
                        }
                        else if ((!fd.isFromClient && TagID == 1) || (fd.isFromClient && TagID == 2))
                        {
                            MessageTypes MsgType = GetMessageType(KerbData, ByteReader);
                            KerbData.frameNo = fd.frameNo;

                            if (MsgType == MessageTypes.KRB_TGS_REP)
                            {
                                //ParseNonErrorResponseUDP(KerbData, ByteReader);
                                IsContinueToNextFrame = true;
                            }
                            else if (MsgType == MessageTypes.KRB_ERROR)
                            {
                                ParseErrorResponseUDP(KerbData, ByteReader);
                                IsContinueToNextFrame = true;
                            }
                        }
                        break;
                    }

                    case 3:

                    {
                        //ByteReader.ReadByte();
                        Len2 = ReadAsnLen(ByteReader);
                        ByteReader.ReadBytes(Len2);         // skip the padata tag.
                        break;
                    }

                    case 4:
                    {
                        //ByteReader.ReadByte(); //skip sequence header of ReqBody
                        ReadAsnLen(ByteReader);
                        int TagId2 = 0;
                        do
                        {
                            TagId2 = ByteReader.ReadByte();
                            Len2   = ReadAsnLen(ByteReader, false);
                            TagId2 = TagId2 & 0x1F;
                            switch (TagId2)
                            {
                            case 0:
                            {
                                ByteReader.ReadByte();
                                int Len3 = ReadAsnLen(ByteReader, false);

                                //Read and skip 'padding'
                                ByteReader.ReadBytes(Len3 - 4);

                                KerbData.IsForwardable = (ByteReader.ReadByte() & 0x40) != 0;

                                //Read remaining three bytes
                                ByteReader.ReadBytes(3);
                                break;
                            }

                            case 1:
                            case 2:
                            case 4:
                            case 5:
                            case 7:
                            case 8:            //skip these tags.
                            {
                                ByteReader.ReadBytes(Len2);
                                break;
                            }

                            case 3:
                            {
                                // UDP SName implementation - replacing with TCP implementation

                                // ReadAsnLen(ByteReader);             //Skip sequence header  of sname
                                // int Len3 = ReadAsnLen(ByteReader);  //Skip Tag0  of sname
                                // ByteReader.ReadBytes(Len3);         //skip nametype
                                // ReadAsnLen(ByteReader);             //Skip  Tag1 of sname
                                // Len3 = ReadAsnLen(ByteReader);      //Skip sequence header  of sname->Tag1
                                // Len3 = ReadAsnLen(ByteReader);      // Read SPN Length - same as the TCP implementation
                                // SPN = ByteReader.ReadAnsiString(Len3);
                                // KerbData.SPNRequested = SPN;

                                // TCP SName implementation

                                ReadAsnLen(ByteReader);                 //Skip sequence header  of sname
                                int Len3 = ReadAsnLen(ByteReader);      //Skip Tag0  of sname
                                //
                                // Read the Name Type:
                                //
                                //  2 = NT-SRV-INST   - has two Strings: Service and Instance. '/' separater is implied
                                // 10 = NT-ENTERPRISE - has one String
                                //
                                // Throw error on all other values
                                //
                                Len3 = ReadAsnLen(ByteReader);
                                if (Len3 != 1)
                                {
                                    throw new Exception("Unexpected length (" + Len3 + ") reading SName Name Type.");
                                }
                                byte NameType = ByteReader.ReadByte();
                                KerbData.SNameType = NameType;
                                if (NameType != 2 && NameType != 10)
                                {
                                    IsContinueToNextFrame = true;
                                    break;
                                }

                                ReadAsnLen(ByteReader);                 //Skip  Tag1 of sname
                                Len3 = ReadAsnLen(ByteReader);          //Skip sequenceheader  of sname.

                                SPN = "";
                                if (NameType == 2)                 // read service type
                                {
                                    Len3 = ReadAsnLen(ByteReader);
                                    SPN  = ByteReader.ReadAnsiString(Len3) + "/";
                                }
                                Len3 = ReadAsnLen(ByteReader);                 // read SPN length
                                SPN += ByteReader.ReadAnsiString(Len3);
                                KerbData.SPNRequested = SPN;

                                break;
                            }

                            default:
                            {
                                throw new Exception("Unknonw tag in kerberos packet");
                            }
                            }
                        } while (TagId2 < 3);

                        break;
                    }

                    default:
                    {
                        // throw new Exception("Un expected tags in kerberos request/response/ problem in parseing");
                        break;
                    }
                    }
                }while ((TagID < 4) && (!IsContinueToNextFrame));
            }

            return(KerbData);
        }
        public static void ProcessUDP(NetworkTrace trace)
        {
            string[] DnsReturnMessage = new string[] {
                "Success",
                "Format error; DNS server did not understand the update request.",
                "DNS server encountered an internal error, such as a forwarding timeout.",
                "A name that should exist does not exist.",
                "DNS server does not support the specified Operation code.",
                "DNS server refuses to perform the update.",
                "A name that should not exist does exist.",
                "A resource record set that should not exist does exist.",
                "A resource record set that should exist does not exist.",
                "DNS server is not authoritative for the zone named in the Zone section.",
                "A name used in the Prerequisite or Update sections is not within the zone specified by the Zone section.",
                "Invalid return code.",
                "Invalid return code.",
                "Invalid return code.",
                "Invalid return code.",
                "Reserved."
            };

            foreach (ConversationData c in trace.conversations)
            {
                //DNS traffic is over UDP. If the current converstion is not UDP then skip that non DNS conversation.
                if (!c.isUDP)
                {
                    continue;
                }

                //Skip the conversation, if  its just UDP, but not DNS
                if ((c.isUDP) && c.destPort != 53)
                {
                    continue;
                }

                trace.DNSRequestCount++;

                try
                {
                    //Parse the DNS frames of the conversation.
                    foreach (FrameData fd in c.frames)
                    {
                        DNS DNSresponse = new DNS();

                        if (fd.payloadLength < 1)
                        {
                            continue;
                        }



                        //DNS data starts at 42nd byte of the total payload. so the payload = (Total Payload - 42) bytes.
                        TDSReader ByteReader = new TDSReader(fd.payload, 0, -1, fd.payloadLength);


                        ByteReader.ReadBigEndianUInt16();     //Skip over the query ID.

                        //Read the Flags and convert into bytes.
                        int FlagsHigh = ByteReader.ReadByte();
                        int FlagsLow  = ByteReader.ReadByte();

                        if ((FlagsHigh & (int)0x80) == (int)0x0)     // DNS request
                        {
                            //DNSresponse.srcServerIP  = c.sourceIP.ToString();
                            DNSresponse.dnsServerIP = c.destIP.ToString();
                        }
                        else if ((FlagsHigh & (int)0x80) == (int)0x80) // DNS response
                        {
                            int rCode = FlagsLow & 0x0F;               // should be between 0 - 15.

                            //DNSresponse.srcServerIP= c.destIP.ToString();
                            DNSresponse.dnsServerIP = c.sourceIP.ToString();
                            DNSresponse.frameNo     = fd.frameNo;
                            DNSresponse.TimeStamp   = new DateTime(((FrameData)c.frames[c.frames.Count - 1]).ticks).ToString(utility.TIME_FORMAT);
                            //new DateTime(((FrameData)trace.frames[0]).ticks).ToString(utility.TIME_FORMAT);
                            DNSresponse.errorCode = rCode;
                            DNSresponse.ErrorDesc = DnsReturnMessage[rCode];

                            //Question Count  - 2 bytes
                            DNSresponse.QuestionCount = ByteReader.ReadInt16();

                            //Answer Count - 2 bytes
                            DNSresponse.AnswerCount = ByteReader.ReadInt16();

                            //Skip 2 bytes - Name Server count
                            ByteReader.ReadInt16();

                            //Skip 2 bytes - Additional count
                            ByteReader.ReadInt16();

                            //Start reading the QName
                            //13th byte of the DNS Payload - payload[12]
                            byte   length = ByteReader.ReadByte();
                            string Name   = "";
                            while (length != 0)
                            {
                                Name  += (Name == "" ? "" : ".") + ByteReader.ReadAnsiString(length);
                                length = ByteReader.ReadByte();
                            }

                            DNSresponse.nameReqested = Name;
                            DNSresponse.convData     = c;
                            //DNSresponse.srcPort = c.sourcePort;

                            // Console.WriteLine(fd.file.filePath + "\t" + fd.frameNo.ToString());
                            if (rCode != (int)DNSReturnCodes.NOERROR)
                            {
                                trace.DNSResponses.Add(DNSresponse);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error parsing DNS conversation: " + ex.Message + "\r\n" + ex.StackTrace);
                    Program.logDiagnostic("Error parsing DNS conversation: " + ex.Message + "\r\n" + ex.StackTrace);
                }
            }
        }
        public string AlternateServer = null;   // server name to reroute the connection to

        public void Read(TDSReader r)
        {
            Length = r.ReadUInt16();
            r.TokenStart(Length);
            EnvChangeType = (TDSEnvChgTokens)r.ReadByte();
            if (EnvChangeType == TDSEnvChgTokens.PromoteTrans)
            {
                r.TokenDone();                                                // Length always 1 for this token type
            }
            switch (EnvChangeType)
            {
            case TDSEnvChgTokens.Database:                   //   1  Database name
            case TDSEnvChgTokens.Language:                   //   2  Language
            case TDSEnvChgTokens.CharSet:                    //   3  Character set                         - TDS 7.0
            case TDSEnvChgTokens.PacketSize:                 //   4  Packet Size
            case TDSEnvChgTokens.UnicodeSortLocale:          //   5  Unicode data sorting locale id        - TDS 7.0
            case TDSEnvChgTokens.UnicodeCompareFlags:        //   6  Unicode data sorting comparison flags - TDS 7.0
            case TDSEnvChgTokens.MirrorPartner:              //  13  Database mirroring partner
            case TDSEnvChgTokens.UserInfo:                   //  19  User instance
            {
                NewValue = r.ReadUnicodeString1();           // returns "" if length argument is zero
                OldValue = r.ReadUnicodeString1();
                break;
            }

            case TDSEnvChgTokens.Collation:                  //   7  SQL collation - generally 5 bytes
            case TDSEnvChgTokens.BeginTrans:                 //   8  Begin transaction          - old data is always 0x00 length
            case TDSEnvChgTokens.CommitTrans:                //   9  Commit transaction         - new data is always 0x00 length
            case TDSEnvChgTokens.RollbackTrans:              //  10  Rollback transaction       - new data is always 0x00 length
            case TDSEnvChgTokens.EnlistDTC:                  //  11  Enlist TDS transaction     - new data is always 0x00 length
            case TDSEnvChgTokens.DefectTrans:                //  12  Defect transaction         - old data is always 0x00 length
            case TDSEnvChgTokens.TransMgrAddress:            //  16  Transaction Manager Address- old data is always 0x00 length - unused token
            case TDSEnvChgTokens.TransEnded:                 //  17  Transaction Ended          - new data is always 0x00 length
            case TDSEnvChgTokens.ResetCompletedAck:          //  18  Reset achknowledgement     - new data and old data both 0x00 length
            {
                NewBytes = r.ReadBytes1();
                OldBytes = r.ReadBytes1();
                break;
            }

            case TDSEnvChgTokens.PromoteTrans:               //  15  Promote transaction        - new data length is 4 bytes, old data is always 0x00 length
            {
                NewBytes = r.ReadBytes4();
                r.ReadByte();             // no real old data, just a 1 byte 0-length indicator
                break;
            }

            case TDSEnvChgTokens.Routing:                    //  20  Routing                    - old data length is always 0x0000
            {
                // new value
                ushort RoutingDataLength = r.ReadUInt16();           // may be sent if ReadOnlyIntent is true in TDS 7.1 - 7.3; could be sent in 7.4 even if the flag is false
                if (RoutingDataLength > 0)
                {
                    Protocol         = r.ReadByte();
                    ProtocolProperty = r.ReadUInt16();
                    AlternateServer  = r.ReadUnicodeString2();
                }
                // old value
                r.ReadUInt16();
                break;
            }
            }
            if (EnvChangeType != TDSEnvChgTokens.PromoteTrans)
            {
                r.TokenDone();                                                 // Length for this token is always 1 even if there is more data; r.DoneToken(0 is called earlier for this token type
            }
        }
        public void Read(TDSReader r)
        {
            byte TDSVer = (byte)(r.TDSVersion & 0x000000FF);

            UserType = (TDSVer < 0x72) ? r.ReadUInt16() : r.ReadUInt32();
            Flags    = r.ReadUInt16();
            Type     = (TDSTokenColumnType)(r.ReadByte());
            switch (Type)
            {
            //
            // no need to read anything else for fixed-length types
            //
            case TDSTokenColumnType.Null:
            case TDSTokenColumnType.TinyInt:
            case TDSTokenColumnType.Bit:
            case TDSTokenColumnType.SmallInt:
            case TDSTokenColumnType.Int:
            case TDSTokenColumnType.SmallDateTime:
            case TDSTokenColumnType.Real:
            case TDSTokenColumnType.Money:
            case TDSTokenColumnType.DateTime:
            case TDSTokenColumnType.Float:
            case TDSTokenColumnType.SmallMoney:
            case TDSTokenColumnType.BigInt:
            {
                break;
            }

            //
            // data types that have a 1 byte length
            //
            case TDSTokenColumnType.GUID:
            case TDSTokenColumnType.VarBinary:
            case TDSTokenColumnType.IntN:
            case TDSTokenColumnType.VarChar:
            case TDSTokenColumnType.DateN:       // question about this type
            case TDSTokenColumnType.Binary:
            case TDSTokenColumnType.Char:
            case TDSTokenColumnType.BitN:
            case TDSTokenColumnType.FloatN:
            case TDSTokenColumnType.MoneyN:
            case TDSTokenColumnType.DateTimeN:
            {
                Length = r.ReadByte();
                break;
            }

            //
            // data types that have a 1 byte length and 1 byte scale
            //
            case TDSTokenColumnType.TimeN:
            case TDSTokenColumnType.DateTime2N:
            case TDSTokenColumnType.DateTimeOffsetN:
            {
                Length = r.ReadByte();
                Scale  = r.ReadByte();
                break;
            }

            //
            // data types that have a 1 byte length, 1 byte precision, and 1 byte scale
            //
            case TDSTokenColumnType.Decimal:
            case TDSTokenColumnType.Numeric:
            case TDSTokenColumnType.DecimalN:
            case TDSTokenColumnType.NumericN:
            {
                Length    = r.ReadByte();
                Precision = r.ReadByte();
                Scale     = r.ReadByte();
                break;
            }

            //
            // data types that have a 2 byte length
            //
            case TDSTokenColumnType.LongVarBinary:
            case TDSTokenColumnType.LongBinary:
            {
                Length = r.ReadUInt16();
                break;
            }

            //
            // data types that have a 2 byte length and an optional 5-byte collation
            //
            case TDSTokenColumnType.LongVarChar:
            case TDSTokenColumnType.LongChar:
            case TDSTokenColumnType.NVarChar:
            case TDSTokenColumnType.NChar:
            {
                Length = r.ReadUInt16();
                if (TDSVer >= 0x71)
                {
                    Collation = r.ReadBytes(5);
                }
                break;
            }

            //
            // data types that have a 4 byte length
            //
            case TDSTokenColumnType.Image:
            case TDSTokenColumnType.Variant:
            case TDSTokenColumnType.NText:
            {
                Length = r.ReadUInt32();
                break;
            }

            //
            // data types that have a 4 byte length and an optional 5-byte collation
            //
            case TDSTokenColumnType.Text:
            {
                Length = r.ReadUInt32();
                if (TDSVer >= 0x71)
                {
                    Collation = r.ReadBytes(5);
                }
                break;
            }

            //
            // CLR User-Defined Type
            //
            case TDSTokenColumnType.UDT:
            {
                Length       = r.ReadUInt16();
                DBName       = r.ReadUnicodeString1();
                SchemaName   = r.ReadUnicodeString1();
                TypeName     = r.ReadUnicodeString1();
                AssemblyName = r.ReadUnicodeString2();         // can be longer than 255 characters
                break;
            }

            //
            // XML
            //
            case TDSTokenColumnType.XML:
            {
                XmlSchemaPresent = r.ReadByte();
                if (XmlSchemaPresent == 1)
                {
                    DBName           = r.ReadUnicodeString1();
                    SchemaName       = r.ReadUnicodeString1();
                    SchemaCollection = r.ReadUnicodeString2();           // can be longer than 255 characters
                }
                break;
            }

            default:
            {
                throw new InvalidTDSException("Unknown TDS data type: " + (byte)(Type) + ".");
            }
            }
            ColumnName = r.ReadUnicodeString1();
        }
        byte[] Nonce          = null; // 32 bytes of data if FedAuth is non-zero

        public void Read(TDSReader r)
        {
            byte      OptionToken = 0;;
            int       DataOffset;
            int       DataLength;
            TDSReader offsetReader = null;

            OptionToken = r.ReadByte();

            while (OptionToken != (byte)TDSTokenType.DONEINPROC) // 255 or 0xFF
            {
                DataOffset   = r.ReadBigEndianUInt16();
                DataLength   = r.ReadBigEndianUInt16();
                offsetReader = r.OffsetReader(DataOffset);

                switch (OptionToken)
                {
                case 0:              // version
                {
                    if (DataLength > 0)
                    {
                        Version  = offsetReader.ReadUInt32();
                        SubBuild = offsetReader.ReadUInt16();
                    }
                    break;
                }

                case 1:             // encryption
                {
                    if (DataLength > 0)
                    {
                        Encryption = offsetReader.ReadByte();
                    }
                    if (Encryption > 3)
                    {
                        throw new InvalidTDSException("Invalid encryption option: " + Encryption);
                    }
                    break;
                }

                case 2:             // instanceValidity validity
                {
                    if (DataLength > 0)
                    {
                        InstanceValidity = offsetReader.ReadByte();
                    }
                    break;
                }

                case 3:             // thread ID
                {
                    if (DataLength > 0)
                    {
                        ThreadID = offsetReader.ReadUInt32();
                    }
                    break;
                }

                case 4:             // MARS
                {
                    if (DataLength > 0)
                    {
                        MarsData = offsetReader.ReadByte();
                    }
                    if (MarsData > 1)
                    {
                        throw new InvalidTDSException("Invalid MARS option: " + MarsData);
                    }
                    break;
                }

                case 5:            // Trace ID
                {
                    if (DataLength > 0)
                    {
                        TraceID = new Guid(offsetReader.ReadBytes(16));
                    }
                    break;
                }

                case 6:            // Federated Auth Required
                {
                    if (DataLength > 0)
                    {
                        FedAuth = offsetReader.ReadByte();
                    }
                    break;
                }

                case 7:            // NONCE Option - 32 bytes of encrypted data
                {
                    if (DataLength > 0)
                    {
                        Nonce = offsetReader.ReadBytes(32);
                    }
                    break;
                }
                }
            }
            r.DoneWithChildReaders();  // updates parent reader offset with child reader high offset - i.e.  causes the parent to jump past the referenced data
        }