
Posted by
Wicher
Topic:
Tech
September 1st
2010

Last night my Sheevaplug’s power supply unit blew up. Slept clean through it but I think the fumes were responsible for the unorthodox dreaming I did that night. Incidentally, the dream was about electronics. I dreamt I was part of some development project, bringing electronics to the Indian countryside and I had just invented this incredibly tiny airplane which could be made from readily available components such as tins and shrubs. It could fly a route autonomously (!) and had a cargo net which could be used for transporting lumber, cattle, children – anything a farmer family would need transported. The size of a large model airplane, one was supposed to hold on to its landing gear (with one’s legs taking over landing gear functions – better bring some bandages) and enjoy the flight. So I was flying around the hot Indian plains, soldering iron tucked under my belt, spreading the tale of this quantum leap in mobility in the land of Vishnu and Sheeva.
Back to my Sheevaplug. It was no more. A capacitator in the power supply unit (that converts 230VAC to 5VDC) had made a complete mess of itself. And the rest of the PSU. It looks like burnt Marshmallows but smells worse.
Also, the button cell that keeps the system clock running when power is lost, had swollen to unhealthy dimensions and had barfed its contents over part of the mainboard:

Well, at least I’m not alone in getting the marshmallow treatment. It appears to be a heat issue on the first version of the development kit.
Amazingly, the PSU still supplied about 2V, enough to make the blue LED blink to signal me that my marshmallows were ready.
I keep this box with old AC/DC adapters around. I’ve adapted my Sheevaplug to contain a socket to plug in a jack from an external 5VDC 2A supply, replaced the CMOS battery, and after some initial problems with the unit losing track of time after being powered down, all is working fine again. But better not take this Sheevaplug to the scorching heat of the land of Sheeva.
Tags: en_GB, kaboom, sheevaplug —
May 10th
2010
Uit de memorie van toelichting wetsvoorstel NRF, pagina 17:
“Voor wat betreft het plaatsen van informatie op de eindapparatuur van de eindgebruiker wordt het bestaande optout regime vervangen door een optin regime. Dat betekent onder meer dat voor het plaatsen van een zogenoemde cookie vooraf toestemming aan de eindgebruiker moet worden gevraagd.”
Dat er een “bestaand” “opt-out regime” is voor cookies, is onzin. Er ís helemaal geen regime. Er is alleen techniek, en die techniek is zodanig dat een webbrowser expliciete actie moet ondernemen om de volgende keer het cookie mee te kunnen sturen. Sja, de meeste browsers doen dat in hun standaardconfiguratie klakkeloos. En in de meeste quiches in de koelvitrine van de supermarkt zit veel te veel zout.
Gelukkig kon ik dit en meer online uitleggen aan Economische Zaken, want er is een internetconsultatie voor dit wetsvoorstel. Dit was mijn uitleg:
Reactie op wetsvoorstel implementatie NRF
Geachte hr/mevr,
Ik ben consument, student Informatica, en weet een ding of drie over hoe http-cookiegerelateerde technieken samenhangen. Staat u mij toe u op de hoogte te brengen van deze zaken, en u zult inzien dat he huidige wetsvoorstel geen hout snijdt.
Hoe een webbrowser cookies dient af te handelen staat beschreven in RFC 2965, sectie 6.1, “User Agent Control”1. Zo’n RFC is vrij technisch (softwareontwikkelaars zijn de doelgroep), maar laat u niet afschrikken: in die RFC staan de meeste mechanismen
beschreven die een consument zou kunnen wensen op het gebied van cookiebeheer, en het staat ontwikkelaars vrij webbrowsers te maken die verder gaan dan deze aanbevelingen. In het bijzonder is er deze aanbeveling:
[...] notify the user when the user agent is about to send a cookie
to the origin server, to offer the option not to begin a session
Een consument die een standaardconforme webbrowser gebruikt, hééft deze optie dus al. Voor de browser Firefox is de documentatie over zulke functionaliteit gewoon online te vinden, op de website van de maker
2, en via het helpmenu.
Het is niet zo dat een webserver een cookie op een webbrowsende computer pláátst; een webserver heeft helemaal geen mogelijkheden daartoe! Wat een webserver doet is vrágen aan de webbrowser of deze zo goed zou willen zijn om bijvoorbeeld bij een volgend contact het woord “hotseflotsie” of het nummer “673” mee te sturen. Of de webbrowser gehoor geeft aan dat verzoek ligt aan hoe deze ontworpen en geconfigureerd is. Welke webbrowser wordt gebruikt en hoe deze geconfigureerd is, zijn keuzes die bij de eindgebruiker – de consument – liggen.
Zo de overheid al moet ingrijpen, dan is het dáár: bij het begrip van de consument. Dat is analoog aan hoe dat op voedinggebied al gebeurt. We weten dat te veel zout slecht is voor de gezondheid. Maar in een kilozak zout uit de supermarkt gaat héél veel zout, en toch is het toegestaan zulks aan te bieden zonder de afnemer te laten expliciteren dat hij of zij bereid is het zout in te gaan nemen! Wat de afnemer met het zout doet is namelijk zijn/haar eigen verantwoordelijkheid.
Het is de taak van de Stichting Voedingscentrum Nederland om de consument te wijzen op de gevaren van teveel zout en zo te voorkomen dat hij of zij het kilopak in één avond helemaal opsnoept.
Cookies zijn een wezenlijk onderdeel van de gebruikerservaring. Het zal u misschien verbazen, maar op de overheidswebsite3 (van de Dienst Publiek en Communicatie) waar ik u deze boodschap achterlaat wordt mijn browser de volgende cookies aangeboden:
- “contrast” met als waarde “hoog”
- “fontsize” met als waarde “2”
- “ASP.NET_SessionId” met als waarde “u5ugib48komzsnzl4wravo45”4
Ik gebruik een degelijke browser en heb deze expliciet verzocht deze cookies op te slaan en mee te sturen met vervolgbezoeken. Er zijn altijd mechanismen geweest waarmee de gebruiker kan ingrijpen in het proces. De vraag die u websitebeheerders aan bezoekers wilt laten stellen, is dezelfde vraag die miljoenen webservers jarenlang en wereldwijd al miljarden keren aan miljoenen browsers hebben gesteld: “beste webbrowser, wil je de volgende keer merkteken zus-en-zo meesturen?”
Dat consumenten hier doorgaans (te) welwillend tegenover staan, of hun browsers configureren hier (te) welwillend tegenover te staan, is niet een probleem dat bij wet of middels méér techniek is op te lossen – het is er één van kennislacune. De consument is meer gebaat bij voorlichting, daarmee wordt hij geholpen in het maken van een geïnformeerde keuze voor een browser die tegemoetkomt aan zijn privacywensen.
Samenvattend, ten andermale, en hopelijk ten overvloede: een webserver kan via cookies geen informatie opvragen die deze webserver niet al eerder zélf aan de browser heeft gegeven. Ook kan een webserver geen cookies op een bezoekende computer opslaan, dat kan alleen de webbrowser doen, en die wordt nog altijd bestuurd door de gebruiker. Wat een supermarktbezoekende klant met een zak zout doet, is niet de zaak van een supermarktexploitant. Wat een websitebezoeker met een aangeboden cookie doet, is noch een zaak van de website-exploitant, noch een zaak van de overheid.
Hoogachtend, Wicher Minnaard.
1) http://www.faqs.org/rfcs/rfc2965.html
2) http://support.mozilla.com/en-US/kb/Cookies
3) http://www.internetconsultatie.nl/nrfimplementatie/reageren
4) Deze laatste waarde heb ik om privacyredenen iets anders weergegeven.
Tags: cookies, politiek —
May 8th
2010
Intro – running a cluster
So I had assembled this computing cluster thing based on execnet for a CS project. The slave nodes were dozens of student lab computers. Those are running firewalls blocking all ingress traffic, not just from the big bad internet but also from the lab networks — which contain only trusted machines and are already protected by a firewall restricting flow to and from larger networks!
Thing is, I need access to the SSH daemons running on those nodes. And I do not (and should not) have root on those machines…
Solving this problem on OSI Layer-8 proved to be an inefficient approach. The best way to fight bureaucracy is to not take it seriously. A bureaucracy (almost by definition) is not creative and cannot keep up with workarounds. To admit existence of creative, necessary workarounds to achieve legitimate ends is to admit defeat and that is why workarounds usually get ignored. It’s ignore and counter-ignore which is a bit sad since there is (or should be) a common goal: education, in this case. But I digress. The solution proved to be to ignore layer 8 and solve the problem on OSI layer 4. That certainly saved a lot of keystrokes!
To punch through the firewall, I have each slave node initiate a reverse tunnel (ssh -R) to a central node, using pubkey authentication. This way the otherwise unreachable SSH daemons on the slave nodes are proxied on the master node and are reachable via a socket on the master nodes’ loopback interface. The slave nodes specify the reverse tunnel endpoint port based on their IP. They connect automatically, and with some clever but too-kludgy-to-show scripting I can dynamically update my running clusterfied program with newly joining slave nodes to export compute jobs to.
Obviously, the slave nodes need to login to the central node via SSH and do so using a single account on the central node. But I don’t fully trust the slave nodes. I want them to be able to initiate reverse tunnels, and not do much else. Here’s how I approached this problem, with the server running OpenSSH 5.3p1.
Chroot
Chrooting comes to mind. With a chroot, you can limit the filesystem locations the user can access to some remote uninteresting branch of the tree.
From man 5 sshd_config:
ChrootDirectory
Specifies a path to chroot(2) to after authentication. This path, and
all its components, must be root-owned directories that are not writable
by any other user or group. After the chroot, sshd(8) changes the
working directory to the user's home directory.
The path may contain the following tokens that are expanded at runtime
once the connecting user has been authenticated: %% is replaced by a
literal '%', %h is replaced by the home directory of the user being
authenticated, and %u is replaced by the username of that user.
I set up a group for that and use the following ‘Match’ stanza in the central node’s sshd_config:
Match Group chrootage
ChrootDirectory %h
%h is the matched user’s homedir.
I set up a user named ‘chroot’ with a not-so-regular home directory. More on that home directory later on. This user needs a valid shell, even if it will never run that shell (I do not want them to run one). Without a valid shell the user will not be able to log in.
ForceCommand
From man 5 sshd_config:
ForceCommand
Forces the execution of the command specified by ForceCommand, ignoring
any command supplied by the client and ~/.ssh/rc if present. The command
is invoked by using the user's login shell with the -c option. This
applies to shell, command, or subsystem execution. It is most useful
inside a Match block.
The command originally supplied by the client is available in the
SSH_ORIGINAL_COMMAND environment variable. Specifying a command of
``internal-sftp'' will force the use of an in-process sftp server that
requires no support files when used with ChrootDirectory.
Well that ought to suit my purposes. Ideally, this command would be a rather boring and useless one that just sits there waiting for input. I could copy cat and the libs it links to over to the chroot directory. I might as well make it the login shell for the chroot user. But the user would then still be able to use sftp. And if I would want to disable sftp, I would have to do so server-wide! Me and the other users use sftp extensively, so I’d then need to run a second SSH daemon with no sftp subsystems especially for this purpose. Hmmm.
Another approach is to limit the user to the internal sftp subsystem. Added benefit is that I do not need to maintain any binaries and libs in the chroot. With this, the user logging in with SSH is presented by a boring interpreter in which he cannot launch any programs — it’s the sftp subsystem. Portforwarding, which is needed for the reverse tunnel, will work. SFTP will work, obviously. Let’s do it.
sshd_config:
Subsystem sftp internal-sftp
Match Group chrootage
ChrootDirectory %h
ForceCommand internal-sftp
Make SFTP boring — chrooted home directory contents
So what do we need inside the chroot directory? No binaries or device nodes, that is one of the advantages of using the internal-sftp subsystem.
We do need an authorized_keys file readable by the chrooted user since this user won’t be able to log in using pubkey auth otherwise. We can’t use AuthorizedKeysFile inside a Match stanza, so the authorized_keys will have to reside in the default location — the .ssh subdirectory of the user’s homedir. I will use authorized_keys to limit the set of hosts this user can login from to the domain of the slave nodes, so obviously the user should not be able to add keys or lift limitations — authorized_keys will need to be read-only. This is what I ended up with.
#ls -Rla /path/to/chrooted_homedir
/path/to/chrooted_homedir/:
total 16
drwxr-xr-x 3 root root 178 May 8 16:36 .
drwxrwxrwt 9 root sys 4887 May 8 16:36 ..
dr-xr-x--- 2 root chrootage 189 May 8 16:22 .ssh
/path/to/chrooted_homedir/.ssh:
total 12
dr-xr-x--- 2 root chrootage 189 May 8 16:22 .
drwxr-xr-x 3 root root 178 May 8 16:36 ..
-rw-r----- 1 root chrootage 1221 May 8 14:25 authorized_keys
This is all the user can view over sftp. It is minimal and extremely boring. Note that there is no place the user can write to. Even if he would have some way of launching programs (he hasn’t, due to ForceCommand) there is no place to upload them to and launch them from in the first place.
On to authorized_keys:
no-pty,from="*.science.uu.nl" ssh-rsa AAAAB3and-the-rest-of-the-pubkey
no-pty serves to prevent the allocation of a terminal. I don’t think it offers any security beyond the measures already in place, but I like to think this saves resources.
Tunneling risks
I need TCP forwarding to get the reverse tunnels to work. That means that using the account, users can set up arbitrary TCP tunnels, using the master node as a proxy… Less nice. But wait – can’t I use PermitOpen inside Match to limit the creation of arbitrary tunnels? Yes. But the reverse tunnel is subjected to the same restrictions. Therefore, I would need a PermitOpen for every slave node and I’d need to know the source port of the incoming client connection in advance. There’s no wildcarding in PermitOpen, so this is infeasable.
‘Match’ directive precedence
The order appears to be significant. That’s also what the manpage seems to hint at where it says
Match:
Introduces a conditional block. If all of the criteria on the Match
line are satisfied, the keywords on the following lines override those
set in the global section of the config file, until either another Match
line or the end of the file.
It’s not as clear as could be what happens to keywords in the next Match directive. What if the next Match directive matches? Nothing! The next Match directives don’t matter! In my tests, incoming connections appeared to be only matched once. The match blocks have no relation to eachother, only to the main config.
That implies that you need to put the most specific match directives — the ones with the most patterns — on top, and that each Match block needs to hold any and all keywords you want to specify beyond the main config. It’s not CSS ;-)
Tags: chroot, en_GB, openssh, sftp, tunnel —
April 16th
2010
It’s not too late for posts about April Fool’s Day pranks I hope?
In the tradition of the Upsidedownternet this April 1st I had some fun with Facebook addicts.
You may not be aware of the fact that any picture on facebook is publicly accessible. Yes, it is. There’s no authentication & authorisation whatsoever. Handling those in a scalable way would ramp up costs. Your privacy is not worth those costs. Contrary to the impression you are trying to deliver through your profile, you are not important. Happy shareholders are important!
Due to this fact I just need to know the URLs of your pictures. From the URL I can determine whether it’s a profile picture, profile picture thumbnail, photo, photo thumbnail, etc.
Wouldn’t it be fun to mix the pictures of the facebook page you are currently viewing with those from facebook pages others are viewing? So when you’re browsing your friend’s albums, you not only see his pictures but pictures from other peoples’ albums too, and vice versa?
The pictures may be requested by the guy across the bar, or by the girl one floor down in the library, or by anyone on the same network as you are — all of you are browsing together with the people in your physical vicinity, sharing whatever pictures you encounter! It’s beyond Facebook. It’s crowdbrowsing. It’s Megafacebook.
While you may not know these newly inserted friends, you might get to. Maybe you bump into one another at the toilets, or at the counter.
“Why is everyone staring at me like that?” you naively wonder. (They’ve seen those pictures).
“Does she know that I know about those pictures of her and her friends? But wait… what might she know about me?”, your paranoid mind ponders.
It’s all about what you think of others and what others think of you. Total absorption. Now that’s what I call social networking. All hail Facebook Social!

Give the wifi crowd at your local coffeeshop the pleasure of learning a little bit more about eachothers lives and friends.
Get to work
You need:
- one network vulnerable to ARP poison routing (that’s most of them) or one network which you already control anyway. Make everyone route their traffic through your machine.
- one installment of the Nginx web server, configured with
--with-http_random_index_module. I use the 0.8.3x series.
- one installment of the Squid http proxy server. I use the 3.1 series.
- Perl and LWP::Simple.
Set up Nginx
Create some directories to hold the images:
mkdir /var/www/facemix/{albums,photos,photosthumb,smoelen,smoelenthumb}
Tell Nginx to respond to requests for those directories by randomly serving one of the files in them:
location ~ ^/facemix/([^/]+)(/?.*)$ {
alias /var/www/facemix/$1/$2;
random_index on;
expires -1;
}
You need the ‘expires -1′ to avoid caching. If proxies or user agents were to cache the results, they wouldn’t be very random anymore now would they.
Stick some files in there and test your installation.
Set up Squid
Set up squid in interception mode. If you’re not NATting the routed traffic, set it to run on port 80. If Nginx is already listening on that socket, make Nginx listen on some other port, or localhost only, while running squid on port 80 but only on the external interface.
Set up networking
This is for iptables.
- You’re NATting the pwned hosts. Run something along the lines of
iptables -t nat -A PREROUTING -i $INTERFACE -p tcp --dport 80 -j REDIRECT --to-port 8080
to redirect all traffic incoming on $INTERFACE and destined for port 80 to port 8080, which is where you need squid to listen on.
- You’re doing 2-way ARP poisoning (cheers!). Run something along the lines of
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination $YOURIP
Squid needs to run on port 80 on interface with IP $YOURIP.
Check Squid’s logs to verify that requests are intercepted successfully.
Run the redirection script
I don’t touch Perl very often, and cobbling together this script made me remember why that is. It’s very usable as a means of frightening little kids.
In a nutshell, what my redirector script does is
- determine whether the URL fed to it by Squid is a facebook picture url;
- if so, and if we don’t have that picture yet, fork off to download it;
- point Squid to a random picture of the same type (served by Nginx).
I like the forking. I dislike the iffed regexes which could probably be condensed into one but then it wouldn’t be ‘cobbling together’ anymore.
Adjust the variables for your setup and tell Squid about the script (eg url_rewrite_program /usr/local/lib/facemix-squidredir.pl).
The Facebook logo will change to reflect the fact that the users are now browsing facebook in Social! mode.
One further note: This is privacy-invasive. I brush away my moral doubts by stating that anyone who signed away their privacy rights when joining facebook AND AT THE SAME TIME entertains any expectations with respect to privacy,
« inhale »
… is utterly mental and has completely lost any and all sense of proportionality. If you care about privacy, why use a service which lets you view any picture of any user regardless of who you are? Who are you kidding?
If you’re still reading, here’s the script:
#!/usr/bin/perl -w
use LWP::Simple;
$WEBROOT = 'http://localhost/facemix/';
$WEBDIR = '/var/www/facemix/';
$CHANCE = 5; #One in X requests gets mixed
$SIG{CHLD} = 'IGNORE';
$|=1;
while (<>) {
local @reqfrags = split(/ /, $_);
local $url = @reqfrags[0];
if ($url =~ /(^http:\/\/.*.fbcdn.net\/rsrc.php\/z7VU4\/hash\/66ad7upf.png$)/) {
print "http://smormedia.gavagai.nl/2010/04/FacebookSocial2.png\n";
}
elsif (($url =~ /(^http:\/\/photos-.*.fbcdn.net\/.*\/.*_n.jpg$)/) || ($url =~ /(^http:\/\/photos-.*.fbcdn.net\/.*\/n.*.jpg$)/)) {
&mixurl('photos/',$url);
}
elsif (($url =~ /(^http:\/\/photos-.*.fbcdn.net\/.*\/.*_s.jpg$)/) || ($url =~ /(^http:\/\/photos-.*.fbcdn.net\/.*\/s.*.jpg$)/)) {
&mixurl('photosthumb/',$url);
}
elsif (($url =~ /(^http:\/\/profile.*.fbcdn.net\/.*\/.*_n.jpg$)/) || ($url =~ /(^http:\/\/profile.*.fbcdn.net\/.*\/n.*.jpg$)/)) {
&mixurl('smoelen/',$url);
}
elsif (($url =~ /(^http:\/\/profile.*.fbcdn.net\/.*\/.*_q.jpg$)/) || ($url =~ /(^http:\/\/profile.*.fbcdn.net\/.*\/q.*.jpg$)/)) {
&mixurl('smoelenthumb/',$url);
}
elsif (($url =~ /(^http:\/\/photos-.*.fbcdn.net\/.*\/.*_a.jpg$)/) || ($url =~ /(^http:\/\/photos-.*.fbcdn.net\/.*\/a.*.jpg$)/)) {
&mixurl('albums/',$url);
}
else
{
print $url."\n";
}
}
sub mixurl {
#args: subdir, url
local $vork = fork();
if ($vork == 0) {&getit($_[0], $_[1]);}
if (int(rand($CHANCE)) == 0) {
print $WEBROOT.$_[0]."\n";
}
else {
print $_[1]."\n";
}
}
sub getit {
#args: subdir, url
local $storedir = $WEBDIR.$_[0];
local @urlfrags = split(/\//, $_[1]);
local $fname = pop(@urlfrags);
if (!stat($storedir.$fname)) {
getstore($_[1],$storedir.'._tmp-'.$fname);
rename($storedir.'._tmp-'.$fname, $storedir.$fname);
}
exit;
}
Tags: aprilfools, en_GB, facebook, security, squid, upsidedownternet, url_rewrite_program —
March 20th
2010
Your mum told you not to touch block devices containing mounted filesystems. But today we’ll be doing exactly that. Specifically, we’re going to use the Linux Device Mapper (DM) snapshot and snapshot-merge target. To do what? To do this:
- Make all reads come from one device, A
- Make all writes go to another block device, B
- Merge the writes stored in B into A
- Without unmounting the filesystem on A!
Why? Well, as pointed out in the comments on this LWN article you could use this as a way to roll back an unfortunate upgrade without taking your system offline. But if the upgrade _is_ fortunate, you might want to merge the changes back in without having to take your filesystem offline.
Or you could use it to speed up writes — perform those against a RAM-based block device, and merge those writes back in when sysload is low. Or use it like I’m planning on doing: to avoid the small but frequent writes (growing logfiles, mainly) to the CF card in my Alix2 which I’ve built my router with.
#1+#2 are old hat — but if you’ve never made a writable snapshot with DM (not LVM) I strongly suggest you read the “Right To Your Own Devices” LinuxGazette article. It’s what got me started.
#3 is fairly recent hat, for ‘kernel 2.6.33′ values of “recent”.
#4 is shiny new hat and is what this post will be about.
Prerequisites
You must be running the Linux kernel, 2.6.33+, and have device mapper support (CONFIG_DM_SNAPSHOT) loaded and ready to go. You also need a recent LVM2 userland, I used version 2.02.60.
Usually one goes about snapshotting with the use of LVM, the Logical Volume Manager. LVM is just an easy high-level way of employing DM functionality for common use cases. Ours is not one of those, hence we’ll be using raw dmsetup-foo. That’s why I strongly recommend you read the LinuxGazette article mentioned before. We’ll not be revisiting DM basics.
Get Dirty
-
Create your base block device of about 500MB.
dd if=/dev/zero of=hard bs=1M count=500
losetup /dev/loop0 hard
Neat, now you have a block device which is actually a file on your file system (which is on a block device). You could mkfs and mount it, but we’re not going to, not yet. We’re going to add yet another layer of indirection: the device mapper.
echo 0 $(blockdev --getsize /dev/loop0) linear /dev/loop0 0 | dmsetup create hard_a
You now have a /dev/mapper/hard_a which is a linear (not mirror, not stripe, not crypt, not anything else but plain boring linear) mapping of blocks to its underlying block device, which was /dev/loop0, which is backed by the file with name hard.
-
Create a device which the writes will end up on. How large should it be? You decide. If you write more data than this volume can hold, it will be dropped and all your writes will be lost. That’s what you get for bad planning! Of course, you could err on the safe side and make it huge. But I don’t think it’s of any use to make it larger than the device whose writes you want it to receive (please correct me if I’m wrong). And by making it huge, you’re wasting space. Why not have it take up exactly the amount of space it needs? Dynamically growing, so to say? With a loop device backed by a sparse file, you can! A sparse file is a file whose empty bytes are represented by metadata. That means they don’t actually have to be there until needed, which is on write.
Let’s make a 200MB sparsely backed device to hold the writes diverted from our other device:
dd if=/dev/zero of=soft_a bs=1 count=0 seek=200M
losetup /dev/loop1 soft_a
-
Now we make yet another device:
top. This is the device we’ll be making a filesystem on. But all writes will go into the file called soft. That’s called a writable snapshot and you can assemble it like this:
echo 0 $(blockdev --getsize /dev/mapper/hard_a) snapshot /dev/mapper/hard_a /dev/loop1 p 8 | dmsetup create top
You now have a /dev/mapper/top block device. Go ahead, mkfs it[*], mount it and stick some files on it. Interestingly, you can see how many blocks (in units of bytes) you have dirtied by looking at the physical size of the ’soft_a’ file:
-
Now for the magic part. Freeze the block device!
All reads and writes to /dev/mapper/top will now block. Processes that were accessing the device will be in suspended animation. Really? Depends. You will observe that you can still do an ls on the filesystem if you’ve run one before and haven’t changed any data in the meantime. That’s because of the kernel’s caches, in this case, the dentry (directory-entry) cache. You can drop those caches (but you don’t have to) by running echo 3 > /proc/sys/vm/drop_caches, and after that, you will observe that an ls incantantion will appear to hang. Leave it like that for the moment.
-
Now we want to merge the dirty blocks back into
hard_a. But if we fiddle with the constituents of /dev/mapper/top through DM, it will be dropped! We can’t merge dirty blocks right back into /dev/mapper/hard_a as DM doesn’t trust us prodding the fundaments. So we fool it by creating a second loop device backed by the same file as the loop device backing /dev/mapper/hard_a:
losetup /dev/loop2 hard
echo 0 $(blockdev --getsize /dev/loop2) linear /dev/loop2 0 | dmsetup create hard_b
If you look at the output of dmsetup table you will notice that DM thinks hard_a and hard_b are different devices. And rightly so, because they are, but they happen to point to the same data: the file called hard.
-
Now we can merge the device that holds the dirty blocks for
hard_a (that would be /dev/loop1) into hard_b:
echo 0 $(blockdev --getsize /dev/mapper/hard_b) snapshot-merge /dev/mapper/hard_b /dev/loop1 p 8 | dmsetup create mergeomatic && dmsetup status mergeomatic
You don’t have to do anything with the mergeomatic device. Just wait for it to finish merging. How do you know when it’s finished? I couldn’t figure it out so I asked the dm-devel list. Turns out you can use dmsetup status mergeomatic, its output format is <sectors_allocated>/<total_sectors> <metadata_sectors> and when the amount of sectors_allocated equals the metadata_sectors it’s finished. I looked at dmsetup status in my experiments but I had never seen anything but the same numbers, possibly because I/O to small loopback devices on a machine with loads of RAM will be blazing fast — writes to the backing file are cached in RAM, I guess.
Done? Remove the snapshot-merge target:
dmsetup remove mergeomatic
-
All that’s left is to create a new device, based on
/dev/mapper/hard_b or its backing file. If you’re tired of COWing around you could do:
dmsetup remove hard_b
echo 0 $(blockdev --getsize /dev/loop2) linear /dev/loop2 0 | dmsetup load top
And if you want to continue this trick you’d just make a fresh sparsely backed loop device and make a snapshot target out of it:
dd if=/dev/zero of=soft_b bs=1 count=0 seek=200M
losetup /dev/loop3 soft_b
echo 0 $(blockdev --getsize /dev/mapper/hard_b) snapshot /dev/mapper/hard_b /dev/loop3 p 8 | dmsetup load top
-
And now for the grand finale:
All blocked processes will spring to life. ls will return a directory listing as if nothing has happened. Mission accomplished.
With dmsetup load we swapped block devices in-flight. The mounted filesystem on /dev/mapper/top didn’t notice — all blocks still look the same. But both DM and we know that the blocks are somewhere else physically now. Little did DM know that /dev/mapper/hard_b is backed by the same physical blocks as /dev/mapper/hard_a.
We’d better do some cleaning up then:
dmsetup remove hard_a
losetup -d /dev/loop{0,1}
rm soft_a
This hasn’t left the toying-around phase yet. But I’m thinking about writing some wrapper scripts and doing some more testing. Maybe I should call it the “WhatwasIthinking Volume Manager” as it’s rather tricky stuff. Especially with all the write buffering on multiple levels. I messed it up more than once during testing ;-)
[*] Not just any FS will do. Don’t use journaled filesystems. They assume their journal will be written to disk in-order. That assumption does not hold with file-backed loop devices, because on those there is yet another filesystem (and buffer layer) below it, deciding what data gets committed first.
Tags: device mapper, DM, en_GB, LVM, snapshot-merge —

Posted by
Wicher
Topic:
Umeå
February 12th
2010
Bijna een jaar geleden vertrok ik naar Zweden om een paar maanden in Umeå te gaan wonen. Nu zat ik in de foto’s te rommelen (heimwee?) en sommige daarvan zijn best aardig als je benieuwd bent naar hoe het daar was/is.
-
- Uitzicht vanuit studentenkamertje
Met driedubbel vensterglas. Voor de mensen uit de Randstad: die malle palen met groene frummels zijn zgn 'bomen'.
Gemaakt: 2009-03-24 09:13:16 2592 x 1944 Uitzicht vanuit studentenkamertje
-
- Huisgenootjes en chocoladecake
Als je Zweden een zak meel geeft zijn ze niet meer te houden. Dan ontstaat er cake of taart of koek.
Gemaakt: 2009-04-06 20:52:36 2592 x 1944 Huisgenootjes en chocoladecake
-
- Meer naast m'n huis. Niet duiken hè!
't Is niet zo heel diep. Wel goed zwemwater — zodra het weer vloeibaar is.
Gemaakt: 2009-03-22 17:37:29 2592 x 1944 Meer naast m'n huis. Niet duiken hè!
-
- Dan maar ijsvissen
Gemaakt: 2009-03-17 14:57:52 2592 x 1944 Dan maar ijsvissen
-
- Of liggen
Gemaakt: 2009-03-17 15:01:35 2592 x 1944 Of liggen
-
- Voetpaden worden loopgraven
Gemaakt: 2009-03-17 15:22:04 2592 x 1944 Voetpaden worden loopgraven
-
- Fietspaden worden bobsleebanen
Gemaakt: 2009-03-17 15:52:18 1944 x 2592 Fietspaden worden bobsleebanen
-
- Dus afgraven die sneeuw
Gemaakt: 2009-03-17 15:54:10 2592 x 1944 Dus afgraven die sneeuw
-
- Maar hier dan weer niet, want dit is de stadsskipiste
Gemaakt: 2009-03-17 15:33:24 2592 x 1944 Maar hier dan weer niet, want dit is de stadsskipiste
-
- Bomen tussen de gebouwen
Gemaakt: 2009-03-17 16:01:49 2592 x 1944 Bomen tussen de gebouwen
-
- Gebouwen tussen de bomen
De stad is in een bos gebouwd. Er zijn dus veel eekhoorns en vogeltjes.
Gemaakt: 2009-03-19 16:54:09 2592 x 1944 Gebouwen tussen de bomen
-
- Parkeren vergt extra aandacht
Gemaakt: 2009-03-21 08:03:08 2592 x 1944 Parkeren vergt extra aandacht
-
- Bevroren rivier, vaselinewangetjes
Gemaakt: 2009-03-24 16:57:15 2592 x 1944 Bevroren rivier, vaselinewangetjes
-
- Van de andere kant
Gemaakt: 2009-04-13 17:50:53 3264 x 1832 Van de andere kant
-
- Koud badhuis lijkt me geen succes nee
Gemaakt: 2009-03-18 19:01:24 2592 x 1944 Koud badhuis lijkt me geen succes nee
-
- Waarom niet, eigenlijk?
Gemaakt: 2009-03-18 17:32:31 2592 x 1944 Waarom niet, eigenlijk?
-
- Ridders!
Gemaakt: 2009-04-29 16:03:16 3264 x 2448 Ridders!
-
- Barbecueue aan het meer. Rechts aan de horizon mijn huis.
Gemaakt: 2009-04-18 19:59:44 2592 x 1944 Barbecueue aan het meer. Rechts aan de horizon mijn huis.
-
- Brandhout wordt door de gemeente bijgevuld (!)
Gemaakt: 2009-04-18 20:01:42 2592 x 1944 Brandhout wordt door de gemeente bijgevuld (!)
-
- Mooi hoor
Gemaakt: 2009-04-18 20:03:08 2592 x 1944 Mooi hoor
-
- Koud ook wel
Gemaakt: 2009-04-18 23:04:27 2592 x 1944 Koud ook wel
-
- IJsvissen: gaatje boren in een rivier
Gemaakt: 2009-04-19 11:34:23 1944 x 2592 IJsvissen: gaatje boren in een rivier
-
- En dan maar wachten
Gemaakt: 2009-04-19 12:23:54 2592 x 1944 En dan maar wachten
-
- 23 april: Sneeuwnegeerdag (Universiteitsbibliotheek)
Hup, truien uit. De grond begint te ontdooien. Over de campus ruisen smeltwaterbeekjes.
Gemaakt: 2009-04-23 12:32:25 2592 x 1944 23 april: Sneeuwnegeerdag (Universiteitsbibliotheek)
-
- Dag ijs!
De Umeälven voert ijs uit Lapland af.
Gemaakt: 2009-04-24 16:47:08 2592 x 1944 Dag ijs!
-
- Verliefde meeuwen op reis
Naar Finland!
Gemaakt: 2009-04-25 16:15:38 2592 x 1944 Verliefde meeuwen op reis
-
- Lui fietswassen
D'r zat overal gravelslijpsel op-, aan- en ingekoekt. Hierna niet meer.
Gemaakt: 2009-06-18 16:09:18 2592 x 1944 Lui fietswassen
-
- 16 mei, weekend hiken: Höga Kusten.
Ontluikende knoppen.
Gemaakt: 2009-05-16 16:29:16 2592 x 1944 16 mei, weekend hiken: Höga Kusten.
-
- Finse mee voor de humor
Gemaakt: 2009-05-16 17:23:11 1944 x 2592 Finse mee voor de humor
-
- Deed het ook maar voor het eerst
Gemaakt: 2009-05-16 13:22:19 2272 x 1704 Deed het ook maar voor het eerst
-
- Boswandelaarsinfra
Je kunt er zo in en het kost niets. Met dank aan de Zweedse staat.
Wel zelf houtjes hakken voor de kachel.
Gemaakt: 2009-05-16 20:13:49 2272 x 1704 Boswandelaarsinfra
-
- mmmüsli
Sloom ontbijten met warme melkpoedermelk.
Gemaakt: 2009-05-17 11:06:27 2592 x 1944 mmmüsli
-
- Sneeuw+meer= adembenemende ochtendduik.
Gemaakt: 2009-05-17 12:24:02 1944 x 2592 Sneeuw+meer= adembenemende ochtendduik.
-
- Ödla, nog sloom van de kou
Volgens M. een zootoca vivipara, en dat er niet zo veel reptielen rond de poolcirkel uithangen.
Gemaakt: 2009-05-17 12:37:22 2592 x 1944 Ödla, nog sloom van de kou
-
- Hierom heet het Höga Kusten
Post-Glacial Rebound. Eustacy. Toppen van 300m. En het staat op de UNESCO-werelderfgoedlijst.
Gemaakt: 2009-05-17 13:10:35 2272 x 1704 Hierom heet het Höga Kusten
-
- Betekent dus dat je soms omhöga moet
Gemaakt: 2009-05-17 13:42:55 1704 x 2272 Betekent dus dat je soms omhöga moet
-
- ravijnen en alles
Gemaakt: 2009-05-17 13:58:03 1944 x 2592 ravijnen en alles
-
- Kraakhelder meertje
De meeste meertjes hebben een theekleur door organische zuren. Maar hier zit veel kalk in de rotsen dat die zuren bindt.
Gemaakt: 2009-05-18 12:18:02 2592 x 1944 Kraakhelder meertje
-
- Bevers: Nature's Hooligans
De beekdelta waar deze detailfoto is genomen was een enorme puinzooi. Ze knagen driekwart van de bomen om en klooien met dammen (die dan weer doorbreken). Het leek wel een crashsite.
Gemaakt: 2009-05-17 15:45:29 2592 x 1944 Bevers: Nature's Hooligans
-
- En
Door de schone lucht en het natte, koude klimaat groeien hier veel (korst)mossen en zwammen. Lange slierten aan boomtakken maken het bos zeer sprookjesachtig. (Maar dit is geen tak.)
Gemaakt: 2009-05-17 14:33:58 2592 x 1944 En
-
- heel veel
Door de schone lucht en het natte, koude klimaat groeien hier veel (korst)mossen en zwammen. Lange slierten aan boomtakken maken het bos zeer sprookjesachtig. (Maar dit is geen tak.)
Gemaakt: 2009-05-17 14:33:10 2592 x 1944 heel veel
-
- (korst)mos
Door de schone lucht en het natte, koude klimaat groeien hier veel (korst)mossen en zwammen. Lange slierten aan boomtakken maken het bos zeer sprookjesachtig. (Maar dit is geen tak.)
Gemaakt: 2009-05-18 14:08:15 2592 x 1944 (korst)mos
Tags: foto, höga kusten —

Posted by
Wicher
Topic:
Tech
February 5th
2010
Some quick numbers for those looking for performance figures on the CESA crypto accelerator. Like I was, since my SheevaPlug has one. From the kernel config:
CRYPTO_DEV_MV_CESA
This driver allows you to utilize the Cryptographic Engines and Security Accelerator (CESA) which can be found on the Marvell Orion and Kirkwood SoCs, such as QNAP’s TS-209.
Currently the driver supports AES in ECB and CBC mode without DMA.
Whether the accelerator will be used depends on whether an application uses the in-kernel crypto algorithms. OpenSSL does not unless it is explicitly enabled to use a certain accelerator, such as is the case with the Via Padlock engine. So this particular engine won’t let your SSH run faster. But it will speed up device mapper crypto if you use an AES cipher.
Right, let’s get on with it.
#uname -a
Linux sheeva 2.6.32-gentoo-r3 #3 Thu Feb 4 23:02:42 CET 2010 armv5tel Feroceon 88FR131 rev 1 (v5l) Marvell SheevaPlug Reference Board GNU/Linux
Quick & oh-so-dirty way of getting a RAM-backed block device (that is, if you don’t have swap enabled):
#mount -t tmpfs tmpfs /mnt/tmp/
#dd if=/dev/zero of=/mnt/tmp/blob bs=1M count=224
#losetup /dev/loop0 /mnt/tmp/blob
#cryptsetup -c aes -h sha1 -d /dev/urandom create test /dev/loop0
First we test without CESA.
#dd if=/dev/zero of=/dev/mapper/test bs=1M count=224
234881024 bytes (235 MB) copied, 41.858 s, 5.6 MB/s
Only 5.6 MB/s and the [kcryptd] kernel process is having your CPU for lunch.
Enter CESA:
#dmsetup remove test
#modprobe mv_cesa
#cryptsetup -c aes -h sha1 -d /dev/urandom create test /dev/loop0
#dd if=/dev/zero of=/dev/mapper/test bs=1M count=224
234881024 bytes (235 MB) copied, 18.0525 s, 13.0 MB/s
13.0 MB/s and there’s a new kernel process, [mv_crypto]. It’s eating about three times as much CPU as [kcryptd]. That means it’s offloading, which is good. The results are consistent over time so let’s say there’s a 2.5-fold performance gain.
The loop device setup causes some overhead. Out in the wild you’ll get about 19 MB/s writing to USB HDD. Cheers!
Tags: benchmark, en_GB, sheevaplug —
January 31st
2010
There are times you need to connect to ‘dirty’ networks such as public WiFi hotspots. Hopefully you’re ensuring that sensitive information is encapsulated in transport layer security enabled protocols such as SSL, because anyone on the same link (in the case of WiFi, that’s the air surrounding you. A vacuum will do, too, but that’s less common) can listen in on the traffic you’re sending. With SSL encapsulation such as HTTP over SSL (https://), your traffic can still be read — but for those who do it’s an extremely boring read because they don’t know the session key, only you and the other endpoint do. Hopefully.
One particularly nasty thing that can happen to you is when your machine is subverted into using the attacker’s machine as the router. That is known as ARP poison routing. The attacker can proceed to not only read the traffic coming from your machine (which, on a shared medium, could be done anyway), or read the traffic going into your machine (again: on a shared medium, that could be done anyway), but the attacker can now also modify the traffic between you and the rest of the non-local network, e.g., the internet, in both directions. And that’s when he can really go to town with your traffic. Injecting a javascript keylogger into all the webpages you visit. ‘Sidejacking‘ your sessions, so he does not even need to know your passwords, just your session cookies — which you happen to transmit with every page request.
All possible unless you use transport layer security, which is tamper-proof once properly set up. Once properly set up. But setting up can have problems of itself — there are ways of preventing you ever going from HTTP to HTTPS. If you know a thing or two about HTTP and SSL you’ll be delighted to learn about Moxie’s very evil but very clever ways of doing so.
Anyway, some level of security can be achieved if you tell your machine to ignore any messages sent to you from the other machines on the local network. That includes messages that will make your machine believe that the router has suddenly changed its physical address — which is quite unlikely to happen, but those messages are exactly the type of message an impersonator would send you. Of course we’d need to whitelist the routers of the network, otherwise we can’t get traffic out of it and onto other networks. DNS resolvers will need whitelisting too, unless you’re running one on your own machine (probably not).
Not openly announcing your presence may also be something you wish for. If you have ever been on a network with a Mac user you have probably seen them popping up in your Zeroconf service browser as “Firstname Lastname’s iSomething”. Let’s cut down on that kind of promiscuity, too. But you should understand now that you can not actually hide unless you turn off your WiFi. Shared medium, remember?
I prepared a simple script to accomplish the above. I’ve used ip from the iproute2 package instead of sticking to old-school route, ifconfig, arp & co. And I must say ip neigh flush nud stale has a poetic ring to it, wouldn’t you agree?
Take note: this will only protect you from some kind of attacks, and only partially. An attacker has a window of opportunity between your machine getting assigned a DHCP lease and you running this script, for instance. Or maybe the access point is rigged. Actually all protection other than end-to-end encryption combined with mutual authentication is pretty useless on shared networks ;-)
Here’s the script. Linux-only. If you want to use it, get the latest version from my public repository.
#!/bin/bash
# arpshield 0.2
# Protects against ARP poisoning and cloaks your machine for all
# local link devices but the router(s) and the DNS server(s).
# Whitelisting DHCP servers also works if you use the dhcpcd program
# to obtain DHCP leases.
# This program is of no help if your setup is already poisoned.
# Have a look at ArpON (http://arpon.sourceforge.net/manpage.html) if
# you need more extensive protection.
#
# Needs 'ip', 'awk', 'sed', 'arptables', and 'arping' and expects
# them on $PATH. Needs appropriate privileges (so use sudo).
# Takes a network interface as an argument. The network interface
# should be up and configured. If no argument is given, clear all
# rules. Obviously you should do that before connecting to a new
# network.
#
# Copyright 2010 Wicher Minnaard (wicher@gavagai.eu)
# License: Creative Commons Attribution-Share Alike 3.0
# Do you use dhcpcd for aquiring DHCP leases? And is it running?
dhcpcdLEASEFILE="/var/lib/dhcpcd-${1}.info"
dhcpcdPIDFILE="/var/run/dhcpcd-${1}.pid"
test -f ${dhcpcdLEASEFILE} && test -f ${dhcpcdPIDFILE} && source ${dhcpcdLEASEFILE}
# In case you lack the luxury of dhcpcd, where is your resolv.conf?
RESOLV="/etc/resolv.conf"
# No user-servicable parts below this line.
DEV="${1}"
# I know, I know. But if your routing table contains 0.333.456.789 you have bigger problems ;-)
IPREGEX="\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}"
# Register
MACreg=""
# If not run as root, bail
[ "$(id -u)" != "0" ] && echo "You need root privileges to modify networking parameters. Exiting." 1>&2 && exit 2
getmac(){
# sets MAC register by IP. Sets to nil, if the MAC is not on the local link.
getMAC=$(ip neigh show ${1} | awk '{print $5}')
if [ -z "${getMAC}" ]; then
arping -c1 -I ${DEV} ${1} > /dev/null 2>&1
getMAC=$(ip neigh show ${1} | awk '{print $5}')
fi
MACreg=${getMAC}
}
allow(){
# Whitelists traffic to and from particular IP+MAC pairings and
# adds them to static ARP.
IP=${1}
MAC=${2}
if [[ -n "${IP}" && -n "${MAC}" ]]; then
arptables -A INPUT -s ${IP} --source-mac ${MAC} -j ACCEPT
arptables -A OUTPUT -d ${IP} --destination-mac ${MAC} -j ACCEPT
ip neigh replace ${IP} lladdr ${MAC} nud permanent dev ${DEV}
fi
}
if [ -n "${DEV}" ]; then
# whitelist the routers
test -z ${GATEWAYS} && GATEWAYS=$(ip route show dev ${DEV}| sed -n "s:.* via \(${IPREGEX}\).*:\1:p")
for GWIP in ${GATEWAYS}; do
MACreg=""
getmac ${GWIP}
allow ${GWIP} ${MACreg}
done
# whitelist the DNS servers
test -z ${DNSSERVERS} && DNSSERVERS=$(sed -n "s:^nameserver \(${IPREGEX}\):\1:p" ${RESOLV})
for DNS in ${DNSSERVERS}; do
MACreg=""
getmac ${DNS}
allow ${DNS} ${MACreg}
done
# if using dhcpcd, we can whitelist the DHCP server too
test -n ${DHCPSID} && getmac ${DHCPSID} && allow ${DHCPSID} ${MACreg}
# set default policy to DROP
arptables -P INPUT DROP
arptables -P OUTPUT DROP
# clear out non-hardcoded ARP cache entries
ip neigh flush nud reachable
ip neigh flush nud stale
else
# No argument given, so clean up.
arptables -F
arptables -P INPUT ACCEPT
arptables -P OUTPUT ACCEPT
ip neigh flush nud permanent
fi
Tags: arp spoofing, en_GB, security, wifi —

Posted by
Wicher
Topic:
Rants
January 24th
2010
Ik ben kwaad. Sacha vertelt waarom:

Dus. We hebben een regering van gekozen volksvertegenwoordigers. Goede zaak zou je zeggen, want die maken beleid dat het algemeen belang dient. Het algemeen belang.
Maar wat doet je minister, Camiel Eurlings? Die gaat nog even exclusief aan de leden van één (1!) belangenvereniging vragen of het beleid hen wel kan bekoren, want zo niet, dan gaat-ie het natuurlijk niet uitvoeren. Maar het is potdorie een hamerstuk waar onze tweede kamer (die jou vertegenwoordigt) al achter staat.
Camiel houdt een privéreferendumpje. Waarmee wordt beslist of autorijden duur mag worden. En alle automobilisten zijn uitgenodigd! Moet je in Nederland een ANWB-partijkaart hebben om je stem uit te mogen brengen?
Die heeft niet iedereen. Marietje, die vanochtend op de fiets naar d’r werk nog door een Hummer de stoep op werd gedrukt, wil er niet eens een. En Camiel gaat dus niet aan oma Truus in d’r met vrachtwagenroet bedekte woning aan de Fijnstofallee vragen wat zij van auto’s vindt. En hij vraagt het ook niet aan kleine Kareltje die achter z’n Playstation kinderdiabetes zit krijgen omdat er buiten niks te spelen valt omdat z’n huis temidden parkeerplaatsen, blik, drukke wegen en andere automobielinfra staat.
Als je het deze mensen zou vragen mag het autorijden best ontmoedigd worden. Maar nee, er wordt een voorstel gedaan zodanig dat autorijders het mee eens zullen zijn — en dus zullen die er niet al te veel op achteruit gaan. Met andere woorden: dat is dus niet het voorstel worden dat er voor gaat zorgen dat jongere generaties een fijne leefomgeving tegemoet gaan.
Goed hee Camiel, draagvlak zoeken. Dat zouden we vaker moeten doen. Zo vind ik dus dat de regering aan de Vereniging Stinkrijke Bonusbankiers had moeten vragen of ze er eigenlijk wel mee akkoord gaan dat die pret aan banden gaat. En we zullen ook nog maar moeten zien of de Nederlandse Delinquentenbond instemt met beter toezicht op verlofregelingen. Ze mogen dan trouwens zelf dat privéreferendumpje organiseren en de stemmen tellen, net als de ANWB. Zo nauw nemen we het immers toch al niet met de integriteit van volksraadpleegmechanismen.
Camiel, als je e.e.a. wil toelichten (graag!), dan kan dat door hieronder je reactie toe te voegen.
Tags: kilometerheffing, politiek, rekeningrijden —

Posted by
Wicher
Topic:
Howto
January 10th
2010
Access remote X11 servers that have their TCP socket disabled
This happens to me regularly. Someone brings a machine along and I want to display some app, running on my machine, on their display. Networked X11 to the rescue, you say? No, their X11 server is started with ‘-nolisten TCP’ wich is the default on most modern Linux distros. Sadly, the TCP socket can’t be enabled ‘in-flight’ — if you decide you do fancy a TCP socket after all, you’ll have to restart your X server which may be a pain if you’re in the middle of something (besides, restarting is just plain uncool).
But there is a way to expose the Unix domain socket as a TCP socket, with the help of socat. The following examples all use bash, so if you run a different shell (if you don’t know, you probably aren’t) you may need to define environment variables differently.
Braindead Proof of Concept (BPOC)
Situation: You want to display an application running on a machine called w00t on another machine, called bling. There’s an X11 server running on bling, but it’s not configured to listen on any TCP socket. DNS is properly setup, so if you ping w00t from bling, you get replies from bling’s IP, and vice versa.
- On bling, find the domain socket of bling’s X11 server. Have a look in
/tmp/.X11-unix/. The socket’s name usually reflects its X server display number (which you can determine by running echo $DISPLAY in an xterm).
- On bling, run something along the lines of
socat TCP-LISTEN:6066 UNIX-CONNECT:/tmp/.X11-unix/X0
This will open up TCP port 6066 on all of bling’s network interfaces, connecting it to the Unix domain socket of the X server.
- In an xterm on bling, run
xhost +. You have now opened up your X11 server to the whole wide world, a silly thing to do. Anyone with access to the TCP socket can now read your keystrokes, read your window contents, click your mouse buttons…
- In an xterm on w00t, run
DISPLAY="bling:66" xclock. You may have noticed that 66 = 6066 – 6000 and indeed, by convention the TCP port number for a certain display is its display number + 6000. Anyhow…. yay, a clock! It’s displayed on bling, but running on w00t.
Improvements
- You may have noticed that in the BPOC, you can use the display on bling only once.
socat will allow only one client, and will exit once that client exits. In some situations, you may consider that a feature (it’s a one-time access grant), but in others you may not. If you want a reusable TCP socket, run something along the lines of
socat TCP-listen:6066,fork,reuseaddr UNIX-CONNECT:/tmp/.X11-unix/X0 which forks off a socat process for every TCP connection.
- You may not want to expose a TCP socket on all interfaces. Maybe you only want to expose a socket on the LAN interface, or on the localhost interface (and wrap the packets in an SSH tunnel). Well, you can, using the ‘bind’ option:
socat TCP-LISTEN:6066,bind=localhost UNIX-CONNECT:/tmp/.X11-unix/X0
Now tunnel it over SSH. On w00t, run ssh -L 6011:localhost:6023 bling. Now localhost:6011 on woot is actually localhost:6023 on bling which is actually /tmp/.X11-unix/X0 on bling. So on w00t you can start an xclock with its display on bling by running DISPLAY="localhost:11" xclock.
xhost + from the BPOC is braindead indeed. There are a couple things you could have done instead, there are good ways of tightening up your authorization scheme.
- First off, you don’t really need to run
xhost + if you properly set up X11 cookies, which you should. Here are some examples on using the xauth scheme, but take note: xauth generate will probably not work on recent X11 releases since the XSECURITY extension is disabled by default. Just use the same cookies on the client and the server.
- Run
xhost +w00t. That’s host-based authentication, which is stupid, but not as stupid as no authorization at all. Any user on w00t can now connect.
- Suppose that on bling (of course!) you’d run
xhost +SI:localuser:theuser with ‘theuser’ being the userID of the unix-user running the socat instance. Now from the point of view of the X server, any client connecting through socat will be coming from ‘theuser’ and will therefore be allowed access. Entertaining, but not much different from just running xhost +. It is something to keep in mind though! Many distros by default add the unix-user that started the X server to the authorization list. That user does not need a cookie. If you run socat as that user you will have the effect of running xhost + even if you run xhost -.
- Just run a nested X11 server, such as Xnest or Xephyr. This way you put untrusted users in a sandbox, preventing them from snooping your keyboard and windows. It’s the X11 equivalent of a chroot.
Tags: en_GB, socat, X11, xauth, xhost —