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 } }
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 }