Category Archives: Computer

All Computer Stuff

Bulk import DHCPD data into pfSense

Similar to my previous post, if you are trying to bulk import your current DHCPD data into pfSense, the built-in pfSense shell comes in handy.

Here we’ll start to use the current ISC-DHCPD configuration file, /etc/dhcp/dhcpd.conf, which will have entries like this:

host pi31 { hardware ethernet AA:BB:CC:DD:EE:FF; fixed-address pi31; }
host pi32 { hardware ethernet DD:EE:FF:AA:BB:CC; fixed-address pi32; }
host MobilePhone { hardware ethernet CC:DD:AA:BB:EE:FF; fixed-address mobilephone; }

Then run the following script – modify it to your needs – which will print out the commands for the pfSense shell. Since my DHCPD configuration is relying upon existing DNS entries and I am having hostnames as “fixed-address” entries, I need to resolve these entries with a dig command. If your file is always using IP addresses, just parse them out:

echo "global \$config;"
echo "parse_config(true);"

index=0
grep '^host' /etc/dhcp/dhcpd.conf | while read line
do
  hostname=$(echo $line | cut -d ' ' -f 2)
  mac=$(echo $line | cut -d '{' -f 2 | cut -d ' ' -f 4 | cut -d';' -f 1)
  ip=$(dig +short $hostname.mydomain.com)

if test -n "$ip"
then
  echo "\$config['dhcpd']['lan']['staticmap']['$index']['mac']=\"$mac\";"
  echo "\$config['dhcpd']['lan']['staticmap']['$index']['cid']=\"$hostname\";"
  echo "\$config['dhcpd']['lan']['staticmap']['$index']['ipaddr']=\"$ip\";"
  echo "\$config['dhcpd']['lan']['staticmap']['$index']['hostname']=\"$hostname\";"
  echo "\$config['dhcpd']['lan']['staticmap']['$index']['descr']=\"Automatically migrated\";"
else
  # echo "NO IP KNOWN FOR $hostname"
  echo -n ""
fi

let index=$index+1
done
echo "write_config();"
echo "exec"

This will generate the following output, ready to paste into the pfSense shell:

global $config;
parse_config(true);
$config['dhcpd']['lan']['staticmap']['0']['mac']="AA:BB:CC:DD:EE:FF";
$config['dhcpd']['lan']['staticmap']['0']['cid']="pi31";
$config['dhcpd']['lan']['staticmap']['0']['ipaddr']="192.168.1.1";
$config['dhcpd']['lan']['staticmap']['0']['hostname']="pi31";
$config['dhcpd']['lan']['staticmap']['0']['descr']="Automatically migrated";
$config['dhcpd']['lan']['staticmap']['1']['mac']="DD:EE:FF:AA:BB:CC";
$config['dhcpd']['lan']['staticmap']['1']['cid']="pi32";
$config['dhcpd']['lan']['staticmap']['1']['ipaddr']="192.168.1.2";
$config['dhcpd']['lan']['staticmap']['1']['hostname']="pi32";
$config['dhcpd']['lan']['staticmap']['1']['descr']="Automatically migrated";
$config['dhcpd']['lan']['staticmap']['2']['mac']="CC:DD:AA:BB:EE:FF";
$config['dhcpd']['lan']['staticmap']['2']['cid']="MobilePhone";
$config['dhcpd']['lan']['staticmap']['2']['ipaddr']="192.168.1.3";
$config['dhcpd']['lan']['staticmap']['2']['hostname']="MobilePhone";
$config['dhcpd']['lan']['staticmap']['2']['descr']="Automatically migrated";
write_config();
exec

Please keep in mind the index starts at 0, valid for an empty list of host names in your pfSense DHCPD configuration. For each already existing entry you have to add 1 to the starting index of 0.

Bulk import DNS data into pfSense

If you are trying to bulk import your current DNS data into pfSense, the built-in pfSense shell comes in handy.

First, get your current data into a file with 2 columns like this:

name.domain.com.  192.168.1.1
name2.domain2.com. 192.168.2.1
name3.domain2.de. 192.168.2.2

Then run the following script – modify it to your needs – which will print out the commands for the pfSense shell:

echo "global \$config;"
echo "parse_config(true);"

index=0
cat alldns.txt | while read name ip
do
  hostname=$(echo $name | cut -d '.' -f 1)
  domain=$(echo $name | cut -d '.' -f 2- | sed -e 's/\.$//')

  echo "\$config['unbound']['hosts']['$index']['host']=\"$hostname\";"
  echo "\$config['unbound']['hosts']['$index']['domain']=\"$domain\";"
  echo "\$config['unbound']['hosts']['$index']['ip']=\"$ip\";"
  echo "\$config['unbound']['hosts']['$index']['descr']=\"Automatically migrated\";"

  let index=$index+1
done
echo "write_config();"
echo "exec"

This will generate the following output, ready to paste into the pfSense shell:

global $config;
parse_config(true);
$config['unbound']['hosts']['0']['host']="name";
$config['unbound']['hosts']['0']['domain']="domain.com";
$config['unbound']['hosts']['0']['ip']="192.168.1.1";
$config['unbound']['hosts']['0']['descr']="Automatically migrated";
$config['unbound']['hosts']['1']['host']="name2";
$config['unbound']['hosts']['1']['domain']="domain2.com";
$config['unbound']['hosts']['1']['ip']="192.168.2.1";
$config['unbound']['hosts']['1']['descr']="Automatically migrated";
$config['unbound']['hosts']['2']['host']="name3";
$config['unbound']['hosts']['2']['domain']="domain2.de";
$config['unbound']['hosts']['2']['ip']="192.168.2.2";
$config['unbound']['hosts']['2']['descr']="Automatically migrated";
write_config();
exec

Please keep in mind the index starts at 0, valid for an empty list of host names in your pfSense Unbound/DNS configuration. For each already existing entry you have to add 1 to the starting index of 0.

OpenVPN complains about wrong user/password without you requesting one?

If your OpenVPN client is complaining about a wrong user/password combination (AUTH_FAILED), although you are not requesting it on your server, it might be a completely different reason.

After migrating to a new operating system but taking OpenVPN’s configuration with me, I was running into this problem. All clients were complaining about wrong username and password.

The reason is simple:

openvpn_client-connect.sh: line 3: mail: command not found
Wed May 25 23:16:22 2016 CertName/192.168.1.12:54211 WARNING: Failed running command (--client-connect): could not execute external program
Wed May 25 23:16:25 2016 CertName/192.168.1.12:54211 PUSH: Received control message: 'PUSH_REQUEST'
Wed May 25 23:16:25 2016 CertName/192.168.1.12:54211 Delayed exit in 5 seconds
Wed May 25 23:16:25 2016 CertName/192.168.1.12:54211 SENT CONTROL [CertName]: 'AUTH_FAILED' (status=1)

I configured OpenVPN to send an email on connect and disconnect of a client. The script wants to use the mail command – which is not installed as default by Xenial. This leads to a client-connect-script error which in turn leads OpenVPN to respond with an AUTH_FAILED. Which in turn gives the “Wrong username/password” error message on the clients.

Solution: Make the client-connect script working again 😀

Installing a Vagrant BaseBox of CentOS

  • Install a minimal system of CentOS in VirtualBox
  • Activate networking on boot by enabling eth0 in
    .
    .
    .
    ONBOOT=yes
    .
    .
    .
    
  • Add a vagrant user and assign the password vagrant to it
  • Give sudo rights to that user by adding vagrant ALL=(ALL) NOPASSWD: ALL with visudo
  • Disable requirement of having a TTY by commenting out the following settings with visudo:
    #Defaults    requiretty
    #Defaults   !visiblepw
  • Add insecure Vagrant public key from https://github.com/mitchellh/vagrant/blob/master/keys/vagrant.pub to vagrant’s authorized_keys
  • Add development tools for building the guest addons with
    yum --disablerepo=\* --enablerepo=c6-media install kernel-devel gcc make dkms perl

    The repo options are useful if you want to install from local installation media (ISOs) instead of fetching all from the net.

  • Install guest addons with
    ./VBoxLinuxAdditions.run --nox11
  • halt the machine
  • Remove all hardware that is not necessary from the base machine or else it will be available on the machines set up with Vagrant later!
  • Package Box with
    vagrant package --base Name-Of-Machine-In-VirtualBox

Done!

Should Vagrant be unable to connect to your boxes derived from that base box, you might have a problem with SELinux, see here how this can be fixed!

SSH doesn’t allow logins with keys? SELinux!

If you have correctly setup your authorized_keys and are sure it should allow you logins with keys – then maybe SELinux is giving you a hard time. Especially if your user is not under the normal home directory folder /home. In your /var/log/{auth,secure} files you will see that sshd is not allowed to open authorized_keys and/or authorized_keys2 after you set the “LogLevel DEBUG” in /etc/ssh/sshd_config.

In that case, try to set the correct settings again:

chcon -t ssh_home_t ~PROBLEMATIC_USER/.ssh/
chcon -t ssh_home_t ~PROBLEMATIC_USER/.ssh/authorized_keys

Now everything will work again.

Charge HP Stream 7 while using it with an OTG cable

After a quite frustrating experience with an HP Stream 7 tablet, which refused to get charged while having a USB stick connected to it via an OTG cable, I found an extremly easy solution:

Just disable the Microsoft AC Power Supply which can be found in the device manager under Batteries.

Voila – that’s it.

I have the German version only where it says Microsoft Ladegerät and can be found under Akkus.

Installing Debian Jessie on an APU1D4

To install Debian Jessie on an APU1D4, it is easiest to go for a network installation. You need
– a TFTP server
– a DHCP server
– the Debian file structure in the TFTP server’s root directory

For DHCP you will need something like the following configuration:

ddns-update-style none;
max-lease-time 186400;
authoritative;

subnet 192.168.66.0 netmask 255.255.255.0 {
  range 192.168.66.100 192.168.66.150;
  option domain-name-servers 192.168.66.1;
  option domain-name "example.com";
  option domain-search "example.com";
  option routers 192.168.66.1;
  option broadcast-address 192.168.66.255;
  default-lease-time 86400;
  max-lease-time 186400;
}

host apuc{
	hardware ethernet 00:0d:b9:12:34:bc;
	fixed-address 192.168.66.66;
        filename "pxelinux.0";
        next-server 192.168.66.1;
}
host apud{
	hardware ethernet 00:0d:b9:12:34:bd;
	fixed-address 192.168.66.66;
        filename "pxelinux.0";
        next-server 192.168.66.1;
}
host apue{
	hardware ethernet 00:0d:b9:12:34:be;
	fixed-address 192.168.66.66;
        filename "pxelinux.0";
        next-server 192.168.66.1;
}

For the TFTP server you need something like the following configuration:

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure"

Then simply extract the debian installer files into /src/tftp . I have included my working configuration into netboot_serial_20150107.tar. Should you want to change its configuration, simply edit the file pxelinux.cfg/default file. Mine looks as follows and is preconfigured for serial console output:

default install
label install
	menu label ^Install
	menu default
	kernel debian-installer/amd64/linux
	append initrd=debian-installer/amd64/initrd.gz --- vga=normal console=tty0 console=ttyS0,115200n8

Attach a serial console cable and fire it up!

Frontend for openssl to check key chains

Since checking SSL key chains with openssl is sometimes a bit tricky, I have written a little perl script as wrapper around it.

Just download check_chain.zip, unzip it and run it as follows:

./check_chain.pl -p server port

-p (optional) prints out the certificates as well
server is the server to check
port (optional) is the port to connect to.

Here is the code:

#!/usr/bin/perl -w

use strict;

my $has_date_parse = 1;
eval {
	require Date::Parse;
	Date::Parse->import( qw/str2time/ )
};

if ( $@ ne "" ) {
	print "Module Date::Parse not found! Skipping expiration date calculation!\n";
	$has_date_parse = 0;
}

my $print_cert = 0;
my $host = shift || &usage();
if ( $host eq '-p' ) {
	$print_cert = 1;
	$host = shift;
}
my $port = (shift || 443);


my $output = `echo "\t" | openssl s_client -host $host -port $port -showcerts 2> /dev/null`;

my $cert_num = 0;

my $line;
my @certs;
my %certs;

foreach $line ( split /\n/, $output ) {
	if ( $line =~ /BEGIN CERTIFICATE/ .. $line =~ /END CERTIFICATE/ ) {
		$certs[$cert_num] .=  "$line\n";
	}
	$cert_num += 1 if $line =~ /END CERTIFICATE/;
}

my $i;
my $serial;
my $attribute;
foreach $i ( 0 .. scalar @certs -1 ) {
	$serial = qx{echo "$certs[$i]" | openssl x509 -serial -noout};
	$serial =~ s/serial=//;
	chomp $serial;
	$certs{$serial}{'certificate'} = $certs[$i];

	foreach $attribute ( qw/issuer subject issuer_hash subject_hash enddate/ ) {
		$certs{$serial}{"$attribute"} = qx{echo "$certs[$i]" | openssl x509 -$attribute -noout};
		chomp $certs{$serial}{"$attribute"};
		$certs{$serial}{"$attribute"} =~ s/notAfter=//;
	}

	# Certificate stored, reuse @certs to keep order with serial number
	$certs[$i] = $serial;
	$certs{$serial}{"order"} = $i;
}

print "\nChecked server: $host on port $port\n";

my $found;
foreach $i ( 0 .. scalar @certs -1 ) {
	print "\nCertificate $i:\n";
	$serial = $certs[$i];
	print "\t", $certs{$serial}{"subject"}, " (hashed: ", $certs{$serial}{"subject_hash"}, ")\n";
	print "\tserial number (check in browser): $serial\n";
	print "\texpires: ", $certs{$serial}{"enddate"};
	if ( $has_date_parse == 1 ) {
		print " (in ", int ((str2time($certs{$serial}{"enddate"}) - time) /60/60/24  ), " days)" ;

	}
	print "\n";
	print "\t", $certs{$serial}{"issuer"}, " (hashed: ", $certs{$serial}{"issuer_hash"}, ")\n";
	print "\tissuer found in chain: ";
	$found = "NO - should be root certificate";
	if ( $certs{$serial}{"issuer_hash"} eq $certs{$serial}{"subject_hash"} ) {
		$found = "SELF SIGNED CERTIFICATE";
	} else {
		foreach ( keys %certs ) {
			if ( $certs{$serial}{"issuer_hash"} eq $certs{$_}{"subject_hash"} ) {
				$found = "YES";
			}
		}
	}
	print "$found\n";
}

if ( $print_cert == 1 ) {
	foreach $i ( 0 .. scalar @certs -1 ) {
		print "\nCertificate $i:\n";
		$serial = $certs[$i];
		print $certs{$serial}{"certificate"}
	}
}

sub usage {
	print "Usage: $0 [-p] server_name [port]\n";
	print "\t-p : also print certificates\n";
	print "\tserver_name : server to check, mandatory\n";
	print "\tport : port to check, default: 443\n";
	exit;
}

Its output is as follows:

$ ./check_chain.pl www.lavalite.de

Checked server: www.lavalite.de on port 443

Certificate 0:
	subject= /C=DE/OU=Domain Control Validated/CN=www.lavalite.de (hashed: dad54aee)
	serial number (check in browser): 11213FB18C3CEF8B39A731AB874D155363F2
	expires: Dec  8 11:13:28 2015 GMT (in 318 days)
	issuer= /C=BE/O=GlobalSign nv-sa/CN=GlobalSign Domain Validation CA - SHA256 - G2 (hashed: 79701ca5)
	issuer found in chain: YES

Certificate 1:
	subject= /C=BE/O=GlobalSign nv-sa/CN=GlobalSign Domain Validation CA - SHA256 - G2 (hashed: 79701ca5)
	serial number (check in browser): 040000000001444EF03E20
	expires: Feb 20 10:00:00 2024 GMT (in 3314 days)
	issuer= /C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA (hashed: b0f3e76e)
	issuer found in chain: NO - should be root certificate