Skip to content

Commit

Permalink
libreswan: uci configuration support
Browse files Browse the repository at this point in the history
- add patch to call hotplug script
- handle uci config with reload in init script

Signed-off-by: Jaymin Patel <[email protected]>
  • Loading branch information
jempatel committed Aug 17, 2022
1 parent 6155b82 commit 9bfb459
Show file tree
Hide file tree
Showing 9 changed files with 581 additions and 19 deletions.
31 changes: 23 additions & 8 deletions net/libreswan/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk

PKG_NAME:=libreswan
PKG_VERSION:=4.7
PKG_RELEASE:=1
PKG_RELEASE:=$(AUTORELEASE)

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://download.libreswan.org/
Expand Down Expand Up @@ -61,9 +61,10 @@ endef

define Package/libreswan/conffiles
/etc/ipsec.d
/etc/ipsec.conf
/etc/ipsec.secrets
/etc/config/libreswan
/etc/ipsec.user
endef

TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed
TARGET_CFLAGS += -flto

Expand Down Expand Up @@ -101,20 +102,34 @@ endef

define Package/libreswan/install
$(INSTALL_DIR) \
$(1)/etc/init.d \
$(1)/etc/ipsec.d/policies \
$(1)/usr/libexec/ipsec \
$(1)/usr/sbin
$(1)/usr/sbin \
$(1)/etc/uci-defaults \
$(1)/etc/config \
$(1)/etc/init.d \
$(1)/etc/hotplug.d/libreswan \
$(1)/usr/libexec/rpcd

$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/ipsec \
$(1)/usr/sbin/ipsec
$(INSTALL_BIN) ./files/ipsec.init $(1)/etc/init.d/ipsec
$(INSTALL_DATA) ./files/ipsec.conf $(1)/etc/ipsec.conf
$(INSTALL_DATA) ./files/ipsec.secrets $(1)/etc/ipsec.secrets
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/etc/ipsec.d/policies/* \
$(1)/etc/ipsec.d/policies/
$(CP) $(PKG_INSTALL_DIR)/usr/libexec/ipsec/* \
$(1)/usr/libexec/ipsec/

$(INSTALL_BIN) ./files/ipsec.init $(1)/etc/init.d/ipsec
$(INSTALL_DATA) ./files/ipsec.conf $(1)/etc/ipsec.conf
$(INSTALL_DATA) ./files/ipsec.secrets $(1)/etc/ipsec.secrets

$(INSTALL_DATA) ./files/libreswan.uci $(1)/etc/config/libreswan
$(INSTALL_DATA) ./files/libreswan.defaults $(1)/etc/uci-defaults/901-libreswan

$(INSTALL_DATA) ./files/user.hotplug $(1)/etc/hotplug.d/libreswan/01-user
$(INSTALL_DATA) ./files/vti.hotplug $(1)/etc/hotplug.d/libreswan/02-vti
$(INSTALL_DATA) ./files/iptables.hotplug $(1)/etc/hotplug.d/libreswan/03-iptables

$(INSTALL_BIN) ./files/libreswan.rpcd $(1)/usr/libexec/rpcd/libreswan
endef

$(eval $(call BuildPackage,libreswan))
234 changes: 223 additions & 11 deletions net/libreswan/files/ipsec.init
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,36 +1,248 @@
#!/bin/sh /etc/rc.common

. /lib/functions/network.sh

START=90
STOP=10

USE_PROCD=1

PROG="/usr/libexec/ipsec/pluto"
IPSEC_SECRETS=/etc/ipsec.secrets
IPSEC_CONF=/etc/ipsec.conf
IPSEC_BIN=/usr/sbin/ipsec
IPSEC_BIN="/usr/sbin/ipsec"

IPSEC_DIR="/var/run/ipsec"
IPSEC_CONF="$IPSEC_DIR/ipsec.conf"
IPSEC_SECRETS="$IPSEC_DIR/ipsec.secrets"
IPSEC_CONF_DIR="$IPSEC_DIR/conf.d"

checkconfig() {
${IPSEC_BIN} addconn --checkconfig || return 1
mkdir -p /var/run/pluto
${IPSEC_BIN} addconn --checkconfig || return 1
mkdir -p /var/run/pluto
}

expand_ike() {
local id="$1"
local encryption_algorithm hash_algorithm dh_group proposal

config_get encryption_algorithm "${id}" encryption_algorithm
config_get hash_algorithm "${id}" hash_algorithm
config_get dh_group "${id}" dh_group

proposal="${encryption_algorithm:+${encryption_algorithm}${hash_algorithm:+-${hash_algorithm}${dh_group:+;${dh_group%% *}}}}"
append ike_proposal "$proposal" ","
}

expand_phase2alg() {
local id="$1"
local encryption_algorithm hash_algorithm dh_group

config_get encryption_algorithm "${id}" encryption_algorithm
config_get hash_algorithm "${id}" hash_algorithm
config_get dh_group "${id}" dh_group

phase2alg_proposal="${encryption_algorithm:+${encryption_algorithm// /+}${hash_algorithm:+-${hash_algorithm// /+}${dh_group:+-${dh_group// /+}}}}"
}

generate_tunnel_config() {
local id=$1
local config_file="$IPSEC_CONF_DIR/$id.conf"
local secret_file="$IPSEC_CONF_DIR/$id.secret"

config_get auto "$id" auto
config_get left "$id" left
config_get right "$id" right
config_get leftid "$id" leftid "$left"
config_get rightid "$id" rightid "$right"
config_get leftsourceip "$id" leftsourceip
config_get rightsourceip "$id" rightsourceip
config_get leftsubnets "$id" leftsubnets
config_get rightsubnets "$id" rightsubnets
config_get_bool ikev2 "$id" ikev2
[ "$ikev2" = "1" ] && ikev2=yes || ikev2=no
config_get_bool rekey "$id" rekey
[ "$rekey" = "1" ] && rekey=yes || rekey=no
config_get ikelifetime "$id" ikelifetime
config_get rekeymargin "$id" rekeymargin
config_get dpdaction "$id" dpdaction
config_get dpdtimeout "$id" dpdtimeout
config_get dpddelay "$id" dpddelay
config_get phase2 "$id" phase2
config_get phase2alg "$id" phase2alg
config_get vti_interface "$id" vti_interface

if [ -n "$vti_interface" ]; then
config_get leftvti "$id" leftvti
config_get mark "$id" mark
fi

config_list_foreach "$id" ike expand_ike
config_list_foreach "$id" phase2alg expand_phase2alg

config_get authby "$id" authby
config_get psk "$id" psk

if [ -n "$leftsubnets" ]; then
[[ "$leftsubnets" =~ 0.0.0.0* ]] && leftsubnets="0.0.0.0/0"
leftsubnets="{${leftsubnets// /,}}"
fi

if [ -n "$rightsubnets" ]; then
[[ "$rightsubnets" =~ 0.0.0.0* ]] && rightsubnets="0.0.0.0/0"
rightsubnets="{${rightsubnets// /,}}"
fi

cat << EOF > "$config_file"
conn $id
auto=${auto}
authby=${authby}
ikev2=${ikev2}
left=${left%% *}
${leftid:+leftid=${leftid}}
${leftsourceip:+leftsourceip=${leftsourceip}}
${leftsubnets:+leftsubnets=${leftsubnets}}
right=${right%% *}
${rightid:+rightid=${rightid}}
${rightsourceip:+rightsourceip=${rightsourceip}}
${rightsubnets:+rightsubnets=${rightsubnets}}
${dpdaction:+dpdaction=${dpdaction}}
${dpdtimeout:+dpdtimeout=${dpdtimeout}}
${dpddelay:+dpddelay=${dpddelay}}
${ikelifetime:+ikelifetime=${ikelifetime}s}
${rekey:+rekey=${rekey}}
${rekeymargin:+rekeymargin=${rekeymargin}s}
${rekeyfuzz:+rekeyfuzz=${rekeyfuzz}}
${phase2:+phase2=${phase2}}
${ike_proposal:+ike=${ike_proposal}}
${phase2alg_proposal:+phase2alg=${phase2alg_proposal}}
${vti_interface:+vti-interface=${vti_interface}}
${leftvti:+leftvti=${leftvti}}
${mark:+mark=${mark}}
EOF

cat << EOF > "$secret_file"
$leftid $rightid : PSK "$psk"
EOF

unset ike_proposal phase2alg_proposal
}

generate_daemon_config() {
config_get_bool debug globals debug 0
[ "$debug" = "0" ] && debug=none || debug=all
config_get_bool uniqueids globals uniqueids 0
[ "$uniqueids" = "0" ] && uniqueids=no || uniqueids=yes
config_get listen globals listen
config_get listen_interface globals listen_interface
[ -n "$listen_interface" ] && network_get_ipaddr listen "$listen_interface"
config_get virtual_private globals virtual_private
[ -z "$virtual_private" ] && virtual_private='10.0.0.0/8 192.168.0.0/16 172.16.0.0/12 25.0.0.0/8 100.64.0.0/10 !100.64.0.0/24'

[ ! -d $IPSEC_DIR ] && mkdir -p $IPSEC_DIR
[ ! -d $IPSEC_CONF_DIR ] && mkdir -p $IPSEC_CONF_DIR

cat << EOF > "$IPSEC_SECRETS"
include /etc/ipsec.d/*.secrets
include $IPSEC_CONF_DIR/*.secret
EOF

cat << EOF > "$IPSEC_CONF"
config setup
${debug:+plutodebug=${debug}}
${uniqueids:+uniqueids=${uniqueids}}
${listen:+listen=${listen}}
${virtual_private:+virtual-private=%v4:${virtual_private// /,%v4:}}
secretsfile=${IPSEC_SECRETS}
include /etc/ipsec.d/*.conf
include $IPSEC_CONF_DIR/*.conf
EOF
}

clean_config() {
rm -f $IPSEC_CONF_DIR/*.conf $IPSEC_CONF_DIR/*.secret
}

config_cb() {
local var="CONFIG_${1}_SECTIONS"
export $var
append "$var" "$2"
}

generate_config() {
config_load libreswan
generate_daemon_config
config_foreach generate_tunnel_config tunnel
}

regenerate_config() {
clean_config
generate_config
}

active_conns() {
local active_conns file _file

active_conns=$(${IPSEC_BIN} --trafficstatus | awk -F'[":/]' '{print $3}' | sort -u)

for file in $IPSEC_CONF_DIR/*.conf; do
_file="${file##*/}"
list_contains active_conns "$_file" || append active_conns "${_file%%.*}"
done

echo "$active_conns"
}

start_service() {
generate_config
checkconfig || return 1

ipsec _stackmanager start
${IPSEC_BIN} _stackmanager start
# Enable nflog if configured
ipsec --checknflog > /dev/null
${IPSEC_BIN} --checknflog > /dev/null

procd_open_instance
procd_set_param command $PROG --config ${IPSEC_CONF} --nofork --secretsfile ${IPSEC_SECRETS}
procd_set_param command $PROG --config ${IPSEC_CONF} --nofork
procd_set_param respawn
procd_close_instance
}

stop_service() {
ipsec whack --shutdown
ipsec _stackmanager stop
ipsec --stopnflog > /dev/null
${IPSEC_BIN} whack --shutdown
${IPSEC_BIN} _stackmanager stop
${IPSEC_BIN} --stopnflog > /dev/null
}

delete_tunnel() {
${IPSEC_BIN} auto --delete "$1" > /dev/null 2>&1
rm -f ${IPSEC_CONF_DIR}/$1.*
}

add_tunnel() {
generate_tunnel_config "$1"
${IPSEC_BIN} auto --add "$1" > /dev/null 2>&1
${IPSEC_BIN} auto --rereadsecrets
${IPSEC_BIN} auto --up "$1" > /dev/null 2>&1 &
}

reload_service() {
local active_tunnels uci_tunnels

config_load libreswan
config_get uci_tunnels tunnel SECTIONS

active_tunnels="$(active_conns)"

for tunnel in $active_tunnels; do
list_contains uci_tunnels "$tunnel" || delete_tunnel "$tunnel"
done

for tunnel in $uci_tunnels; do
list_contains active_tunnels "$tunnel" || add_tunnel "$tunnel"
done

${IPSEC_BIN} auto --rereadall
}

service_triggers() {
procd_add_reload_trigger 'libreswan'
}
44 changes: 44 additions & 0 deletions net/libreswan/files/iptables.hotplug
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh

. /lib/functions.sh

IPTABLES="iptables -w"
IPSEC_HOOK="ipsec_hook"
IPSEC_SET="IPSEC_REMOTE_SUBNETS"

init_ipsec_chains_rules() {
$IPTABLES -t filter -N "$IPSEC_HOOK"
$IPTABLES -t filter -C forwarding_rule -j "$IPSEC_HOOK"
[ $? -ne 0 ] && $IPTABLES -t filter -I forwarding_rule -j "$IPSEC_HOOK"

$IPTABLES -t filter -C "$IPSEC_HOOK" -m set --match-set "$IPSEC_SET" src -j ACCEPT
[ $? -ne 0 ] && $IPTABLES -t filter -A "$IPSEC_HOOK" -m set --match-set "$IPSEC_SET" src -j ACCEPT

$IPTABLES -t nat -N "$IPSEC_HOOK"
$IPTABLES -t nat -C postrouting_rule -j "$IPSEC_HOOK"
[ $? -ne 0 ] && $IPTABLES -t nat -I postrouting_rule -j "$IPSEC_HOOK"

$IPTABLES -t nat -C "$IPSEC_HOOK" -m set --match-set "$IPSEC_SET" dst -m policy --dir out --pol ipsec -j ACCEPT
[ $? -ne 0 ] && $IPTABLES -t nat -A "$IPSEC_HOOK" -m set --match-set "$IPSEC_SET" dst -m policy --dir out --pol ipsec -j ACCEPT
}

rightsubnets_rules() {
local id=$1
local subnet

config_get rightsubnets "$id" rightsubnets

ipset flush "$IPSEC_SET"
for subnet in $rightsubnets; do
[ -z "$subnet" ] && continue
ipset -exist add "$IPSEC_SET" "$subnet" comment "$id"
done
}

update_ipsec_ipsets() {
config_load libreswan
config_foreach rightsubnets_rules tunnel
}

init_ipsec_chains_rules
update_ipsec_ipsets
31 changes: 31 additions & 0 deletions net/libreswan/files/libreswan.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh

. /lib/functions.sh

add_firewall_include() {
local include=libreswan_rules

if [ "$(uci_get firewall $include)" != "include" ]; then
uci_add firewall include "$include"
uci_set firewall "$include" path "/etc/hotplud.d/ipsec/03-iptables"
uci_set firewall "$include" reload "1"
fi
}

add_firewall_ipset() {
local ipset=IPSEC_REMOTE_SUBNETS

if [ "$(uci_get firewall $ipset)" != "ipset" ]; then
uci_add firewall ipset "$ipset"
uci_set firewall "$ipset" name "$ipset"
uci_set firewall "$ipset" match "dst_net"
uci_set firewall "$ipset" storage "hash"
uci_set firewall "$ipset" enabled "1"
uci_set firewall "$ipset" comment "1"
fi
}

add_firewall_include
add_firewall_ipset

uci_commit firewall
Loading

0 comments on commit 9bfb459

Please sign in to comment.