private static void CompareTcpOptions(XElement element, TcpOptions options) { int currentOptionIndex = 0; foreach (var field in element.Fields()) { if (currentOptionIndex >= options.Count) { Assert.IsFalse(options.IsValid, "Options IsValid"); Assert.IsTrue( field.Show().StartsWith("Unknown (0x0a) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net field.Show().Contains("bytes says option goes past end of options") || field.Show().Contains(") (with too-short option length = "), "Options show: " + field.Show()); Assert.AreEqual(options.Count, currentOptionIndex, "Options Count"); return; } TcpOption option = options[currentOptionIndex]; switch (field.Name()) { case "": switch (option.OptionType) { case TcpOptionType.SelectiveNegativeAcknowledgements: // TODO: Support Selective Negative Acknowledgements. Assert.IsTrue(field.Show().StartsWith(option.GetWiresharkString())); field.AssertNoFields(); break; case (TcpOptionType)78: // TODO: Support Riverbed. break; default: field.AssertShow(option.GetWiresharkString()); break; } switch (option.OptionType) { case TcpOptionType.WindowScale: TcpOptionWindowScale windowScale = (TcpOptionWindowScale)option; foreach (var subField in field.Fields()) { switch (subField.Name()) { case "tcp.option_kind": subField.AssertShowDecimal((byte)windowScale.OptionType); break; case "tcp.option_len": subField.AssertShowDecimal(windowScale.Length); break; case "tcp.options.wscale.shift": subField.AssertShowDecimal(windowScale.ScaleFactorLog); break; case "tcp.options.wscale.multiplier": subField.AssertShowDecimal(1L << (windowScale.ScaleFactorLog % 32)); break; default: throw new InvalidOperationException("Invalid tcp options subfield " + subField.Name()); } } break; case TcpOptionType.SelectiveAcknowledgment: var selectiveAcknowledgmentOption = (TcpOptionSelectiveAcknowledgment)option; int blockIndex = 0; foreach (var subField in field.Fields()) { switch (subField.Name()) { case "tcp.options.sack": subField.AssertShowDecimal(true); break; case "tcp.options.sack_le": subField.AssertShowDecimal(selectiveAcknowledgmentOption.Blocks[blockIndex].LeftEdge); break; case "tcp.options.sack_re": subField.AssertShowDecimal(selectiveAcknowledgmentOption.Blocks[blockIndex].RightEdge); ++blockIndex; break; default: throw new InvalidOperationException("Invalid tcp options subfield " + subField.Name()); } } break; case TcpOptionType.Timestamp: var timestampOption = (TcpOptionTimestamp)option; foreach (var subField in field.Fields()) { switch (subField.Name()) { case "tcp.option_kind": subField.AssertShowDecimal((byte)option.OptionType); break; case "tcp.option_len": subField.AssertShowDecimal(option.Length); break; case "tcp.options.timestamp.tsval": subField.AssertShowDecimal(timestampOption.TimestampValue); break; case "tcp.options.timestamp.tsecr": subField.AssertShowDecimal(timestampOption.TimestampEchoReply); break; default: throw new InvalidOperationException("Invalid tcp options subfield " + subField.Name()); } } break; default: field.AssertNoFields(); break; } ++currentOptionIndex; break; case "tcp.options.mss": Assert.AreEqual(TcpOptionType.MaximumSegmentSize, option.OptionType); field.AssertShowDecimal(true); field.AssertNoFields(); break; case "tcp.options.mss_val": field.AssertShowDecimal(((TcpOptionMaximumSegmentSize)option).MaximumSegmentSize); field.AssertNoFields(); ++currentOptionIndex; break; case "tcp.options.echo": Assert.IsTrue(option is TcpOptionEchoReply || option is TcpOptionEcho); field.AssertShowDecimal(1); field.AssertNoFields(); break; case "tcp.options.cc": Assert.IsTrue(option is TcpOptionConnectionCountBase); field.AssertShowDecimal(1); field.AssertNoFields(); break; case "tcp.options.scps.vector": Assert.AreEqual((TcpOptionType)20, option.OptionType); if (field.Show() == "0") { ++currentOptionIndex; } ++currentOptionIndex; break; case "tcp.options.scps": Assert.AreEqual((TcpOptionType)20, option.OptionType); Assert.IsFalse(field.Fields().Any()); break; case "tcp.options.snack": // TODO: Support Selective Negative Acknowledgements. case "tcp.options.snack.offset": case "tcp.options.snack.size": Assert.AreEqual(TcpOptionType.SelectiveNegativeAcknowledgements, option.OptionType); field.AssertNoFields(); break; case "tcp.options.sack_perm": Assert.AreEqual(TcpOptionType.SelectiveAcknowledgmentPermitted, option.OptionType); field.AssertNoFields(); ++currentOptionIndex; break; case "tcp.options.rvbd.probe": Assert.AreEqual((TcpOptionType)76, option.OptionType); // TODO: Support Riverbed. ++currentOptionIndex; break; case "tcp.options.rvbd.trpy": Assert.AreEqual((TcpOptionType)78, option.OptionType); // TODO: Support Riverbed. ++currentOptionIndex; break; default: throw new InvalidOperationException("Invalid tcp options field " + field.Name()); } } }
private static void CompareTcpOptions(XElement element, TcpOptions options) { int currentOptionIndex = 0; foreach (var field in element.Fields()) { if (field.Name() == "_ws.expert") { continue; } if (currentOptionIndex >= options.Count) { Assert.IsFalse(options.IsValid, "Options IsValid"); Assert.IsTrue( field.Show().StartsWith("Unknown (0x09) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net. field.Show().StartsWith("Unknown (0x0a) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net. field.Show().StartsWith("Unknown (0x19) ") || // Unknown in Wireshark but known (and invalid) in Pcap.Net. field.Show().StartsWith("Unknown (0x2d) ") || // Unknown in Wireshark and unknown and invalid in Pcap.Net. field.Show().StartsWith("Unknown (0xa9) ") || // Unknown in Wireshark and unknown and invalid in Pcap.Net. field.Show().StartsWith("Echo reply (with option length = ") || field.Show().Contains("bytes says option goes past end of options") || field.Show().Contains(") (with too-short option length = ") || field.Show().EndsWith(" (length byte past end of options)"), "Options show: " + field.Show()); Assert.AreEqual(options.Count, currentOptionIndex, "Options Count"); return; } TcpOption option = options[currentOptionIndex]; switch (field.Name()) { case "": switch (option.OptionType) { case TcpOptionType.WindowScale: TcpOptionWindowScale windowScale = (TcpOptionWindowScale)option; byte scaleFactorLog = windowScale.ScaleFactorLog; field.AssertShow(string.Format("Window scale: {0} (multiply by {1})", scaleFactorLog, (1L << (scaleFactorLog % 32)))); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } switch (subField.Name()) { case "tcp.options.wscale.shift": subField.AssertShowDecimal(windowScale.ScaleFactorLog); break; case "tcp.options.wscale.multiplier": subField.AssertShowDecimal(1L << (windowScale.ScaleFactorLog % 32)); break; default: throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.SelectiveAcknowledgment: var selectiveAcknowledgmentOption = (TcpOptionSelectiveAcknowledgment)option; IEnumerable <TcpOptionSelectiveAcknowledgmentBlock> blocks = selectiveAcknowledgmentOption.Blocks; field.AssertShow("SACK:" + (blocks.Count() == 0 ? string.Empty : ((TcpOptionSelectiveAcknowledgment)option).Blocks.SequenceToString(" ", " "))); int blockIndex = 0; foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } subField.AssertNoFields(); switch (subField.Name()) { case "tcp.options.sack": subField.AssertShowDecimal(true); break; case "tcp.options.sack_le": subField.AssertShowDecimal(selectiveAcknowledgmentOption.Blocks[blockIndex].LeftEdge); break; case "tcp.options.sack_re": subField.AssertShowDecimal(selectiveAcknowledgmentOption.Blocks[blockIndex].RightEdge); ++blockIndex; break; case "tcp.options.sack.count": subField.AssertShowDecimal(selectiveAcknowledgmentOption.Blocks.Count); break; default: throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.Timestamp: var timestampOption = (TcpOptionTimestamp)option; field.AssertShow("Timestamps: TSval " + timestampOption.TimestampValue + ", TSecr " + timestampOption.TimestampEchoReply); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } subField.AssertNoFields(); switch (subField.Name()) { case "tcp.options.timestamp.tsval": subField.AssertShowDecimal(timestampOption.TimestampValue); break; case "tcp.options.timestamp.tsecr": subField.AssertShowDecimal(timestampOption.TimestampEchoReply); break; default: throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.ConnectionCount: field.AssertShow("CC: " + ((TcpOptionConnectionCount)option).ConnectionCount); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } subField.AssertNoFields(); switch (subField.Name()) { default: throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.Echo: field.AssertShow("Echo: " + ((TcpOptionEcho)option).Info); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } subField.AssertNoFields(); switch (subField.Name()) { default: throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.ConnectionCountNew: field.AssertShow("CC.NEW: " + ((TcpOptionConnectionCountNew)option).ConnectionCount); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } subField.AssertNoFields(); switch (subField.Name()) { default: throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.EndOfOptionList: field.AssertShow("End of Option List (EOL)"); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } switch (subField.Name()) { default: subField.AssertNoFields(); throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.ConnectionCountEcho: field.AssertShow("CC.ECHO: " + ((TcpOptionConnectionCountEcho)option).ConnectionCount); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } subField.AssertNoFields(); switch (subField.Name()) { default: throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.Md5Signature: field.AssertShow("TCP MD5 signature"); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } switch (subField.Name()) { case "tcp.options.type": subField.AssertShowDecimal((byte)TcpOptionType.Md5Signature); break; default: subField.AssertNoFields(); throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } } break; case TcpOptionType.NoOperation: field.AssertShow("No-Operation (NOP)"); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } break; case TcpOptionType.EchoReply: field.AssertShow("Echo reply: " + ((TcpOptionEchoReply)option).Info); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } throw new InvalidOperationException("Invalid tcp option subfield " + subField.Name()); } break; case TcpOptionType.SelectiveAcknowledgmentPermitted: field.AssertShow("SACK permitted"); field.AssertNoFields(); break; case TcpOptionType.SelectiveNegativeAcknowledgements: // TODO: Support Selective Negative Acknowledgements. Assert.IsTrue(field.Show().StartsWith("SACK permitted")); field.AssertNoFields(); break; case (TcpOptionType)20: // TODO: Support 20. field.AssertShow("SCPS capabilities" + (option.Length >= 4 ? string.Empty : " (with option length = " + option.Length + " bytes; should be >= 4)")); break; case (TcpOptionType)22: field.AssertShow("SCPS record boundary (with option length = " + option.Length + " bytes; should be 2)"); // TODO: Support 22. break; case (TcpOptionType)23: field.AssertShow("SCPS corruption experienced (with option length = " + option.Length + " bytes; should be 2)"); // TODO: Support 23. break; case (TcpOptionType)30: // TODO: Support 30. Assert.IsTrue(field.Show().StartsWith("Multipath TCP")); break; case (TcpOptionType)78: field.AssertShow("Riverbed Transparency (with option length = " + option.Length + " bytes; should be 16)"); // TODO: Support 78 - Support Riverbed. break; case TcpOptionType.PartialOrderConnectionPermitted: // 9. case TcpOptionType.PartialOrderServiceProfile: // 10. case TcpOptionType.AlternateChecksumRequest: // 14. case TcpOptionType.AlternateChecksumData: // 15. case TcpOptionType.Mood: // 25. case TcpOptionType.TcpAuthentication: // 29. field.AssertShow(string.Format("Unknown (0x{0}) ({1} bytes)", ((byte)option.OptionType).ToString("x2"), option.Length)); field.AssertNoFields(); break; default: field.AssertNoFields(); field.AssertShow("Unknown (0x" + ((byte)option.OptionType).ToString("x") + ") (" + option.Length + " bytes)"); break; } ++currentOptionIndex; break; case "tcp.options.mss": Assert.AreEqual(TcpOptionType.MaximumSegmentSize, option.OptionType); var maximumSegmentSize = (TcpOptionMaximumSegmentSize)option; field.AssertShowname("Maximum segment size: " + maximumSegmentSize.MaximumSegmentSize + " bytes"); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } subField.AssertNoFields(); switch (subField.Name()) { case "tcp.options.mss_val": subField.AssertShowDecimal(maximumSegmentSize.MaximumSegmentSize); break; default: throw new InvalidOperationException("Invalid tcp options subfield " + subField.Name()); } } ++currentOptionIndex; break; case "tcp.options.mss_val": field.AssertShowDecimal(((TcpOptionMaximumSegmentSize)option).MaximumSegmentSize); field.AssertNoFields(); ++currentOptionIndex; break; case "tcp.options.echo": Assert.IsTrue(option is TcpOptionEchoReply || option is TcpOptionEcho); field.AssertShowDecimal(1); field.AssertNoFields(); break; case "tcp.options.cc": Assert.IsTrue(option is TcpOptionConnectionCountBase); field.AssertShowDecimal(1); field.AssertNoFields(); break; case "tcp.options.scps.vector": // TODO: Support 20. Assert.AreEqual((TcpOptionType)20, option.OptionType); // if (field.Show() == "0") // ++currentOptionIndex; ++currentOptionIndex; break; case "tcp.options.scps": // TODO: Support 20. Assert.AreEqual((TcpOptionType)20, option.OptionType); Assert.IsFalse(field.Fields().Any()); break; case "tcp.options.snack": // TODO: Support Selective Negative Acknowledgements. case "tcp.options.snack.offset": case "tcp.options.snack.size": Assert.AreEqual(TcpOptionType.SelectiveNegativeAcknowledgements, option.OptionType); field.AssertNoFields(); break; case "tcp.options.sack_perm": Assert.AreEqual(TcpOptionType.SelectiveAcknowledgmentPermitted, option.OptionType); foreach (var subField in field.Fields()) { if (HandleOptionCommonFields(subField, option)) { continue; } subField.AssertNoFields(); throw new InvalidOperationException("Invalid tcp options subfield " + subField.Name()); } ++currentOptionIndex; break; case "tcp.options.rvbd.probe": Assert.AreEqual((TcpOptionType)76, option.OptionType); // TODO: Support Riverbed. ++currentOptionIndex; break; case "tcp.options.rvbd.trpy": Assert.AreEqual((TcpOptionType)78, option.OptionType); // TODO: Support Riverbed. ++currentOptionIndex; break; case "tcp.options.experimental": Assert.IsTrue(new [] { (TcpOptionType)253, (TcpOptionType)254 }.Contains(option.OptionType)); // TODO: Support Experimental. ++currentOptionIndex; break; default: throw new InvalidOperationException("Invalid tcp options field " + field.Name()); } } }