Here it is:
tcpdump tcp[13] == 2
Here, tcp[13] contains the value of the 13th octet in the TCP header. And, to match only SYN packets, this value must be equal to 2 when interpreted as a 8-bit unsigned integer in network byte order.
Follow-up question: what would be the tcpdump format to see both SYN and ACK packets (but not SYN-ACK)?
Answer:
tcpdump ‘tcp[13] & 2 == 2′
To see only SYN and ACK packet (& not SYN-ACK packets) we will have to logically AND the value for the 13th octet. As it is entioned in the man pages of tcpdump:
In order to achieve our goal, we need to logically AND the binary value of octet 13 with some other value to pre‐
serve the SYN bit. We know that we want SYN to be set in any case, so we’ll logically AND the value in the 13th
octet with the binary value of a SYN:
00010010 SYN-ACK 00000010 SYN
AND 00000010 (we want SYN) AND 00000010 (we want SYN)
——– ——–
= 00000010 = 00000010
We see that this AND operation delivers the same result regardless whether ACK or another TCP control bit is set.
The decimal representation of the AND value as well as the result of this operation is 2 (binary 00000010), so we
know that for packets with SYN set the following relation must hold true:
( ( value of octet 13 ) AND ( 2 ) ) == ( 2 )
This points us to the tcpdump filter expression
tcpdump -i xl0 ’tcp[13] & 2 == 2’