My understanding about X11 was wrong
Recently worked on X11 issues both personally and at work. I had faced X11 display errors in the past and fixed them but didn't get a chance to understand X11 architecture in-depth.?
But this time, I wanted to understand why I was executing particular X11 command mentioned in multiple articles about X11 display issues. After spending a couple of days, I gained a basic understanding of X11. I plan to share my basic knowledge about X11 in this article.?
Note:- I am no expert on the X11 application. There might be some mistakes in my understanding. All the X11 commands have been executed only on Amazon Linux 2 and Mac OS, So few commands might not work on other operating systems.
What is X11?
The X Window System is software that helps to display text and graphics. It can show the GUI application over the network. 'X' Windows System is cross-platform and runs on multiple OS. The 'X' protocol is a display server protocol. It helps communication between the 'X' client and the 'X' server. X11 means version 11, which is the 'X' protocol version.
X Window System Architecture
[1]
[2]
What is the DISPLAY variable, and why is it needed?
'DISPLAY' variable beautifully informs the 'X' client where the 'display server' or 'X' server is running. 'X' server is the one that interacts with Kernel and hardware and displays the GUI.
Format of 'DISPLAY' variable is '<hostname>:<displaynumber>.<screen number>
Hostname: refers to the server which displays the GUI. Default value 'localhost.'
Display number:??Each X Server that is running gets a number. The default value is 0. By default 'X' server starts on port '6000', and this value is added to '6000' to get the 'X' server port. For example, if the display number value is '0', 'X' server runs on port 6000. If the display number is '10', 'X' server runs on port 6010.
Screen Number:?It tells which physical monitor to display the GUI. Default value is '0'. Allows moving GUI across all the physical monitors. If the value is '1' displays GUI on physical monitor 1.
Few examples
export DISPLAY=:0 means "X Server is running on localhost on port 6000".
export DISPLAY=:10.0 means "X Server is running on localhost on port 6010."
export DISPLAY=192.168.1.230:10.0 means "X Server is running on the server 192.168.1.230 on port 6010."
X Server Authorization
'X' server will not accept connections from just anywhere. We can authorize 'X' clients with the below methods.
1) xhost?allows authorization based on hostnames. This setting is applied at the server level. The server maintains a list of servers(X Clients) allowed to connect. We can also disable host checking entirely, which means any host can connect 'X' server but this is a huge security risk.
It is better to choose 'ssh' or 'xauth' authorization for security risks with 'xhost' authorization.?
Example:
xhost +1.2.3.4 # allows 'X' client from 1.2.3.4
2) xauth?allows access to anyone who has the 'MIT-MAGIC-COOKIE-1'. The ~/.Xauthority file stores the cookie. The 'X' client presents the cookie to the 'X' server, and I guess the 'X' server matches the client cookie with the cookie it has. If the cookies don't match, the 'X' Server will reject the connection from the 'X' Client and throws an 'authentication' error.
commands:
xauth list # lists the authorization entries for each specified display
xauth generate #generates authorization token and adds to 'X' server.
xauth add # adds the authorization entry to ~/.Xauthority file.
3) ssh?allows X11 forwarding over an encrypted connection. To display over SSH, we need to turn on 'ForwardX11' on 'sshd' daemon and connect using the '-X' option using 'ssh.'
sudo cat /etc/ssh/sshd_config | grep -i X11 | grep -v '#'
X11Forwarding yes
ssh -X -i <private_key> ec2-user@<server>
Examples
领英推荐
1) ssh(Amazon Linux 2)
This example shows the 'X' server and 'X' client setup using 'ssh.' In this example, the 'X' server and 'X' client runs on the remote server, and X11 packets are forwarded to the laptop over an encrypted SSH connection.
Prerequisites
1) Make sure 'X11Forwarding' is enabled on 'sshd'.
sudo cat /etc/ssh/sshd_config | grep -i X11 | grep -v '#'
2) Install 'xauth' package. This package contains 'xauth'.
sudo yum install xorg-x11-xauth -y
3) Install 'xorg-x11-apps'. This package contain 'X' client tools.
sudo yum install xorg-x11-apps -y?
4) Install 'xorg-x11-utils'. This package contain 'X' utilities like 'xdpyinfo'.
sudo yum install xorg-x11-utils -y
ssh
ssh -X -i <private_key> <user>@<server>
$ echo $DISPLAY
localhost:10.0
$ sudo netstat -anp | grep -i 6010
$ xauth list
$ xeyes # opens the GUI.
What's happening in the background?
Without the ' X ' option, let's connect to the remote server using 'ssh.'
1) DISPLAY variable is empty.
$echo $DISPLAY
2) 'X' server is not running.
$sudo netstat -anp | egrep -i '6000|6010'
3) 'X' client will not work.
xeyes
Error: Can't open display:?
Now let's connect to the remote server using 'ssh' using the '-X' option.
When we launch the 'ssh' connection using the '-X' option, 'sshd' daemon starts proxy 'X' server, updates '~/.Xauthority' file with 'MAGIC COOKIE' and sets the DISPLAY variable to the 'X' server.
1) 'sshd' daemon starts the proxy 'X' server.
$sudo netstat -anp | egrep -i '6000|6010' | grep -i '\<tcp\>' | grep -i LISTEN
tcp? ? ? ? 0? ? ? 0 127.0.0.1:6010? ? ? ? ? 0.0.0.0:*? ? ? ? ? ? ? ?LISTEN? ? ? 30924/sshd: ec2-use?
2) Updates ~/.Xauthority file with MAGIC COOKIE
$ cat ~/.Xauthority
$ xauth list
3) Sets the DISPLAY variable.
$ echo $DISPLAY
localhost:10.0
4) 'X' client tools work now. For example 'xeyes'.
$ xeyes
2) xhost(Mac OSX)
In this example, we run the 'JMeter' docker container which runs JMeter GUI('X' Client) and this 'X' client connects to the 'X' Server which is the 'XQuartz' server running on Mac OSX.
Prerequisites
1) Install 'XQuartz' which is 'X' server for Mac OSX.
brew install --cask xquartz
2) Open 'xquartz'. This starts the 'X' server and sets the DISPLAY variable. Also we can see 'X' server running on port 6000.
$ netstat -an | grep -i 6000 | grep -i tcp4 | grep -i LISTEN
tcp4 ? ? ? 0? ? ? 0? *.6000 ? ? ? ? ? ? ? ? *.*? ? ? ? ? ? ? ? ? ? LISTEN
$ echo $DISPLAY
xhost
1) Now we will use 'xhost' authorization to allow 'X' clients to connect to 'X' server
2) ip=$(ifconfig en0 | grep -i '\<inet\>' | cut -d " " -f2)
3) Before 'xhost' authorization, we get below error, even though 'DISPLAY' variable is set by 'XQuartz' server.
$ docker run -e DISPLAY=$ip:0.0 docker.io/justb4/jmeter:5.4
An error occurred: Can't connect to X11 window server using '192.1.1.40:0.0' as the value of the DISPLAY variable.
4) Enable 'xhost' authorization
xhost +$ip
192.1.1.40 being added to access control list
5) Now run the docker container again. It will display the JMeter GUI.
docker run -e DISPLAY=$ip:0.0 docker.io/justb4/jmeter:5.4
What's happening in the background?
In this scenario, 'X Client' is 'JMeter' GUI. And we set the DISPLAY to the 'X' Server, the 'XQuartz' server.
Let's try to run the JMeter container without the 'X' Server(XQuartz Server). The 'X' Client cannot display the GUI because the 'X' Server is not running.
1) Lets run the JMeter docker container.
$ ip=$(ifconfig en0 | grep -i '\<inet\>' | cut -d " " -f2)
$ docker run -e DISPLAY=$ip:0.0 docker.io/justb4/jmeter:5.4?
2) Docker container throws below error.
An error occurred: Can't connect to X11 window server using '192.1.1.40:0.0' as the value of the DISPLAY variable.
3) Above error means 'XClient'(JMeter GUI) is trying to connect to the 'X' server running at '192.1.1.40' on port '6000'.
4) We can confirm nothing is running on port '6000'
$ netstat -an | egrep -i '6000|6010' | grep -i LISTEN
'X' Client is not working with Sudo
Let's suppose we ssh into the remote server using the 'ec2-user' with the '-X' option. 'ec2-user' will not have any issues displaying 'X' Client tools like 'xeyes' because 'sshd' daemon sets 'X' Server authorization using 'xauth' in the file '~/.Xauthority'.
But the '~/.Xauthority' file is created in the user home directory, and this home directory changes when we 'sudo'. Also, the DISPLAY variable is unavailable when we 'sudo' to another user. Due to these reasons, 'X,' Client applications don't work when we 'sudo'.
How to fix 'sudo' issue
We can fix this issue using the below solution. In the below example let's suppose we try to 'sudo' to 'ssm-user'.
# Below command updates sudo user ~/.Xauthority with MAGIC Cookie
$echo "xauth add $(xauth list | grep unix$(echo $DISPLAY | cut -c10-12))" | sudo su - ssm-user
# Below command sets the DISPLAY variable for the sudo user.
$sudo -Eu ssm-user bash -c 'echo export DISPLAY=$DISPLAY >> ~/.bash_profile'
# We can see 'MAGIC COOKIE' of sudo user 'ssm-user' and original user 'ec2-user' is same. If the 'MAGIC COOKIE' is different, we will get authentication error because the cookies of 'X' Server and 'X' Client doesn't match.
$xauth list
Note:- The above commands need to be executed every time we log in using 'ssh -X' because 'MAGIC COOKIE' is changed by 'sshd' every time. This process can be automated using ec2 'user data', which updates the login user profile.
Important utilities/tools
$xdpyinfo | grep -i 'name of display'
$xlsclients
Conclusion
Before this journey of understanding how the 'X' Windows system works, I was always under the impression that the 'X' Server runs on the remote server and the 'X' client is a local machine. But I was wrong. Recent issues helped me understand how the 'X' Windows system works. No more random copy and paste of DISPLAY variable.
References