How I can capture the X11 protocol's traffic?
I need find a way to capture X11 traffic between two machines and also between an X11 server and an X11 client on local machine.
How I can capture the X11 protocol's traffic?
I need find a way to capture X11 traffic between two machines and also between an X11 server and an X11 client on local machine.
You can talk X11 over TCP, or over a Unix domain socket or (on Linux) on a Unix domain socket in the abstract namespace.
When DISPLAY is set to host:4
, short for tcp/host:4
, clients use TCP to connect to the server. The TCP port is then 6000 plus the display number (in that case 6004).
In that case, you can capture the traffic with any network sniffer like tcpdump
or wireshark
by capturing the TCP traffic on that port.
When $DISPLAY
is only :4
(short for unix/:4
), then clients use a unix domain socket. Either /tmp/.X11-unix/X4
or the same path in the ABSTRACT namespace (usually shown as @/tmp/.X11-unix/X4
in netstat
output).
Capturing the traffic is then trickier.
If your X server listens on TCP (but they tend not to anymore nowadays), the easiest is to change DISPLAY
to localhost:4
instead of :4
and capture the network traffic on port 6004 on the loopback interface.
If it doesn't, you can use socat
as a man in the middle that accepts connections as TCP and forwards them as unix or abstract:
socat tcp-listen:6004,reuseaddr,fork unix:/tmp/.X11-unix/X4
You can then set $DISPLAY
to localhost:4
and capture the network traffic as above or tell socat
to dump it with -x -v
.
Now, if you can't change $DISPLAY
and want to capture the traffic of an already running local X application that uses unix domain sockets, that's where it gets tricky.
One approach could be to use strace
(or the equivalent command on your system if not Linux) to trace the send/receive system calls that your application does to communicate with the X server.
Here for xterm
, I observe it does writev()
, recvfrom()
and recvmsg()
system calls on file descriptor 3 for that. So I can do:
strace -qqxxttts9999999 -e writev,recvmsg,recvfrom -p "$xterm_pid" 2>&1 |
perl -lne '
if (($t,$f,$p) = /^([\d.]+) (writev|recvmsg|recvfrom)\(3, (.*)/) {
@p = ($p =~ /\\x(..)/g);
$dir = $f eq "writev" ? "O" : "I";
while (@p) {print "$dir $t 0000 " . join(" ", splice @p,0,64000)}
}' | text2pcap -T6000,1234 -Dqt %s. - - | wireshark -ki -
(or tshark -Vi -
).
The idea being to extract the timestamp and bytes sent/received from the output of strace
and use text2pcap
to convert that into a pcap
(adding dummy TCP headers on port 6000 with -T6000,1234
) before feeding to wireshark
. We also split packets to avoid the 64kiB limit on the maximum length of a pcap record.
Note that for text2pcap
to work properly with regards to getting the traffic direction right, you need a relatively recent version of wireshark.
If you are mainly interested in the X11 protocol and not the underlying TCP/IP and ethernet stuff, and if you are able to adjust the client or the server settings, you might use a tool specifically designed to capture and decode the traffic between an X11 client and an X11 server. Unlike the wireshark
X11 dissector, these tools are unlikely to be confused by the traffic, being fully involved with it.
The main one is xscope which, despite not being available as a binary for some Unix or Linux distributions, can easily be built from source.
Alternatively, there are also xtruss and xtrace but I have no experience with them.
All of these tools acts like reverse-proxies relaying connections to a real X11 server. The clients simply use a different DISPLAY variable (or -display argument) to connect to the proxy.
eg:
$ wget http://xorg.freedesktop.org/archive/individual/app/xscope-1.4.1.tar.gz
..
$ tar xzf xscope-1.4.1.tar.gz
..
$ cd xscope-1.4.1
$ ./configure && ./make
..
$ ./xscope & sleep 5; xclock -display :1
...
0.00: Client --> 12 bytes
byte-order: LSB first
major-version: 000b
minor-version: 0000
0.00: 692 bytes <-- X11 Server
protocol-major-version: 000b
protocol-minor-version: 0000
release-number: 00adfef8
resource-id-base: 04c00000
resource-id-mask: 001fffff
motion-buffer-size: 00000100
image-byte-order: LSB first
bitmap-format-bit-order: LSB first
bitmap-format-scanline-unit: 20
bitmap-format-scanline-pad: 20
min-keycode: 8 (^H)
max-keycode: 255 (\377)
vendor: "The X.Org Foundation"
pixmap-formats: (7)
roots: (1)
0.00: Client --> 20 bytes
............REQUEST: QueryExtension
name: "BIG-REQUESTS"
0.00: 32 bytes <-- X11 Server
..............REPLY: QueryExtension
present: True
major-opcode: 85
Note: If for some reason you cannot change the X11 clients settings (display), you might be able to reconfigure the server to listen to a different port (typically 6001 vs 6000) and then configure xscope
to listen on the original port (6000).
6c 00 0b 00 00 00 00 00 00 00 00 00
. Authorization protocol name and data are empty here, as allowed by the X11 protocol.
– jlliagre
May 31 '17 at 23:39
xtrace -D:1 -d:0 -k
. (Or x11trace, as the executable is named on some distros)
– Aleksi Torhamo
Feb 11 '18 at 01:26
X11 uses TCP as its transport protocol. The TCP port range for X11 is usually 6000-6063 but most likely you will see TCP port 6000 being used.
So, you should be able to use any network monitor of your choice to observe the traffic by filtering for this port range and the hosts in question. I also know, that wireshark
, for instance, already contains a filter preset x11
to monitor the traffic you are interested in.
For example, to monitor all X11 traffic on the local machine (if using TCP; refer to the answer of @Stéphane Chazelas) use the following filter:
x11 and ip.src=127.0.0.1 and ip.dst=127.0.0.1
lsof -U | grep '^X'
.
– goldilocks
Mar 23 '15 at 15:46
... and tcp.port == 6004
if you're listening to multiple displays at the same time.
– yyny
Feb 24 '20 at 19:44