Browse Source

Fastd configuration magic.

Signed-off-by: Maximilian Wilhelm <max@rfc2324.org>
Maximilian Wilhelm 7 years ago
parent
commit
991bfab692
9 changed files with 434 additions and 0 deletions
  1. 65 0
      fastd/fastd.conf
  2. 11 0
      fastd/fastd@.service
  3. 30 0
      fastd/ff_fastd_con
  4. 89 0
      fastd/ff_update_peers
  5. 5 0
      fastd/ff_update_peers.cron
  6. 184 0
      fastd/init.sls
  7. 15 0
      fastd/inter-gw.peer.tmpl
  8. 34 0
      fastd/peers.sls
  9. 1 0
      fastd/secret.conf.tmpl

+ 65 - 0
fastd/fastd.conf

@@ -0,0 +1,65 @@
+#
+# {{ site }} / {{ network }} FASTd configuration (Salt managed)
+#
+
+log to syslog level info;
+
+interface "{{ site }}_{{ network }}";
+
+{%- if 'aes' in grains['cpu_flags'] %}
+method "aes128-ctr+umac";
+{%- else %}
+#method "aes128-ctr+umac";	# Not supported by CPU on this machine
+{%- endif %}
+method "salsa2012+umac";
+
+
+{#- nodes{4,6} VPNs #}
+{%- if network_type == 'nodes' %}
+  {%- set proto = network.split ('-')[-1] %}
+  {%- set port = 10000 + site_no|int %}
+  {%- if network == 'nodes4' %}
+bind 0.0.0.0:{{ port }} interface "vrf_external";
+  {%- else %}
+bind [::]:{{ port }} interface "vrf_external";
+  {%- endif %}
+ 
+{#- intergw VPN #}
+{%- else %}
+{%- set port = 11000 + site_no|int %}
+bind 0.0.0.0:{{ port }} interface "vrf_external";
+bind [::]:{{ port }} interface "vrf_external";
+{%- endif %}
+
+# Mark packets to make sure they are associated to VRF vrf_external.
+# Specifying the interface and setsockopt() isn't enough for fastd.
+packet mark 0x1023;
+
+include "secret.conf";
+mtu 1406;
+
+status socket "/var/run/fastd.{{ site }}_{{ network }}.sock";
+
+on up "
+	ifconfig $INTERFACE down
+	ip link set address {{ mac_address }} dev $INTERFACE
+	ifconfig $INTERFACE up
+
+	batctl -m bat-{{ site }}-ext if add $INTERFACE
+";
+
+on down "
+	batctl -m bat-{{ site }}-ext if del $INTERFACE
+";
+
+{%- if 'nodes' in network %}
+#on establish    async "/usr/local/bin/ff_log_vpnpeer establish";
+#on disestablish async "/usr/local/bin/ff_log_vpnpeer disestablish";
+
+include peers from "/etc/freifunk/peers";
+  {%- if peer_limit %}
+peer limit {{ peer_limit }};
+  {%- endif %}
+{%- elif 'intergw' in network %}
+include peers from "gateways";
+{%- endif %}

+ 11 - 0
fastd/fastd@.service

@@ -0,0 +1,11 @@
+[Unit]
+Description=Fast and Secure Tunnelling Daemon (connection %I)
+After=network.target
+
+[Service]
+Type=notify
+ExecStart=/usr/bin/fastd --syslog-level info --syslog-ident fastd@%i -c /etc/fastd/%i/fastd.conf
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target

+ 30 - 0
fastd/ff_fastd_con

@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Maximilian Wilhelm <max@rfc2324.org>
+#  --  Mon 31 Aug 2015 08:55:27 AM CEST
+#
+
+if [ $# != 1 ]; then
+	echo "Usage: $(basename $0) fastd_instance | -a" >&2
+	exit 1
+fi
+
+fastd_con () {
+	socket_path=$(grep "status socket" "/etc/fastd/${1}/fastd.conf" | grep -o '/[0-9a-z/_.-]\+')
+
+	echo -n "$1: "
+	socat - "UNIX-CONNECT:${socket_path}" | jq '.peers[] | select( .connection ) | .name' | wc -l
+}
+
+if [ "${1}" = '-a' ]; then
+	for fastd_instance in $(find /etc/fastd -mindepth 1 -maxdepth 1 -type d  -exec basename {} \;); do
+		fastd_con ${fastd_instance}
+	done
+else
+	if [ ! -d "/etc/fastd/${1}" ]; then
+		echo "Invalid fastd instance \"$1\"." >&2
+		exit 1
+	fi
+
+	fastd_con "${1}"
+fi

+ 89 - 0
fastd/ff_update_peers

@@ -0,0 +1,89 @@
+#!/bin/sh
+#
+# Simple script to update fastd peers from git upstream
+# and only send HUP to fastd when changes happend.
+#
+# (C) 2014 Helge Jung <hej@c3pb.de>
+# (C) 2014 Maximilian Wilhelm <max@rfc2324.org>
+#
+
+
+# CONFIGURE THIS TO YOUR PEER DIRECTORY
+DEFAULT_PEERS_DIRECTORY="/etc/freifunk/peers"
+SSH_IDENTITY="/root/.ssh/ffho_peers_git.id_rsa"
+
+getCurrentVersion() {
+	# Get hash from latest revision
+	git log --format=format:%H -1 | tr -d '\n'
+}
+
+[ -z "$RELOAD_FASTD" ] && RELOAD_FASTD="yes"
+
+[ -z "$PEERS_DIRECTORY" ] && PEERS_DIRECTORY=$DEFAULT_PEERS_DIRECTORY
+if [ ! -d "$PEERS_DIRECTORY" ]; then
+	echo "Peers directory not found ($PEERS_DIRECTORY). Cannot update."
+	exit 1
+fi
+if [ ! -d "${PEERS_DIRECTORY}/.git" ]; then
+	echo "Peers directory does not seem to be a git repository. Cannot update."
+	exit 1
+fi
+cd "${PEERS_DIRECTORY}"
+
+ssh-add -l > /dev/null 2>&1
+if [ "$?" -ne 0 ]; then
+	eval $(ssh-agent) > /dev/null
+	ssh-add "${SSH_IDENTITY}" 2> /dev/null
+	SSH_AGENT_STARTED=yes
+else
+	SSH_AGENT_STARTED=no
+fi
+
+# Get current version hash
+LAST_REVISION="$(getCurrentVersion)"
+
+if [ "$(git status --porcelain)" ]; then
+	echo "Local changes to peers directory. Cowardly refusing to update this repository!" >&2
+	exit 1
+fi
+
+
+if ! git pull --quiet --rebase >/dev/null; then
+	echo "Update of peers repository failed... :-(" >&2
+	exit 2
+fi
+
+# Get new version hash
+GIT_NEW_REVISION="$(getCurrentVersion)"
+
+if [ "${LAST_REVISION}" != "${GIT_NEW_REVISION}" ]; then
+	if [ "$RELOAD_FASTD" != "no" ]; then
+		fastd_pids=$(pidof fastd)
+		if [ ! "${fastd_pids}" ]; then
+			echo "Oh noes, there is no fastd running here.. Thou shalt fix this now, br0!" >&2
+			exit 3
+		fi
+
+		kill -HUP ${fastd_pids}
+	fi
+
+	# Get list of commits since last local version
+	num_commits="$(git log --abbrev-commit --pretty=oneline ${LAST_REVISION}..${GIT_NEW_REVISION} | wc -l)"
+	last_msg="$(git log --abbrev-commit --pretty=oneline ${LAST_REVISION}..${GIT_NEW_REVISION} | head -n1)"
+
+	if [ ! -z "$GENALIASES_FILE" ]; then
+		./gen_aliases.sh . > "$GENALIASES_FILE"
+		ALIASES_UPDATED=1
+	else
+		ALIASES_UPDATED=0
+	fi
+
+	echo -n "Peers"
+	if [ $ALIASES_UPDATED -eq 1 ]; then echo -n " and aliases"; fi
+	echo " updated: ${num_commits} commits (last: ${last_msg})"
+fi
+
+if [ "$SSH_AGENT_STARTED" = "yes" ]; then
+	ssh-agent -k > /dev/null
+	unset SSH_AGENT_PID
+fi

+ 5 - 0
fastd/ff_update_peers.cron

@@ -0,0 +1,5 @@
+# Update /etc/freifunk/peers repository
+
+MAILTO="{{ salt['pillar.get']('ffho:tech_c_mail') }}"
+
+*/5 * * * *     root    /usr/local/sbin/ff_update_peers 2>&1 | /usr/local/bin/ff_log_to_bot

+ 184 - 0
fastd/init.sls

@@ -0,0 +1,184 @@
+#
+# Fastd for gateways
+#
+
+{% set sites_all = pillar.get ('sites') %}
+{% set sites_node = salt['pillar.get']('nodes:' ~ grains['id'] ~ ':sites', {}) %}
+{% set device_no = salt['pillar.get']('nodes:' ~ grains['id'] ~ ':id', -1) %}
+
+include:
+  - network.interfaces
+{% if 'fastd_peers' in salt['pillar.get']('nodes:' ~ grains['id'] ~ ':roles', []) %}
+  - fastd.peers
+{% endif %}
+
+
+fastd-repo:
+  pkgrepo.managed:
+    - human_name: Neoraiders fastd repository
+    - name: deb http://repo.universe-factory.net/debian/ sid main
+    - dist: sid
+    - file: /etc/apt/sources.list.d/fastd.list
+    - keyserver: keyserver.ubuntu.com
+    - keyid: CB201D9C
+
+
+# Install fastd (after fastd-repo and the network are configured)
+fastd:
+  pkg.installed:
+    - name: fastd
+    - require:
+      - pkgrepo: fastd-repo
+      - sls: network.interfaces
+
+/etc/systemd/system/fastd@.service:
+  file.managed:
+    - source: salt://fastd/fastd@.service
+
+/etc/fastd:
+  file.directory:
+    - user: root
+    - group: root
+    - mode: 711
+  require:
+    - pkg: fastd
+
+#
+# Set up fastd configuration for every network (nodes4, nodes6, intergw-vpn)
+# for every site associated for the current minion ID.
+#
+{% for site in sites_node %}
+  {% set site_no = salt['pillar.get']('sites:' ~ site ~ ':site_no') %}
+
+  {% set networks = ['intergw'] %}
+  {% if 'fastd_peers' in salt['pillar.get']('nodes:' ~ grains['id'] ~ ':roles', []) %}
+    {% do networks.extend (['nodes4', 'nodes6']) %}
+  {% endif %}
+
+  {% for network in networks %}
+    {% set network_type = 'nodes' if network.startswith ('nodes') else network %}
+    {% set instance_name = site ~ '_' ~ network %}
+    {% set mac_address = salt['ffho_net.gen_batman_iface_mac'](site_no, device_no, network) %}
+
+/etc/fastd/{{ instance_name }}:
+  file.directory:
+     - makedirs: true
+     - mode: 755
+     - require:
+       - file: /etc/fastd
+
+/etc/fastd/{{ instance_name }}/fastd.conf:
+  file.managed:
+    - source: salt://fastd/fastd.conf
+    - template: jinja
+      network: {{ network }}
+      network_type: {{ network_type }}
+      site: {{ site }}
+      site_no: {{ site_no }}
+      mac_address: {{ mac_address }}
+      peer_limit: {{ salt['pillar.get']('nodes:' ~ grains['id'] ~ ':fastd:peer_limit', False) }}
+    - require:
+      - file: /etc/fastd/{{ instance_name }}
+    - watch_in:
+  
+/etc/fastd/{{ instance_name }}/secret.conf:
+  file.managed:
+    - source: salt://fastd/secret.conf.tmpl
+    - template: jinja
+      secret: {{ salt['pillar.get']('nodes:' ~ grains['id'] ~ ':fastd:' ~ network_type + '_privkey') }}
+    - mode: 600
+    - user: root
+    - group: root
+    - require:
+      - file: /etc/fastd/{{ instance_name }}
+
+
+# Create systemd start link
+fastd@{{ instance_name }}:
+  service.running:
+    - enable: True
+    - reload: True
+    - require:
+      - file: /etc/systemd/system/fastd@.service
+      - file: /etc/fastd/{{ instance_name }}/fastd.conf
+      - file: /etc/fastd/{{ instance_name }}/secret.conf
+    - watch:
+      - file: /etc/fastd/{{ instance_name }}/fastd.conf
+      - file: /etc/fastd/{{ instance_name }}/secret.conf
+  {% endfor %} # // foreach network in $site
+
+
+#
+# Generate Inter-GW peers from pillar
+/etc/fastd/{{ site }}_intergw/gateways:
+  file.directory:
+    - makedirs: true
+    - mode: 755
+    - require:
+      - file: /etc/fastd/{{ site }}_intergw
+
+#
+# Gather all nodes configured for this site
+  {% set nodes = [] %}
+  {% for node, node_config in salt['pillar.get']('nodes').items () %}
+    {% if site in node_config.get ('sites', {}) and 'fastd' in node_config %}
+      {% do nodes.append (node) %}
+    {% endif %}
+  {% endfor %} # // foreach node
+
+# Set up Inter-Gw-VPN link to all nodes of this site
+  {% for node in nodes|sort %}
+/etc/fastd/{{ site }}_intergw/gateways/{{ node }}:
+  file.managed:
+    - source: salt://fastd/inter-gw.peer.tmpl
+    - template: jinja
+      site: {{ site }}
+      site_no: {{ site_no }}
+      node: {{ node }}
+      pubkey: {{ salt['pillar.get']('nodes:' ~ node ~ ':fastd:intergw_pubkey') }}
+    - require:
+      - file: /etc/fastd/{{ site }}_intergw/gateways
+  {% endfor %} # // foreach site peer
+{% endfor %} # // foreach site
+
+
+#
+# Cleanup configurations for previosly configured instances.
+# Stop fastd instance before purging the configuration.
+{% for site in sites_all if site not in sites_node %}
+  {% for network in ['intergw', 'nodes4', 'nodes6'] %}
+    {% set instance_name = site ~ '_' ~ network %}
+Cleanup /etc/fastd/{{ instance_name }}:
+  file.absent:
+    - name: /etc/fastd/{{ instance_name }}
+
+# Create systemd start link
+Stop fastd@{{ instance_name }}:
+  service.running:
+    - enable: False
+    - reload: False
+    - prereq:
+      - file: Cleanup /etc/fastd/{{ instance_name }}
+  {% endfor %}
+{% endfor %}
+
+
+/usr/local/bin/ff_log_vpnpeer:
+  file.managed:
+    - source: salt://fastd/ff_log_vpnpeer
+    - template: jinja
+    - mode: 755
+
+
+ff_fastd_con_pkgs:
+  pkg.installed:
+    - pkgs:
+      - socat
+      - jq
+
+/usr/local/bin/ff_fastd_conn:
+  file.managed:
+    - source: salt://fastd/ff_fastd_con
+    - mode: 755
+    - user: root
+    - group: root

+ 15 - 0
fastd/inter-gw.peer.tmpl

@@ -0,0 +1,15 @@
+# Peer config for {{ node }} in site {{ site }} (Salt managed)
+{%- set node_config = salt['pillar.get']('nodes:' ~ node) %}
+{%- set ips = salt['ffho_net.get_node_iface_ips'](node_config, 'vrf_external') %}
+
+{# {%- if not no_peer %} #}
+{%- set port = 11000 + site_no|int %}
+{%- for ipv4 in ips['v4'] %}
+remote ipv4 "{{ ipv4 }}" port {{ port }};
+{%- endfor %}
+{%- for ipv6 in ips['v6'] %}
+remote ipv6 "{{ ipv6 }}" port {{ port }};
+{%- endfor %}
+{# {%- endif %} #}
+
+key "{{ pubkey }}";

+ 34 - 0
fastd/peers.sls

@@ -0,0 +1,34 @@
+#
+# FFPB Gateways specific stuff
+#
+
+# include ffpb stuff (git.c3pb.pubkey, ffpb.id_rsa)
+include:
+  - ffho_base
+  - keys
+
+# Pull fastd mesh peers git
+peers-git:
+  git.latest:
+    - name: git@git.c3pb.de:freifunk-sensitive/knoten.git
+    - target: /etc/freifunk/peers
+    - rev: master
+    - identity: /root/.ssh/ffho_peers_git.id_rsa
+    - user: root
+    - require:
+      - ssh_known_hosts: git.c3pb.pubkey
+      - file: /root/.ssh/ffho_peers_git.id_rsa
+
+# Update script
+/usr/local/sbin/ff_update_peers:
+  file.managed:
+    - source: salt://fastd/ff_update_peers
+    - user: root
+    - group: root
+    - mode: 744
+
+## update cronjob
+#/etc/cron.d/ff_update_peers:
+#  file.managed:
+#    - source: salt://fastd/ff_update_peers.cron
+#

+ 1 - 0
fastd/secret.conf.tmpl

@@ -0,0 +1 @@
+secret "{{ secret }}";