Sunday, June 7, 2020

Enabling IPv6 on Scaleway Dedibox using FreeBSD

First steps

There are two ways to configure IPv6 on a Dedibox:

  1. either your server supports SLAAC (see Dedibox' IPv6 SLAAC to see if it's the case)
  2. or using a DHCPv6 client

Either way, the first thing to do is to accept ICMPv6 Router Advertisements, this will get you a default route using a link-local IPv6 address:

# ifconfig bce0 inet6 accept_rtadv
# grep ^ifconfig_bce0_ipv6 /etc/rc.conf
ifconfig_bce0_ipv6="inet6 accept_rtadv"
# # netstat -rnf inet6 | grep ^default
default                           fe80::be16:65ff:fefb:d23f%bce0 UG        bce0

Also it doesn't hurt to start rtsold(8) (it looked like it worked without it though):

# grep ^rtsold /etc/rc.conf
rtsold_enable="YES"
# /etc/rc.d/rcsold start
Starting rtsold.

If your server supports SLAAC then I believe you can stop here. In my case I was unlucky and I had to use DHCPv6.

After some experimentation, I realized that you need to make you DHCP client request Prefix Delegation (PD), otherwise the router won't let you through. This is very loosely defined in Online´s documentation, because they use dhclient -P. But PD doesn't request a normal address, so you also need to requests a Non-temporary Address (NA) for this.

Unfortunately, FreeBSD's dhclient doesn't support IPv6, so you need another one. There are some references on Internet of people using net/dual-dhclient (GitHub) but I can't use this since my IPv4 setup is static.

Using ISC's dhclient from ports (failed)

Then I moved to net/isc-dhcp44-client because it supports IPv6. The first problem here is that it's not clear to me that FreeBSD's rc.conf(5) allows you to use DHCP only for IPv6. After glancing at /etc/network.subr it's not clear to me that the ifconfig_<if>_ipv6 actually support "DHCP" as a parameter but I may be wrong (and I didn't test that far, see below). Some post seems to indicate that's the case, since they use "DHCP" both in $ifconfig_em0 and ifconfig_em0_ipv6.

As explained in Dedibox' /48 IPv6 prefix page, you need to configure your DHCP unique identifier (DUID) in your dhclient.conf(5) file, which is /usr/local/etc/dhclient.conf (given you use dhclient(8) from the package). The default configuration contains some stuff, you can remove it all:

# cat /usr/local/etc/dhclient.conf
interface "bce0" {
        # DUID given by Dedibox
        # https://console.online.net/en/network/
        send dhcp6.client-id 01:23:45:67:89:AB:CD:EF:01:23;
}

Optionally, if you don't want dhclient-script(8) to overwrite resolv.conf(5), you need to create the following file (I hate the fact the path is hard coded but there are worse evils in the world):

# cat /etc/dhclient-enter-hooks 
make_resolv_conf() { :; }

Here is what you get:

# /usr/local/sbin/dhclient -6 -d -v bce0
Internet Systems Consortium DHCP Client 4.4.2
Copyright 2004-2020 Internet Systems Consortium.
All rights reserved.                                                  
For info, please visit https://www.isc.org/software/dhcp/ 
                                   
Listening on Socket/bce0                                              
Sending on   Socket/bce0                                              
PRC: Soliciting for leases (INIT).                                    
XMT: Forming Solicit, 0 ms elapsed.                                                                                                          
XMT:  X-- IA_NA 52:cd:78:96                                           
XMT:  | X-- Request renew in  +3600        
XMT:  | X-- Request rebind in +5400 
XMT: Solicit on bce0, interval 1090ms.
RCV: Advertise message on bce0 from fe80::be16:65ff:fefb:d23f.
RCV:  X-- Preference 255.
RCV:  X-- IA_NA 52:cd:78:96
RCV:  | X-- starts 1591003129
RCV:  | X-- t1 - renew  +10800
RCV:  | X-- t2 - rebind +172800
RCV:  | X-- [Options]
RCV:  | | X-- IAADDR 2001:aaaa:3bac::1
RCV:  | | | X-- Preferred lifetime 54000.
RCV:  | | | X-- Max lifetime 86400. 
RCV:  X-- Server ID: 00:01:00:01:1b:ac:bc:2d:10:60:4b:9b:0a:f4
RCV:  Advertisement immediately selected.
PRC: Selecting best advertised lease.
PRC: Considering best lease.
PRC:  X-- Initial candidate 00:01:00:01:1b:ac:bc:2d:10:60:4b:9b:0a:f4 (s: 10105, p: 255).
XMT: Forming Request, 0 ms elapsed. 
XMT:  X-- IA_NA 52:cd:78:96
XMT:  | X-- Requested renew  +3600
XMT:  | X-- Requested rebind +5400
XMT:  | | X-- IAADDR 2001:aaaa:3bac::1
XMT:  | | | X-- Preferred lifetime +7200
XMT:  | | | X-- Max lifetime +7500
XMT:  V IA_NA appended.
XMT: Request on bce0, interval 1040ms.
RCV: Reply message on bce0 from fe80::be16:65ff:fefb:d23f.
RCV:  X-- Preference 255.
RCV:  X-- IA_NA 52:cd:78:96
RCV:  | X-- starts 1591003129
RCV:  | X-- t1 - renew  +10800
RCV:  | X-- t2 - rebind +172800
RCV:  | X-- [Options]
RCV:  | | X-- IAADDR 2001:aaaa:3bac::1
RCV:  | | | X-- Preferred lifetime 7200.
RCV:  | | | X-- Max lifetime 86400. 
RCV:  X-- Server ID: 00:01:00:01:1b:ac:bc:2d:10:60:4b:9b:0a:f4
PRC: Bound to lease 00:01:00:01:1b:ac:bc:2d:10:60:4b:9b:0a:f4.
PRC: Renewal event scheduled in 10800 seconds, to run for 162000 seconds.
PRC: Depreference scheduled in 7200 seconds.
PRC: Expiration scheduled in 86400 seconds.

The interface will get an global IPv6 address but as I said above, Online's router won't let you unless request Prefix Delegation PD, so this is pretty useless. You do this with the -P flag but if you read the manual:

-P Enable IPv6 prefix delegation. This implies −6 and also disables the normal address query. See −N to restore it. Multiple prefixes can be requested with multiple −P flags. Note only one requested interface is allowed.

-N Restore normal address query for IPv6. This implies -6. It is used to restore normal operation after using -T or -P. Multiple addresses can be requested with multiple −N flags.

So that's what I did:

# /usr/local/sbin/dhclient  -d -v -6 bce0 -P -N
Internet Systems Consortium DHCP Client 4.4.2
Copyright 2004-2020 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/
Listening on Socket/bce0
Sending on   Socket/bce0
PRC: Confirming active lease (INIT-REBOOT).
XMT: Forming Rebind, 0 ms elapsed.
XMT:  X-- IA_NA 52:cd:78:96
XMT:  | X-- Request renew in  +3600
XMT:  | X-- Request rebind in +5400
XMT:  X-- IA_PD 52:cd:78:96
XMT:  | X-- Requested renew  +3600
XMT:  | X-- Requested rebind +5400
XMT:  | | X-- IAPREFIX 2001:aaaa:3bac::/48
XMT:  | | | X-- Preferred lifetime +7200
XMT:  | | | X-- Max lifetime +7500
XMT:  V IA_PD appended.
XMT: Rebind on bce0, interval 990ms.
RCV: Reply message on bce0 from fe80::be16:65ff:fefb:d23f.
RCV:  X-- Preference 255.
RCV:  X-- IA_NA 52:cd:78:96
RCV:  | X-- starts 1591559136
RCV:  | X-- t1 - renew  +10800
RCV:  | X-- t2 - rebind +172800
RCV:  | X-- [Options]
RCV:  | | X-- IAADDR 2001:aaaa:3bac::1
RCV:  | | | X-- Preferred lifetime 54000.
RCV:  | | | X-- Max lifetime 86400.
RCV:  X-- IA_PD 52:cd:78:96
RCV:  | X-- starts 1591559136
RCV:  | X-- t1 - renew  +10800
RCV:  | X-- t2 - rebind +172800
RCV:  | X-- [Options]
RCV:  | | X-- IAPREFIX 2001:aaaa:3bac::/48
RCV:  | | | X-- Preferred lifetime 7200.
RCV:  | | | X-- Max lifetime 86400. 
RCV:  X-- Server ID: 00:01:00:01:1b:ac:bc:2d:10:60:4b:9b:0a:f4
PRC: Bound to lease 00:01:00:01:1b:ac:bc:2d:10:60:4b:9b:0a:f4.
Prefix REBIND6 old=2001:aaaa:3bac::/48 new=2001:aaaa:3bac::/48
PRC: Renewal event scheduled in 10800 seconds, to run for 162000 seconds.
PRC: Depreference scheduled in 7200 seconds.
PRC: Expiration scheduled in 86400 seconds.

But then I check my interface but the IPv6 address hadn't been assigned. This is were I threw the towel as I considered I had been too deep in the rabbit whole already.

Theorically I could just have used -P to open the router's gate and then rely on static IPv6 configuration. That would have actually been my favorite solution but I'm not sure FreeBSD's rc.conf(5) would allow this. Actually, it maybe be possible by usng /etc/start_if.bce0; to start /usr/local/sbin/dhclient -6 -P bce0 (and probably remove the ifdisabled inet6 flag on the interface first), but I haven't tried.

Using KAME's dhcp6

As I was wondering about Prefix Delegation and how I could re-use the information I got from the DHCP server to assign IPv6 addresses to my hosts, I came across this post. It's the way it should be: simple and straightforward. dhcp6c requests both PD and NA and in the PD response handler, you tell it how to assign an IPv6 address to the other interfaces. Then rtadvd(8) does the rest.

But I digress and I'm not there yet, I just want an IPv6 for my host. My point is that it's neat. I created a super basic configuration file for dhcp6c:

# cat /usr/local/etc/dhcp6c.conf
interface bce0 {
        send ia-na 1;
        send ia-pd 1;
        send rapid-commit;
};

id-assoc pd 1 {
};

id-assoc na 1 {
};

The attentive reader will notice there's a problem here. Where is the DUID configured? Well it turns out that dhcp6c doesn't allow to configure it by hand... I found this on Google Books (page 469 of IPv6 Advanced Protocols Implementation):

A DHCPv6 client or server needs its DUID for the protocol operation. The user does not have to configure the ID by hand: dhcp6c and dhcp6s automatically generate their type 1 DUIDs on their first invocation, and them them in volatile files, /var/db/dhcp6c_duid and /var/db/dhcp6sduid.

So we need to generate /var/db/dhcp6c_duid. Fortunately someone already did the work:

echo 01:23:45:67:89:AB:CD:EF:01:23 | \
  awk '{ gsub(":"," "); printf "0: 0a 00 %s\n", $0 }' | \
  xxd -r > /var/db/dhcp6c_duid

Let's try it manually:

# dhcp6c -df -c /usr/local/etc/dhcp6c.conf bce0
Jun/07/2020 23:35:12: failed to open /usr/local/etc/dhcp6cctlkey: No such file or directory
Jun/07/2020 23:35:12: failed initialize control message authentication
Jun/07/2020 23:35:12: skip opening control port
Jun/07/2020 23:35:13: Sending Solicit
Jun/07/2020 23:35:13: unexpected advertise
Jun/07/2020 23:35:13: Sending Request
Jun/07/2020 23:35:13: dhcp6c Received REQUEST
Jun/07/2020 23:35:13: add an address 2001:aaaa:3bac::1/128 on bce0

# ping6 -qc 1 google.com
PING6(56=40+8+8 bytes) 2001:aaaa:3bac::1 --> 2a00:1450:4007:811::200e

--- google.com ping6 statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 2.047/2.047/2.047/0.000 ms

Let's just enable dhcp6c at boot time:

# grep ^dhcp6 /etc/rc.conf
dhcp6c_enable="YES"
dhcp6c_interfaces="bce0"

One last thing: if you're using a firewall, be sure to let IPv6 UDP packets on port 546 come in. This is how DHCPv6 works. With pf, this would look like:

# grep 'port 546' /etc/pf.conf 
pass in log inet6 proto udp to port 546

And voilĂ !

Friday, May 1, 2020

Using Lenovo X1 Carbon volume/brightness keys under a bare X11

This is going to be a quick post.

When you don't use a fancy Window Manager (I'm using i3), there are many things which don't come out of the box. Well i3 supports keyboard bindings, but I'm not sure about special keys like volume/brightness. You may ask "but what are you using this then?", well it's another topic but I'll just say that I like its lightweightness.

Anyway, I'm sure there's more than one way to do this but one pretty neat method I found and like is using xbindkeys(1). Here is the relevant snippet of my $HOME/.xbindkeyrc:

"xterm"
  control + b:2

# Increase backlight
"xbacklight -inc 5"
  XF86MonBrightnessUp

# Decrease backlight
"xbacklight -dec 5"
  XF86MonBrightnessDown

# Increase volume
"amixer set Master 5%+"
  XF86AudioRaiseVolume

# Decrease volume
"amixer set Master 5%-"
  XF86AudioLowerVolume

# Mute
"amixer set Master toggle"
  XF86AudioMute

I let you figure out what this does, but that shouldn't be too hard...

Note that of other XF86 symbols, you can visit this page: http://wiki.linuxquestions.org/wiki/XF86_keyboard_symbols. You can also use xev(1) to figure out which code is emitted when one key is pressed.

Finally, xbindkeys(1) is a daemon which needs to be started, so just add this to your $HOME/.xinitrc:

xbindkeys

Have fun!

Saturday, February 15, 2020

Using acme.sh to generate a Let's Encrypt certificate

Like almost any individual on Earth involved a little bit in open-source, I use Let's Encrypt to generate my web certificates.

The first client I used for this was acme-client. It was conveniently available as FreeBSD's security/acme-client port but it has been removed. The reason, as far as I understand, is a bit silly: acme-client has been imported in OpenBSD and is now maintained there. The code on the original website is not updated anymore so the port has been removed. (It's a bit more work to maintain a tool from OpenBSD as a port, as someone needs to manually extract it from time to time and store it somewhere, I guess that's the fundamental reason.)

Anyway I had to find something else and after a bit of googling, I found a replacement: acme.sh, which is packaged as security/acme.sh. At first this is a bit scary (7000 lines of shell script, but well people have reported it works well and it's simple, so I gave it a try.

So here is how set it up (note that the ordering is important):

  1. First you need to configure you web server so that Let's Encrypt's service can read the challenge and verify the domain you claim is indeed yours. In my case, with Nginx:
        # This host only exist on port 443. Just accept Let's Encrypt challenges
        # in plain text and redirect anything else to the port 443.
        server {
            listen       80;
            server_name  foo.chchile.org;
            access_log   /var/log/nginx/foo-access.log;
            error_log    /var/log/nginx/foo-error.log info;
            allow all;
    
            root   /var/empty;
    
            location ^~ /.well-known/acme-challenge/ {
                alias /usr/local/www/acme/.well-known/acme-challenge/;
            }
    
            location / {
                return  301 https://foo.chchile.org$request_uri;
            }
        }
        
  2. Then you can run acme.sh to issue the certificate. It's really straightforward:
    # /usr/local/sbin/acme.sh  --issue -d foo.chchile.org -w /usr/local/www/acme
                            
    [Sat Feb 15 21:40:18 UTC 2020] Create account key ok.
    [Sat Feb 15 21:40:18 UTC 2020] Registering account                                                                                           
    [Sat Feb 15 21:40:19 UTC 2020] Registered                                                                                                    
    [Sat Feb 15 21:40:19 UTC 2020] ACCOUNT_THUMBPRINT='...'
    [Sat Feb 15 21:40:19 UTC 2020] Creating domain key
    [Sat Feb 15 21:40:19 UTC 2020] The domain key is here: /root/.acme.sh/foo.chchile.org/foo.chchile.org.key                        [Sat Feb 15 21:40:19 UTC 2020] Single domain='foo.chchile.org'                                                                         [Sat Feb 15 21:40:19 UTC 2020] Getting domain auth token for each domain                             
    [Sat Feb 15 21:40:20 UTC 2020] Getting webroot for domain='foo.chchile.org'
    [Sat Feb 15 21:40:20 UTC 2020] Verifying: foo.chchile.org
    [Sat Feb 15 21:40:24 UTC 2020] Success
    [Sat Feb 15 21:40:24 UTC 2020] Verify finished, start to sign.
    [Sat Feb 15 21:40:24 UTC 2020] Lets finalize the order, Le_OrderFinalize: https://acme-v02.api.letsencrypt.org/acme/finalize/78264375/2343222
    453
    [Sat Feb 15 21:40:25 UTC 2020] Download cert, Le_LinkCert: https://acme-v02.api.letsencrypt.org/acme/cert/04236a2f1bd00075bda7c3ed8bb9d2953b0
    0
    [Sat Feb 15 21:40:25 UTC 2020] Cert success.
    -----BEGIN CERTIFICATE-----
    [...]
    -----END CERTIFICATE-----
    [Sat Feb 15 21:40:25 UTC 2020] Your cert is in  /root/.acme.sh/foo.chchile.org/foo.chchile.org.cer 
    [Sat Feb 15 21:40:25 UTC 2020] Your cert key is in  /root/.acme.sh/foo.chchile.org/foo.chchile.org.key 
    [Sat Feb 15 21:40:25 UTC 2020] The intermediate CA cert is in  /root/.acme.sh/foo.chchile.org/ca.cer 
    [Sat Feb 15 21:40:25 UTC 2020] And the full chain certs is there:  /root/.acme.sh/foo.chchile.org/fullchain.cer 
        
  3. Now, let's configure the desired certificate paths in Nginx (there's not there yet, this will be the next step):
       server {
            listen       443 ssl;
            server_name  foo.chchile.org;
            access_log   /var/log/nginx/foo-access.log;
            error_log    /var/log/nginx/foo-error.log debug;
    
            ssl_certificate      /usr/local/etc/ssl/acme/foo.chchile.org/fullchain.pem;
            ssl_certificate_key  /usr/local/etc/ssl/acme/private/foo.chchile.org/privkey.pem;
    
            ssl_session_timeout  5m;
    
            ssl_protocols  TLSv1.1 TLSv1.2;
            ssl_ciphers  HIGH:!aNULL:!MD5;
            ssl_prefer_server_ciphers   on;
    
            [...]
        }
        
  4. It's almost done. acme.sh uses /root/.acme.sh as its work space. The certificate and the key are there but it's not advised to use them as is since the internal layout may chance in the future. So you need to install (read "copy") the certificate:
    # /usr/local/sbin/acme.sh --install-cert -d foo.chchile.org \
      --key-file /usr/local/etc/ssl/acme/private/foo.chchile.org/privkey.pem \
      --cert-file /usr/local/etc/ssl/acme/foo.chchile.org/cert.pem \
      --fullchain-file /usr/local/etc/ssl/acme/foo.chchile.org/fullchain.pem \
      --reloadcmd "service nginx restart"
    [Sat Feb 15 21:42:24 UTC 2020] Installing cert to:/usr/local/etc/ssl/acme/foo.chchile.org/cert.pem
    [Sat Feb 15 21:42:24 UTC 2020] Installing key to:/usr/local/etc/ssl/acme/private/foo.chchile.org/privkey.pem
    [Sat Feb 15 21:42:24 UTC 2020] Installing full chain to:/usr/local/etc/ssl/acme/foo.chchile.org/fullchain.pem
    [Sat Feb 15 21:42:24 UTC 2020] Run reload cmd: service nginx restart
    Performing sanity check on nginx configuration:
    nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
    Stopping nginx.
    Waiting for PIDS: 29714.
    Performing sanity check on nginx configuration:
    nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
    Starting nginx.
    [Sat Feb 15 21:42:24 UTC 2020] Reload success
        
  5. And finally, set up a cron job to renew the certificate whenever it's needed. That's where acme.sh is neat, everything you typed above has been recorded in /root/acme.sh, so the crontab(5) line just looks like:
    0       0       *       *       *       root    /usr/local/sbin/acme.sh --cron > /dev/null
        

Blog re-purpose

It's a been a long time since my last post.

My life has changed a lot since then and I don't have much time anymore to play with my computer for fun, even less to write articles to share my knowledge and learning. Hence from now on, when I will post something this will be mostly as a memo for myself for future use. Since it's public, I will still try to make the posts look decent but the style will be much more terse.

So why keep posting at all? I doubt I have any reader anyway. But maybe sometimes someone will be desperate enough to go to Google's 10th result page and will come across my blog. If this can help this soul, I'll be more than happy!

Sunday, July 27, 2014

Installing FreeBSD on a Dedibox (online.net)

Created: 2014/07/27
Updated: 2014/08/12 - higher-end Dedibox
Updated: 2014/08/14 - software RAID-1

My first server was a Dedibox. I then switched to OVH's Kimsufi (for the anecdote, "Kimsufi" sounds like "enough for me" in French) which at the time was more attractive (15 EUR/month instead of 20).  My setup then evolved to make use of failover IPs (an extra IP address which you can switch from one OVH server to another).

But now my Kimsufi servers are getting old and slow or expensive, depending for which side you're looking at it and I'd like to upgrade them. OVH has very attractive prices like 5 EUR/month for the cheapest one (at least theoritically given I've never seen them available despite them constantly announcing the last server was shipped a few hours ago).  For the price I pay today overall, I could get an i5 CPU on the main server and a cheap and low-grade server for the failover...

... if only OVH was still proposing failover IPs on Kimsufi grade servers. The Kimsufi offer has spun off to really focus on home-servers where -- I guess -- people don't need such fancy services. If you want to have a failover IP at OVH now, you need to get an enterprise grade server which costs at least 80 EUR/month.  I guess this move has been motivated by the IPv4 addresses crunch.

Anyway.  I'm now going back to Dedibox which still offers failover IPs. Also they offer access to the server's console through a Java applet, which can be super useful. Something OVH did back in the time but then removed. However Dedibox don't offer FreeBSD by default (which Kumsufi did at the time, and maybe still do) so you have to install it yourself. Here is how:

  • Boot an Ubuntu rescue system, login and run sudo to be root.
  • Download a FreeBSD release or snapshot ISO; 10-STABLE can be found here: http://ftp2.fr.freebsd.org/pub/FreeBSD/snapshots/ISO-IMAGES/10.0/
  • Install QEMU:
    apt-get update && apt-get install qemu-kvm
    
  • Start QEMU with a VNS server, attached to the raw disk, booting on the ISO:
    qemu-system-x86_64 -no-kvm -hda /dev/sda -cdrom FreeBSD-*.iso -net nic,model=e1000 -vnc :1 -boot d
    or, if you have two disks:
    qemu-system-x86_64 -no-kvm -hda /dev/sda -hdb /dev/sdb -cdrom FreeBSD-*.iso -net nic,model=e1000 -vnc :1 -boot d
  • Connect in using VNC:
    xvncviewer ${server_ip}:1
Now you can install FreeBSD. The only thing is that the bootloader won't be installed (correctly?) for some unknown reason. So you need to do it yourself.
I couldn't come up with the a way to partition the server the way I want with the bsdinstaller, so I typically switch to the console (Alt-F4) right after choosing the keymap to make it using gpart. I'll describe it here for the record, so it will save me from research the next time I'll do it.

Here is the partitioning scheme:
  • We're in 2014, so we're using GPT boot, which requires a small partition for the bootloader.
  • I want the base system in UFS, mainly because it's less brittle to deal with remotely and you can use nextboot(8) fully (the new kernel will be booted only once and they the previous one will be reinstated, so you can try kernels); although all this is less mandatory if you have a working console as with Dedibox.
  • A small swap partition.
  • The remaining in ZFS.

You have a single disk or a hardware RAID controller

Here is how to do it from scratch:

###
### Setup partitions
###
# dd if=/dev/zero of=/dev/ada0 bs=64k count=128
128+0 records in
128+0 records out
8388608 bytes transferred in 0.042453 secs (197599244 bytes/sec)
# gpart show
# gpart create -s GPT ada0
ada0 created
# gpart add -t freebsd-boot -s 64k -i 1 ada0
ada0p1 added
# gpart add -t freebsd-ufs -s 20G -i 2 ada0
ada0p2 added
# gpart add -t freebsd-swap -s 2G -i 3 ada0
ada0p3 added
# gpart add -t freebsd-zfs -i 4 ada0
ada0p4 added
###
### Create the filesystems
###
# newfs -j /dev/ada0p2
[...]
# zpool create tank /dev/ada0p4
cannot mount '/tank': failed to create mountpoint (this is expected and harmless)
###
### Install the bootcode manually as it will fail for some reason
###
# gpart bootcode -b /boot/pbmr -p /boot/gptboot -i 1 ada0
bootcode written to ada0

Now go ahead and install FreeBSD.

You want to software RAID-1

Note that we use geom_mirror for the first three partition, and ZFS mirroring for the pool as I think it has better performances.

Also, note that the current bsdinstaller does not seem to understand what is a geom_mirror device and wants us to create a partitioning scheme on it.  We will therefore mount the partition to /mnt manually.

###
### Setup partitions on the first disk, ada0
###
# dd if=/dev/zero of=/dev/ada0 bs=64k count=128
128+0 records in
128+0 records out
8388608 bytes transferred in 0.042453 secs (197599244 bytes/sec)
# gpart show
# gpart create -s GPT ada0
ada0 created
# gpart add -t freebsd-boot -s 64k -i 1 ada0
ada0p1 added
# gpart add -t freebsd-ufs -s 20G -i 2 ada0
ada0p2 added
# gpart add -t freebsd-swap -s 2G -i 3 ada0
ada0p3 added
# gpart add -t freebsd-zfs -i 4 ada0
ada0p4 added
###
### Now duplicate those steps for ada1.
###
[...]
###
### Now create the mirror
###
# kldload geom_mirror
# gmirror label gm-root ada0p2 ada1p2
# gmirror label gm-swap ada0p3 ada1p3
###
### Create the filesystems
###
# newfs -j /dev/ada0p2
[...]
# zpool create tank mirror /dev/ada0p4 /dev/ada1p4
cannot mount '/tank': failed to create mountpoint (this is expected and harmless)
###
### Install the bootcode manually as it will fail for some reason
###
# gpart bootcode -b /boot/pbmr -p /boot/gptboot -i 1 ada0
bootcode written to ada0
# gpart bootcode -b /boot/pbmr -p /boot/gptboot -i 1 ada1
bootcode written to ada1
###
### Mount the partition to install FreeBSD
###
# mount /dev/mirror/gm-root /mnt

Now when the installer asks you about the partitioning, select "Shell" and FreeBSD will be installed to /mnt once you exit this shell.

End of installation

A few notes (some for myself):
  • The default router in online.net's network is .1.
  • Add the following lines to /etc/rc.conf
  • sendmail_submit_enable=NO
    sendmail_outbound_enable=NO
    sendmail_msp_queue_enable=NO
    
  • YMMV but on QEMU I have an em0 interface, but on the real server it can be igb0 or bce0; so I need to change my /etc/rc.conf accordingly. What I typically do if I'm not sure, is duplicate the ifconfig_em0 line to ifconfig_igb0 and ifconfig_bce0.
  • Add a user or enable root login on sshd.
  • If you are using software RAID, add geom_mirror_load="YES" to /boot/loader.conf.
  • If your server has a PERC h200 controller, the disk won't be /dev/ada0 but /dev/da0, even on FreeBSD10, so change /etc/fstab accordingly.
  • Add the swap to /etc/fstab.
Small example of what /etc/fstab look like (with a software mirror in that case, but you cannot boot on a mirror, the subsystem is not there yet at boot, so you need to pick one of the disk):
/dev/mirror/gm-root     /               ufs     rw      1       1
/dev/mirror/gm-swap     none            swap    sw      0       0
Now before trying to boot FreeBSD on the real server, just try it on QEMU, this will save you some time if you missed something. First umount cleanly your disks and then kill QEMU from the host. Now re-run it using:
qemu-system-x86_64 -no-kvm -hda /dev/sda -net nic,model=e1000 -vnc :1 -boot c
This should go to the boot pompt. Shut down cleanly. Then you can try to boot it on the real server. If it does not come only, you can still use the Java console to debug it (for example, the interface name may not be correct).

Tuesday, May 6, 2014

Netboot OpenBSD on a Soekris

This post is a reminder for me on how to do this. This is the second time I spend two entire evenings to achieve this, and I seem to remember both time I succeeded using different methods. This time I decided to dump what I have in mind because in 2014, this is just silly how backward and complicated it is :). By the way, I know some people more experienced than me in OpenBSD who may read this, feel free to comment and tell me what I'm doing wrong to end up with something so convoluted :).

I'm using a Debian machine as a server. There is a direct Ethernet cable from the Soekris to the server (10.0.0.1), nothing else is on the network.

  1. Download the OpenBSD release and extract it to /openbsd.
  2. Install the following packages on the Debian server:
    • udhcpd, because it's way simpler than ISC dhcpd
    • atftpd, do NOT use the tftpd package, which is the implementation from NetKit, this is really broken and althrough supposed to be very simple I wasted hours on this
    • rarpd
    • bootparamd
    • nfs-kernel-server
  3. Here are the relevant bits for /etc/udhcpd.conf:
    start     10.0.0.100
    end       10.0.0.110
    interface eth2
    siaddr    10.0.0.1
    sname     debian
    bootfile  /tftpboot/pxeboot
    option    dns      8.8.8.8 8.8.4.4
    option    router   10.0.0.1
    option    domain   domain.local
    option    subnet   255.255.255.0
    option    lease    864000
    option    rootpath /openbsd
    
  4. Start it:
    udhcpd -f /etc/udhcpd.conf
  5. atftpd probably added a similar line to /etc/inetd.conf; keep everything as-is and change the serving path (last argument):
    tftp            dgram   udp4    wait    nobody /usr/sbin/tcpd /usr/sbin/in.tftpd --tftpd-timeout 300 --retry-timeout 5 --mcast-port 1758 --mcast-addr 239.239.239.0-255 --mcast-ttl 1 --maxthread 100 --verbose=5 /openbsd
  6. Start or reload inetd.
  7. Now I advise to start a
    tcpdump -ev
    in one terminal t
    o see what's going on on the wire, and
    tail -f /var/log/daemon.log
    in an other. You can give a try to the Soekris: provided you have a serial cable on it (otherwise I don't even know why you're reading this), hit Ctrl-P at the boot and type:
    boot f0
    This won't work, but note the Soekris MAC address and the IP address which has been distributed to it.
  8. Now fill up /etc/ethers for rarpd (that's oldschool, isn't it? :)):
    00:00:24:14:11:80   10.0.0.102
  9. Now let's configure bootparamd by first telling the Soekris name in /etc/hosts:
    10.0.0.102   soekris
    and then giving NFS root in /etc/bootparams.conf (!)
    soekris root=10.0.0.1:/openbsd
  10. Export /openbsd in NFS in /etc/exports:
    /openbsd   10.0.0.0/24(rw,no_root_squash)
    and reload the list of exported filesystems:
    /etc/init.d/nfs-kernel-server restart
  11. Now configure a bit OpenBSD before booting it:
    1. /openbsd/etc/boot.conf (set the console to see the kernel boot and tell pxeboot where to find the kernel):
      stty com0 19200
      set tty com0
      boot tftp:/tftpboot/bsd
    2. /openbsd/etc/ttys (enable getty on the console and set the correct speed):
      console "/usr/libexec/getty std.19200"  vt220   on  secure
  12. Verify that everything is running: inetd, udhcpd, rarpd, all RPC daemons (rpcbind should be start before all of them), including rpc.bootparamd.
  13. You should now be able to boot, with root having no password!

Thursday, February 21, 2013

Poor man's browser sandboxing

Last update: Sat Feb 23 15:14:13 CET 2013

Nowadays I use my browser most of the time, as you probably do as well. And like me, you are probably quite annoyed to run this big software blob and its unavoidable bugs against so many websites. Yes, browsers are the prime attack vector now.

So why not sandbox it as another user so as to insulate it from you sensitive data (ssh keys/agent, files, ...)? You can do this in about 15 minutes. This is more a quick reminder for me than a full-fledged blog post, so the explanations and commands are a little terse. Adapt them to fit your need.

$ sudo adduser -m browser
$ sudo mkdir ~browser/.ssh
$ sudo cp ~/.ssh/id_rsa.pub ~browser/.ssh/authorized_keys

# You should shut down your browsers before doing this.
$ sudo mkdir ~browser/.config
$ sudo cp -Rp ~/.config/google-chrome ~browser/.config/
$ sudo cp -Rp ~/.mozilla ~browser/
$ sudo chown -R browser ~browser

$ cat > bin/runasbrowser.sh << EOF
#!/bin/sh
exec ssh -Xf browser@localhost "$@"
EOF
$ chmod +x bin/runasbrowser.sh

# Be sure that your ~/bin belongs to your $PATH.
$ runasbrowser Xephyr :1
$ runasbrowser google-chrome

Notes:

  • You will probably need to put user "browser" in a group to allow him to play music :).
  • I've got the idea of this here; you can see that the author did much more things than me to set this up. I'm not sure why it works for me with so few steps.