18

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.

zh_
  • 181

3 Answers3

24

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.

  • Do you know the reason behind defaulting to unix domain sockets? Does TCP have any (significant) impact on performance or other drawbacks? – inVader Mar 23 '15 at 16:15
  • 1
    @inVader, well yes, that's a whole TCP/IP protocol to implement, going through several layers... I suppose the system can take shortcuts (like not implement the usual congestion avoidance algorithm) for loopback connections, but still, in my tests I get twice as much throughput with a simplewith unix-domain socket as with a tcp socket socat test. – Stéphane Chazelas Mar 23 '15 at 16:28
16

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).

jlliagre
  • 61,204
  • I tried to compile xscope ... "No package 'xproto' found". pls can you write here the dump of the first packet ( 12 bytes ) ? – Massimo May 31 '17 at 21:33
  • @Massimo Did you install the missing package? – jlliagre May 31 '17 at 22:19
  • I am using a linux istance on Amazon, and yum doesn't know xproto. Pls can you post the dump of the first packet ? I only need that, thks. – Massimo May 31 '17 at 22:21
  • beacuse the usual first packet is 21 bytes, not 12, see "Connection Initiation" in https://www.x.org/releases/current/doc/xproto/x11protocol.html – Massimo May 31 '17 at 22:30
  • @Massimo Here is the first packet: 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
  • 1
    Just tried xtrace - can confirm that it also works fine; its output is more compact, with one line per message - so also easily greppable. Run with eg. xtrace -D:1 -d:0 -k. (Or x11trace, as the executable is named on some distros) – Aleksi Torhamo Feb 11 '18 at 01:26
4

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
inVader
  • 248
  • 1
    The local client-server messages are passed via a unix domain socket, lsof -U | grep '^X'. – goldilocks Mar 23 '15 at 15:46
  • You can further restrict the filter with ... and tcp.port == 6004 if you're listening to multiple displays at the same time. – yyny Feb 24 '20 at 19:44