At
work, we have our telephony applications. We send SIP-calls here and
there, bouncing between different application. Sometimes when I get
logs of a callscenario someone had problem with it can be a bit hard to
understand exactly how the three calls has interacted with each other.
Then I remembered that Wireshark has the ability to show SIP traffic as a flow-diagram. Quite nifty really.
Then I remembered that Wireshark has the ability to show SIP traffic as a flow-diagram. Quite nifty really.
I had an idea that I should take our own logs, extract the SIP messages and generate a pcap-file from that. Then using Wireshark to produce a graph like the one shown above.
Perhaps a bit round-about way to get a call-graph. But still, sounds simple, right?
As a starter I found the format specification for the pcap file. It looked simple enough, just a couple of C-structs written straight to disk.
http://wiki.wireshark.org/Development/LibpcapFileFormat#File_Format
So in an hour I wrote a program that parsed our logs and filled struct matching the C-structs. One unexpected hardship I encountered was converting structs to binary format. I could not find a "C-like" serializer! But writing byte-by-byte manually still worked.
However the pcap-files created this was didn't work. Write shark complained that it was malformed IP-packets, segmented IP-packets with invalid checksum and so on.
To summarize, it didn't work!
Sometimes when my I have run my efforts straight into the wall I think "This shouldn't be hard. Someone has to have done this before." But I didn't find anything. (However I never found managed to phrase a good google-question. All I found was people trying to get tcpdump to log and similar.)
Ok, Internet couldn't help me. So I tried the next thing, Stack Overflow. "Are there a .net-library available to write arbitrary data to a pcap-file?"
And yes there where.
SharkPcap And the sibling Packet.Net.
To quote the project: SharkPcap is a libpcap/winpcap wrapper. Packet.Net is is a networking packet parser.
After some more poking around I found how to use the libraries. Open a CaptureFileWriterDevice, and indicate that the file-format should be raw. (Rather then Ethernet, Tokenring or something similar.)
Then create a UdpPacket, wrap that in a IpPacket. Get the bytes from the IpPacket and write that to the capture device.
Done.
public void WritePCap(
string filename, DateTime dt, IPAddress srcIp, IPAddress dstIp,
UInt16 srcPort, UInt16 dstPort, byte[] data )
{
IpPacket ip = new IPv4Packet(srcIp, dstIp);
ip.TimeToLive = 70;
UdpPacket payload = new UdpPacket(srcPort, dstPort) {
SourcePort = srcPort,
DestinationPort = dstPort,
PayloadData = data,
ParentPacket = ip
};
ip.PayloadPacket = payload;
payload.UpdateCalculatedValues();
ip.UpdateCalculatedValues();
byte[] ipData = ip.Bytes;
CaptureFileWriterDevice storeDevice = new CaptureFileWriterDevice(
PacketDotNet.LinkLayers.Raw, null, filename, FileMode.OpenOrCreate);
PcapHeader hdr = new PcapHeader(
ToUnixTime(dt), (uint)(dt.Millisecond * 1000),
(uint)ipData.Length, (uint)ipData.Length);
storeDevice.Write(ipData, hdr);
}