Advanced Programming in the UNIX Environment

CS631 - APUE - NetBSD/VirtualBox Setup


This document will guide you through the setup of a NetBSD VM using VirtualBox to perform all your course work on. Please follow these steps as shown; if you run into problems or have questions, please send them to the class mailing list.

Installing your NetBSD VM

Creating a new VirtualBox Image

First, install VirtualBox from https://www.virtualbox.org/.

Next, download the latest ISO for NetBSD/amd64 from e.g. https://cdn.netbsd.org/pub/NetBSD/NetBSD-8.1/images/NetBSD-8.1-amd64.iso and save it as /tmp/NetBSD.iso.

Start VirtualBox.

Screenshot: VirtualBox at first start

Select 'New' and fill in the following values:

Name "apue"
Type: BSD
Version: NetBSD (64-bit)

Screenshot: Creating a new VirtualBox image

Accept all defaults after this, clicking 'Continue' until the initial VM image is configured:

Screenshot: A new VirtualBox image

Configuring the new VM

Select the newly created image and go to 'Settings':

Go to 'System' and bump up 'Hard Disk' in the boot order to the top.

Screenshot: VirtualBox Bootorder Screen

We do this, so that we can initially boot off the CD, but then boot off the disk once the OS installed without having to eject the CD from the VM (although we will do that later, too).

Go to 'Storage':

Select the (empty) CD drive on the left-hand side, then select the disc icon on the right-hand side next to the 'Optical Drive: IDE Secondary Master' option.

Screenshot: VirtualBox Storage Screen

Select 'Choose Virtual Optical Disk File...'.

Find the ISO you had downloaded before, i.e. /tmp/NetBSD.iso.

Select 'Network':

Screenshot: VirtualBox Network Screen

Select the first adapter, keep it as 'NAT', select 'Advanced' and then 'Port Forwarding'.

Add a new rule (upper right), and fill in:

Name: ssh
Protocol: TCP
Host IP: 127.0.0.1
Host Port: 2222
Guest IP:
Guest Port: 22

Screenshot: VirtualBox Portforwarding Screen

If you want a dual-stack environment, and your network serves you an IPv6 address, you can enable another interface in bridge mode (NAT does not apply to IPv6):

To do that, select 'Adapter 2', 'Enable Network Adapter', and select 'Bridged Adapter'.

Finally, select 'Ok' to commit your configuration changes.

Installing NetBSD

Start your newly created VM by selecting 'Start'.

The VM should start and get you to the NetBSD install screen, where we'll follow a very basic NetBSD installation:

NetBSD Installation Screenshot

Select 'Install messages in English', then leave the keyboard type 'unchanged', then select 'Install NetBSD to hard disk'. Then:

Shall we continue? yes
Available disks: wd0
This is the correct geometry
Use the entire disk
Do you want to install the NetBSD bootcode? yes
Use existing partition sizes
Partition sizes are ok
Accept default name.
Shall we continue? 'yes'
Use the BIOS console
Select your distribution: 'Installation without X11'
Install from: 'CD-ROM'

NetBSD Installation Screenshot: Set Extraction

After extraction is complete, 'hit enter to continue', then configure the network:

Available interfaces: 'wm0'
Network media type: autoselect
Perform autoconfiguration? yes

This should get you a DHCP lease and an overall network configuration that we wish to commit to the system:

Are they ok? yes
Do you want it installed in /etc?
yes

(If you enabled a second interface above for IPv6 only, then leave wm1 unconfigured; we will configure that interface manually further below.)

Back on the configuration screen, 'enable installation of binary packages'. While not immediately necessary, this will allow you to later on install additional software via the pkgin tool, so is a useful step to complete here.

Accept all defaults and select:

'x: Install pkgin and update package summary'
'hit enter to continue'

Next, select:

'g: Enable sshd'
'h: Enable ntpd'
'o: Add a user'

Add your username, e.g., "jschauma'.

Note: it is required for this class to create and run your code as a non-root user, so this step is not optional.

Add the user to 'wheel', so you can su(1).

Select a shell, e.g. /bin/sh and set a password.

(Note: we did not set a password for the root account. If you like, you can do that. You may also choose not to do that, but it's important to understand why that might be acceptable: root is not allowed to log in remotely (which is one of the reasons why you had to create an additional user account), but any user on the system could run su(1) to become the super user without requiring a password.

NetBSD requires users to be in the 'wheel' group to run su(1), so only your newly created user should be able to do this.

This, together with the fact that the VM is intended for nothing of importance whatsoever may make it ok to not have any additional protections on the superuser account.)

Now you're back at the main install menu, where we will perform a few minor configuration changes before we reboot, so select 'x: Exit install System. This drops you into a shell. Mount the virtual disk and edit the file /etc/rc.conf on it:

mount /dev/wd0a /mnt
vi /mnt/etc/rc.conf

If you want to enable the second network interface for IPv6 only connectivity, update dhcpcd_flags="-qM wm0" to become dhcpcd_flags="-qM wm0 wm1". Either way append the following lines, then write the file and quit (:wq):

no_swap=YES
hostname=apue

NetBSD /etc/rc.conf configuration

If you are connected to an IPv6 enabled network, and you previously created the second network interface in bridged mode, then you can now configure it for IPv6 only. To do that, run the following command to append the right lines to /mnt/etc/dhcpcd.conf:

( echo; echo "interface wm1"; echo "ipv6only"; ) >> /mnt/etc/dhcpcd.conf

Finally, unmount the disk and reboot the system. It should now boot into your newly installed system with the ISO still in the CD drive:

umount /mnt
shutdown -r now

NetBSD boot selector

When the system comes up, it should display messages about DHCP etc. and ultimately present you with a prompt:

NetBSD login screen

You can now log in and verify network connectivity (for IPv6 only if your network is IPv6 enabled and you did configure the second interface as described above), then eject the CD:

NetBSD/amd64 (apue) (console)

login: jschauma
Password:

NetBSD 8.1 (GENERIC) #0: Fri May 31 08:43:59 UTC 2019

Welcome to NetBSD!

apue$ ifconfig -a
wm0: flags=0x8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        capabilities=2bf80<TSO4,IP4CSUM_Rx,IP4CSUM_Tx,TCP4CSUM_Rx>
        capabilities=2bf80<TCP4CSUM_Tx,UDP4CSUM_Rx,UDP4CSUM_Tx,TCP6CSUM_Tx>
        capabilities=2bf80<UDP6CSUM_Tx>
        enabled=0
        ec_capabilities=7<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU>
        ec_enabled=0
        address: 08:00:27:db:b9:08
        media: Ethernet autoselect (1000baseT full-duplex)
        status: active
        inet 10.0.2.15/24 broadcast 10.0.2.255 flags 0x0
        inet6 fe80::a00:27ff:fedb:b908%wm0/64 flags 0x0 scopeid 0x1
wm1: flags=0x8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        capabilities=2bf80<TSO4,IP4CSUM_Rx,IP4CSUM_Tx,TCP4CSUM_Rx>
        capabilities=2bf80<TCP4CSUM_Tx,UDP4CSUM_Rx,UDP4CSUM_Tx,TCP6CSUM_Tx>
        capabilities=2bf80<UDP6CSUM_Tx>
        enabled=0
        ec_capabilities=7<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU>
        ec_enabled=0
        address: 08:00:27:30:f5:5b
        media: Ethernet autoselect (1000baseT full-duplex)
        status: active
        inet6 fe80::5464:961e:7368:2449%wm1/64 flags 0x0 scopeid 0x2
        inet6 2001:470:1f07:1d1:32bb:2d83:face:e3/64 flags 0x0
lo0: flags=0x8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 33624
        inet 127.0.0.1/8 flags 0x0
        inet6 ::1/128 flags 0x20<NODAD>
        inet6 fe80::1%lo0/64 flags 0x0 scopeid 0x3
apue$ ping -c 3 www.yahoo.com
PING atsv2-fp-shed.wg1.b.yahoo.com (74.6.142.32): 56 data bytes
64 bytes from 74.6.142.32: icmp_seq=0 ttl=254 time=23.906584 ms
64 bytes from 74.6.142.32: icmp_seq=1 ttl=254 time=27.090306 ms
64 bytes from 74.6.142.32: icmp_seq=2 ttl=254 time=24.113525 ms

----atsv2-fp-shed.wg1.b.yahoo.com PING Statistics----
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 23.906584/25.036805/27.090306/1.781392 ms
apue$ ping6 -c 3 www.yahoo.com
PING6(56=40+8+8 bytes) 2001:470:1f07:1d1:32bb:2d83:face:e3 --> 2001:4998:58:207::1000
16 bytes from 2001:4998:58:207::1000, icmp_seq=0 hlim=53 time=25.138 ms
16 bytes from 2001:4998:58:207::1000, icmp_seq=1 hlim=53 time=28.066 ms
16 bytes from 2001:4998:58:207::1000, icmp_seq=2 hlim=53 time=27.468 ms

--- atsv2-fp-shed.wg1.b.yahoo.com ping6 statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 25.138/26.891/28.066/1.547 ms
apue$ su root -c "eject cd0"
apue$ 

Set up your VM for this class

Set up SSH

Next, verify that ssh(1) to the system works from outside the VM. From your host OS:

$ ssh -p 2222 jschauma@127.0.0.1
The authenticity of host '[127.0.0.1]:2222 ([127.0.0.1]:2222)' can't be established.
ECDSA key fingerprint is SHA256:SBZki7bOfy68Mv+SnCQWLDLP4cNbzD0MR/xq28Lc0ic.
Are you sure you want to continue connecting (yes/no)? 

Compare against the fingerprint as seen on your VM:

apue$ ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key.pub
521 SHA256:SBZki7bOfy68Mv+SnCQWLDLP4cNbzD0MR/xq28Lc0ic root@apue (ECDSA)

(Verifying the SSH host key in this context is something we do primarily out of good security hygiene and habit. A MitM attack against 'localhost' on your VM network is rather unlikely. However, you should get into the habit of verifying host keys when you connect to other systems.)

Once you have confirmed that you can log in, let's create an SSH key pair so that you no longer need a password to access the VM. On your parent OS (i.e., outside your VM), run the following command:

$ ssh-keygen -b 4096 -f ~/.ssh/apue
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in ~/.ssh/apue.
Your public key has been saved in ~/.ssh/apue.pub.
The key fingerprint is:
SHA256:LTvdolG8oNYxPX6wQq8T3gYpuKneDwhpC3fQahfvdO0 jan@localhost
The key's randomart image is:
+---[RSA 4096]----+
|                 |
|   .             |
|  . o            |
| . o o   =       |
|+.+ o.o S.O      |
|o+.+.o.=+% *     |
| .. .o+o*+E o    |
|   .oo  o*oo     |
| .o.... oo       |
+----[SHA256]-----+
$ 

Next, copy the public key to your VM and install it under ~/.ssh/authorized_keys:

$ scp -P 2222 ~/.ssh/apue.pub jschauma@127.0.0.1: Password for jschauma@127.0.0.1: apue.pub 100% 401 565.1KB/s 00:00 $ ssh -p 2222 jschauma@127.0.0.1 Password for jschauma@127.0.0.1: apue$ mkdir ~/.ssh apue$ mv apue.pub ~/.ssh/authorized_keys apue$ exit $

With that in place, you should now be able to ssh to the VM using your key. If you are on macOS, your ssh agent will automatically store the key's passphrase in the login keychain, so after the first time, you won't have to provide it any longer.

$ ssh -p 2222 -i ~/.ssh/apue jschauma@127.0.0.1 Enter passphrase for key '/Users/jan/.ssh/apue': Last login: Tue Sep 3 15:07:22 2019 from 10.0.2.2 NetBSD 8.1 (GENERIC) #0: Fri May 31 08:43:59 UTC 2019 Welcome to NetBSD! apue$

So far, so good: you can ssh to your VM using your ssh key without having to enter a passphrase. But that's a lot of typing just to log in there. Let's save ourselves some work by adding the right lines to our ~/.ssh/config (on the parent OS), then verify that just typing 'ssh apue' works:

$ cat >> ~/.ssh/config <<EOF
Host apue
        HostName 127.0.0.1
        IdentityFile ~/.ssh/apue
        Port 2222
        User jschauma
EOF
$ ssh apue
Last login: Tue Sep  3 15:10:53 2019 from 10.0.2.2
NetBSD 8.1 (GENERIC) #0: Fri May 31 08:43:59 UTC 2019

Welcome to NetBSD!

apue$ 

Set up your C development environment

Next, let's set up our C development environment. As discussed in class, _all code *must* be compiled using the '-Wall -Werror' flags. To do this, we first set the CFLAGS environment variable in our shell and then create an alias for the compiler to use these flags. Assuming your user uses /bin/sh as the default shell, you would do this as follows:

$ ssh apue
apue$ cat >>~/.shrc <<EOF
# APUE compiler flags and alias
# export CFLAGS='-Wall -Werror -Wextra'
# alias cc='cc \${CFLAGS}'
# EOF
$ 

Next, fetch all the code examples from our lectures and extract them in the VM so you can run the programs as you prepare for class:

apue$ ftp https://stevens.netmeister.org/631/apue-code.tar.gz
Trying [2001:470:30:84:e276:63ff:fe72:3900]:443 ...
Trying 166.84.7.99:443 ...
Requesting https://stevens.netmeister.org/631/apue-code.tar.gz
100% |***********************************| 67278 243.74 KiB/s    00:00 ETA
67278 bytes retrieved in 00:00 (243.44 KiB/s)
apue$ tar zxf apue-code.tar.gz
apue$ rm apue-code.tar.gz
apue$ ls
01 02 03 04 05 06 07 08 09 10 11 12 13
apue$ 

Finally, we also want to avoid having to use the VirtualBox application GUI every time we want to work with our VM. So instead of relying on the GUI to start our VM, we will use the command-line utility 'VBoxManage'. To verify that this works as intended, let's first shut down and power off our VM. For that, we need super-user privileges, which we gain via the su(1) command, and because we're notoriously lazy, we immediately create another alias to save ourselves some typing:

apue$ cat >> ~/.shrc <<EOF

alias poff='su root -c "/sbin/shutdown -p now"'
EOF
apue$ . ~/.shrc
apue$ poff
*** FINAL System shutdown message from jschauma@apue ***                     
System going down IMMEDIATELY                                                  

System shutdown time has arrived

About to run shutdown hooks...
Stopping cron.
Stopping inetd.
Saved entropy to /var/db/entropy-file.
Forcibly unmounting tmpfs filesystems
Removing block-type swap devices
Tue Sep  3 15:57:06 UTC 2019

Done running shutdown hooks.
Connection to 127.0.0.1 closed by remote host.
Connection to 127.0.0.1 closed.
$ 

And now to start the VM again, we create an alias in our parent OS, here assuming your login shell is bash(1):

$ cat >> ~/.bashrc <<EOF

alias start-apue='VBoxManage startvm "apue" --type headless'
EOF
$ . ~/.bashrc
$ start-apue
Waiting for VM "apue" to power on...
VM "apue" has been successfully started.
$ 

Now you can even take this one step further and combine the starting of the VM, waiting for it to come online, and ssh'ing to it into yet another alias (e.g., 'start-apue && sleep 60 && ssh apue'), but this, and any further customizations of the VM are up to you.


[Course Website]