From a363bde3483d45a0e5903b811fdc55af844fcaf8 Mon Sep 17 00:00:00 2001 From: Martin Schuette Date: Mon, 31 Mar 2014 23:18:29 +0200 Subject: [PATCH] Initial commit --- Modulefile | 10 + README.md | 6 + files/etc/iptables/rules.v4 | 26 + files/etc/openvpn/mullvad.conf | 45 ++ files/root/bin/autoupdate_fastd_keys.sh | 35 ++ files/usr/local/bin/check_gateway | 22 + files/usr/share/munin/plugins/udp-statistics | 40 ++ files/usr/share/munin/plugins/vnstat_ | 132 +++++ manifests/init.pp | 459 ++++++++++++++++++ manifests/sysadmin.pp | 136 ++++++ templates/etc/bird.conf.erb | 143 ++++++ templates/etc/bird6.conf.erb | 79 +++ templates/etc/dhcp/dhcpd.conf.erb | 25 + .../etc/fastd/ffhh-mesh-vpn/fastd.conf.erb | 16 + templates/etc/radvd.conf.erb | 15 + 15 files changed, 1189 insertions(+) create mode 100644 Modulefile create mode 100644 README.md create mode 100644 files/etc/iptables/rules.v4 create mode 100644 files/etc/openvpn/mullvad.conf create mode 100644 files/root/bin/autoupdate_fastd_keys.sh create mode 100644 files/usr/local/bin/check_gateway create mode 100644 files/usr/share/munin/plugins/udp-statistics create mode 100644 files/usr/share/munin/plugins/vnstat_ create mode 100644 manifests/init.pp create mode 100644 manifests/sysadmin.pp create mode 100644 templates/etc/bird.conf.erb create mode 100644 templates/etc/bird6.conf.erb create mode 100644 templates/etc/dhcp/dhcpd.conf.erb create mode 100644 templates/etc/fastd/ffhh-mesh-vpn/fastd.conf.erb create mode 100644 templates/etc/radvd.conf.erb diff --git a/Modulefile b/Modulefile new file mode 100644 index 0000000..1a94eab --- /dev/null +++ b/Modulefile @@ -0,0 +1,10 @@ +name 'puppet-ff_gw' +version '0.1.0' +license 'BSD 2-clause license' +author 'Martin Schuette ' +dependency 'puppetlabs/apt', '>= 1.4.0' +dependency 'puppetlabs/vcsrepo', '>= 0.2.0' +dependency 'saz/sudo', '>= 3.0.1' +dependency 'torrancew/account', '>= 0.0.5' +summary "Freifunk Hamburg Gateway" +description "A module to setup and configure a Freifunk (Hamburg) Gateway" diff --git a/README.md b/README.md new file mode 100644 index 0000000..36b1e55 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Freifunk Gateway Module + +Martin Schütte + +This module tries to automate the configuration of a Freifunk (Hamburg) Gateway. + diff --git a/files/etc/iptables/rules.v4 b/files/etc/iptables/rules.v4 new file mode 100644 index 0000000..14e4a4c --- /dev/null +++ b/files/etc/iptables/rules.v4 @@ -0,0 +1,26 @@ +# Generated by iptables-save v1.4.14 on Sun Mar 24 14:14:50 2013 +*filter +:INPUT ACCEPT [273:40363] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [194:28568] +COMMIT +# Completed on Mon Mar 25 19:41:40 2013 +# Generated by iptables-save v1.4.14 on Mon Mar 25 19:41:40 2013 +*mangle +:PREROUTING ACCEPT [286:41734] +:INPUT ACCEPT [273:40363] +:FORWARD ACCEPT [0:0] +:OUTPUT ACCEPT [194:28568] +:POSTROUTING ACCEPT [194:28568] +-A PREROUTING -i br-ffhh -j MARK --set-xmark 0x1/0xffffffff +COMMIT +# Completed on Mon Mar 25 19:41:40 2013 +# Generated by iptables-save v1.4.14 on Mon Mar 25 19:41:40 2013 +*nat +:PREROUTING ACCEPT [15:1459] +:INPUT ACCEPT [2:88] +:OUTPUT ACCEPT [1:74] +:POSTROUTING ACCEPT [1:74] +-A POSTROUTING -o mullvad -j MASQUERADE +COMMIT +# Completed on Mon Mar 25 19:41:40 2013 diff --git a/files/etc/openvpn/mullvad.conf b/files/etc/openvpn/mullvad.conf new file mode 100644 index 0000000..a438799 --- /dev/null +++ b/files/etc/openvpn/mullvad.conf @@ -0,0 +1,45 @@ +client + +dev mullvad +dev-type tun + +proto udp + +remote nl.mullvad.net # Servers in the Netherlands + +# Keep trying indefinitely to resolve the +# host name of the OpenVPN server. Very useful +# on machines which are not permanently connected +# to the internet such as laptops. +resolv-retry infinite + +# Most clients don't need to bind to +# a specific local port number. +nobind + +# Try to preserve some state across restarts. +persist-key +persist-tun + +# Enable compression on the VPN link. +comp-lzo + +# Set log file verbosity. +verb 3 + +remote-cert-tls server + +ping-restart 60 + +# Allow calling of built-in executables and user-defined scripts. +script-security 2 + +# Parses DHCP options from openvpn to update resolv.conf +route-noexec +up /etc/openvpn/mullvad/mullvad-up + +ping 10 + +ca /etc/openvpn/mullvad/ca.crt +cert /etc/openvpn/mullvad/client.crt +key /etc/openvpn/mullvad/client.key diff --git a/files/root/bin/autoupdate_fastd_keys.sh b/files/root/bin/autoupdate_fastd_keys.sh new file mode 100644 index 0000000..ae797d5 --- /dev/null +++ b/files/root/bin/autoupdate_fastd_keys.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Simple script to update fastd peers from git upstream +# and only send HUP to fastd when changes happend. + +# CONFIGURE THIS TO YOUR PEER DIRECTORY +FASTD_PEERS=/etc/fastd/ffhh-mesh-vpn/peers + +function getCurrentVersion() { + # Get hash from latest revision + git log --format=format:%H -1 +} + +cd $FASTD_PEERS + +# Get current version hash +GIT_REVISION=$(getCurrentVersion) + +# Automagically commit local changes +# This preserves local changes +git commit -m "CRON: auto commit" + +# Pull latest changes from upstream +git fetch +git merge origin/master -m "Auto Merge" + +# Get new version hash +GIT_NEW_REVISION=$(getCurrentVersion) + +if [ $GIT_REVISION != $GIT_NEW_REVISION ] +then + # Version has changed we need to update + echo "Reload fastd peers" + kill -HUP $(pidof fastd) +fi + diff --git a/files/usr/local/bin/check_gateway b/files/usr/local/bin/check_gateway new file mode 100644 index 0000000..91059e0 --- /dev/null +++ b/files/usr/local/bin/check_gateway @@ -0,0 +1,22 @@ +#!/bin/bash +INTERFACE=mullvad +shopt -s nullglob + +ping -q -I $INTERFACE 8.8.8.8 -c 4 -i 1 -W 5 >/dev/null 2>&1 + +if test $? -eq 0; then + NEW_STATE=server +else + NEW_STATE=off +fi + +for MESH in /sys/class/net/*/mesh; do +OLD_STATE="$(cat $MESH/gw_mode)" +[ "$OLD_STATE" == "$NEW_STATE" ] && continue + echo $NEW_STATE > $MESH/gw_mode + echo 54MBit/54MBit > $MESH/gw_bandwidth + logger "batman gateway mode changed to $NEW_STATE" +done + +# vim: noai:ts=4:sw=4:ff=unix:ft=text:fdm=marker + diff --git a/files/usr/share/munin/plugins/udp-statistics b/files/usr/share/munin/plugins/udp-statistics new file mode 100644 index 0000000..5a3e78a --- /dev/null +++ b/files/usr/share/munin/plugins/udp-statistics @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w + +if ( $ARGV[0] ) { + + if ( $ARGV[0] eq 'autoconf' ) { + if ( -r '/bin/netstat') { + print "yes\n"; + exit 0; + } + print "no\n"; + exit 0; + + } elsif ( $ARGV[0] eq 'config' ) { + print < + +#%# family=contrib +#%# capabilities=autoconf + +# par1 message +error() { + [ $# = 1 ] && echo "$1" >&2 + exit 1 +} + +# par1: "hourly", "daily" or "monthly" +# par2: "tx" or "rx" +getBandwidth() { + [ $# != 2 ] && exit 1 + + local FIELD=-1 + [ $2 = "rx" ] && FIELD=4 + [ $2 = "tx" ] && FIELD=5 + + [ "$FIELD" -eq -1 ] && exit 1 + + local DATA=$(echo "$VNSTAT" | grep "^${1:0:1};0") + local MIB=$(echo "$DATA" | cut -d ';' -f $FIELD) + local KIB=$(echo "$DATA" | cut -d ';' -f $(( $FIELD + 2 )) ) + + echo "scale=3; $MIB + ( $KIB / 1024 )" | bc +} + +# par1: "hourly", "daily" or "monthly" +# par2: value so far +getEstimate() { + [ $# != 2 ] && exit 1 + + case "$1" in + "hourly") + local MINUTESPASSED=$(( $( date +%M ) )) + local MINUTESTOTAL=60 + ;; + "daily") + local MINUTESPASSED=$( echo "$( date +%H ) * 60 + $( date +%M )" | bc ) + local MINUTESTOTAL=1440 + ;; + "monthly") + local MINUTESPASSED=$( echo "( $( date +%d ) - 1 ) * 1440 + $( date +%H ) * 60 + $( date +%M )" | bc ) + local DAYSINMONTH=$(date -d "$(date +%Y)-$(($(date +%-m)+1))-01 -1 day" +%d) + local MINUTESTOTAL=$(( $DAYSINMONTH * 1440 )) + ;; + esac + + echo "scale=1; $MINUTESTOTAL * $2 / $MINUTESPASSED" | bc +} + +PARAMS=${0#*vnstat_} +INTERFACE=$(echo "$PARAMS" | cut -d _ -f 1) # eth0 +PERIOD=$(echo "$PARAMS" | cut -d _ -f 2) # hourly, daily, monthly +DIRECTION=$(echo "$PARAMS" | cut -d _ -f 3) # rx or tx + +# determine whether estimates should be shown +[ \( "${estimate:-0}" = 1 \) -o \( "${estimate:-0}" = "yes" \) -o \( "${estimate:-0}" = "true" \) ] && ESTIMATE=1 || ESTIMATE=0 + +# sanity checks +[ "$PERIOD" = "hourly" ] || [ "$PERIOD" = "daily" ] || [ "$PERIOD" = "monthly" ] || error "Invalid period." +[ "$DIRECTION" = "rx" ] || [ "$DIRECTION" = "tx" ] || [ "$DIRECTION" = "total" ] || [ "$DIRECTION" = "rxtx" ] || error "Invalid direction." + +case "$1" in + config) + echo graph_category network + echo graph_vlabel MiB + + PERIODSTRING=${PERIOD%ly} + PERIODSTRING=${PERIODSTRING/dai/day} + if [ "$DIRECTION" = "rxtx" ]; then + echo "graph_title Network bandwidth for $INTERFACE ($PERIOD, rx and tx)" + echo value.label rx + echo value2.label tx + + # show estimates + if [ $ESTIMATE -eq 1 ]; then + echo "estimate.label rx estimate for this $PERIODSTRING" + echo "estimate2.label tx estimate for this $PERIODSTRING" + fi + else + echo "graph_title Network bandwidth for $INTERFACE ($PERIOD, $DIRECTION)" + echo value.label $DIRECTION + [ $ESTIMATE -eq 1 ] && echo "estimate.label estimate for this ${PERIODSTRING}" + fi + + exit 0;; + autoconf) + if ! which vnstat > /dev/null; then + echo "no (vnstat unavailable)" + elif ! which bc > /dev/null; then + echo "no (bc unavailable)" + else + echo yes + fi + + exit 0 + ;; +esac + +VNSTAT=$(vnstat -i $INTERFACE --dumpdb) + +if [ "$DIRECTION" = "total" ] || [ "$DIRECTION" = "rxtx" ]; then + VALUE1=$(getBandwidth $PERIOD rx) + [ $? = 1 ] && error "Could not obtain data." + VALUE2=$(getBandwidth $PERIOD tx) + [ $? = 1 ] && error "Could not obtain data." + + [ "$DIRECTION" = "total" ] && VALUE1=$( echo "scale=3; $VALUE1 + $VALUE2" | bc ) +else + VALUE1=$(getBandwidth $PERIOD $DIRECTION) + [ $? = 1 ] && error "Could not obtain data." +fi + +if [ "$DIRECTION" = "rxtx" ]; then + echo value.value $VALUE1 + echo value2.value $VALUE2 + + if [ "$ESTIMATE" -eq 1 ]; then + echo estimate.value $(getEstimate $PERIOD $VALUE1) + echo estimate2.value $(getEstimate $PERIOD $VALUE2) + fi +else + echo value.value $VALUE1 + [ "$ESTIMATE" -eq 1 ] && echo estimate.value $(getEstimate $PERIOD $VALUE1) +fi diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..e4746ec --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,459 @@ +class ff_gw($mesh_mac, $gw_ipv4, $gw_ipv6, $secret_key, $dhcprange_start, $dhcprange_end) { + class { 'ff_gw::apt': } + -> + class { 'ff_gw::software': } + -> + class { 'ff_gw::fastd': + mesh_mac => $mesh_mac, + gw_ipv4 => $gw_ipv4, + gw_ipv6 => $gw_ipv6, + secret_key => $secret_key, + } + -> + class { 'ff_gw::dhcpd': + gw_ipv4 => $gw_ipv4, + dhcprange_start => $dhcprange_start, + dhcprange_end => $dhcprange_end, + } + -> + class { 'ff_gw::radvd': + own_ipv6 => $gw_ipv6, + } + -> + class { 'ff_gw::vpn': } + -> + class { 'ff_gw::iptables': } + -> + class { 'ff_gw::dnsmasq': } + -> + class { 'ff_gw::bird': + own_ipv4 => $gw_ipv4, + own_ipv6 => $gw_ipv6, + } +} + +class ff_gw::apt() { + class { '::apt': + always_apt_update => true + } + # batman repo + apt::source { 'universe-factory': + location => 'http://repo.universe-factory.net/debian/', + release => 'sid', + repos => 'main', + key => 'AB7A88C5B89033D8', + key_server => 'pgpkeys.mit.edu', + } +} + +class ff_gw::software { + package { + 'batctl': + ensure => installed; + 'batman-adv-dkms': + ensure => installed; + 'fastd': + ensure => installed; + 'bridge-utils': + ensure => installed; + } + exec { + 'enable_batman_mod': + command => 'echo batman-adv >> /etc/modules', + unless => 'grep -q ^batman-adv /etc/modules', + path => ['/bin', '/usr/sbin'], + } +} + +class ff_gw::fastd($mesh_mac, $gw_ipv4, $gw_ipv6, $secret_key) { + validate_re($mesh_mac, '^de:ad:be:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}$') + + file { + '/etc/fastd/ffhh-mesh-vpn': + ensure => directory; + '/etc/fastd/ffhh-mesh-vpn/fastd.conf': + ensure => file, + notify => Service['fastd'], + content => template('ff_gw/etc/fastd/ffhh-mesh-vpn/fastd.conf.erb'); + '/etc/fastd/ffhh-mesh-vpn/secret.conf': + ensure => file, + content => inline_template('secret "<%= @secret_key %>";'); + '/root/bin': + ensure => directory; + '/root/bin/autoupdate_fastd_keys.sh': + ensure => file, + mode => '0755', + source => 'puppet:///modules/ff_gw/root/bin/autoupdate_fastd_keys.sh'; + '/usr/local/bin/check_gateway': + ensure => file, + mode => '0755', + source => 'puppet:///modules/ff_gw/usr/local/bin/check_gateway'; + '/etc/network/interfaces': + ensure => file, + # + content => inline_template('# managed by puppet + +# The loopback network interface +auto lo +iface lo inet loopback + +# The primary network interface +allow-hotplug eth0 +iface eth0 inet dhcp + +auto br-ffhh +iface br-ffhh inet6 static + bridge-ports none + address <%= @gw_ipv6 %> + netmask 64 +iface br-ffhh inet static + address <%= @gw_ipv4 %> + netmask 255.255.192.0 + +allow-hotplug bat0 +iface bat0 inet6 manual + pre-up modprobe batman-adv + pre-up batctl if add ffhh-mesh-vpn + up ip link set $IFACE up + post-up brctl addif br-ffhh $IFACE + post-up batctl it 10000 + post-up /sbin/ip rule add from all fwmark 0x1 table 42 + pre-down brctl delif br-ffhh $IFACE || true + down ip link set $IFACE down +'); + } + -> + vcsrepo { '/etc/fastd/ffhh-mesh-vpn/peers': + ensure => present, + provider => git, + source => 'git@freifunk-gw01.hamburg.ccc.de:fastdkeys', + } + + cron { + 'autoupdate_fastd': + command => '/root/bin/autoupdate_fastd_keys.sh', + user => root, + minute => '*/5'; + 'check_gateway': + command => '/usr/local/bin/check_gateway', + user => root, + minute => '*'; + } + exec { + 'start_bridge_if': + command => '/sbin/brctl addbr br-ffhh && /sbin/ifup br-ffhh', + unless => '/sbin/ifconfig br-ffhh'; + 'batman_mod': + command => '/sbin/modprobe batman-adv', + unless => '/sbin/lsmod | /bin/grep -q "^batman_adv"'; + } + -> + service { + 'fastd': + ensure => running, + enable => true, + } +} + +class ff_gw::dhcpd($gw_ipv4, $dhcprange_start, $dhcprange_end) { + if ! is_ip_address($dhcprange_start) + or ! is_ip_address($dhcprange_end) + or ! is_ip_address($gw_ipv4) { + fail('require gateway IP and DHCP range start/end') + } + + # this class uses way too much dependencies + # -- but with all those exec resources we really want + # to stop processing if anything goes wrong + + package { + 'isc-dhcp-server': + ensure => installed; + } + -> + file { + '/etc/dhcp/dhcpd.conf': + ensure => file, + notify => Service['isc-dhcp-server'], + content => template('ff_gw/etc/dhcp/dhcpd.conf.erb'); + } + -> + user { + 'dhcpstatic': + ensure => present, + home => '/home/dhcpstatic'; + } + -> + file { + '/home/dhcpstatic': + ensure => directory, + owner => dhcpstatic; + } + -> + vcsrepo { '/home/dhcpstatic/dhcp-static': + ensure => present, + provider => git, + user => 'dhcpstatic', + source => 'https://github.com/freifunkhamburg/dhcp-static', + } + -> + exec { + 'updateStatics': + command => '/home/dhcpstatic/dhcp-static/updateStatics.sh', + creates => '/etc/dhcp/static.conf'; + } + -> + cron { + 'update_statics': + command => '/home/dhcpstatic/dhcp-static/updateStatics.sh', + user => root, + minute => '*/5'; + } + -> + file { + '/var/log/dhcpd.log': + ensure => file, + owner => 'root', + group => 'adm', + mode => '0600'; + '/etc/rsyslog.d/dhcpd.conf': + ensure => file, + notify => Service['rsyslog'], + content => 'local7.warn /var/log/dhcpd.log'; + '/etc/default/isc-dhcpd': + ensure => file, + content => '# managed by puppet + +#DHCPD_CONF=/etc/dhcp/dhcpd.conf +#DHCPD_PID=/var/run/dhcpd.pid +#OPTIONS="" +# On what interfaces should the DHCP server (dhcpd) serve DHCP requests? +# Separate multiple interfaces with spaces, e.g. "eth0 eth1". +INTERFACES="br-ffhh" +'; + } + -> + exec { + 'syslog_filter_l7': + command => 'sed -i \'s:\*\.\*;auth,authpriv\.none:*.*;auth,authpriv.none;local7.none:\' /etc/rsyslog.conf', + unless => 'grep -q \'authpriv.none;local7.none\' /etc/rsyslog.conf', + path => ['/bin', '/usr/sbin'], + notify => Service['rsyslog']; + } + -> + service { + 'rsyslog': + ensure => running, + enable => true, + } + -> + service { + 'isc-dhcp-server': + ensure => running, + enable => true, + } +} + +class ff_gw::dnsmasq() { + package { + 'dnsmasq': + ensure => installed; + } + -> + user { + 'ffdnsmasq': + ensure => present, + home => '/home/ffdnsmasq', + } + -> + file { + '/home/ffdnsmasq': + ensure => directory, + owner => 'ffdnsmasq', + } + -> + vcsrepo { '/home/ffdnsmasq/dnsmasq': + ensure => present, + provider => git, + user => 'ffdnsmasq', + source => 'https://github.com/freifunkhamburg/dnsmasq', + } + -> + exec { + 'updateDnsmasq': + command => '/home/ffdnsmasq/dnsmasq/updateDnsmasq.sh', + creates => '/etc/dnsmasq.d/rules'; + 'fix_dnsmasq_init.d': + command => 'sed -i -e \'s/^# Required-Start: \$network \$remote_fs \$syslog/# Required-Start: $network $remote_fs $syslog openvpn/\' /etc/init.d/dnsmasq', + unless => 'grep \'^# Required-Start: $network $remote_fs $syslog openvpn$\' /etc/init.d/dnsmasq', + path => ['/bin'], + } + -> + cron { + 'update_Dnsmasq': + command => '/home/ffdnsmasq/dnsmasq/updateDnsmasq.sh', + user => root, + minute => '*/5'; + } + -> + service { + 'dnsmasq': + ensure => running, + enable => true, + require => Service['openvpn'], + } +} + +class ff_gw::radvd($own_ipv6) { + package { + 'radvd': + ensure => installed; + } + -> + file { + '/etc/radvd.conf': + ensure => file, + content => template('ff_gw/etc/radvd.conf.erb'); + } + -> + service { + 'radvd': + ensure => running, + enable => true, + } + + augeas { 'enable_ip_forwarding': + context => '/files/etc/sysctl.conf', + changes => [ + 'set net.ipv4.ip_forward 1', + 'set net.ipv6.conf.all.forwarding 1' + ], + } + ~> + exec { + 'sysctl': + command => '/sbin/sysctl -p', + # this gets notified to run only if /etc/sysctl.conf is changed: + refreshonly => true; + } +} + +class ff_gw::vpn($openvpn_version, $vpnname, $ca_crt, $usr_crt, $usr_key, $ensure = 'running') { + package { + 'openvpn': + ensure => $openvpn_version; + } + -> + file { + "/etc/openvpn/${vpnname}": + ensure => directory; + "/etc/openvpn/${vpnname}/ca.crt": + ensure => file, + content => $ca_crt; + "/etc/openvpn/${vpnname}/client.crt": + ensure => file, + content => $usr_crt; + "/etc/openvpn/${vpnname}/client.key": + ensure => file, + mode => '0600', + content => $usr_key; + "/etc/openvpn/${vpnname}/mullvad-up": + ensure => file, + mode => '0755', + content => '#!/bin/sh +ip route replace 0.0.0.0/1 via $5 table 42 +ip route replace 128.0.0.0/1 via $5 table 42 +exit 0'; + "/etc/openvpn/${vpnname}.conf": + ensure => file, + source => "puppet:///modules/ff_gw/etc/openvpn/${vpnname}.conf"; + } + ~> + service { 'openvpn': + ensure => $ensure, + enable => true, + } + ~> + exec { 'openvpn_sleep': + # OpenVPN takes some time to set up the interface + command => '/bin/sleep 5', + refreshonly => true, + } +} + +class ff_gw::iptables { + package { + 'iptables-persistent': + ensure => installed; + } + -> + file { + '/etc/iptables/rules.v4': + ensure => file, + source => 'puppet:///modules/ff_gw/etc/iptables/rules.v4'; + '/etc/rc.local': + ensure => file, + content => '#!/bin/sh -e +# managed by puppet +# +# rc.local +# +# This script is executed at the end of each multiuser runlevel. +# Make sure that the script will "exit 0" on success or any other +# value on error. +# +# In order to enable or disable this script just change the execution +# bits. +# +# By default this script does nothing. + +/sbin/ip route add unreachable default table 42 +/sbin/ip rule add from all fwmark 0x1 table 42 +exit 0'; + } + ~> + service { + 'iptables-persistent': + ensure => running, + enable => true, + } +} + +class ff_gw::bird($own_ipv4, $own_ipv6, $peerings_v4, $peerings_v6, $version = 'present') { + package { + 'bird6': + ensure => $version, + } + -> + file { + '/etc/bird6.conf': + ensure => file, + content => template('ff_gw/etc/bird6.conf.erb'); + } + ~> + service { + 'bird6': + ensure => running, + enable => true, + require => Service['openvpn'], + } + + + package { + 'bird': + ensure => $version, + } + -> + file { + '/etc/bird.conf': + ensure => file, + content => template('ff_gw/etc/bird.conf.erb'); + } + ~> + service { + 'bird': + ensure => running, + enable => true, + require => Service['openvpn'], + } +} diff --git a/manifests/sysadmin.pp b/manifests/sysadmin.pp new file mode 100644 index 0000000..88caf39 --- /dev/null +++ b/manifests/sysadmin.pp @@ -0,0 +1,136 @@ +# kitchen sink class for various small settings +class ff_gw::sysadmin { + + # use Hiera as a Puppet data source + file { + '/etc/puppet/hiera.yaml': + # content from git repo, not from puppet + ensure => file; + '/etc/hiera.yaml': + ensure => link, + target => '/etc/puppet/hiera.yaml'; + } + + # use backports repo + apt::source { 'wheezy-backports': + location => 'http://ftp.de.debian.org/debian/', + release => 'wheezy-backports', + repos => 'main', + } + # some more packages + package { + ['vim-nox', 'git', 'etckeeper', 'pv', 'curl', 'atop', + 'screen', 'tcpdump', 'rsync', 'file']: + ensure => installed, + } + + # Sudo + include sudo + sudo::conf { 'admins': + priority => 10, + content => '%sudo ALL=(ALL) NOPASSWD: ALL', + } + + # sshd + augeas { 'harden_sshd': + context => '/files/etc/ssh/sshd_config', + changes => [ + 'set PermitRootLogin no', + 'set PasswordAuthentication no', + 'set PubkeyAuthentication yes' + ], + } + ~> + service { 'ssh': + ensure => running, + enable => true, + } + + # zabbix + apt::source { 'zabbix': + location => 'http://repo.zabbix.com/zabbix/2.2/debian', + release => 'wheezy', + repos => 'main', + key => '79EA5ED4', + key_server => 'pgpkeys.mit.edu', + } + -> + package { 'zabbix-agent': + ensure => latest; + } + -> + file { '/etc/zabbix/zabbix_agentd.d/argos_monitoring.conf': + ensure => file, + content => "# managed by puppet +Server=argos.mschuette.name +HostnameItem=${::hostname} +"; + } + ~> + service { 'zabbix-agent': + ensure => running, + enable => true, + } + + # munin + package { + [ 'munin-node', 'vnstat' ]: + ensure => installed, + } + -> + file { + '/etc/munin/munin-node.conf': + ensure => file, + # mostly Debin pkg default + content => inline_template('# managed by puppet +log_level 4 +log_file /var/log/munin/munin-node.log +pid_file /var/run/munin/munin-node.pid + +background 1 +setsid 1 + +user root +group root + +# Regexps for files to ignore +ignore_file [\#~]$ +ignore_file DEADJOE$ +ignore_file \.bak$ +ignore_file %$ +ignore_file \.dpkg-(tmp|new|old|dist)$ +ignore_file \.rpm(save|new)$ +ignore_file \.pod$ + +port 4949 + +host_name <%= @fqdn %> +cidr_allow 78.47.49.236/32 +host <%= @ipaddress_eth0 %> +'); + '/usr/share/munin/plugins/vnstat_': + ensure => file, + mode => '0755', + source => 'puppet:///modules/ff_gw/usr/share/munin/plugins/vnstat_'; + '/etc/munin/plugins/vnstat_eth0_monthly_rxtx': + ensure => link, + target => '/usr/share/munin/plugins/vnstat_'; + '/usr/share/munin/plugins/udp-statistics': + ensure => file, + mode => '0755', + source => 'puppet:///modules/ff_gw/usr/share/munin/plugins/udp-statistics'; + '/etc/munin/plugins/udp-statistics': + ensure => link, + target => '/usr/share/munin/plugins/udp-statistics'; + # TODO: delete not needed plugins + '/etc/munin/plugin-conf.d/vnstat': + ensure => file, + content => '[vnstat_eth0_monthly_rxtx] +env.estimate 1'; + } + ~> + service { 'munin-node': + ensure => running, + enable => true; + } +} diff --git a/templates/etc/bird.conf.erb b/templates/etc/bird.conf.erb new file mode 100644 index 0000000..de8ff14 --- /dev/null +++ b/templates/etc/bird.conf.erb @@ -0,0 +1,143 @@ +router id <%= @own_ipv4 %>; + +table ffhh; # BGP Peerings +table ibgp; +table icvpn; # BGP Peerings (ICVPN) +table freifunk; # Kernel table 42 (Routing from Freifunk networks) + +function is_freifunk_dn42() { + return (net ~ [ + 10.0.0.0/8{12,32}, + 10.100.0.0/14, + 172.22.0.0/15+, + 172.31.0.0/16 + ]); +} + +function is_freifunk() { + return (net ~ [10.0.0.0/8+]); +} + +function is_chaosvpn() { + return (net ~ [172.31.0.0/16+]); +} + +function is_self_net() { + return (net ~ [10.112.0.0/16+]); +} + +function is_self() { + return (proto = "static_ffhh"); +} + +function is_dn42_aggregate() { + return (net ~ [172.22.0.0/15{16,32}]); +} + +filter ffhh_internal_export { + if (proto = "dn42_aggregate_ffhh" || proto = "local_ffhh") then accept; + if (source != RTS_BGP && proto != "pipe_icvpn") then reject; + if (proto ~ "bgp_ibgp_*") then reject; + if (is_dn42_aggregate()) then reject; + accept; +} + + +protocol pipe pipe_ffhh { + peer table ffhh; + import all; + export none; +}; + +protocol pipe pipe_icvpn { + table ffhh; + peer table icvpn; + export where is_self(); + import all; + mode opaque; +}; + +protocol pipe pipe_freifunk { + peer table freifunk; + import none; + export all; +}; + +protocol pipe pipe_ibgp { + peer table ibgp; + import all; + export where !is_self_net(); + mode opaque; +}; + +protocol kernel kernel_master { + scan time 20; + import none; + export filter { + krt_prefsrc = <%= @own_ipv4 %>; + accept; + }; +}; + +protocol kernel kernel_freifunk { + scan time 20; + import none; + export filter { + krt_prefsrc = <%= @own_ipv4 %>; + accept; + }; + table freifunk; + device routes; + kernel table 42; +}; + +# This pseudo-protocol watches all interface up/down events. +protocol device { + scan time 10; # Scan interfaces every 10 seconds +}; + +protocol static unreachable_default { + table freifunk; + route 0.0.0.0/0 reject; +}; + +protocol static static_ffhh { + table ffhh; + route 10.112.0.0/16 reject; +}; + +protocol static local_ffhh { + table ffhh; + route 10.112.0.0/18 via "freifunk"; +}; + +protocol static dn42_aggregate_ffhh { + table ffhh; + route 172.22.0.0/15 reject; +}; + + +template bgp bgp_ibgp { + local as 65112; + table ibgp; + import filter { + preference = 99; + accept; + }; + export all; + gateway direct; + next hop self; +}; + +template bgp bgp_icvpn { + local as 65112; + table icvpn; + import where (is_freifunk_dn42() && !is_self_net()); + export all; +}; + +<% @peerings_v4.each_pair do |key, hash| -%><% if hash["ip"] != @own_ipv4 -%> +protocol bgp <%= key %> from <%= hash["template"] %> { + neighbor <%= hash["ip"] %> as <%= hash["as"] %>; +}; +<% end -%><% end -%> diff --git a/templates/etc/bird6.conf.erb b/templates/etc/bird6.conf.erb new file mode 100644 index 0000000..7b52d4f --- /dev/null +++ b/templates/etc/bird6.conf.erb @@ -0,0 +1,79 @@ +# managed by puppet +# +# the ff ip of the gateway +router id <%= @own_ipv4 %>; + +# routing tables +table ffhh; + +# filter to check ulas +function is_ula() { + return (net ~ [ fc00::/7{48,64} ]); +} + +function is_self() { + return (proto = "static_ffhh"); +} + +filter ffhh_internal_export { + if (proto = "local_ffhh") then accept; + if (source != RTS_BGP) then reject; + if (is_ula() && proto != "static_ffhh") then accept; + else reject; +} + +# don't use kernel's routes for bird, but export bird's routes to kernel +protocol kernel { + scan time 20; # Scan kernel routing table every 20 seconds + import none; # Default is import all + export all; +} + +# This pseudo-protocol watches all interface up/down events. +protocol device { + scan time 10; # Scan interfaces every 10 seconds +} + +# define our routes +protocol static static_ffhh { + table ffhh; + # reject route if announced from external + route fd51:2bb2:fd0d::/48 reject; +}; + +protocol static local_ffhh { + table ffhh; + route fd51:2bb2:fd0d::/64 via "br-ffhh"; +}; + +protocol pipe pipe_ffhh { + peer table ffhh; + import all; + export none; +}; + +# template for internal routing +template bgp bgp_ibgp { + table ffhh; + local as 65112; + source address <%= @own_ipv6 %>; + import all; + export where source = RTS_BGP; + gateway direct; + next hop self; +}; + +# icvpn template for hamburg03 +template bgp bgp_icvpn { + local as 65112; + source address <%= @own_ipv6 %>; + table ffhh; + import where is_ula(); + export where is_self() || (source = RTS_BGP); +}; + +<% @peerings_v6.each_pair do |key, hash| -%><% if hash["ip"] != @own_ipv6 -%> +protocol bgp <%= key %> from <%= hash["template"] %> { + neighbor <%= hash["ip"] %> as <%= hash["as"] %>; +}; +<% end -%><% end -%> diff --git a/templates/etc/dhcp/dhcpd.conf.erb b/templates/etc/dhcp/dhcpd.conf.erb new file mode 100644 index 0000000..733d413 --- /dev/null +++ b/templates/etc/dhcp/dhcpd.conf.erb @@ -0,0 +1,25 @@ +# The ddns-updates-style parameter controls whether or not the server will +# attempt to do a DNS update when a lease is confirmed. We default to the +# behavior of the version 2 packages ('none', since DHCP v2 didn't +# have support for DDNS.) +ddns-update-style none; + +# option definitions common to all supported networks... +option domain-name ".ffhh"; + +default-lease-time 600; +max-lease-time 3600; + +log-facility local7; + +subnet 10.112.0.0 netmask 255.255.192.0 { + authoritative; + range <%= @dhcprange_start %> <%= @dhcprange_end %>; + + # DNS: srv01 (10.112.1.1) & gw01 (10.112.14.1) + option domain-name-servers 10.112.1.1, 10.112.14.1; + option routers <%= @gw_ipv4 %>; +} + +include "/etc/dhcp/static.conf"; + diff --git a/templates/etc/fastd/ffhh-mesh-vpn/fastd.conf.erb b/templates/etc/fastd/ffhh-mesh-vpn/fastd.conf.erb new file mode 100644 index 0000000..0ea508d --- /dev/null +++ b/templates/etc/fastd/ffhh-mesh-vpn/fastd.conf.erb @@ -0,0 +1,16 @@ +# managed by puppet -- editing is futile + +log to syslog level info; +interface "ffhh-mesh-vpn"; +method "salsa2012+gmac"; # new method, between gateways for the moment (faster) +method "xsalsa20-poly1305"; # old method +bind 0.0.0.0:10000; +hide ip addresses yes; +hide mac addresses yes; +include "secret.conf"; +mtu 1426; # 1492 - IPv4 Header - fastd Header... +include peers from "peers"; +on up " + ifup bat0 + ip link set address <%= @mesh_mac %> up dev $INTERFACE +"; diff --git a/templates/etc/radvd.conf.erb b/templates/etc/radvd.conf.erb new file mode 100644 index 0000000..50cffde --- /dev/null +++ b/templates/etc/radvd.conf.erb @@ -0,0 +1,15 @@ +# managed by puppet +interface br-ffhh +{ + AdvSendAdvert on; + + MaxRtrAdvInterval 200; + + prefix fd51:2bb2:fd0d::/64 { + }; + + RDNSS <%= @own_ipv6 %> { + }; +}; + +# vim: noai:ts=4:sw=4:ff=unix:ft=text:fdm=marker