“Using your own display and audio hardware is so last year!”
Jay runs the X window system and sndio over the network
Reckless Guide
Part 8
This week, Jay shows us how to run graphical programs over the network, and forward audio from programs running remotely back to our local workstation.
If you've never used X in a networked configuration before, get ready for an exciting ride!
This article is part of a series - check out the index.
Website themes
The Exotic Silicon website is available in ten themes, but you haven't chosen one yet!
Re-purposing exising functionality
Whilst the original motivations for remote display might not be as useful in modern times as they used to be, we can certainly find other ways to put this functionality to work.
Plus, it's also an interesting historical insight into a protocol developed in a much earlier era.
Why bother?
Running a graphical program remotely and sending the raw framebuffer data back over the network for display on the local workstation might sound extremely awkward and inefficient.
With modern high-resolution displays, that's a lot of data to be shuffling around, even between two directly connected machines on a fast LAN.
However, there certainly are advantages to doing this, and numerous interesting aspects that we can make use of.
Let's be clear here that we are not talking about simple ‘screen and keyboard mirroring’ of a remote machine for maintenance purposes.
Rather, we're talking about running a program such as a webbrowser on a remote CPU, and interacting with it within our local graphical X session together with other graphical programs running on our machine, as if the program running on the remote CPU was in fact just another X application running normally on the local workstation.
Possibilities of using remote X
  • The remote machine can be a different hardware architecture.
  • The remote machine can be running a different operating system.
  • The remote machine doesn't need any graphical hardware.
  • The program running remotely is effectively sandboxed from the local machine and can't directly execute code or access files on it.
  • The program running remotely has fast access to any data stored locally on that remote machine.
  • We can potentially connect to multiple remote machines and run diverse software from all of them simultaneously on our workstation.
  • We can avoid the need to install excessive amounts of software on our main workstation, facilitating upgrades and other maintenance.
Already, some of the potential advantages should have become clear...
This whole concept of a networked windowing system might seem alien to anybody who has only worked in the IT industry in the modern era. CPU and graphics hardware has become cheap enough that even the most basic workstation won't struggle with typical business applications such as web browsers, graphics manipulation programs, and even video editors.
However, the X window system was conceived in a different era, when powerful CPUs and graphics hardware were much more expensive than they are today. It made a lot of sense to allow users to send graphical output elsewhere. This was also relatively straightforward to implement, in part because it was expected to be run across a trusted network, with little need for security.
Whilst the original motivations for remote display might not be as useful in modern times as they used to be, we can certainly find other ways to put this functionality to work.
The graphical output that we see from X applications, is produced by an X server. Usually, users interact directly with an X server running on their own workstation. This X server accepts, processes, and forwards keystrokes and pointer movements to the applications, which are it's clients.
Users can also interact with X applications in other ways. They can be started from a text console, accept input from that console's standard input, be controlled by the shell running on that console, and receive signals, just like any regular non-X application.
Communication between the X applications and the X server that they are connected to, takes place over one of several possible communications channels. Typically, connections to an X server running on the same machine will be made using a local UNIX-domain socket, and remote connections will use a TCP socket. A running X server can listen on both a UNIX-domain socket and a TCP socket, and there can be multiple independent X servers running on the same machine.
In either case, the byte stream flowing over the socket connection is the X Window System Protocol. This low-level protocol is an open specification, freely available on the internet.
To set up a networked X11 connection, we essentially only need to configure the X server to listen on a remotely accessible TCP port, configure the client programs to use that same port for their communication with the X server, and ensure that appropriate authentication records are in place to grant access to the X server to the client.
However, in practice, we will also usually want to take steps to encrypt the network traffic.
Important note
Native networking functionality verses ssh port forwarding
Other guides to setting up networked X connections often rely on specific X11 forwarding functionality built into the ssh program. This works slightly differently to the way described here, which just uses the native networking functionality of the X server.
Although the X11 forwarding functionality in ssh can be useful as a quick and easy way of making occasional ad-hoc connections to remote X servers, it comes with a protocol overhead which is not insignificant. Especially for connections over a trusted LAN where encryption is not required, performance will likely be much improved by configuring the connection directly without using an ssh tunnel. Furthermore, understanding how X networking is configured natively may be useful when diagnosing problems running the X protocol over ssh.
In essence, using ssh for X11 forwarding is the lazy solution. If you still want to use the ssh forwarding method instead of the method described here, the manual page for ssh(1) explains it.
Example hostnames
In the examples that follow, we'll be considering two machines.
The local workstation, which will run the X server, has hostname desk.lan.
The remote machine, which will run the X application and send it's output over the network to the X server running on desk.lan, has hostname rack.lan.
We'll also assume that the local X server is being invoked manually, rather than via a display manager such as xenodm, although most of the same principles apply in both cases.
Selecting one X server from many
Virtually all X applications check the value of the DISPLAY environment variable to find out where to send their graphical output.
When we run a single X server on the local machine, we don't usually need to concern ourselves with the setting of the DISPLAY environment variable. If X is invoked by a user from the command line, then this variable is usually set by xinit.
When accessing remote servers, (or our local server from a remote machine), we need to set it manually.
The first, (and often only), X display on the local machine is designated :0. If the X server is listening on TCP sockets, this will usually be the display that is using port 6000.
The same display accessed remotely would be designated by prefixing the display number with the hostname, as hostname:0.
desk$ ssh rack.lan
rack$ export DISPLAY=desk.lan:0
Connect to a remote machine, and point the DISPLAY environment variable back to the local host
Setting the DISPLAY environment variable manually can also be useful if we want to start an X application on the local display, from a text-based virtual terminal also on the local machine. In this case a simple export DISPLAY=:0 will suffice.
Enabling TCP connectivity to the X server
The most commonly used TCP port for the X Window System Protocol is 6000, with any second and subsequent servers using ports 6001 onwards. Although it's possible to run the protocol on an alternative set of ports, most software sets this port range at compile time, so doing so is likely to be cumbersome.
The command line option to enable listening on a particular connection type is -listen:
desk$ X -listen tcp
Start the X server, configured to allow inbound TCP connections
Of course, starting a bare X server with no window manager is not usually what we want to do. It might be useful if we want to build a dedicated X terminal, but in most cases we will want to start our regular X environment instead:
desk$ startx -- -listen tcp
Run the startx script, but allow inbound TCP connections
Note the use of -- to signal the end of the argument list to the startx script itself, to allow the -listen option to be passed directly to the X server.
The -listen tcp option will configure the X server to listen on both IPv4 and IPv6 addresses. To restrict listening to a single protocol, we can use the options -listen inet6 for IPv6, or -listen inet for legacy IPv4.
By default, the X server listens on all interfaces. The firewall ruleset that comes in the base OpenBSD installation blocks TCP ports 6000 to 6010 on all interfaces except localhost, so we need to adjust this as necessary to grant access to the hosts that will be connecting.
Once we've enabled listening of the X server via a TCP port, then assuming that network connectivity between the machines is correctly configured, with no firewall blocking access, we can connect to the X server from the remote machine:
rack$ nc -v desk.lan 6000
Connection to desk.lan (2001:db8::1) 6000 port [tcp/*] succeeded!
Test network-level connectivity
Once we have basic network connectivity to the correct port, we can move on to configuring X authentication records.
Configuring X authentication records
If we try to run a program on the remote host and direct it's graphical output back to our local server, we'll see that it doesn't work:
desk$ ssh rack.lan
rack$ export DISPLAY=desk.lan:0
rack$ xclock
No protocol specified
Error: Can't open display: desk:0
Connecting to an X server without first configuring authentication records isn't much fun!
But at least TCP/IP connectivity is working!
Note that the above error, specifically the ‘No protocol specified’, implies that connectivity at the TCP/IP networking level is working.
If we were, instead, trying to connect to a closed port, such as might occur if the X server wasn't actually running on desk.lan, then we would just see the ‘can't open display’ line:
Connecting to a closed port which immediately returns a RST packet.
The absense of the ‘No protocol specified’ line suggests a network connectivity issue.
desk$ ssh rack.lan
rack$ export DISPLAY=desk.lan:0
rack$ xclock
Error: Can't open display: desk:0
Subtly different
No protocol specified? Huh???
The ‘no protocol specified’ error message may appear somewhat cryptic to users who are not familiar with networked X connections. The error message effectively means that no credentials have been supplied to authenticate with the remote machine. The protocol it refers to is an authorisation protocol. The design of the X Window System Protocol allows for various different authorisation protocols to be used, and since we haven't provided any credentials at all, obviously no protocol has been specified either, hence the reference to this in the error message.
The authentication protocol that we will be using is a simple 128-bit cookie that is generated by the X server, and passed to the remote host to which we want to allow access. The remote host then passes the cookie back whenever it needs to authenticate itself. The name of this protocol is MIT-MAGIC-COOKIE-1.
MIT-MAGIC-COOKIE-1 is your friend
Important note
Important note:
Although the X window system supports various ‘security features’, these are extremely primative by today's standards.
For effective access control, privacy, and confidentiality, the transport of the X Window System Protocol across the network should be protected by an encrypted tunnel. Access to the open network ports on the host should additionally be restricted with the use of a firewall, to further protect against the potential exploit of any as yet un-discovered vulnerabilities that might be present in the X server.
The native security features are still somewhat useful, however, to protect against mis-configuration or casual operator errors such as connecting to the wrong X server on a network. For this reason, we configure them rather than simply globally disable them.
To generate a suitable cookie, we use the xauth program
desk$ xauth -f new_cookie generate desk.lan:0 .
xauth: file new_cookie does not exist
desk$ scp -p new_cookie desk:.Xauthority
Generate a new 128-bit cookie, and send it to the remote machine
The ‘file new_cookie does not exist’ message is informational, and not an error.
If the file does already exist, it will be silently overwritten.
Note the use of the -p argument to scp. The file created by xauth has it's permissions set to 0600, and we want to ensure that the transferred file is only accessible by the user, and not group or world readable.
At this point, we can run X applications on rack.lan, and their output will appear on the X server running on desk.lan:
desk$ ssh rack.lan
rack$ export DISPLAY=desk.lan:0
rack$ xclock
Running an X application remotely, with display on the local X server
Important note
Host-based access control
Access to an X server can also be controlled via a host-based access control list. This is usually manipulated by the xhost program.
By default on OpenBSD, host-based access control is enabled, and the list of permitted hosts is empty. In this configuration, no connections are permitted, (including local connections via UNIX-domain sockets), unless authorised via an authentication record created by xauth.
Although the xhost program and it's functionality still exist, in most cases there is little reason to use this method of access control instead of the user-based cookie system described above. Additionally, xhost doesn't support the concept of trusted and untrusted connections that xauth does, so all connections authenticated in this way will effectively be trusted connections, as explained in the next section.
Trusted verses untrusted connections
By default, authorisations created using ‘xauth generate’ are untrusted.
The concept of trusted and untrusted clients provides us with a way to implement a very limited form of isolation between different client programs.
Many users don't realise the extent to which different client applications using the same X server are able to interact with each other via the window system itself.
An obvious example would be taking a screenshot of the whole desktop...
desk$ xwd -root -out screenshot.xwd
Dumping the contents of the root window to a file
However, an X application can also send keystrokes to another X application, and change it's properties. For example, we can start xclock, and from a completely separate instance of xterm, change the title displayed by the window manager for the xclock window:
desk$ xprop -name xclock -set WM_NAME chronograph
Modifying the WM_NAME property of another X application
Ignoring the fact that this might be undesirable even in a local single user environment, it's quite easy to see that it's even less of a good idea when the X server accepts connections from other hosts.
If we try the same command from rack.lan, however, by default it fails:
desk$ xclock &
desk$ ssh rack.lan
rack$ export DISPLAY=desk.lan:0
rack$ xprop -name xclock -set WM_NAME chronograph
X Error of failed request: BadAccess (attempt to access private resource denied)
Major opcode of failed request: 18 (X_ChangeProperty)
Serial number of failed request: 27
Current serial number in output stream: 29
Trying but failing to modify the WM_NAME property of a locally run program, from an untrusted remote session.
Unfortunately, that's about as far as this security feature goes.
This happens because the authorisation that we created for our user on rack.lan is untrusted. Untrusted clients are limited in what they can do to trusted clients. And unfortunately, that's about as far as this security feature goes. There is a broad two-way distinction between two classes of client, but there is nothing to stop one untrusted client from interfering with another untrusted client, nor to stop a trusted client from interfering with anything.
Handy hint!
Avoiding spurious application crashes
Untrusted clients will crash if they try to access the root window, or the terminal bell.
This latter restriction can be a source of much frustration when editing a text file in vi, and hitting escape once too often. Invoking xterm with the visual bell option -vb is a convenient workaround for this.
Copy and paste is also not supported from untrusted to trusted clients, although text copied from trusted clients can be pasted into untrusted ones. Certain other operations are also restricted.
Despite these limitations, however, overall most X client programs will work quite happily when run in an untrusted environment.
We could, of course, have just created a trusted authorisation all along:
desk$ xauth -f new_cookie generate desk.lan:0 . trusted
Creating a trusted authorisation
Now, clients connecting and authenticating using this cookie will not have the restrictions we described above placed on them. The example above of renaming the xclock window would succeed.
Once again, this security feature is very limited in it's scope. Just because a client is ‘trusted’ doesn't imply anything beyond it having unlimited access to the other resources on the X server.
Format of the .Xauthority file
The format of the .Xauthority file is defined in /usr/xenocara/lib/libXau/include/X11/Xauth.h, as the ‘xauth’ structure. The .Xauthority file we generated earlier on desk.lan would look something like this:
00000000 00 06 00 10 20 01 0d b8 00 00 00 00 00 00 00 00 |.... ...........|
00000010 00 00 00 01 00 01 30 00 12 4d 49 54 2d 4d 41 47 |......0..MIT-MAG|
00000020 49 43 2d 43 4f 4f 4b 49 45 2d 31 00 10 45 78 4f |IC-COOKIE-1...?Q|
00000030 74 49 63 53 69 4c 69 43 6f 4e a6 af bc |D..gG~<......|
00000000 00 06 00 10 20 01 0d b8 00 00 00 00 00 00 00 00 |.... ...........|
00000010 00 00 00 01 00 01 30 00 12 4d 49 54 2d 4d 41 47 |......0..MIT-MAG|
00000020 49 43 2d 43 4f 4f 4b 49 45 2d 31 00 10 45 78 4f |IC-COOKIE-1...?Q|
00000030 74 49 63 53 69 4c 69 43 6f 4e a6 af bc |D..gG~<......|
00000000 00 06 00 10 20 01 0d b8 00 00 00 00 00 00 00 00 |.... ...........|
00000010 00 00 00 01 00 01 30 00 12 4d 49 54 2d 4d 41 47 |......0..MIT-MAG|
00000020 49 43 2d 43 4f 4f 4b 49 45 2d 31 00 10 45 78 4f |IC-COOKIE-1...?Q|
00000030 74 49 63 53 69 4c 69 43 6f 4e a6 af bc |D..gG~<......|
00000000 00 06 00 10 20 01 0d b8 00 00 00 00 00 00 00 00 |.... ...........|
00000010 00 00 00 01 00 01 30 00 12 4d 49 54 2d 4d 41 47 |......0..MIT-MAG|
00000020 49 43 2d 43 4f 4f 4b 49 45 2d 31 00 10 45 78 4f |IC-COOKIE-1...?Q|
00000030 74 49 63 53 69 4c 69 43 6f 4e a6 af bc |D..gG~<......|
00000000 00 06 00 10 20 01 0d b8 00 00 00 00 00 00 00 00 |.... ...........|
00000010 00 00 00 01 00 01 30 00 12 4d 49 54 2d 4d 41 47 |......0..MIT-MAG|
00000020 49 43 2d 43 4f 4f 4b 49 45 2d 31 00 10 45 78 4f |IC-COOKIE-1...?Q|
00000030 74 49 63 53 69 4c 69 43 6f 4e a6 af bc |D..gG~<......|
A hexdump of a typical .Xauthority file...
00000000 00 06 00 10 20 01 0d b8 00 00 00 00 00 00 00 00 |.... ...........|
00000010 00 00 00 01 00 01 30 00 12 4d 49 54 2d 4d 41 47 |......0..MIT-MAG|
00000020 49 43 2d 43 4f 4f 4b 49 45 2d 31 00 10 45 78 4f |IC-COOKIE-1...?Q|
00000030 74 49 63 53 69 4c 69 43 6f 4e a6 af bc |D..gG~<......|
Note: The IP address is included in the .Xauthority file...
As we can see, the IP address of the host - 2001:db8::1 - is included in the structure along with the actual 128 bits of cookie data.
This detail might seem unimportant now, but will later prove to be useful.
Fun fact!
Location of the authentication credentials
If you're wondering where the X server stores it's copy of the authentication credentials, it's in the file specified by the -auth argument when invoking X. On OpenBSD, this will usually be a temporary file with a name in the format of $HOME/.serverauth.XXXXXXXXXX, where XXXXXXXXXX are random characters.
Authentication records created with xauth expire and are removed from the X server if they remain idle, with no connections using them, for a set period of time.
Trying to connect to the X server using the cookie we generated above after it has expired will return an ‘Invalid MIT-MAGIC-COOKIE-1 key’ error message:
Invalid MIT-MAGIC-COOKIE-1 key
Often, although not always, caused by using an expired cookie.
By default, the timeout period is set to 60 seconds. However, this can be increased by supplying the timeout argument to xauth when generating the new cookie:
desk$ xauth -f new_cookie generate desk.lan:0 . timeout 120
Create an authorisation with a timeout of 120 seconds
Multi-homed hosts
If your local workstation is multi-homed, some extra considerations might be necessary if you want remote hosts to be able to connect to an X server running on an IP address that is not associated with your machine's hostname.
Think ahead!
Virtually multi-homed configurations
Although the X server might not be running on a physically multi-homed machine, if we set up an IPSEC tunnel as described in the next section to encrypt the network traffic, the local machine will gain an extra IP address for the tunnel endpoint, thus making it multi-homed.
We'll assume that our host desk.lan is at IPv6 address 2001:db8::1, but also has IPv6 address 2001:db8:ffff::1, which is listed in DNS as workstation.lan.
In this case, the local .Xauthority file will contain two entries. The first will be of address family FamilyLocal, containing the literal hostname ‘desk.lan’ as the address. The second will be of address type FamilyInternet6, (which is defined in /usr/xenocara/proto/xorgproto/include/X11/X.h), containing the literal IPv6 address of that hostname, ‘20010db8000000000000000000000001’. Even though desk.lan is listening on port 6000 of 2001:db8:ffff::1, no entry will be created in our local .Xauthority file for this IP address.
If we want to connect from rack.lan to workstation.lan, we need to generate a cookie containing the correct IP address of 2001:db8:ffff::1, (remember the important detail mentioned above). Since xauth needs to connect to the server to run the generate command, and we don't have an entry in the local .Xauthority file to connect to that address, we can't generate the necessary cookie to send to rack.lan.
There are various ways to overcome this.
One way is to edit /usr/X11R6/bin/startx and replace the code that sets the environment variable hostname from the output of /bin/hostname with a hard-coded assign to ‘workstation.lan’.
Alternatively, we could create our own 128-bit key as a series of 32 hex digits, and add it to both the server's authority file and the .Xauthority file on rack.lan:
desk$ xauth -f .serverauth.oYUN9tQusv add desk.lan:0 . a1850df6d42eb2f1b9ab332e15915b31
desk$ xauth -f new_cookie add desk.lan:0 . a1850df6d42eb2f1b9ab332e15915b31
desk$ scp -p new_cookie desk:.Xauthority
desk$ ssh rack.lan
rack$ export DISPLAY=desk.lan:0
rack$ xclock
Adding a specific 128-bit cookie to the server authorisation file, and also sending it to the remote machine - manual keying
Note however, that unlike authorisation entries added using ‘generate’, those added in this way can't be set as untrusted.
Running the X Window System Protocol through an IPSEC tunnel
Since the native X Window System Protocol is unencrypted, if we want to run it over anything other than a private LAN with other users that we trust, some sort of encrypted tunneling is obviously desirable.
One way to do this is by using IPSEC. If you've read the previous installment of this series, you'll know how to generate the necessary keys and certificates for iked.
Once this is done, to tunnel port 6000 between our two machines desk.lan and rack.lan, we first configure a new virtual interface on each:
desk# ifconfig vether0 create
desk# ifconfig vether0 inet6 2001:db8:ffff::1
desk# echo "inet6 2001:db8:ffff::1" > /etc/hostname.vether0
rack# ifconfig vether0 create
rack# ifconfig vether0 inet6 2001:db8:ffff::2
rack# echo "inet6 2001:db8:ffff::2" > /etc/hostname.vether0
Create and configure new virtual NICs
Hostnames for these new IP addresses obviously either need to be added to DNS or the /etc/hosts file on each peer:
# echo "2001:db8:ffff::1 workstation.lan" >> /etc/hosts
# echo "2001:db8:ffff::2 erack.lan" >> /etc/hosts
Add entries to /etc/hosts, using unique hostnames
Now we just need to configure iked:
On the local workstation running the X server:
ikev2 active esp proto tcp from workstation.lan port 6000 to erack.lan peer rack.lan ecdsa384
On the remote host running the X application:
ikev2 esp proto tcp from erack.lan to workstation.lan port 6000 peer desk.lan ecdsa384
At this point we should be able to run X applications on rack.lan, and have their output sent to the local X server over the encrypted tunnel:
desk$ xauth -f new_cookie generate workstation.lan:0 .
desk$ scp -p new_cookie desk:.Xauthority
desk$ ssh rack.lan
rack$ export DISPLAY=workstation.lan:0
rack$ xclock
Run an X application over the encrypted link
A primer on sndiod
Whilst our graphical programs running on a remote machine are now happily displaying their output on our workstation's local X server, our speakers are eerily quiet.
Luckily, OpenBSD comes with a network capable audio abstraction daemon in the base installation, in the form of sndiod. We can use this to establish remote access to our audio devices, in much the same way as we've just set up remote access to our X server.
In a default installation of OpenBSD, sndiod is already set to run in /etc/rc.conf, but only runs locally and doesn't accept or make any network connections, listening only on a local UNIX-domain socket.
The default TCP port assignment for sndiod is 11025 for the first unit configured, and subsequent ports for the following units. In practice, many setups will only have a single unit configured, using port 11025. Again, this is broadly similar to the way that the X Window System Protocol uses a range of ports starting at 6000 for the first configured display.
Just like the X Window System Protocol, the bytestream that sndiod will send over the network is unencrypted. If this is an issue, we can solve it in the same way as we did before, by creating an IPSEC tunnel for the connections.
The sndiod protocol doesn't include any kind of access control at the protocol level, except for being able to specify the bind address on the server, and using a 128-bit session cookie. The session cookie mostly serves to prevent two different users from connecting to the same sndiod server simultaneously. As a result, controlling access at the network level with suitable firewall rules is essential. Failing to do this will essentially give all remote users the ability to connect to our sndiod server. This in turn, depending on which audio devices are being shared, could give them access to our local speakers, microphone and other audio inputs.
Additionally, any user on the remote machine who is able to access the sndiod cookie, (for example, the root user), will be able to join in the current session, so appropriate care should be taken if you don't have exclusive root access on the remote machine.
Unfortunately, in stark contrast to the X Window System Protocol, the actual format of the sndiod bytestream doesn't seem to be documented anywhere. The source for /usr/src/usr.bin/sndiod/sock.c might provide some clues if you have the patience to read through almost 2000 lines of poorly commented code, littered with single character variable names.
Setting up sndiod for remote audio
Configuring sndiod to listen for incoming connections on a TCP port is done using the -L argument:
desk# /etc/rc.d/sndiod stop
desk# sndiod -dd -L desk.lan
Enable listening on port 11025 on desk.lan
In the previous example, we are running sndiod in debug mode so that we can see inbound connections for troubleshooting purposes. For production use, we would usually want to add a line to /etc/rc.conf.local:
desk# echo "sndiod_flags=-L desk.lan" >> /etc/rc.conf.local
Start sndiod from rc.d with custom flags
This is the most basic configuration, in which we export access to both the recording and playback devices.
Connecting to a remote sndiod instance
Setting the environment variable AUDIODEVICE allows us to control where audio input and output is sent:
rack$ export AUDIODEVICE=snd@desk.lan/0
rack$ perl -e 'print ((((chr(0).chr(8)) x 48).((chr(0).chr(248)) x 48))x1000);' | aucat -i -
Set the default audio device and play a 1 Khz tone
An IPSEC tunnel for sndio traffic
Adding port 11025 to the ipsec.conf that we saw earlier is straightforward:
On the local workstation with the audio hardware that we want to use, (and which is running the X server, if we are also forwarding an X11 connection):
ikev2 active esp proto tcp from workstation.lan port 6000 to erack.lan from workstation.lan port 11025 to erack.lan peer rack.lan ecdsa384
On the remote host running the audio producing application:
ikev2 esp proto tcp from erack.lan to workstation.lan port 6000 from erack.lan to workstation.lan port 11025 peer desk.lan ecdsa384
We can then run the sndiod server set to listen on hostname workstation.lan instead of desk.lan:
sndiod_flags=-L workstation.lan
Set sndiod to listen on the correct address
The only change necessary on the remote host is to the AUDIODEVICE environment variable:
rack$ export AUDIODEVICE=snd@workstation.lan/0
Set the AUDIODEVICE environment variable
This week we saw how to configure a local X server to accept connections from remote clients over the network, looked at some legacy security features of the X window system, explored the actual structure of the .Xauthority file, and then looked at how to secure the transport of the data stream using an encrypted IPSEC tunnel. As well as all that, we set up sndiod to listen over TCP so that we could send audio data from the same remote hosts that are connecting to the X server!
Don't miss next week's installment, where we'll be covering upgrading by re-installing.