How do I tell Network Monitor which packets use my protocol?
- I have written a parser for my UDP-based protocol, which has a port number assigned to it (say 4567). This is of course the port that my server listens on, but clients can use any client port they want, and usually specify 0 which tells the OS to choose one. If the client port is chosen to be one that matches another protocol, the other protocol parser is sometimes chosen over mine. Specifically, if the client chooses port 1701, then the packet is displayed using the L2TP protocol.I have the following in my parser:
[RegisterBefore(UDP.Ssrp, MyProtocol, 4567)]
How can I tell it that if either the source or destination port is 4567 then always use my protocol parser?Similarly, we have a TCP-based protocol as well, which usually uses the same port number, but doesn't have to, so it's possible that neither the client NOR the server will be using port 4567. How can I tell Network Monitor that those packets use my protocol?
All Replies
- By default, the UDP parser should check both source and destination ports. The UDP logic adds both source and destination and uses that to compare. So for UDP we see:
[Local.UDPPort.AddToProperty(srcPort, ADD_TO_PROPERTY_FLAG_NO_DUPLICATES),
Local.UDPPort.AddToProperty(destPort, ADD_TO_PROPERTY_FLAG_NO_DUPLICATES)]
switch(Local.UDPPort)
So we add both ports to a property. The switch then searches this property which will compare each element that was added. If this is not working, please let me know but we have a lot of logic that depends on this so this would seem unlikely.
For your TCP question, this is a little bit more difficult. Usually when protocols use a random port, there will be a negotiation. If this is the case, you can setup a global property to track this information and then register yourself in the section of TCP where we do explicit comparisons. In TCP, the first swithc does inplicit compres against port numbers. But lower in one of the nested defaults, we do more explict comparisons like for NNS or MSRPC. If you regsiter yourself here, you can do a comparison against the global property you setup.
If there is no negotiation, then the user will probably have to modify the NPL manually to look for the port. You could do this with another global that the user has to set in my_sparser.npl.
Please let me know if you need more info.
Paul - I have a capture file where the client happened to choose port 1701 for its source address. When I view it, NetMon decides that this must be an L2TP packet because it uses port 1701. I just need to tell it to check the port number of my protocol first. It doesn't even need to be a bulletproof solution, since this is an unpublished protocol so we'll only be using this parser internally. If it works for my protocol but completely screws up L2TP or other protocols, I don't care. :-)For TCP, it's even more difficult, since the negotiation you mention is done through UDP. The client sends a UDP packet to a well-known port number, and the server responds. Part of the response is the port number to use for the TCP connection. The client makes a TCP connection to that port and the connection continues. So I'd have to set a global to the right port number when parsing the UDP... and then what?Scott
I'm not sure why this is happening, but I've found you can fix this by RegisterBefore UDPPayload.RIP instead or SSRP. Please let me know if that works for you.
For the TCP connection, after you set the UDP port in a global, then you create a check for that global in TCP. So for instance in your UDP protocol, you would set a global based on the port number as an index.
[Global.myport$[1278]="somekey"]This uses a global MultiValueStorage array (as denoted by the $ and indexing[]). I've hard coded the port 1278 above, but in your protocol you can use a port from your data to index the array. Then I set it to some arbitrary string.
Then in your ResgisterBefore, you can look for this arbitraty string based on the tcp src/dst ports.
[RegisterBefore(TCPPayload.SSL, MyProtocol, Global.myport$[tcp.srcport]=="somekey" || Global.myport$[tcp.dstport]=="somekey")]Paul
- Problem 1 is solved - changing SSRP to RIP as you suggested worked. Thanks.However, I'm not having any luck with the second part. I've changed my UDP packet parser so that in the place where the port number is given in the response, I have:
[Global.myport$[resp_port_num]="MyPortNumber"] UINT16 resp_port_num;
Then in the TCP parser, I have basically what you said, replacing the protocol name with my own and replacing "somekey" with "MyPortNumber", but it's not working. However, the third argument to RegisterBefore should be the port number, should it not? In the case above, what is the value of Global.myport$[tcp.srcport]=="somekey" || Global.myport$[tcp.dstport]=="somekey"? I changed it to this, but it still didn't work:[RegisterAfter(TCP.TCPPayload.Ftp, MyProtocol, Global.myport$[tcp.srcport]=="MyPortNumber" ? Global.myport$[tcp.srcport] : 0 )] [RegisterAfter(TCP.TCPPayload.Ftp, MyProtocol, Global.myport$[tcp.dstport]=="MyPortNumber" ? Global.myport$[tcp.dstport] : 0 )]
- If you regsister in the section where you have an explicit port number, like in FTP, then yes it has to be a port number. However, there's not early evaulation in RegisterAfter. So the third argument for doens't get evaluted in this switch because it expects only a number and not an evaluation.
That is why I did my evaulation in "TCPPayload.SSL". In this part of TCP, each swtich evaluation is an expression rather than an explicit port number.
Now if your ports still conflict and reuse well known ports, then your only choice is to modify the TCP parser and have it to a check for your ports first. However, this will affect performance of regular parsing since it will always have to do your check first. But it is possible.

