Systemd and Centos

Centos systemd-networkd … The tale of the missing packets.

The symptoms are strange to say the least. It appears that the traffic leaving the virtual interface are correctly being processed by the POSTROUTING chains and yet even with replies from the outside world the traffic does not return to the virtual interface. Almost as if it were being dropped on the external interface. Checking the usual ip_forward file will show that it is indeed forwarding and the fact that the traffic leaves the virtual interface and goes out to the world shows that works. Each interface also has its own forwarding file called .. ‘forwarding’ and they reside in the /proc/sys/net/ipv4/conf directory separated by their own directories per interface. 

Enter systemd-networkd. The apparent issue is that systemd-networkd sets the forwarding for the specific interfaces it controls to 0 by default and fights to keep it that way. That’s the simple version. Change it to a 1 and a few minutes later your back to 0. Constant appearances of ‘systemd-networkd: eno1: link configured’ in the logs following a sysctl -w net.ipv4.ip_forward=0 and then sysctl -w net.ipv4.ip_forward=1 give the problem away.

Libvirtd will by default set any interface created from the virbr0-nic, virbr0 to vnet0 etc. to forwarding=1 but systemd-networkd will keep resetting this for interfaces it ‘manages’. This stuffs up the ability of the lan / wan interface to forward traffic BACK to the virtual interfaces. The solution is actually rather simple… Locate /etc/systemd/network/YOUR_INTERFACE and then find the [Network] section. 

There you need to change the forwarding policy for the interface with the line :

IPForward=ipv4

and perhaps

IPForward=ipv6

Don’t disable or remove systemd-networkd else you will need to get the rescue console fired up … note to self 🙂

I think Hetzner has started to push this in the Centos 7.7 install image because he-8 says
[root@isdhe-8 ~]# systemctl status systemd-networkdUnit systemd-networkd.service could not be found.

Which implies it’s not installed and hence no issues. This is Centos 7.7 but an upgrade.

A new 7.7 container image shows ..

[root@systemd systemd]# ls -l

total 32

-rw-r–r– 1 root root  720 Sep 13 18:19 bootchart.conf

-rw-r–r– 1 root root  615 Sep 13 18:19 coredump.conf

-rw-r–r– 1 root root  983 Sep 13 18:19 journald.conf

-rw-r–r– 1 root root  957 Sep 13 18:19 logind.conf

drwxr-xr-x 9 root root 4096 Oct  1 07:15 system

-rw-r–r– 1 root root 1552 Sep 13 18:19 system.conf

drwxr-xr-x 2 root root 4096 Sep 13 18:19 user

-rw-r–r– 1 root root 1127 Sep 13 18:19 user.conf

And the lack of network directory seems to imply no systemd-networkd

[root@systemd ~]# systemctl status systemd-networkd

Unit systemd-networkd.service could not be found.

The above confirms.

So let’s install it 🙂

Running transaction

  Installing : systemd-networkd-219-67.el7_7.1.x86_64                                                         1/1

  Verifying  : systemd-networkd-219-67.el7_7.1.x86_64                                                         1/1

Installed:

  systemd-networkd.x86_64 0:219-67.el7_7.1                                                                        

Complete!

The article for the tests: https://renediepstraten.nl/?p=56

More info .. https://wiki.archlinux.org/index.php/Systemd-networkd#[Network]

After following the article it seems I have give control of the network to systemd-networkd

[root@systemd ~]# networkctl status eth0

● 14: eth0

   Link File: n/a

Network File: /etc/systemd/network/10-main.network

     Type: ether

    State: routable (configured)

  HW Address: 00:16:3e:af:0a:96 (Xensource, Inc.)

      MTU: 1500

  Address: 10.95.6.114

           fe80::216:3eff:feaf:a96

  Gateway: 10.95.6.1

           10.95.6.1

      DNS: 10.95.6.1

[root@systemd ~]# more /etc/systemd/network/10-main.network  

[Match]

Name=eth0

[Network]

DHCP=yes

And …

[root@systemd ~]# cat /proc/sys/net/ipv4/conf/eth0/forwarding

0

[root@systemd ~]# cat /proc/sys/net/ipv4/ip_forward       

1

So NO forwarding on the eth0 interface despite the global policy

Patched the network file 10-main.network 

[Match]

Name=eth0

[Network]

DHCP=yes

IPForward=ipv4

And 

[root@systemd ~]# systemctl restart systemd-networkd

[root@systemd ~]# cat /proc/sys/net/ipv4/conf/eth0/forwarding

1

[root@systemd ~]# cat /proc/sys/net/ipv4/ip_forward

1

🙂 

All working. The world is changing it seems.

fsck check of partition inside KVM image

So here is a fun one. We have a corrupted Linux disk partition within a
KVM image. We want to run fsck on the root partition inside the KVM image.

To do this we can mount it as a loop device

losetup -vf path_to_your_image

we then

kpartx -av /dev/loop0

/dev/mapper now contains links to the partitions so we can simply run

fsck /dev/mapper/path_to_partition

unmount /dev/loop0 when done 🙂

Get outstanding balancedetails emailed from Digital Ocean

I recently looked at Digital Ocean as a possible replacement VM host as a company project and have now chosen to use them for my own personal VM. Since I am using a prepaid option the need to get some warning when my prepaid amount was due to run out became a requirement. Below is the Ruby code I use to pull the remaining credit and email on a daily basis. Hope you find it useful. I run this daily via a cron entry. The requirements are Ruby 1.9+ (I am sure it will work on lower but only tested on 1.9+) and the mechanize Ruby gem.

#!/usr/bin/ruby

require 'mechanize'
require 'net/smtp'

user = 'your_username_here'
pass = 'your_password_here'

# login
agent = Mechanize.new { |a|
a.follow_meta_refresh = true
}
agent.get("https://cloud.digitalocean.com/login")
form = agent.page.forms[0]
form["user[email]"] = user
form["user[password]"] = pass
form.submit

# get balance
billing_page = agent.get("https://cloud.digitalocean.com/billing")
balance = (billing_page.body.scan(/\$\d*\.\d*/).first.scan(/\d*\.\d*/).first).to_f

# email results
subject = "Digital Ocean billing checker - #{DateTime.now.ctime.to_s}"
subject = "WARNING - " + subject if balance < 1.00
message = <<MESSAGE_END
From: Digital Ocean billing checker <your_email_address_here>
To: your_email_address_here
Subject: #{subject}

The current credit is : $#{balance.to_s}
MESSAGE_END
Net::SMTP.start('localhost') do |smtp|
smtp.send_message message, 'your_email_address_here', 'your_email_address_here'
end

Migrating backuppc configuration to a new system / VM

Recently I needed to re-create a backuppc virtual machine from an existing one. The reason for this was to create a smaller primary partition which would take up less space on the host machine. After some searching, and I must admit rather unsuccessful searching, the solution appears to be far simpler than expected. Basically on Ubuntu 12.04 it appears that there are two main directories that are required. The first is the /etc/backuppc directory which seems to house a series of perl scripts, one for each machine that is being backed up. This directory also houses the htpasswd and apache config files. The second is the /var/lib/backuppc directory which contains the all important .ssh files. This directory contains the know_hosts and ssh keys required to migrate the config to another machine without having to login and update the keys for each machine. Given that all the machines the backuppc is syncing use rsyncd this would have taken a load of time. The host file is also important as is the resolv.conf files. These are used to resolve the names given to your backups within backuppc. So basically setup a new machine or VM and install backuppc from the Ubuntu repositories. In my case I was lucky enough to migrate to another VM which has the same version of OS as the previous setup. Once the /etc/backuppc, /var/lib/backuppc/.ssh, /etc/hosts and /etc/resolv.conf are copied / update you are almost ready to go. Update the permissions on the. /var/lib/backuppc/.ssh and /etc/backups files and restart your apache2 service. From there your setup may be different since in my case SSL was used for the apache2 setup. As a test start the backuppc service and login to your backuppc interface. A good sign is if the username and passwords are the same 🙂 I am sure there are hundreds of other scenarios that are not covered here but this seems to have worked for me.

Very simple ruby gem

I decided to create a simple gem to hold some date requirements that I had. Basically here is what you need to build a simple gem.

Create a working directory. In my case this was called fuzzydates. Change into the directory and create a lib directory so that you now have a directory structure that looks like this:

fuzzydates
fuzzydates/lib

For a very basic gem all we need is a gemspec file and the actual code in a .rb file. Firstly lets create the gemspec file in the base directory that you created (fuzzydates). Mine is called fuzzydates.gemspec

Gem::Specification.new do |s|
s.name = 'fuzzydates'
s.version = '0.0.1'
s.date = '2013-02-10'
s.summary = "a summary of your gem"
s.description = "describe your gem"
s.authors = ["your name"]
s.email = 'your email address'
s.files = ["lib/fuzzydates.rb"]
s.homepage = 'your website'
end

Paste the above text into the file and update the fields as required. The version number is up to you but will have a bearing on the version that gem sees or your rails application requires. The s.files section needs to contain the names of the .rb files you add to the lib directory. The s.name will be the name as your gem. Once update, save the file and then change to the lib directory that you created.

Once there create a file with the same name as you used in the s.files section above. In my case this was fuzzydates.rb

Now create a basic class and have it do something as a test. Mine just returns some dates.

class Fuzzydates
def self.end_of_this_month
return Date.current+1.month-Date.current.day
end
def self.first_of_next_month
Fuzzydates.end_of_this_month+1.day
end
end

Once you have saved this file return to the base directory where the .gemspec file is and run

gem build fuzzydates.gemspec

If all goes well it will build a .gem file and report the following (or similar)

Successfully built RubyGem
Name: fuzzydates
Version: 0.0.1
File: fuzzydates-0.0.1.gem

You can now install the gem using the normal gem install command from inside the directory where the .gem file is located.

There are other ways of using rvm and bundle to create the basic gem template but this works for me.

Make XFCE application menu appear when using Windows key

To make the XFCE application menu pop up when you hit the Windows key add the following application via the keyboard shortcuts and press the Windows key when prompted.

xfce4-popup-applicationsmenu

It doesn’t work exactly the same as windows since hitting the key twice does not make the menu disappear.

UPDATE : On 14.04 this appears to now be called

xfce4-popup-whiskermenu

Seeing what files a debian package contains and what files it will install

I have just needed to install a dev package on my Xubuntu system and wanted to see what and where the package would install the files to. It seems that there is an apt-file command which is not installed by default. So I installed it…

apt-get install apt-file

and then followed by

apt-file update

In my case it wanted to update about 23.6M of information from the web. Once this was done I could run the command

apt-file list libusb-dev

and get a nice long list of what files would be installed and where they would be located.

udev rules for most Android based phones

Some time back I had issues using the Android Debug Bridge (ADB) from my linux laptop and had to hunt the web for the udev rules for my specific device. After my recent laptop reload I had to do this again so thanks to this article http://rootzwiki.com/topic/258-udev-rules-for-any-device-no-more-starting-adb-with-sudo/ found on RootzWiki all is well again. The basic requirements are below.

The udev rules need to be placed in a file in the /etc/udev/rules.d directory. As with the article above I placed these in 99-android.rules
The udev rules to be pasted into the file are as follows:

#Acer
SUBSYSTEM=="usb", SYSFS{idVendor}=="0502", MODE="0666"
#Dell
SUBSYSTEM=="usb", SYSFS{idVendor}=="413c", MODE="0666"
#Foxconn
SUBSYSTEM=="usb", SYSFS{idVendor}=="0489", MODE="0666"
#Garmin-Asus
SUBSYSTEM=="usb", SYSFS{idVendor}=="091E", MODE="0666"
#Google
SUBSYSTEM=="usb", SYSFS{idVendor}=="18d1", MODE="0666"
#HTC
SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"
#Huawei
SUBSYSTEM=="usb", SYSFS{idVendor}=="12d1", MODE="0666"
#Kyocera
SUBSYSTEM=="usb", SYSFS{idVendor}=="0482", MODE="0666"
#LG
SUBSYSTEM=="usb", SYSFS{idVendor}=="1004", MODE="0666"
#Motorola
SUBSYSTEM=="usb", SYSFS{idVendor}=="22b8", MODE="0666"
#Nvidia
SUBSYSTEM=="usb", SYSFS{idVendor}=="0955", MODE="0666"
#Pantech
SUBSYSTEM=="usb", SYSFS{idVendor}=="10A9", MODE="0666"
#Samsung
SUBSYSTEM=="usb", SYSFS{idVendor}=="04e8", MODE="0666"
#Sharp
SUBSYSTEM=="usb", SYSFS{idVendor}=="04dd", MODE="0666"
#Sony Ericsson
SUBSYSTEM=="usb", SYSFS{idVendor}=="0fce", MODE="0666"
#ZTE
SUBSYSTEM=="usb", SYSFS{idVendor}=="19D2", MODE="0666"

Once this is done save the file, set the permissions and restart the udev service via
sudo chmod a+r /etc/udev/rules.d/99-android.rules
sudo service udev restart