TCP options of a SYN packet

Dear All,

Just wondering if anyone knows a way (an event) to obtain TCP options of a SYN packet?

Your help will be very much appreciated.

Thank you.

Best regards,


Hi Thomas,

there is the tcp_option event, that might help you (see If that does not fit for you, you might have a look into the TCPRS-plugin ( I have never used it but I think it also parses some TCP options and thus might be a good starting point.

Best regards,


Dear Jan,

Many thanks for you reply. I am using tcp_option event. However, it seems to me that the event can’t tell which TCP options are from the SYN packet of a connection and which ones are from other packets of the connection. I think I will look into the TCPRS-plugin.

Best regards,


Dear All,

I have checked out the TCPRS-plugin ( Unfortunately, it does not do the job. It cannot get TCP options and the order of the options down from a SYN packet. The TCP options of a SYN packet I am concerning are described below.

NOP option

EOL option

window scaling option, value nnn (or * or %nnn)

maximum segment size option, value nnn (or * or %nnn)

selective ACK OK


timestamp with zero value

unrecognized option number n.

Your kind help will be very much appreciated.

Best regards,


It sounds like you might want to write your own plugin but it might even be possible that that’s not enough and you’d have to add a feature to Bro’s core to generate an event only for SYN packets. (although you generally have to be very careful about even generating an event for a single packet).


This probebly explains your problem

in bro-plugins/tcprs/src/

UsesTSOption = false;
sack_in_use = false;


in bro-plugins/tcprs/src/

usesTimestamps = false;
checkedForTSOptions = false;


Dear Seth,

Actually, I am writing a module using the outputs from Bro to detect Operating Systems running on remote host machines. I need to get the fingerprints of these OS for classification. I want to know if there is any means to obtain p0f-like OS fingerprints.

Best regards,


Dear Daniel,

Thanks for your reply. Could you give me an example or documentation detailing how I could achieve my goal?

Best regards,



Bro has p0f support built-in. See:

That being said, the original p0f fingerprints are very out of date, and
it's possible that Bro will stop supporting p0f in the future. I did
some research on the fingerprints with the Windows XP end of life, and
ended up leveraging some of Bro's other capabilities to write a much
better detection:

Generally, I think the interest is in moving up the stack and performing
this kind of fingerprinting at a higher, more reliable, layer.


Thomas Tan <> writes:

Hi Vlad,

Thanks for your reply.

I am aware of the support of p0f in Bro. You are right. The original p0f v2 fingerprints are out-dated. In my work, I am not using the p0f v2 fingerprints but collecting OS fingerprints from network connections initiated by remote machines. A multi-class classifier will be applied to assign these OS fingerprints to their respective OS types.

Best regards,


Indeed. Modern OS literally scream their versions over the network. Personally I find Bro's software detection capability to determine applications and libraries used on devices I cannot login to. Think IoT.

Doing OS recognition per packet, based on IP options has always been a poor idea. Prone to false positives, difficult to update and does not scale.

I’m sorry I didn’t see this earlier. I’m curious. Why is the order of the options important? Are you searching for OS specific behavior?

Hi Thomas,

Tcp options and specific the option-timestamp is very important for device detection oflinux-like kernels. P0f is really outdated and unuseable for mobile devices. We did some
research on detecting devices behind a NAT router. Mac and windows can be followed by
taking a look at source port behaviour (windows can be done with the ip-id field). But if
you have a linux machine is behaves with random ports (see linux kernel source). The
tcp-options ts uses the time since the device is up. So if you do a capture_ts - (tcp_ts*factor)
you get a “constant” number per device. The factor depends on the kernel source.
I’ll have a look at the code, Thomas, I’ll get back later.



As you noted already, TCPRS doesn’t provide that type of behavior. The options of interest to TCPRS are limited and only reported via the TCPRS::conn_config event, which certainly does not fit your needs. That said, extending the TCPRS plugin, or the TCP analyzer within bro doesn’t seem to be something that is out of the realm of possibility here.

As Seth mentioned above, generating an event for every syn is potentially expensive. SYN retransmissions may generate duplicate records.

You could create a new event in the source for syn options, but I’m not aware of any bro constructs that would (easily) allow for providing the options in the order they are observed in the header(Seth,Vlad,Daniel - please chime in here). It might be possible to send (ID, value) tuples to the script with a new event, given that the tuples are inserted into a vector in the order they are observed in the header. Once in the script, you could convert the ID (option identifier) into the string representation and create a single string that could easily be parsed.

Example record: 2000 2001 TCPOPT_MAXSEG=3,TCPOPT_WSCALE=1

Obviously, the output format is dictated by the bro script, so that isn’t terribly important here since that would be up to your design.

I’m sure you are already aware of issues with fingerprinting, but some values might differ within the same OS depending if the kernel has been modified or kernel config options have been modified from their default values.

If this type of approach interests you, let me know.

I agree TCPRS is not the place.
When i look at the analyzer, i miss
some options available from /usr/include/netinet/tcp.h

define TCPOPT_EOL 0

define TCPOPT_NOP 1





define TCPOPT_SACK_PERMITTED 4 /* Experimental */


define TCPOPT_SACK 5 /* Experimental */




It would be nice to have them available when needed. OS fingerprint can be done
on how it was constructed, the order is free and each kernel treats the rules different.
This can tell you what type of os you see, but some are universal.
But if you want to detect two or more devices and want to relate the traffic to the device,
you really need the timestamp.
It could also provide a method to detect cooked packets or a virus that creates its own packets.
And I think it is actually very cheap because you are sure you only get 1 syn (beside retrans)
per connection and that is way less than HTTP for example.



I agree TCPRS is not the place.

Agreed. I would like TCPRS to be useful in this case, but the feature falls out of the scope of design of TCPRS.

It might not be difficult to write a simple analyzer that looks only at syn packets and produces the events that Thomas is looking to generate. A simple analyzer may not need to retain packets like TCPRS does and would have a much faster execution and lower memory footprint because it doesn’t need to do retrospective analysis on the connection.

Dear Daniel and Jame,

Thank you so much for your comments and advice. I had been away for a quite few days and just got time to check the emails. I will try to write my simple analyzer and will come back to you later.

Best regards,