Debian Live webboot & DNS

Setting up Debian Live webboot image is pretty much undocumented. The only “documentation” I found was a message on a mailing list and an Ubuntu live-boot man page

So I began setting everything up. First, I downloaded webboot image from http://cdimage.debian.org/debian-cd/current-live/amd64/webboot/ into a directory served by HTTP server at http://pxe.local/ (vhost).

I already had DHCP, TFTP, HTTP and iPXE installed and configured:

/etc/dhcp/dhcpd.conf
1
2
3
4
5
6
7
8
9
10
11
12
# ...
subnet 192.168.1.0 netmask 255.255.255.0 {
option routers 192.168.1.1;
option domain-name-servers 192.168.1.1;
next-server 192.168.1.1;
if exists user-class and option user-class = "iPXE" {
filename "http://pxe.local/menu.cfg";
} else {
filename "ipxe.kpxe";
}
}
# ...
/etc/apache2/sites-enabled/pxe.local
1
2
3
4
<VirtualHost *:80>
ServerName pxe.local
DocumentRoot /srv/tftp
</VirtualHost>
/etc/default/tftp-hpa
1
2
3
4
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure"
/srv/tftp/menu.cfg
1
2
3
4
5
6
7
8
9
10
11
12
#!ipxe
:main
menu PXE menu
item debian-live Debian Live
item --default diskboot Boot from hard disk
choose --timeout 5000 choice && goto ${choice}
goto main
:debian-live
# ???
:diskboot
sanboot --no-describe --drive 0x80
exit
ls /srv/tftp
1
2
3
4
5
6
$ ls /srv/tftp
debian-live-8.3.0-amd64-standard.initrd.img
debian-live-8.3.0-amd64-standard.squashfs
debian-live-8.3.0-amd64-standard.vmlinuz
ipxe.kpxe
menu.cfg

So I tried simply to add the lines described on the mailing list to menu.cfg:

1
2
3
4
:debian-live
kernel debian-live-8.3.0-amd64-standard.vmlinuz live fetch=http://pxe.local/debian-live-8.3.0-amd64-standard.squashfs
initrd debian-live-8.3.0-amd64-standard.initrd.img
boot

What I ended up with was the error message:

Begin: Checking  file system ... fsck from util-linux 2.25.2
done.
mount: can't find /root in /etc/fstab
done.
Target filesystem doesn't have requested /sbin/init.
Begin: Running /scripts/local-bottom ... done.
Begin: Running /scripts/init-bottom ...
mount: mounting /dev on /root/dev failed: No such file or directory
done.
No init found. Try passing init= bootarg.

Of course, the system did not even try to download a filesystem image from the given URL. I have found that the correct option is not live, but boot=live. I have also noticed that the fetch option does not accept a hostname:

Due to current limitations in busyboxs wget and DNS resolution,
an URL can not contain a hostname but an IP only.

Nevertheless, let’s try again:

1
2
3
4
:debian-live
kernel debian-live-8.3.0-amd64-standard.vmlinuz boot=live fetch=http://pxe.local/debian-live-8.3.0-amd64-standard.squashfs
initrd debian-live-8.3.0-amd64-standard.initrd.img
boot

The manual was right - hostname resolution does not work:

IP-Config: eth0 hardware address: XX:XX:XX:XX:XX:XX mtu 1500 DHCP RARP
IP-Config: eth0 guessed broadcast address 192.168.1.255
IP-Config: eth0 complete (dhcp from 192.168.1.1):
 address: 192.168.1.2      broadcast: 192.168.1.255    netmask: 255.255.255.0
 gateway: 192.168.1.1      dns1     : 192.168.1.1      dns2   :
 domain : local
 rootserver: 192.168.1.1 rootpath:
 filename: ipxe.kpxe
Creating /etc/resolv.conf
Begin: Trying wget http://pxe.local/debian-live-8.3.0-amd64-standard.squashfs
-O /live/medium/live/debian-live-8.3.0-amd64-standard.squashfs ... wget: bad
address 'pxe.local'
Unable to find a live file system on the network

How to get DNS to work? There are quite a few entries about it. All mention LIVE_DNS option that must be set during live image building process.

However, there is a simple workaround that does not require any hacks or image rebuilds:

  1. Dowload the libc6-udeb and libnss-dns-udeb packages (for jessie 8.2 on amd64 these would be libc6-udeb_2.19-18+deb8u2_amd64.udeb and libnss-dns-udeb_2.19-18+deb8u2_amd64.udeb):

    1
    2
    3
    cd /tmp
    wget http://httpredir.debian.org/debian/pool/main/g/glibc/libc6-udeb_2.19-18+deb8u2_amd64.udeb
    wget http://httpredir.debian.org/debian/pool/main/g/glibc/libnss-dns-udeb_2.19-18+deb8u2_amd64.udeb
  2. Extract it:

    1
    2
    dpkg-deb -x libc6-udeb_2.19-18+deb8u2_amd64.udeb udeb
    dpkg-deb -x libnss-dns-udeb_2.19-18+deb8u2_amd64.udeb udeb
  3. Copy the libresolv and libnss_dns libraries to the TFTP/PXE root:

    1
    2
    cp udeb/lib/libresolv.so.2 /srv/tftp/
    cp udeb/lib/libnss_dns.so.2 /srv/tftp/
  4. Modify menu.cfg to include the libraries in the initrd image:

    1
    2
    3
    4
    5
    6
    :debian-live
    kernel debian-live-8.3.0-amd64-standard.vmlinuz live fetch=http://pxe.local/debian-live-8.3.0-amd64-standard.squashfs
    initrd debian-live-8.3.0-amd64-standard.initrd.img
    initrd libresolv.so.2 /lib/libresolv.so.2
    initrd libnss_dns.so.2 /lib/libnss_dns.so.2
    boot
  5. Enjoy!

PS. The default login/password for the Debian Live systems is user/live.

XMLDocument.getElementById()

Getting element with specified ID (eg. id="id1") from XML file received via xmlHttpRequest is really hard! Let’s take the following JavaScript code:

1
2
3
4
5
6
7
8
9
10
11
12
var ajax = new XMLHttpRequest();
ajax.open('GET', 'test.xml');
ajax.onreadystatechange = function() {
if(ajax.readyState == 4 && ajax.status == 200) {
var doc = ajax.responseXML;
doc.getElementById('id1').appendChild(
doc.createTextNode('abc')
);
// anything else...
}
};
ajax.send();

and test.xml:

1
2
3
4
<xml>
<thiselement id="id1" />
<thiselement id="id2" />
</xml>

You know what would happen? Script will fail (in Firefox and Opera; Chrome will do fine) in this line:

1
doc.getElementById('id1').appendChild()

It’s obvious that you cannot convert doc.getElementById('id1') to object, right? If not - go ahead.

Your browser does not know (or does not want to know), that id="" is really a unique identifier. Everything will start to work when, at the beginning of an XML file, we put:

1
<!DOCTYPE xml [ <!ATTLIST tenelement id ID #IMPLIED> ]>

Until… we would try to send this document to the server:

1
2
3
4
var ajax2 = new XMLHttpRequest();
ajax2.open('POST', 'save.php');
ajax2.onreadystatechange = function() {};
ajax2.send(ajax.responseXML);

Browser will send the DOCTYPE, but without the most important thing ([ <!ATTLIST tenelement id ID #IMPLIED> ]). To make it work, I had to modify the received file in save.php by adding a missing part of a DOCTYPE. Someone knows a better solution?

getNamedItem() in IE6 & IE7

How to access element’s attribute (<element name=”value”>) in JavaScript?

It would seem that this code is the answer:

1
return element.attributes["name"];

If you want to support IE 6 & 7 - it is not so easy!

Here is the appropriate equivalent for those browsers:

1
2
3
4
5
for(var i=0; i<element.attributes.length; i++) {
if(element.attributes[i].name == 'nazwa') {
return element.attributes[i].value;
}
}

Yes, IE supports getNamedItem() method only since version 8! See: http://msdn.microsoft.com/en-us/library/ms536441(v=vs.85).aspx