How do I change PCap.Net packet data? - c#

I have a (production) WireShark capture file that I need to 'replay' over my (debug) network. I can read and interpret the packets, but I need to tweak a few details before the packets can be sent, like source IP addresses and ports.
The problem, however, is that all data in the PcapDotNet.Packets.Packet is read-only. It just has setters.
So like setting for instance the Ethernet.IpV4.Source will not work.
IpV4Address.TryParse("192.168.1.10", out var newAddress); // for demo sake.
packet.Ethernet.IpV4.Source = newAddress; // Won't work
Is there a simple way to avoid building a new packet from scratch, or is that the only way to create a slightly different packet?

Instead of changing the packet inplace, you should just create a new one based on the old one.
You can use ExtractLayer() on each layer you want to keep from the old packet, and then change the layer properties if necessary.
In this case, you can do:
IpV4Layer ipV4Layer = packet.Ethernet.IpV4.ExtractLayer();
ipV4Layer.Source = newAddress;
Packet newPacket = PacketBuild.Build(DateTime.Now, packet.Ethernet.ExtractLayer(), ipV4Layer, packet.Ethernet.IpV4.Payload.ExtractLayer());
You probably also want to reset the IPv4 checksum, so you should do:
ipV4Layer.HeaderChecksum = null;
And you might need to something similar to the UDP or TCP layers on top of the IPv4 layer, in case you have them.

Related

WinPcap equivalent to Wireshark 'dtls' filter

I used to filter packets into Wireshark with the simple dtls argument as filter. (Data Transport Layer Security which is some UDP TLS protocol)
Now, i wanted to do the same using C# and PcapDOTNet wrapper that uses WinPcap filters.
Sadly, i can't find anywhere the equivalent, and dtls is not recognised in the C# app, and so doesn't grab any packet anymore. (Simply it crashes the interpreter since the string is not recognised)
using (PacketCommunicator communicator = selectedDevice.Open(65536, PacketDeviceOpenAttributes.None, 1000))
{
using (BerkeleyPacketFilter filter = communicator.CreateFilter("dtls") {
communicator.SetFilter(filter);
communicator.ReceivePackets(1, packetHandler);
}
}
Is there any equivalent, please ?
EDIT : It looks like dtls is only a DISPLAY filter, and not a CAPTURE one. I could only capture filter by using udp port xx (xx being the port) but since the used ports are always randoms, i can't. So i would be glad to find another filtering workaround if you have one! I prefer only capturing the desired packets, rather than capturing everything then filtering the datas...
Wireshark : DTLS
There is only two packets i would like to capture. The one containing The Server Hello Done message or the one containing handshake message (the one with Record Layer) :
EDIT 2 : Ok, i am close to find what i need, but i need your help.
This answer from here must be the solution. tcp[((tcp[12] & 0xf0) >> 2)] = 0x16 is looking for handshake 22, but dtls is udp and not tcp and so the 12 offset might be different. Can anyone help me figure out what would be the correct formula to adapt it for dtls instead of tcp tls ?
I tried to use this on wireshark, but the filter is invalid and i don't really know why. If at least you could make it to work into wireshark, i could experiment differents value myself and come back with a final answer. udp[((udp[12] & 0xf0) >> 2)] = 0x16 is not a valid filter on wireshark.
So, i gave up on the dynamical way of finding the correct position of the data.
But this is what i ended with :
using (PacketCommunicator communicator = selectedDevice.Open(65536, PacketDeviceOpenAttributes.None, 1000))
{
using (BerkeleyPacketFilter filter = communicator.CreateFilter("udp && ((ether[62:4] = 0x16fefd00) || (ether[42:4] = 0x16fefd00))") {
communicator.SetFilter(filter);
communicator.ReceivePackets(1, packetHandler);
}
}
bytes[62:4] is the position of 16fefd00 for ipv6 packets, (42 for ipv4).
The 16 is for Content type handshake protocol 22 and the following fefd is for DTLS version 1.2. The last two zeros are just because using slice of bytes only works for 1,2 or 4, not 3. So i had to take them in consideration.
This is absolutly not perfect, i know, but for now, it works, since i couldn't find any other workaround yet.

C# UDPClient JoinMulticastGroup. What is the local address?

I'm new to this networking stuff to configure and I'm trying to understand the following code.
var Server = new UdpClient();
var multicastIp = IPAddress.Parse(_connectionParams[0]);
IPAddress localIp;
if (IPAddress.TryParse(_connectionParams[1], out localIp))
Server.JoinMulticastGroup(multicastIp, localIp);
else
Server.JoinMulticastGroup(multicastIp);
var endPoint = new IPEndPoint(multicastIp, int.Parse(_connectionParams[2]));
Based on my understanding, Multicasting is sending the data to the multicast ip (like 233.7.6.5) through router and the receiver might need to join the group to receive data.
Server.JoinMulticastGroup(multicastIp, localIp);
On the above line, What is the use of localIp here? providing localip will unicast the data to particular ip? or something else that I need to understand.
No clues in Microsoft documentation: https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.udpclient.joinmulticastgroup?view=netframework-4.8#System_Net_Sockets_UdpClient_JoinMulticastGroup_System_Net_IPAddress_System_Net_IPAddress_
Server.JoinMulticastGroup(multicastIp, localIp);
In IPv4, a localIp can be provided as the way to look up a physical interface, if you don't choose a local interface or select the wildcard INADDR_ANY(0.0.0.0), the system gets to decide which of your interfaces it will join the group on, which might not be what you want on a system with many physical interfaces.
An OS is only allowed to create its own rules in multicast specifications for very narrow things, i.e. selecting the default interface in this case, so you can rely on any systems documentation you find helpful to determine what steps take what input, for example: linux's tldp documentation.

Understanding and creating a protocol for Python

I have documentation on how to use a TCP/IP binary stream API. The attached images show the protocol. I have a working example of this in C#. I want to do this using python instead, as I don't know c# or windows.
I am assuming I would use python sockets, then I have to send the API messages, with payloads looking at this docs.
Could you point me in the right direction to get this going with python?
How would I set it to know this is the authentication message, 0x21 and compress the data etc?
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.sendall(u"{'username':'username', 'password':'password'}".encode('utf8'))
in OSI model you are above layer 4 (transport, TCP/IP,...) on at least layer 5 (session). there are some examples of implementations of session layer protocols like http, ftp,... i.e. in http://github.com/python-git/python/blob/master/Lib/ftplib.py or http://github.com/python-git/python/blob/master/Lib/httplib.py
as your protocol includes headers maybe http is the better example
to use the TCP/IP API in http protocol see
http://www.stackoverflow.com/questions/8315209/sending-http-headers-with-python
import socket
sock = socket.socket()
sock.bind(('', 8080))
sock.listen(5)
client, adress = sock.accept()
print "Incoming:", adress
print client.recv(1024)
print
client.send('HTTP/1.0 200 OK\r\n')
client.send("Content-Type: text/html\r\n\r\n")
client.send('<html><body><h1>Hello World</body></html>')
client.close()
print "Answering ..."
print "Finished."
sock.close()
as far as i can see you skipped the headers (version, sequence, type, encoding, ...) in your code completely you have to add them whenever you send a frame
so try
self.socket.send(...headers...)
self.socket.send(u"{'username':'username', 'password':'password'}".encode('utf8')) // has to be send as JSON ???
see also http://www.stackoverflow.com/questions/22083359/send-tetx-http-over-python-socket
ftp example (no headers...)
# Internal: send one line to the server, appending CRLF
def putline(self, line):
line = line + CRLF
if self.debugging > 1: print '*put*', self.sanitize(line)
self.sock.sendall(line)
also see scapy
I try to use tcp protocol once. You can send authorization values(username ,password ) in all requests.And other data with it exp({'username':'username', 'password':'password','data':'value'}).With this there is no any current standart for data. Many of tcp clients send that data like this #A#:username;password;#D:value\n (A -authorization ,D -data), example

PcapDotNet and Datalink type

I'm trying to manipulate some network captures (pcap format) using Pcap.net.
I'm opening the pcap file and creating the dumper with:
OfflinePacketDevice selectedDevice = new OfflinePacketDevice(pcapInFile);
using (PacketCommunicator PcapReader = selectedDevice.Open(655360, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
PacketDumpFile PcapWriter = PcapReader.OpenDump(pcapOutFile);
PcapReader.ReceivePackets(count, PacketDispatcher);
}
And the PacketDispatcher would be something like:
private void PacketDispatcher(Packet packet)
{
// Manipulate the packet
PcapWriter.Dump(packet);
}
Everything is ok as far as the pcapInFile Datalink is ethernet type. But i have several captures without ethernet layer (rawip) and i have to build a new ethernet layer. In this kind of caps the datalink type is the same as the pcapInFile (raw ip) and i want to change it to ethernet...
If i store all the manipulated packets in a ienumerable and dump them with:
PacketDumpFile.Dump(pcapOutFile, new PcapDataLink(1), Packets.Count(), Packets);
It works fine... But, this is not very useful if you are dealing with files of several gigas...
Any idea?
Thanks!
Assuming the concern is about having all packets in RAM, you can create an IEnumerable that doesn't contain everything in RAM using yield.
This way as Dumper dumps packets it will call your method to populate the next item using yield.
Well, despite this is not an answer but a workaround, and since nobody wrote a better solution this is how a fixed it:
Use SharPcap instead of PcapDotNet, then you can declare a reader and a writer this way:
public CaptureFileReaderDevice PcapReader;
public CaptureFileWriterDevice PcapWriter;
PcapReader = new CaptureFileReaderDevice(fileIn);
PcapReader.OnPacketArrival += packetDispatcher;
PcapReader.Capture();
In the packetDispatcher function:
RawCapture raw = new RawCapture(LinkLayers.Ethernet, e.Packet.Timeval,RebuildNullLinkLayer(e, offset));
CaptureHandler.PcapWriter.Write(raw);
And in the RebuildNullLinkLayer function you can add the ethernet layer, modify whatever you want, etc...
Note that when you call the RawCapture Constructor you can choose the Link Layer (mi original issue with Pcap.Net...), so if you are parsing a RawIp capture, you can convert the packets to Ethernet.

protobuf-csharp-port

I'm using Jon Skeet's (excellent) port of Google's Protocol Buffers to C#/.Net.
For practice, I have written a dummy Instant Messenger app that sends some messages down a socket. I have a message definition as follows:-
message InstantMessage {<br/>
required string Message = 1;<br/>
required int64 TimeStampTicks = 2; <br/>
}
When the sender serialises the message, it sends it really elegantly:-
...
InstantMessage.Builder imBuild = new InstantMessage.Builder();
imBuild.Message = txtEnterText.Text;
imBuild.TimeStampTicks = DateTime.Now.Ticks;
InstantMessage im = imBuild.BuildPartial();
im.WriteTo(networkStream);
...
This works great. But at the other end, I'm having trouble getting the ParseFrom to work.
I want to use:-
InstantMessage im = InstantMessage.ParseFrom(networkStream);
But instead I have had to read it to bytes and then parse it from here. This is obviously not ideal for a number of reasons. Current code is:-
while (true)
{
Byte[] byteArray = new Byte[10000000];
int intMsgLength;
int runningMsgLength = 0;
DateTime start = DateTime.Now;
while (true)
{
runningMsgLength += networkStream.Read(byteArray, runningMsgLength, 10000000 - runningMsgLength);
if (!networkStream.DataAvailable)
break;
}
InstantMessage im = InstantMessage.ParseFrom(byteArray.Take(runningMsgLength).ToArray());
When I try to use ParseFrom, control does not return to the calling method even when I know a valid GB message is on the wire.
Any advice would be gratefully received,
PW
Sorry for taking a while to answer this. As Marc says, protocol buffers don't have a terminator, and they aren't length prefixed unless they're nested. However, you can put on the length prefix yourself. If you look at MessageStreamIterator and MessageStreamWriter, you'll see how I do this - basically I pretend that I'm in the middle of a message, writing a nested message as field 1. Unfortunately when reading the message, I have to use internal details (BuildImpl).
There's now another API to do this: IMessage.WriteDelimitedTo and IBuilder.MergeDelimitedFrom. This is probably what you want at the moment, but I seem to remember there's a slight issue with it in terms of detecting the end of the stream (i.e. when there isn't another message to read). I can't remember whether there's a fix for it at the moment - I have a feeling it's changed in the Java version and I may not have ported the change yet. Anyway, that's definitely the area to look at.
Protobuf has no terminator - so either close the stream, or use your own length prefix etc. Protobuf-net exposes this easily via SerializeWithLenghtPrefix / DeserializeWithLengthPrefix.
Simply: without this, it can't know where each message ends, so keeps trying to read to the end of the stream.

Categories