.. FreeBSD setup for Thinkpad X230

Important note: set BIOS to boot legacy instead of UEFI if boot-environments required to work with full-disk-encryption (explanation).

Create first boot-environment

pkg install beadm
beadm create fresh-install

Enable shell history

.logout

# sync multiple terminal window history
history -S

.cshrc

set history = 2000
set savehist = (2000 merge)

Change to LATEST repo

mkdir -p /usr/local/etc/pkg/repos/
cat >> /usr/local/etc/pkg/repos/FreeBSD.conf <<HERE
FreeBSD: {
  url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest"
}
HERE
pkg upgrade

Apply security patches to base system

freebsd-update fetch
freebsd-update install

Setup synth to mix packages and ports safely

pkg install synth
synth configure
# Press 'N', 'T', 'RET' to enable package fetching
synth status # dry-run
synth upgrade-system
# Check on progress by visiting `/var/log/synth/Report/index.html`

Compile drm-next-kmod for improved Intel graphics

# Get kernel source
cd /tmp
fetch ftp://ftp.freebsd.org/pub/`uname -s`/releases/`uname -m`/`uname -r`/src.txz
[ ! -d /usr/src ] && mkdir /usr/src
tar -C / -xvzf src.txz

# Get ports tree
portsnap fetch
portsnap extract

# Compile drm-next-kmod
cd /usr/ports/graphics/drm-next-kmod
make build && make install

/etc/rc.conf

# load the drm-next-kmod video driver
kld_list="/boot/modules/i915kms.ko"

# Add hald and dbus because Xorg needs them
hald_enable="YES"
dbus_enable="YES"

Install and test xorg:

# load the drm-next-kmod video driver
kld_list="/boot/modules/i915kms.ko"

# Add hald and dbus because Xorg needs them
hald_enable="YES"
dbus_enable="YES"

# manually load the service configured in step 5
service hald start
service dbus start

# manually unload the generic video driver modules
kldunload i915kms.ko
kldunload drm.ko
# manually load the drm-next-kmod module
kldload /boot/modules/i915kms.ko

# try to start Xorg
startx

Add user to video group:

pw groupmod video -M login_name

Default to sound with headphones only

/etc/sysctl.conf

hw.snd.default_unit=1

And run sysctl hw.snd.default_unit=1 to activate without reboot.

Make laptop speakers much louder

/etc/sysctl.conf

hw.snd.vpc_0db=1

And run sysctl hw.snd.vpc_0db=1 to activate without reboot.

Fix applications reporting libgl errors in the console

/etc/devfs.rules

[localrules=10]
add path 'dri/*' mode 0666 group operator

/etc/rc.conf

devfs_system_ruleset="localrules"

Run:

system devfs restart

Make user member of group operator:

pw groupmod operator -m joe
# logout and back in

Correct locale

/etc/login.conf

# append to existing umask
:umask=022:\
:charset=UTF-8:\
:lang=en_GB.UTF-8:

And execute cap_mkdb /etc/login.conf.

Shutdown on low battery

pkg install battmond

/etc/rc.conf

battmond_enable="YES"
battmond_flags="-W 10 -H 7"

Enable battmond:

service battmond start

Stop scattered core files

/etc/sysctl.conf

kern.corefile=/tmp/%N.core

And run sysctl kern.corefile=/tmp/%N.core to activate without reboot.

Fix resume from suspend

/boot/loader.conf

kern.vty=vt # already set by default
acpi_ibm_load="YES"
acpi_video_load="YES"

/etc/sysctl.conf

hw.usb.no_suspend_wait=1
hw.pci.do_power_suspend=0
hw.pci.do_power_resume=1
hw.pci.do_power_nodriver=3

Fix without reboot (if already running vt console (default)):

kldload acpi_ibm
kldload acpi_video
sysctl hw.usb.no_suspend_wait=1
sysctl hw.pci.do_power_suspend=0
sysctl hw.pci.do_power_resume=1 # already set by default
sysctl hw.pci.do_power_nodriver=3

Load correct wifi firmware

/boot/loader.conf

iwn6000g2afw_load="YES"

Laptop performance tweaks and powersaving

Adapted from various sources1.

Install some packages:

pkg install cups powerd++ sddm webcamd

/etc/rc.conf

ifconfig_wlan0="WPA DHCP powersave"

hald_enable="YES"
dbus_enable="YES"

sddm_enable="YES"

powerdxx_enable="YES"
powerdxx_flags="-a hiadaptive -b adaptive -i 75 -r 85 -p 500"
performance_cx_lower="Cmax"
economy_cx_lowest="Cmax"
 
# sync clock on boot
ntpd_flags="-g"

# enable printing
cupsd_enable="YES"

# enable use of the webcam (haven't tested yet)
webcamd_enable="YES"

/boot/loader.conf

hw.pci.do_power_nodriver="3"
hint.p4tcc.0.disabled="1"
hint.acpi_throttle.0.disabled="1"
hint.ahcich.0.pm_level="5"
hint.ahcich.1.pm_level="5"
hint.ahcich.2.pm_level="5"
hint.ahcich.3.pm_level="5"
hint.ahcich.4.pm_level="5"
hint.ahcich.5.pm_level="5"

# Devil worship in loader logo
loader_logo="beastie"

# Keep logo
boot_mute="YES"

# Boot-time kernel tuning
kern.ipc.shmseg=1024
kern.ipc.shmmni=1024
kern.maxproc=100000

# Filesystems in Userspace
fuse_load="YES"

# In-memory filesystems
tmpfs_load="YES"

# Asynchronous I/O
aio_load="YES"

# Handle Unicode on removable media
libiconv_load="YES"
libmchain_load="YES"
cd9660_iconv_load="YES"
msdosfs_iconv_load="YES"

# Intel i915 tunables (many of those are often default in Linux distros)
#enable power savings
drm.i915.powersave=1
#enable render C-state 6.
drm.i915.enable_rc6="7"
#enable Intel IOMMU,
drm.i915.intel_iommu_enabled="1"
#enable LVDS downlock,
drm.i915.lvds_downclock=1
#use semaphores for inter-ring sync
drm.i915.semaphores="1"
#enable framebuffer compression
drmi915_enable_fbc=1

#higher sound card buffering latency
hw.snd.latency=7

#enable LCD screen brightness control (see below)
acpi_video_load="YES"

#enable Thinkpad ACPI driver (see below); will likely allow suspending/resuming easily, see           # acpi_ibm(4) man page
acpi_ibm_load="YES"

#limit ZFS ARC (4G instead of default  half=8Gb out of 16)
vfs.zfs.arc_max="4G"

#enable CPU freq monitoring
cpufreq_load="YES"
#enable temperature monitoring
coretemp_load="YES"

/etc/sysctl.conf

hw.acpi.video.lcd0.brightness=85
hw.acpi.video.lcd0.economy=60
hw.acpi.video.lcd0.fullpower=95

dev.acpi_ibm.0.thinklight=0
dev.acpi_ibm.0.bluetooth=0 #disables bluetooth

net.local.stream.recvspace=65536
net.local.stream.sendspace=65536

# Enhance shared memory X11 interface
kern.ipc.shmmax=67108864
kern.ipc.shmall=32768

# Enhance desktop responsiveness under high CPU use (200/224)
kern.sched.preempt_thresh=224

# Bump up maximum number of open files
kern.maxfiles=200000

# increase UFS readahead
vfs.read_max=128

# allow users to mount disks without root permissions
vfs.usermount=1

# disable annoying system beep
hw.syscons.bell=0
kern.vt.enable_bell=0

# needed for chromium to work
kern.ipc.shm_allow_removed=1

Linux compatibility

/etc/fstab

proc	/proc	procfs	rw	0	0
fdesc	/dev/fd	fdescfs	rw,auto,late	0	0

Quick suspend

Run visudo.

%operator ALL=(root) NOPASSWD: /usr/sbin/zzz

~/.cshrc

alias zzz /usr/local/bin/sudo /usr/sbin/zzz

Now zzz command will suspend system without requiring password.

KDE 5 fixes

Missing battery icon, shutdown, reboot buttons, etc

kde5 metapackage does not pull in complete plasma packages.

Fix this with:

pkg install plasma5-plasma upower

Fix Akonadi

mkdir -p ~/.local/share/akonadi/db_data ; akonadictl start

Mount device permissions

/usr/local/etc/PolicyKit/PolicyKit.conf

<config version="0.1"> 
        <define_admin_auth group="operator"/> 
        <match action="org.freedesktop.hal.storage.mount-removable"> 
                <return result="yes"/> 
        </match> 
        <match action="org.freedesktop.hal.storage.mount-fixed"> 
                <return result="yes"/> 
        </match> 
        <match action="org.freedesktop.hal.storage.eject"> 
                <return result="yes"/> 
        </match> 
</config>

Get sound and video working in KDE apps

pkg install phonon-vlc-qt5

Fix permissions with devfs

/etc/devfs.rules

[localrules=10]
add path 'dri/*' mode 0666 group operator

/etc/rc.conf

devfs_system_ruleset="localrules"

Run:

system devfs restart

Make user member of group operator:

pw groupmod operator -m joe
# logout and back in

Change KDE login theme

/usr/local/etc/sddm.conf

[Theme]
# Current theme name
Current=sddm-freebsd-black-theme

OpenVPN setup

Setup on second routing table.

pkg install openvpn

##Type the following verbatim commands and press enter after each:
cat >> /etc/rc.conf <<HERE
static_routes="vpn"
route_vpn="default -iface wlan0 -fib 1"
openvpn_enable="YES"
openvpn_configfile="/usr/local/etc/openvpn/openvpn.conf"
HERE

cd /tmp
mkdir openvpn ; cd openvpn
fetch https://www.privateinternetaccess.com/openvpn/openvpn-strong.zip
unzip openvpn-strong.zip

printf "UUUUUUUU\nPPPPPPPPPP\n" > pass.txt
mkdir /usr/local/etc/openvpn
cp ca.rsa.4096.crt crl.rsa.4096.pem pass.txt /usr/local/etc/openvpn/
cp UK\ London.ovpn /usr/local/etc/openvpn/openvpn.conf

# Manually change `auth-user-pass` to `auth-user-pass pass.txt` in `/usr/local/etc/openvpn/openvpn.conf` and paste the following:

cat >> /usr/local/etc/openvpn/openvpn.conf <<HERE
auth-nocache
user _openvpn
group _openvpn
script-security 2
up "/usr/local/etc/openvpn/link-up.sh tun0"
route-noexec
chroot chroot
HERE

mkdir /usr/local/etc/openvpn/chroot
ln -s /usr/local/etc/openvpn/* /usr/local/etc/openvpn/chroot
mkdir /usr/local/etc/openvpn/chroot/bin
cp /bin/sh /usr/local/etc/openvpn/chroot/bin
mkdir /usr/local/etc/openvpn/chroot/tmp

cat >> /usr/local/etc/openvpn/link-up.sh  <<HERE
#!/bin/sh
IP=`/sbin/ifconfig $1 | grep "inet " | cut -d" " -f4`
echo "LINK-UP - SETTING AS DEFAULT GATEWAY FOR ROUTING TABLE 1: $IP"
/usr/sbin/setfib -1 /sbin/route delete default
/usr/sbin/setfib -1 /sbin/route add default $IP
HERE

chmod +x /usr/local/etc/openvpn/link-up.sh
pw groupadd -n _openvpn -g 1197
pw useradd -n _openvpn -c "OpenVPN daemon,,," -d "/var/empty" -u 1197 -g _openvpn -s /usr/sbin/nologin
chown -R _openvpn:_openvpn /usr/local/etc/openvpn
echo 'net.fibs=2' >> /boot/loader.conf

Prevent DNS leaks with DNSCRYPT

Create a jail for DNSCRYPT

zfs create zroot/jails
zfs create zroot/jails/_base
bsdinstall jail /zroot/jails/_base
# you may wish to chroot into the jail first and e.g., change locale before making a snapshot
zfs snapshot zroot/jails/_base@11.2-bootstrapped

/etc/rc.conf

jail_enable="YES"

cloned_interfaces="lo1"
ifconfig_lo1="inet 10.0.0.254 netmask 255.255.255.0"

pf_enable="YES"
pflog_enable="YES"

/etc/jail.conf (example)

# Common configs for all jails
allow.nomount;
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
exec.clean;
interface = "lo1";
host.hostname = "$name.driftshell.com";
ip4.addr = 10.0.0.$ip;
mount.devfs;
path = "/zroot/jails/$name";

# The dns jail

dns {
    $ip = 2;
}

Enter the jail e.g.,:

jexec 1 /bin/tcsh

Allow jail to resolve itself by adding to /etc/hosts (in jail):

10.0.0.2                dns.driftshell.com dns

Configure jail for dnscrypt-proxy2 and local_unbound

Setup a dns jail as per above.

Outside jail:

pkg -j dns install dnscrypt-proxy2

Inside jail:

fetch ftp://ftp.internic.net/domain/named.cache -o /var/unbound/root.hints
unbound-anchor -a "/var/unbound/root.key"

/etc/unbound/unbound.conf

server:
  logfile: "/var/log/unbound.log"
  verbosity: 1
  chroot: ""
  pidfile: "/var/run/unbound.pid"

  port: 53    # port to answer queries from
  do-ip4: yes    # Enable IPv4, "yes" or "no".
  do-ip6: no    # Enable IPv6, "yes" or "no".
  do-udp: yes    # Enable UDP, "yes" or "no".
  do-tcp: yes

  hide-identity: yes
  hide-version: yes
  rrset-roundrobin: yes
  minimal-responses: no
  use-caps-for-id: yes
  cache-min-ttl: 60
  prefetch: yes
  prefetch-key: yes
  num-threads: 1  # 1 is enough for not heavy loaded server

  # client ips that are allowed to query to this server.
  access-control: 192.168.1.0/24 allow
  access-control: 10.0.0.0/24 allow
  access-control: 127.0.0.0/24 allow

  # Enforce privacy of these addresses.
  private-address: 192.168.1.0/24
  private-address: 10.0.0.0/24

  root-hints: "/var/unbound/root.hints"

  # You need these to turn on DNSSEC validation
  auto-trust-anchor-file: "/var/unbound/root.key"
  module-config: "validator iterator"

  # You need this as no for dnscrypt-proxy to work
  do-not-query-localhost: no

  forward-zone:
  name: "."
     forward-addr: 10.0.0.2@5353  # dnscrypt-proxy

Change parameters of /usr/local/etc/dnscrypt-proxy/dnscrypt-proxy.toml to:

server_names = ['cloudflare']
require_dnssec = true

/etc/rc.conf

local_unbound_enable="YES"
## (if from ports, use) unbound_enable="YES"
dnscrypt_proxy_enable="YES"

And run:

service dnscrypt-proxy start
service local_unbound start

On the host:

/etc/resolv.conf

nameserver 10.0.0.2

Test with:

drill -D 00f.net
drill -D 00f.net

Response time should be 0ms on second run.

And test if dnssec detected here.

Stop DHCP changing DNS on reboot:

/etc/resolvconf.conf

# disable resolvconf from running any subscribers
resolvconf="NO"

Yubikey setup

/etc/devd.conf

# Yubikey fix
attach 100 {
        match "vendor" "0x1050";
        match "product" "0x0116";
        action "/usr/bin/pkill -9 scdaemon";
};

detach 100 {
        match "vendor" "0x1050";
        match "product" "0x0116";
        action "/usr/bin/pkill -9 scdaemon";
};

~/.gnupg/gpg-agent.conf

enable-ssh-support
pinentry-program /usr/local/bin/pinentry-qt5
default-cache-ttl 60
max-cache-ttl 120

Install pinentry program:

pkg install pinentry-qt5

/etc/rc.conf

devfs_system_ruleset="localrules"

/etc/devfs.rules

add path 'usb/*' mode 0660 group usb

Make sure user is in usb group:

pw groupadd usb
pw group mod usb -m joe

~/.cshrc

setenv  GPG_TTY `tty`

# start the agent
gpg-connect-agent /bye
setenv  SSH_AUTH_SOCK $HOME/.gnupg/S.gpg-agent.ssh

# gpg-agent tty in case user switches into an X session
gpg-connect-agent updatestartuptty /bye >/dev/null

Now make sure any imported public keys are 'Ultimately' trusted.

Load emacs quicker

Make an editor executable to run an emacsclient that connects to a running emacs –daemon.

/usr/local/bin/editor

#!/bin/sh
if [ -z "$DISPLAY" ]; then
    IS_GRAPHICAL=0
else
    ## Check if an X toolkit is installed. To do so, we check if 'tool-bar-mode is available.
    IS_GRAPHICAL=$(emacs -batch -Q --eval='(if (fboundp '"'"'tool-bar-mode) (message "1") (message "0"))' 2>&1)
fi

if [ $IS_GRAPHICAL -eq 1 ]; then
    /usr/local/bin/emacsclient -a "" -nc "$@" &
else
    /usr/local/bin/emacsclient -a "" -t "$@" &
fi
chmod +x /usr/local/bin/editor

~/.xprofile

emacs --daemon &

~/.cshrc

alias e /usr/local/bin/editor

Logout and back in to test.

Make KDE use above script in place of emacs

Input:

/usr/local/bin/editor %F

Wifi tray

pkg install pcbsd-utils-qt5

The above causes all PCBSD utils to load on startup. To only load the wifi-tray on startup, save and execute this script somewhere:

#!/bin/sh
mkdir -p ~/.config/autostart
basename `ls /usr/local/etc/xdg/autostart/pcbsd*` | grep -v nettray | while read -r line ; do touch ~/.config/autostart/"$line" ; done

Manually kill the following processes, or KDE 5 session will start them next time:

pkill pc-mounttray lifepreserver life-preserver-tray pc-mixer

If you later decide to re-enable some of the other apps, then remove the corresponding dummy file from the local user autostart e.g.,:

rm ~/.config/autostart/pcbsd-life-preserver.desktop

If anyone finds an uncomplicated alternative to any of the steps above, email me.

Creating an OpenBSD guest with bhyve

Adapted from various sources2.

Create a zvol to install to

As root:

zfs create zroot/vm
zfs create -V9G -o volmode=dev zroot/vm/openbsd.img

Prepare environment

As root:

kldload vmm nmdm
ifconfig tap0 create
sysctl net.link.tap.up_on_open=1
sysctl net.inet.ip.forwarding=1
ifconfig bridge0 create
ifconfig bridge0 addm wlan0 172.16.0.1/24 up addm tap0
ifconfig bridge0 up
pkg install uefi-edk2-bhyve

As root:

/etc/sysctl.conf:

net.link.tap.up_on_open=1

/etc/rc.conf:

# make sure you merge any other cloned_interfaces line (only one allowed)
cloned_interfaces="bridge0 tap0 lo1"
ifconfig_bridge0="addm wlan0 172.16.0.1/24 up addm tap0"
ifconfig_lo1="inet 10.0.0.254 netmask 255.255.255.0"
kld_list="nmdm vmm"

gateway_enable="yes"
pf_enable="YES"
pflog_enable="YES"

/etc/pf.conf:

ext_if="wlan0"
int_if="lo1"
vm_if="tap0"
localnet=$int_if:network

scrub in all fragment reassemble
set skip on lo0
set skip on lo1

#nat for jails
nat on $ext_if inet from $localnet to any -> ($ext_if)
#nat for bhyve
nat on $ext_if inet from {172.16.0.0/24} to any -> ($ext_if)

Restart services as needed:

service netif restart
service pf restart
service jails restart

As user:

mkdir -p $HOME/VM/iso
fetch -o $HOME/VM/iso https://ftp.openbsd.org/pub/OpenBSD/6.3/amd64/install63.fs

$HOME/VM/boot_openbsd.sh:

#!/bin/sh

bhyve -c 2 -m 4G -w -u -H \
        -s 0,amd_hostbridge \
        -s 3,ahci-hd,$HOME/VM/iso/install63.fs \
        -s 4,virtio-blk,/dev/zvol/zroot/vm/openbsd.img \
        -s 5,virtio-net,tap0 \
        -s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,vga=off,wait \
        -s 30,xhci,tablet \
        -s 31,lpc -l com1,stdio \
        -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
        openbsd-uefi

Still as user:

chmod +x $HOME/VM/boot_openbsd.sh
sudo -E $HOME/VM/boot_openbsd.sh

In another terminal:

krdc vnc://:5900 &

Install OpenBSD into the bhyve zvol

Select High quality graphics when using kdrc. If you connect to early, the vnc screen may freeze. Simply quit krdc and rerun krdc vnc://:5900 &.

  1. press Enter until it asks for the installation device
  2. press ?
  3. look for the virtio device in the list e.g., sd1, and remember it
  4. type disk for 'Location of sets'
  5. type no for 'Is the disk partition already mounted?'
  6. if you chose sd1 for step 3, then choose sd0 for the sets location, and vice versa
  7. select the bsd type partition in the partition table for the set device

If a mistake is made at any time, then start fresh, as root:

bhyvectl --force-poweroff --vm=openbsd-uefi
# wait for output from the terminal still running boot_openbsd.sh
# now run:
bhyvectl --destroy --vm=openbsd-uefi
zfs destroy zroot/vm/openbsd.img
zfs create -V9G -o volmode=dev zroot/vm/openbsd.img
# and rerun as user:
sudo -E $HOME/VM/boot_openbsd.sh
# in another terminal as user
krdc vnc://:5900 &

After successful install, type H to halt the system. The VNC session will close.

As root, ensure the VM is destroyed:

/usr/sbin/bhyvectl --force-poweroff --vm=openbsd-uefi
/usr/sbin/bhyvectl --destroy --vm=openbsd-uefi

Boot into the bhyve OpenBSD VM

As user, we must make the zvol priority.

$HOME/VM/boot_openbsd.sh (modify):

#!/bin/sh

bhyve -c 2 -m 4G -w -u -H \
        -s 0,amd_hostbridge \
        -s 3,virtio-blk,/dev/zvol/zroot/vm/openbsd.img \
        -s 5,virtio-net,tap0 \
        -s 29,fbuf,tcp=0.0.0.0:5900,w=800,h=600,vga=off,wait \
        -s 30,xhci,tablet \
        -s 31,lpc -l com1,stdio \
        -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
        openbsd-uefi

Still as user:

sudo -E $HOME/VM/boot_openbsd.sh
krdc vnc://:5900 &

OpenBSD will boot in the vnc window.

Network settings inside the OpenBSD VM

/etc/hostname.vio0:

inet 172.16.0.2 255.255.255.0

/etc/mygate:

172.16.0.1

/etc/resolv.conf (example):

nameserver 1.1.1.1

Run:

sh /etc/netstart vio0
ping bbc.co.uk

Hopefully pinging works.

Sources:

  1. Cullum Smith's blog, FreeBSD forum's user 'JAW', and cooltrainer.org
  2. FreeBSD handbook, vm-bhyve wiki

Author: Joe White

Email: joe@driftshell.com

Enlive 1.1.6