diff --git a/net/olsrd/Makefile b/net/olsrd/Makefile new file mode 100644 index 0000000000000..f86f3d5936e16 --- /dev/null +++ b/net/olsrd/Makefile @@ -0,0 +1,333 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2009-2016 OpenWrt.org +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=olsrd +PKG_SOURCE_DATE:=2024-06-09 +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/OLSR/olsrd.git +PKG_SOURCE_VERSION:=d72be9ad60f65dda28a0543b4ffff8cd9a5da2d7 +PKG_MIRROR_HASH:=e05d2724e6c76233148ce460b9611bafccff2114904542fa3b5caf75dc1c4e04 + +PKG_MAINTAINER:=Nick Hainke +PKG_BUILD_PARALLEL:=0 +PKG_LICENSE:=BSD-3-Clause +PKG_LICENSE_FILES:=license.txt + +include $(INCLUDE_DIR)/package.mk + +TARGET_CFLAGS += $(FPIC) + +define Package/olsrd/template + SECTION:=net + CATEGORY:=Network + SUBMENU:=Routing and Redirection + TITLE:=OLSR (Optimized Link State Routing) daemon + URL:=https://www.olsr.org/ +endef + +define Package/olsrd + $(call Package/olsrd/template) + MENU:=1 + DEPENDS:=+libpthread +libubus +iptables +IPV6:ip6tables +endef + +define Package/olsrd/conffiles +/etc/config/olsrd +/etc/config/olsrd6 +endef + +define Package/olsrd-mod-arprefresh + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Kernel ARP cache refresh plugin +endef + +define Package/olsrd-mod-dot-draw + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Dot topology information plugin +endef + + +define Package/olsrd-mod-filtergw + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Filter Gateway plugin +endef + +define Package/olsrd-mod-bmf + $(call Package/olsrd/template) + DEPENDS:=olsrd +kmod-tun + TITLE:=Basic multicast forwarding plugin +endef + +define Package/olsrd-mod-dyn-gw + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Dynamic internet gateway plugin +endef + +define Package/olsrd-mod-dyn-gw-plain + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Dynamic internet gateway plain plugin +endef + +define Package/olsrd-mod-httpinfo + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Small informative web server plugin +endef + +define Package/olsrd-mod-jsoninfo + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Small informative plugin with JSON output +endef + +define Package/olsrd-mod-netjson + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=netjson plugin with JSON output +endef + +define Package/olsrd-mod-mdns + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=MDNS/Zeroconf/Bonjour packet distribution +endef + +define Package/olsrd-mod-nameservice + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Lightweight hostname resolver plugin +endef + +define Package/olsrd-mod-p2pd + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Peer to Peer Discovery plugin +endef + +define Package/olsrd-mod-pgraph + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=output network topology for pgraph +endef + +define Package/olsrd-mod-pud + $(call Package/olsrd/template) + DEPENDS:=olsrd +libgps + TITLE:=Position Update Distribution plugin +endef + +define Package/olsrd-mod-quagga + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Quagga plugin +endef + +define Package/olsrd-mod-secure + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Message signing plugin to secure routing domain +endef + +define Package/olsrd-mod-sgwdynspeed + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Smart Gateway dynamic speed plugin +endef + +define Package/olsrd-mod-txtinfo + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Small informative web server plugin +endef + +define Package/olsrd-mod-watchdog + $(call Package/olsrd/template) + DEPENDS:=olsrd + TITLE:=Watchdog plugin +endef + +define Package/olsrd-utils + $(call Package/olsrd/template) + DEPENDS:=olsrd +jshn + TITLE:=Utils for OLSRD +endef + +define Package/olsrd-mod-pud/conffiles +/etc/olsrd.d/olsrd.pud.position.conf +endef + +define Package/olsrd-mod-secure/conffiles +/etc/olsrd.d/olsrd_secure_key +endef + +define Package/olsrd-mod-sgwdynspeed/conffiles +/etc/olsrd.d/olsrd.sgw.speed.conf +endef + +MAKE_FLAGS+= \ + NO_DEBUG_MESSAGES=1 \ + VERS="$(PKG_VERSION)" \ + OS="linux" \ + DESTDIR="$(PKG_INSTALL_DIR)" \ + STRIP="true" \ + INSTALL_LIB="true" \ + SUBDIRS="arprefresh bmf dot_draw dyn_gw dyn_gw_plain httpinfo filtergw jsoninfo netjson mdns nameservice p2pd pgraph pud quagga secure sgwdynspeed txtinfo watchdog" + +define Build/Compile + $(call Build/Compile/Default,all) + $(call Build/Compile/Default,libs) +endef + +define Package/olsrd/install + $(INSTALL_DIR) $(1)/lib/functions + $(INSTALL_DATA) ./files/olsrd.sh $(1)/lib/functions/olsrd.sh + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/olsrd.config $(1)/etc/config/olsrd + $(INSTALL_CONF) ./files/olsrd6.config $(1)/etc/config/olsrd6 + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/olsrd $(1)/usr/sbin/ + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/olsrd4.init $(1)/etc/init.d/olsrd + $(INSTALL_BIN) ./files/olsrd6.init $(1)/etc/init.d/olsrd6 +endef + +define Package/olsrd-mod-arprefresh/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/arprefresh/olsrd_arprefresh.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-filtergw/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/filtergw/olsrd_filtergw.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-dot-draw/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/dot_draw/olsrd_dot_draw.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-bmf/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/bmf/olsrd_bmf.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-dyn-gw/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/dyn_gw/olsrd_dyn_gw.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-dyn-gw-plain/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/dyn_gw_plain/olsrd_dyn_gw_plain.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-httpinfo/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/httpinfo/olsrd_httpinfo.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-jsoninfo/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/jsoninfo/olsrd_jsoninfo.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-netjson/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/netjson/olsrd_netjson.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-mdns/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/mdns/olsrd_mdns.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-nameservice/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/nameservice/olsrd_nameservice.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-p2pd/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/p2pd/olsrd_p2pd.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-pgraph/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/pgraph/olsrd_pgraph.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-pud/install + $(INSTALL_DIR) $(1)/etc/olsrd.d + $(CP) ./files/olsrd.pud.position.conf $(1)/etc/olsrd.d/ + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/pud/nmealib/lib/libnmea.so $(1)/usr/lib/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/pud/wireformat/lib/libOlsrdPudWireFormat.so $(1)/usr/lib/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/pud/olsrd_pud.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-quagga/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/quagga/olsrd_quagga.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-secure/install + $(INSTALL_DIR) $(1)/etc/olsrd.d + $(CP) ./files/olsrd_secure_key $(1)/etc/olsrd.d/ + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/secure/olsrd_secure.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-sgwdynspeed/install + $(INSTALL_DIR) $(1)/etc/olsrd.d + $(CP) ./files/olsrd.sgw.speed.conf $(1)/etc/olsrd.d/ + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/sgwdynspeed/olsrd_sgwdynspeed.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-txtinfo/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/txtinfo/olsrd_txtinfo.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-mod-watchdog/install + $(INSTALL_DIR) $(1)/usr/lib + $(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/watchdog/olsrd_watchdog.so.* $(1)/usr/lib/ +endef + +define Package/olsrd-utils/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) ./files/olsrd-neigh.sh $(1)/usr/bin/olsrd-neigh +endef + +$(eval $(call BuildPackage,olsrd)) +$(eval $(call BuildPackage,olsrd-mod-arprefresh)) +$(eval $(call BuildPackage,olsrd-mod-dot-draw)) +$(eval $(call BuildPackage,olsrd-mod-filtergw)) +$(eval $(call BuildPackage,olsrd-mod-bmf)) +$(eval $(call BuildPackage,olsrd-mod-dyn-gw)) +$(eval $(call BuildPackage,olsrd-mod-dyn-gw-plain)) +$(eval $(call BuildPackage,olsrd-mod-httpinfo)) +$(eval $(call BuildPackage,olsrd-mod-jsoninfo)) +$(eval $(call BuildPackage,olsrd-mod-netjson)) +$(eval $(call BuildPackage,olsrd-mod-mdns)) +$(eval $(call BuildPackage,olsrd-mod-nameservice)) +$(eval $(call BuildPackage,olsrd-mod-p2pd)) +$(eval $(call BuildPackage,olsrd-mod-pgraph)) +$(eval $(call BuildPackage,olsrd-mod-pud)) +$(eval $(call BuildPackage,olsrd-mod-quagga)) +$(eval $(call BuildPackage,olsrd-mod-secure)) +$(eval $(call BuildPackage,olsrd-mod-sgwdynspeed)) +$(eval $(call BuildPackage,olsrd-mod-txtinfo)) +$(eval $(call BuildPackage,olsrd-mod-watchdog)) +$(eval $(call BuildPackage,olsrd-utils)) diff --git a/net/olsrd/files/olsrd-neigh.sh b/net/olsrd/files/olsrd-neigh.sh new file mode 100755 index 0000000000000..bf78f51a5b87c --- /dev/null +++ b/net/olsrd/files/olsrd-neigh.sh @@ -0,0 +1,120 @@ +#!/bin/sh + +. /usr/share/libubox/jshn.sh + +hostsfile_getname() +{ + local config="$1" + local i=0 + local value file + + while value="$( uci -q get $config.@LoadPlugin[$i].library )"; do { + case "$value" in + 'olsrd_nameservice'*) + file="$( uci -q get $config.@LoadPlugin[$i].hosts_file )" + break + ;; + esac + + i=$(( i + 1 )) + } done + + echo "${file:-/var/run/hosts_olsr}" +} + +read_hostnames() +{ + local file_list=" $( hostsfile_getname 'olsrd' ) $(hostsfile_getname 'olsrd6' ) " + local line ip hostname file file_list_uniq + + for file in $file_list; do { + case " $file_list_uniq " in + *" $file "*) + ;; + *) + file_list_uniq="$file_list_uniq $file" + ;; + esac + } done + + for file in $file_list_uniq; do { + [ -e "$file" ] || continue + + while read -r line; do { + case "$line" in + [0-9]*) + # 2001:ffff:ffff:ffff::1 SomeNode-core.olsr # myself + # 10.0.0.1 SomeNode # 10.0.0.1 + set -f + set +f -- $line + ip="$1" + hostname="$2" + + # both values are announced by other nodes in the + # mesh, so reject anything that is not a plain + # address/hostname before it reaches eval + case "$ip$hostname" in *[!A-Za-z0-9.:_-]*) continue ;; esac + + # global vars, e.g. + # IP_1_2_3_4='foo' or IP_2001_ffff_ffff_ffff__1='bar' + eval IP_${ip//[.:]/_}="$hostname" + ;; + esac + } done <"$file" + } done +} + +read_hostnames + +VARS='localIP:Local remoteIP:Remote validityTime:vTime linkQuality:LQ' +VARS="$VARS neighborLinkQuality:NLQ linkCost:Cost remoteHostname:Host" + +for HOST in '127.0.0.1' '::1';do + # check for availability of HOST + nc $HOST 9090 >/dev/null 2>&1 + if [ $? != 0 ]; then + continue + fi + + json_init + json_load "$( echo /links | nc $HOST 9090 | sed -n '/^[}{ ]/p' )" # remove header/non-json + + if json_is_a links array;then + json_select links + for v in ${VARS};do + eval _${v%:*}=0 + done + for j in 0 1;do + case ${j} in 1) + for v in ${VARS};do + eval printf \"%-\${_${v%:*}}s \" ${v#*:} + done + echo + ;;esac + i=1;while json_is_a ${i} object;do + json_select ${i} + json_get_vars $(for v in ${VARS};do echo ${v%:*};done) + + # remoteIP is announced by other nodes in the mesh and + # is interpolated into a variable name below, so reject + # anything that is not a plain address + case "$remoteIP" in *[!A-Za-z0-9.:_-]*) remoteIP= ;; esac + + case ${j} in 0) + for v in ${VARS};do + eval "test \${_${v%:*}} -lt \${#${v%:*}} && _${v%:*}=\${#${v%:*}}" + done + ;;*) + for v in ${VARS};do + eval printf \"%-\${_${v%:*}}s \" \$${v%:*} + eval remoteHostname="\$IP_${remoteIP//[.:]/_}" + done + echo + ;;esac + json_select .. + i=$(( i + 1 )) + done + done + fi + echo +done diff --git a/net/olsrd/files/olsrd.config b/net/olsrd/files/olsrd.config new file mode 100644 index 0000000000000..68024ed3bda82 --- /dev/null +++ b/net/olsrd/files/olsrd.config @@ -0,0 +1,29 @@ +config olsrd + # uncomment the following line to use a custom config file instead: + #option config_file '/etc/olsrd.conf' + +config LoadPlugin + option library 'olsrd_arprefresh.so.0.1' + +config LoadPlugin + option library 'olsrd_dyn_gw.so.0.5' + +config LoadPlugin + option library 'olsrd_httpinfo.so.0.1' + option port '1978' + list Net '0.0.0.0 0.0.0.0' + +config LoadPlugin + option library 'olsrd_nameservice.so.0.4' + +config LoadPlugin + option library 'olsrd_txtinfo.so.1.1' + option accept '0.0.0.0' + +config Interface + list interface 'wlan' + +config procd procd + option respawn_threshold '3600' + option respawn_timeout '15' + option respawn_retry '0' diff --git a/net/olsrd/files/olsrd.pud.position.conf b/net/olsrd/files/olsrd.pud.position.conf new file mode 100644 index 0000000000000..0ab0fb749b462 --- /dev/null +++ b/net/olsrd/files/olsrd.pud.position.conf @@ -0,0 +1,51 @@ +# +# OLSrd PUD plugin position configuration file +# + +# GPS operating mode. +# Values : bad, 2d, 3d +# Default: bad +# Note : a value of 'bad' will make the resulting position information invalid +# (the mask will indicate that all other information is not present) +#fix = bad + +# GPS quality indicator. +# Values : bad, low, mid, high +# Default: high +#sig = high + +# HDOP (Horizontal Dilution Of Precision) +# Values : floating point value +# Default: 0.0 +# Note : From HDOP, VDOP and PDOP are determined: VDOP = HDOP, and PDOP = sqrt(2) * HDOP. +#hdop = 0.0 + +# Latitude +# Values : floating point value +# Unit is NMEA like latitude: ddmm.sssss (d=degrees, m=minutes, s=seconds) +# Default: 0000.00000 +#lat = 0000.00000 + +# Longitude +# Values: floating point value +# Unit is NMEA like longitude: dddmm.sssss (d=degrees, m=minutes, s=seconds) +# Default: 00000.00000 +#lon = 00000.00000 + +# Elevation +# Values: floating point value +# Unit is meters above the mean sea level (geoid) +# Default: 0.0 +#elv = 0.0 + +# Speed +# Values: floating point value +# Unit is over the ground in kph +# Default: 0.0 +#speed = 0.0 + +# Direction/Track +# Values: floating point value +# Unit is (compass) degrees +# Default: 0.0 +#direction = 0.0 diff --git a/net/olsrd/files/olsrd.sgw.speed.conf b/net/olsrd/files/olsrd.sgw.speed.conf new file mode 100644 index 0000000000000..ae795d87d05f4 --- /dev/null +++ b/net/olsrd/files/olsrd.sgw.speed.conf @@ -0,0 +1,14 @@ +# +# OLSrd Smart Gateway uplink speed configuration file +# + + +# +# Upstream speed in kilobit/s +# Default: 128 +#upstream=128 + +# +# Downstream speed in kilobit/s +# Default: 1024 +#downstream=1024 diff --git a/net/olsrd/files/olsrd.sh b/net/olsrd/files/olsrd.sh new file mode 100644 index 0000000000000..cb52d1973a791 --- /dev/null +++ b/net/olsrd/files/olsrd.sh @@ -0,0 +1,852 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2008-2017 OpenWrt.org + +OLSRD_OLSRD_SCHEMA='ignore:internal config_file:internal DebugLevel=0 AllowNoInt=yes' +OLSRD_IPCCONNECT_SCHEMA='ignore:internal Host:list Net:list2' +OLSRD_LOADPLUGIN_SCHEMA='ignore:internal library:internal Host4:list Net4:list2 Host:list Net:list2 Host6:list Net6:list2 Ping:list redistribute:list NonOlsrIf:list name:list lat lon latlon_infile HNA:list2 hosts:list2 ipv6only:bool' +OLSRD_INTERFACE_SCHEMA='ignore:internal interface:internal AutoDetectChanges:bool LinkQualityMult:list2' +OLSRD_INTERFACE_DEFAULTS_SCHEMA='AutoDetectChanges:bool' + +T=' ' +N=' +' + +log() { + logger -t olsrd -p daemon.info -s "${initscript}: $*" +} + +error() { + logger -t olsrd -p daemon.err -s "${initscript}: ERROR: $*" +} + +warn() { + logger -t olsrd -p daemon.warn -s "${initscript}: WARNING: $*" +} + +validate_varname() { + local varname="$1" + [ -z "$varname" -o "$varname" != "${varname%%[!A-Za-z0-9_]*}" ] && return 1 + return 0 +} + +olsrd_list_configured_interfaces() +{ + local i=0 + local interface + + while interface="$( uci -q get $OLSRD.@Interface[$i].interface )"; do { + case "$( uci -q get $OLSRD.@Interface[$i].ignore )" in + 1|on|true|enabled|yes) + # is disabled + ;; + *) + echo "$interface" # e.g. 'lan' + ;; + esac + + i=$(( i + 1 )) + } done +} + +olsrd_interface_already_in_config() +{ + # e.g.: 'Interface "eth0.1" "eth0.2" "wlan0"' + if grep -s ^'Interface ' "/var/etc/$OLSRD.conf" | grep -q "\"$DEVICE\""; then + logger -t olsrd_hotplug -p daemon.debug "[OK] already_active: '$INTERFACE' => '$DEVICE'" + return 0 + else + logger -t olsrd_hotplug -p daemon.info "[OK] ifup: '$INTERFACE' => '$DEVICE'" + return 1 + fi +} + +olsrd_interface_needs_adding() +{ + local interface + + # likely and cheap operation: + olsrd_interface_already_in_config && return 1 + + for interface in $(olsrd_list_configured_interfaces); do { + [ "$interface" = "$INTERFACE" ] && { + olsrd_interface_already_in_config || return 0 + } + } done + + logger -t olsrd_hotplug -p daemon.debug "[OK] interface '$INTERFACE' => '$DEVICE' not used for $OLSRD" + return 1 +} + +validate_olsrd_option() { + local str="$1" + [ -z "$str" -o "$str" != "${str%%[! 0-9A-Za-z.%/|:_-]*}" ] && return 1 + return 0 +} + +system_config() { + local cfg="$1" + local cfgt hostname latlon oldIFS + + config_get cfgt "$cfg" TYPE + + if [ "$cfgt" = "system" ]; then + config_get hostname "$cfg" hostname + hostname="${hostname:-OpenWrt}" + SYSTEM_HOSTNAME="$hostname" + fi + + if [ -z "$SYSTEM_LAT" -o -z "$SYSTEM_LON" ]; then + config_get latlon "$cfg" latlon + oldIFS="$IFS"; IFS=" ${T}${N},"; set -- $latlon; IFS="$oldIFS" + SYSTEM_LAT="$1" + SYSTEM_LON="$2" + fi + + if [ -z "$SYSTEM_LAT" -o -z "$SYSTEM_LON" ]; then + config_get latlon "$cfg" latitude + SYSTEM_LAT="$latlon" + config_get latlon "$cfg" longitude + SYSTEM_LON="$latlon" + fi +} + +olsrd_find_config_file() { + local cfg="$1" + validate_varname "$cfg" || return 0 + + config_get_bool ignore "$cfg" ignore 0 + [ "$ignore" -ne 0 ] && return 0 + config_get OLSRD_CONFIG_FILE "$cfg" config_file + + return 0 +} + +warning_invalid_value() { + local funcname="warning_invalid_value" + local package="$1" + validate_varname "$package" || package= + local config="$2" + validate_varname "$config" || config= + local option="$3" + validate_varname "$option" || option= + + if [ -n "$package" -a -n "$config" ]; then + log "$funcname() in option '$package.$config${option:+.}$option', skipped" + else + log "$funcname() skipped" + fi + + return 0 +} + +olsrd_write_option() { + local param="$1" + local cfg="$2" + validate_varname "$cfg" || return 1 + local option="$3" + validate_varname "$option" || return 1 + local value="$4" + local option_type="$5" + + if [ "$option_type" = bool ]; then + case "$value" in + 1|on|true|enabled|yes) value=yes;; + 0|off|false|disabled|no) value=no;; + *) warning_invalid_value olsrd "$cfg" "$option"; return 1;; + esac + fi + + if ! validate_olsrd_option "$value"; then + warning_invalid_value olsrd "$cfg" "$option" + return 1 + fi + + if [ "$value" != "${value%%[G-Zg-z_-]*}" ]; then + if [ "$option" != "Ip6AddrType" -a "$option" != "LinkQualityMult" -a "$value" != "yes" -a "$value" != "no" ]; then + value="\"$value\"" + fi + fi + + printf '%s' "${N}$param$option $value" +} + +olsrd_write_plparam() { + local funcname="olsrd_write_plparam" + local param="$1" + local cfg="$2" + local option="$3" + local value="$4" + local option_type="$5" + local _option oldIFS + + validate_varname "$cfg" || return 1 + validate_varname "$option" || return 1 + + if [ "$option_type" = bool ]; then + case "$value" in + 1|on|true|enabled|yes) value=yes;; + 0|off|false|disabled|no) value=no;; + *) warning_invalid_value olsrd "$cfg" "$option"; return 1;; + esac + fi + + if ! validate_olsrd_option "$value"; then + warning_invalid_value olsrd "$cfg" "$option" + return 1 + fi + + oldIFS="$IFS" + IFS='-_' + set -- $option + option="$*" + IFS="$oldIFS" + _option="$option" + + if [ "$option" = 'hosts' ]; then + set -- $value + option="$1" + shift + value="$*" + fi + + if [ "$option" = 'NonOlsrIf' ]; then + if validate_varname "$value"; then + if network_get_device ifname "$value"; then + log "$funcname() Info: mdns Interface '$value' ifname '$ifname' found" + else + log "$funcname() Warning: mdns Interface '$value' not found, skipped" + fi + else + warning_invalid_value olsrd "$cfg" "NonOlsrIf" + fi + + [ -z "$ifname" ] || value=$ifname + fi + + printf '%s' "${N}${param}PlParam \"$option\" \"$value\"" +} + +config_update_schema() { + local schema_varname="$1" + local command="$2" + local option="$3" + local value="$4" + local schema + local cur_option + + validate_varname "$schema_varname" || return 1 + validate_varname "$command" || return 1 + validate_varname "$option" || return 1 + + case "$varname" in + *_LENGTH) return 0;; + *_ITEM*) return 0;; + esac + + eval "export -n -- \"schema=\${$schema_varname}\"" + + for cur_option in $schema; do + [ "${cur_option%%[:=]*}" = "$option" ] && return 0 + done + + if [ "$command" = list ]; then + set -- $value + if [ "$#" -ge "3" ]; then + schema_entry="$option:list3" + elif [ "$#" -ge "2" ]; then + schema_entry="$option:list2" + else + schema_entry="$option:list" + fi + else + schema_entry="$option" + fi + + append "$schema_varname" "$schema_entry" + + return 0 +} + +config_write_options() { + local funcname="config_write_options" + local schema="$1" + local cfg="$2" + validate_varname "$cfg" || return 1 + local write_func="$3" + [ -z "$write_func" ] && output_func=echo + local write_param="$4" + + local schema_entry option option_length option_type default value list_size list_item list_value i position speed oldIFS + local list_speed_vars="HelloInterval HelloValidityTime TcInterval TcValidityTime MidInterval MidValidityTime HnaInterval HnaValidityTime" + + get_value_for_entry() + { + local schema_entry="$1" + + default="${schema_entry#*[=]}" + [ "$default" = "$schema_entry" ] && default= + option="${schema_entry%%[=]*}" + + oldIFS="$IFS"; IFS=':'; set -- $option; IFS="$oldIFS" + option="$1" + option_type="$2" + + validate_varname "$option" || return 1 + [ -z "$option_type" ] || validate_varname "$option_type" || return 1 + [ "$option_type" = internal ] && return 1 + + config_get value "$cfg" "$option" + [ "$option" = "speed" ] && return 1 + + return 0 + } + + already_in_schema() + { + case " $schema " in + *" $1 "*) + return 0 + ;; + *) + return 1 + ;; + esac + } + + already_in_schema "speed" && { + get_value_for_entry "speed" + + if test 2>/dev/null "$value" -gt 0 -a "$value" -le 20 ; then + speed="$value" + else + log "$funcname() Warning: invalid speed-value: '$value' - allowed integers: 1...20, fallback to 6" + speed=6 + fi + + for schema_entry in $list_speed_vars; do { + already_in_schema "$schema_entry" || schema="$schema $schema_entry" + } done + } + + for schema_entry in $schema; do + if [ -n "$speed" ]; then # like sven-ola freifunk firmware fff-1.7.4 + case "$schema_entry" in + HelloInterval) + value="$(( speed / 2 + 1 )).0" + ;; + HelloValidityTime) + value="$(( speed * 25 )).0" + ;; + TcInterval) # todo: not fisheye? -> $(( speed * 2 )) + value=$(( speed / 2 )) + [ $value -eq 0 ] && value=1 + value="$value.0" + ;; + TcValidityTime) + value="$(( speed * 100 )).0" + ;; + MidInterval) + value="$(( speed * 5 )).0" + ;; + MidValidityTime) + value="$(( speed * 100 )).0" + ;; + HnaInterval) + value="$(( speed * 2 )).0" + ;; + HnaValidityTime) + value="$(( speed * 25 )).0" + ;; + *) + get_value_for_entry "$schema_entry" || continue + ;; + esac + + is_speed_var() + { + case " $list_speed_vars " in + *" $1 "*) + return 0 + ;; + *) + return 1 + ;; + esac + } + + is_speed_var "$schema_entry" && option="$schema_entry" + else + get_value_for_entry "$schema_entry" || continue + fi + + if [ -z "$value" ]; then + oldIFS="$IFS"; IFS='+'; set -- $default; IFS="$oldIFS" + value=$* + elif [ "$value" = '-' -a -n "$default" ]; then + continue + fi + + [ -z "$value" ] && continue + + case "$option_type" in + list) list_size=1;; + list2) list_size=2;; + list3) list_size=3;; + *) list_size=0;; + esac + + if [ "$list_size" -gt 0 ]; then + config_get option_length "$cfg" "${option}_LENGTH" + if [ -n "$option_length" ]; then + i=1 + while [ "$i" -le "$option_length" ]; do + config_get list_value "$cfg" "${option}_ITEM$i" + "$write_func" "$write_param" "$cfg" "$option" "$list_value" "$option_type" || break + i=$((i + 1)) + done + else + list_value= + i=0 + for list_item in $value; do + append "list_value" "$list_item" + i=$((i + 1)) + position=$((i % list_size)) + if [ "$position" -eq 0 ]; then + "$write_func" "$write_param" "$cfg" "$option" "$list_value" "$option_type" || break + list_value= + fi + done + [ "$position" -ne 0 ] && "$write_func" "$write_param" "$cfg" "$option" "$list_value" "$option_type" + fi + else + "$write_func" "$write_param" "$cfg" "$option" "$value" "$option_type" + fi + done + + return 0 +} + +olsrd_write_olsrd() { + local cfg="$1" + validate_varname "$cfg" || return 0 + local ignore + + config_get_bool ignore "$cfg" ignore 0 + [ "$ignore" -ne 0 ] && return 0 + + [ "$OLSRD_COUNT" -gt 0 ] && return 0 + + config_get smartgateway "$cfg" SmartGateway + config_get smartgatewayuplink "$cfg" SmartGatewayUplink + export smartgateway + export smartgatewayuplink + + config_write_options "$OLSRD_OLSRD_SCHEMA" "$cfg" olsrd_write_option + echo + OLSRD_COUNT=$((OLSRD_COUNT + 1)) + return 0 +} + +olsrd_write_ipcconnect() { + local cfg="$1" + validate_varname "$cfg" || return 0 + local ignore + + config_get_bool ignore "$cfg" ignore 0 + [ "$ignore" -ne 0 ] && return 0 + + [ "$IPCCONNECT_COUNT" -gt 0 ] && return 0 + + printf '%s' "${N}IpcConnect${N}{" + config_write_options "$OLSRD_IPCCONNECT_SCHEMA" "$cfg" olsrd_write_option "${T}" + echo "${N}}" + IPCCONNECT_COUNT=$((IPCCONNECT_COUNT + 1)) +} + +olsrd_write_hna4() { + local cfg="$1" + validate_varname "$cfg" || return 0 + local ignore + + config_get_bool ignore "$cfg" ignore 0 + [ "$ignore" -ne 0 ] && return 0 + + config_get netaddr "$cfg" netaddr + if ! validate_olsrd_option "$netaddr"; then + warning_invalid_value olsrd "$cfg" "netaddr" + return 0 + fi + + config_get netmask "$cfg" netmask + if ! validate_olsrd_option "$netmask"; then + warning_invalid_value olsrd "$cfg" "netmask" + return 0 + fi + + [ "$HNA4_COUNT" -le 0 ] && printf '%s' "${N}Hna4${N}{" + printf '%s' "${N}${T}${T}$netaddr $netmask" + HNA4_COUNT=$((HNA4_COUNT + 1)) +} + +olsrd_write_hna6() { + local cfg="$1" + validate_varname "$cfg" || return 0 + local ignore + + config_get_bool ignore "$cfg" ignore 0 + [ "$ignore" -ne 0 ] && return 0 + + config_get netaddr "$cfg" netaddr + if ! validate_olsrd_option "$netaddr"; then + warning_invalid_value olsrd "$cfg" "netaddr" + return 0 + fi + + config_get prefix "$cfg" prefix + if ! validate_olsrd_option "$prefix"; then + warning_invalid_value olsrd "$cfg" "prefix" + return 0 + fi + + [ "$HNA6_COUNT" -le 0 ] && printf '%s' "${N}Hna6${N}{" + printf '%s' "${N}${T}${T}$netaddr $prefix" + HNA6_COUNT=$((HNA6_COUNT + 1)) +} + +find_most_recent_plugin_libary() +{ + local library="$1" # e.g. 'olsrd_dyn_gw' or 'olsrd_txtinfo.so.1.1' + local file file_fullpath unixtime + + for file in "/lib/$library"* "/usr/lib/$library"* "/usr/local/lib/$library"*; do { + [ -f "$file" ] && { + file_fullpath="$file" + file="$( basename "$file" )" + # make sure that we do not select + # 'olsrd_dyn_gw_plain.so.0.4' if user wants + # 'olsrd_dyn_gw.so.0.5' -> compare part before 1st dot + [ "${library%%.*}" = "${file%%.*}" ] && { + unixtime="$( date +%s -r "$file_fullpath" )" + echo "$unixtime $file" + } + } + } done | sort -n | tail -n1 | cut -d' ' -f2 +} + +olsrd_write_loadplugin() +{ + local funcname='olsrd_write_loadplugin' + local cfg="$1" + local ignore name suffix lat lon latlon_infile + + validate_varname "$cfg" || return 0 + + config_get_bool ignore "$cfg" ignore 0 + [ "$ignore" -ne 0 ] && return 0 + + # e.g. olsrd_txtinfo.so.1.1 or 'olsrd_txtinfo' + config_get library "$cfg" library + + library="$( find_most_recent_plugin_libary "$library" )" + if [ -z "$library" ]; then + log "$funcname() Warning: Plugin library '$library' not found, skipped" + return 0 + else + library="$( basename "$library" )" + fi + + validate_olsrd_option "$library" || { + warning_invalid_value olsrd "$cfg" 'library' + return 0 + } + + case "$library" in + 'olsrd_nameservice.'*) + config_get name "$cfg" name + [ -z "$name" ] && config_set "$cfg" name $SYSTEM_HOSTNAME + + config_get suffix "$cfg" suffix + [ -z "$suffix" ] && config_set "$cfg" suffix '.olsr' + + config_get lat "$cfg" lat + config_get lon "$cfg" lon + config_get latlon_infile "$cfg" latlon_infile + if [ \( -z "$lat" -o -z "$lat" \) -a -z "$latlon_infile" ]; then + if [ -f '/var/run/latlon.txt' ]; then + config_set "$cfg" lat '' + config_set "$cfg" lon '' + config_set "$cfg" latlon_infile '/var/run/latlon.txt' + else + config_set "$cfg" lat "$SYSTEM_LAT" + config_set "$cfg" lon "$SYSTEM_LON" + fi + fi + + for f in latlon_file hosts_file services_file resolv_file macs_file; do + config_get $f "$cfg" $f + done + + [ -z "$latlon_file" ] && config_set "$cfg" latlon_file '/var/run/latlon.js' + ;; + 'olsrd_watchdog.'*) + config_get wd_file "$cfg" file + ;; + esac + + printf '%s' "${N}LoadPlugin \"$library\"${N}{" + config_write_options "$OLSRD_LOADPLUGIN_SCHEMA" "$cfg" olsrd_write_plparam "${T}" + echo "${N}}" +} + +olsrd_write_interface() { + local funcname="olsrd_write_interface" + local cfg="$1" + validate_varname "$cfg" || return 0 + local ignore + local interfaces + local interface + local ifnames + + config_get_bool ignore "$cfg" ignore 0 + [ "$ignore" -ne 0 ] && return 0 + + ifnames= + config_get interfaces "$cfg" interface + + for interface in $interfaces; do + if validate_varname "$interface"; then + if network_get_device IFNAME "$interface"; then + ifnames="$ifnames \"$IFNAME\"" + ifsglobal="$ifsglobal $IFNAME" + elif network_get_physdev IFNAME "$interface"; then + local proto="$(uci -q get network.${interface}.proto)" + if [ "$proto" = "static" -o "$proto" = "none" ]; then + ifnames="$ifnames \"$IFNAME\"" + ifsglobal="$ifsglobal $IFNAME" + fi + elif [[ "$(ip -details link show dev $interface)" == *"wireguard"* ]]; then + # wireguard interface + ifnames="$ifnames \"$interface\"" + ifsglobal="$ifsglobal $interface" + else + log "$funcname() Warning: Interface '$interface' not found, skipped" + fi + else + warning_invalid_value olsrd "$cfg" "interface" + fi + done + + [ -z "$ifnames" ] && return 0 + + printf '%s' "${N}Interface$ifnames${N}{" + config_write_options "$OLSRD_INTERFACE_SCHEMA" "$cfg" olsrd_write_option "${T}" + echo "${N}}" + INTERFACES_COUNT=$((INTERFACES_COUNT + 1)) +} + +olsrd_write_interface_defaults() { + local cfg="$1" + validate_varname "$cfg" || return 0 + + printf '%s' "${N}InterfaceDefaults$ifnames${N}{" + config_write_options "$OLSRD_INTERFACE_DEFAULTS_SCHEMA" "$cfg" olsrd_write_option "${T}" + echo "${N}}" + + return 1 +} + +olsrd_update_schema() { + local command="$1" + local varname="$2" + local value="$3" + local cfg="$CONFIG_SECTION" + local cfgt + + validate_varname "$command" || return 0 + validate_varname "$varname" || return 0 + + config_get cfgt "$cfg" TYPE + case "$cfgt" in + olsrd) config_update_schema OLSRD_OLSRD_SCHEMA "$command" "$varname" "$value";; + IpcConnect) config_update_schema OLSRD_IPCCONNECT_SCHEMA "$command" "$varname" "$value";; + LoadPlugin) config_update_schema OLSRD_LOADPLUGIN_SCHEMA "$command" "$varname" "$value";; + Interface) config_update_schema OLSRD_INTERFACE_SCHEMA "$command" "$varname" "$value";; + InterfaceDefaults) config_update_schema OLSRD_INTERFACE_DEFAULTS_SCHEMA "$command" "$varname" "$value";; + esac + + return 0 +} + +olsrd_write_config() { + OLSRD_COUNT=0 + config_foreach olsrd_write_olsrd olsrd + IPCCONNECT_COUNT=0 + config_foreach olsrd_write_ipcconnect IpcConnect + HNA4_COUNT=0 + config_foreach olsrd_write_hna4 Hna4 + [ "$HNA4_COUNT" -gt 0 ] && echo "${N}}" + HNA6_COUNT=0 + config_foreach olsrd_write_hna6 Hna6 + [ "$HNA6_COUNT" -gt 0 ] && echo "${N}}" + config_foreach olsrd_write_loadplugin LoadPlugin + INTERFACES_COUNT=0 + config_foreach olsrd_write_interface_defaults InterfaceDefaults + config_foreach olsrd_write_interface Interface + echo + + return 0 +} + +get_wan_ifnames() +{ + local wanifnames word catch_next + + command -v ip >/dev/null || return 1 + + set -- $( ip route list exact 0.0.0.0/0 table all ) + for word in $*; do + case "$word" in + dev) + catch_next="true" + ;; + *) + [ -n "$catch_next" ] && { + case "$wanifnames" in + *" $word "*) + ;; + *) + wanifnames="$wanifnames $word " + ;; + esac + + catch_next= + } + ;; + esac + done + + echo "$wanifnames" +} + +olsrd_setup_smartgw_rules() { + local funcname="olsrd_setup_smartgw_rules" + local file= + + for file in /etc/modules.d/[0-9]*-ipip; do :; done + [ -e "$file" ] || { + log "$funcname() Warning: kmod-ipip is missing. SmartGateway will not work until you install it." + return 1 + } + + local wanifnames="$( get_wan_ifnames )" + + if [ -z "$wanifnames" ]; then + nowan=1 + else + nowan=0 + fi + + IP4T="$( command -v iptables )" + IP6T="$( command -v ip6tables )" + + # Delete smartgw firewall rules first + if [ "$UCI_CONF_NAME" = "olsrd6" ]; then + while $IP6T -D forwarding_rule -o tnl_+ -j ACCEPT 2> /dev/null; do :;done + for IFACE in $wanifnames; do + while $IP6T -D forwarding_rule -i tunl0 -o $IFACE -j ACCEPT 2> /dev/null; do :; done + done + for IFACE in $ifsglobal; do + while $IP6T -D input_rule -i $IFACE -p 4 -j ACCEPT 2> /dev/null; do :; done + done + else + while $IP4T -D forwarding_rule -o tnl_+ -j ACCEPT 2> /dev/null; do :;done + for IFACE in $wanifnames; do + while $IP4T -D forwarding_rule -i tunl0 -o $IFACE -j ACCEPT 2> /dev/null; do :; done + done + for IFACE in $ifsglobal; do + while $IP4T -D input_rule -i $IFACE -p 4 -j ACCEPT 2> /dev/null; do :; done + done + while $IP4T -t nat -D postrouting_rule -o tnl_+ -j MASQUERADE 2> /dev/null; do :;done + fi + + # var 'smartgateway' + 'smartgatewayuplink' build in olsrd_write_olsrd() + if [ "$smartgateway" = "yes" ]; then + log "$funcname() Notice: Inserting firewall rules for SmartGateway" + + if [ ! "$smartgatewayuplink" = "none" ]; then + if [ "$smartgatewayuplink" = "ipv4" ]; then + # Allow everything to be forwarded to tnl_+ and use NAT for it + $IP4T -I forwarding_rule -o tnl_+ -j ACCEPT + $IP4T -t nat -I postrouting_rule -o tnl_+ -j MASQUERADE + # Allow forwarding from tunl0 to (all) wan-interfaces + if [ "$nowan" = '0' ]; then + for IFACE in $wanifnames; do + $IP4T -A forwarding_rule -i tunl0 -o $IFACE -j ACCEPT + done + fi + # Allow incoming ipip on all olsr-interfaces + for IFACE in $ifsglobal; do + $IP4T -I input_rule -i $IFACE -p 4 -j ACCEPT + done + elif [ "$smartgatewayuplink" = "ipv6" ]; then + $IP6T -I forwarding_rule -o tnl_+ -j ACCEPT + if [ "$nowan" = '0' ]; then + for IFACE in $wanifnames; do + $IP6T -A forwarding_rule -i tunl0 -o $IFACE -j ACCEPT + done + fi + for IFACE in $ifsglobal; do + $IP6T -I input_rule -i $IFACE -p 4 -j ACCEPT + done + else + $IP4T -t nat -I postrouting_rule -o tnl_+ -j MASQUERADE + for IPT in $IP4T $IP6T; do + $IPT -I forwarding_rule -o tnl_+ -j ACCEPT + if [ "$nowan" = '0' ]; then + for IFACE in $wanifnames; do + $IPT -A forwarding_rule -i tunl0 -o $IFACE -j ACCEPT + done + fi + for IFACE in $ifsglobal; do + $IPT -I input_rule -i $IFACE -p 4 -j ACCEPT + done + done + fi + fi + fi +} + +olsrd_generate_config() { + UCI_CONF_NAME="$1" + SYSTEM_HOSTNAME= + SYSTEM_LAT= + SYSTEM_LON= + config_load system + config_foreach system_config system + + option_cb() { + olsrd_update_schema "option" "$@" + } + + list_cb() { + olsrd_update_schema "list" "$@" + } + + . /lib/functions/network.sh + + config_load $UCI_CONF_NAME + reset_cb + + OLSRD_CONFIG_FILE= + config_foreach olsrd_find_config_file olsrd + + if [ -z "$OLSRD_CONFIG_FILE" ]; then + mkdir -p -- /var/etc/ + olsrd_write_config > /var/etc/$UCI_CONF_NAME.conf || return 1 + if [ "$INTERFACES_COUNT" -gt 0 -a "$OLSRD_COUNT" -gt 0 ]; then + OLSRD_CONFIG_FILE=/var/etc/$UCI_CONF_NAME.conf + fi + fi + + [ -z "$OLSRD_CONFIG_FILE" ] && return 1 +} diff --git a/net/olsrd/files/olsrd4.init b/net/olsrd/files/olsrd4.init new file mode 100644 index 0000000000000..62cb66d6ffac3 --- /dev/null +++ b/net/olsrd/files/olsrd4.init @@ -0,0 +1,79 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2008-2013 OpenWrt.org + +. $IPKG_INSTROOT/lib/functions/olsrd.sh + +START=65 +USE_PROCD=1 +BIN=/usr/sbin/olsrd +OLSRD=olsrd +CONF=/var/etc/$OLSRD.conf +PID=/var/run/olsrd.pid + +wait_for_network() +{ + ubus -t 15 wait_for network.interface.$1 2>/dev/null +} + +wait_for_wireless() +{ + local count=0 + ubus -t 15 wait_for network.wireless 2>/dev/null + while [ $count -lt 30 ]; do + if [ "$(ubus call network.wireless status | jsonfilter -e '@[*]["pending"]' | grep true | wc -l)" == "0" ]; then + break + fi + count=$((count+1)) + sleep 1 + done +} + +boot() +{ + config_load network + config_foreach wait_for_network interface + wait_for_wireless + rc_procd start_service +} + +start_service() { + olsrd_generate_config $OLSRD + + procd_open_instance + + config_load olsrd + local _respawn_threshold + local _respawn_timeout + local _respawn_retry + + config_get _respawn_threshold procd respawn_threshold 3600 + config_get _respawn_timeout procd respawn_timeout 15 + config_get _respawn_retry procd respawn_retry 0 + + procd_set_param command "$BIN" + procd_append_param command -f ${CONF} + procd_append_param command -nofork + procd_append_param command -pidfile ${PID} + + # restart if olsrd dies + procd_set_param respawn $_respawn_threshold $_respawn_timeout $_respawn_retry + + # automatically restart olsrd if generated cfg has changed + procd_set_param file $CONF + + procd_set_param pidfile $PID + + procd_close_instance + + olsrd_setup_smartgw_rules +} + +service_triggers() { + # reload if config changed via uci + procd_add_reload_trigger "olsrd" + + # restart on ifup interface events + for n in $(olsrd_list_configured_interfaces $OLSRD); do + procd_add_reload_interface_trigger $n /etc/init.d/$OLSRD reload + done +} diff --git a/net/olsrd/files/olsrd6.config b/net/olsrd/files/olsrd6.config new file mode 100644 index 0000000000000..52a9b21cd73aa --- /dev/null +++ b/net/olsrd/files/olsrd6.config @@ -0,0 +1,16 @@ +config olsrd + # uncomment the following line to use a custom config file instead: + #option config_file '/etc/olsrd6.conf' + +config LoadPlugin + option library 'olsrd_txtinfo.so.1.1' + option accept '::' + option port '2007' + +config Interface + list interface 'wlan' + +config procd procd + option respawn_threshold '3600' + option respawn_timeout '15' + option respawn_retry '0' diff --git a/net/olsrd/files/olsrd6.init b/net/olsrd/files/olsrd6.init new file mode 100644 index 0000000000000..1b4560f5e119b --- /dev/null +++ b/net/olsrd/files/olsrd6.init @@ -0,0 +1,79 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2008-2013 OpenWrt.org + +. $IPKG_INSTROOT/lib/functions/olsrd.sh + +START=65 +USE_PROCD=1 +BIN=/usr/sbin/olsrd +OLSRD=olsrd6 +CONF=/var/etc/$OLSRD.conf +PID=/var/run/olsrd6.pid + +wait_for_network() +{ + ubus -t 15 wait_for network.interface.$1 2>/dev/null +} + +wait_for_wireless() +{ + local count=0 + ubus -t 15 wait_for network.wireless 2>/dev/null + while [ $count -lt 30 ]; do + if [ "$(ubus call network.wireless status | jsonfilter -e '@[*]["pending"]' | grep true | wc -l)" == "0" ]; then + break + fi + count=$((count+1)) + sleep 1 + done +} + +boot() +{ + config_load network + config_foreach wait_for_network interface + wait_for_wireless + rc_procd start_service +} + +start_service() { + olsrd_generate_config $OLSRD + + procd_open_instance + + config_load olsrd6 + local _respawn_threshold + local _respawn_timeout + local _respawn_retry + + config_get _respawn_threshold procd respawn_threshold 3600 + config_get _respawn_timeout procd respawn_timeout 15 + config_get _respawn_retry procd respawn_retry 0 + + procd_set_param command "$BIN" + procd_append_param command -f ${CONF} + procd_append_param command -nofork + procd_append_param command -pidfile ${PID} + + # restart if olsrd dies + procd_set_param respawn $_respawn_threshold $_respawn_timeout $_respawn_retry + + # automatically restart olsrd if generated cfg has changed + procd_set_param file $CONF + + procd_set_param pidfile $PID + + procd_close_instance + + olsrd_setup_smartgw_rules +} + +service_triggers() { + # reload if config changed via uci + procd_add_reload_trigger "olsrd6" + + # restart on ifup interface events + for n in $(olsrd_list_configured_interfaces $OLSRD); do + procd_add_reload_interface_trigger $n /etc/init.d/$OLSRD reload + done +} diff --git a/net/olsrd/files/olsrd_secure_key b/net/olsrd/files/olsrd_secure_key new file mode 100644 index 0000000000000..2b3b07661cbd1 --- /dev/null +++ b/net/olsrd/files/olsrd_secure_key @@ -0,0 +1 @@ +1234567890123456 diff --git a/net/olsrd/patches/102-olsrd-prevent-storm-patches.patch b/net/olsrd/patches/102-olsrd-prevent-storm-patches.patch new file mode 100644 index 0000000000000..69d5952162bc6 --- /dev/null +++ b/net/olsrd/patches/102-olsrd-prevent-storm-patches.patch @@ -0,0 +1,83 @@ +From 4dabd94d598dd893aaaffbd71c315923c8827a14 Mon Sep 17 00:00:00 2001 +From: Nick Hainke +Date: Wed, 22 Jun 2022 14:08:04 +0200 +Subject: [PATCH] olsrd: prevent storm patches + +As described in the PR: + + Limit the positive sequence number difference which is considered valid, + and prevent network storms. + Source: https://github.com/aredn/aredn_packages/pull/5 + +Signed-off-by: Nick Hainke +--- + src/duplicate_set.c | 16 ++++++++-------- + src/duplicate_set.h | 5 +++-- + 2 files changed, 11 insertions(+), 10 deletions(-) + +--- a/src/duplicate_set.c ++++ b/src/duplicate_set.c +@@ -70,7 +70,7 @@ void olsr_cleanup_duplicates(union olsr_ + + entry = (struct dup_entry *)olsrd_avl_find(&duplicate_set, orig); + if (entry != NULL) { +- entry->too_low_counter = DUP_MAX_TOO_LOW - 2; ++ entry->out_of_bounds_counter = DUP_MAX_OUT_OF_BOUNDS - 2; + } + } + +@@ -82,7 +82,7 @@ olsr_create_duplicate_entry(void *ip, ui + if (entry != NULL) { + memcpy(&entry->ip, ip, olsr_cnf->ip_version == AF_INET ? sizeof(entry->ip.v4) : sizeof(entry->ip.v6)); + entry->seqnr = seqnr; +- entry->too_low_counter = 0; ++ entry->out_of_bounds_counter = 0; + entry->olsrd_avl.key = &entry->ip; + entry->array = 0; + } +@@ -160,12 +160,12 @@ olsr_message_is_duplicate(union olsr_mes + } + + diff = olsr_seqno_diff(seqnr, entry->seqnr); +- if (diff < -31) { +- entry->too_low_counter++; ++ if (diff < -31 || diff > DUP_SEQNR_DIFF_HIGH_LIMIT) { ++ entry->out_of_bounds_counter++; + +- // client did restart with a lower number ? +- if (entry->too_low_counter > DUP_MAX_TOO_LOW) { +- entry->too_low_counter = 0; ++ // client did restart with a too low or too high number ? ++ if (entry->out_of_bounds_counter > DUP_MAX_OUT_OF_BOUNDS) { ++ entry->out_of_bounds_counter = 0; + entry->seqnr = seqnr; + entry->array = 1; + return false; /* start with a new sequence number, so NO duplicate */ +@@ -174,7 +174,7 @@ olsr_message_is_duplicate(union olsr_mes + return true; /* duplicate ! */ + } + +- entry->too_low_counter = 0; ++ entry->out_of_bounds_counter = 0; + if (diff <= 0) { + uint32_t bitmask = 1u << ((uint32_t) (-diff)); + +--- a/src/duplicate_set.h ++++ b/src/duplicate_set.h +@@ -54,13 +54,14 @@ + #define DUPLICATE_CLEANUP_INTERVAL 15000 + #define DUPLICATE_CLEANUP_JITTER 25 + #define DUPLICATE_VTIME 120000 +-#define DUP_MAX_TOO_LOW 16 ++#define DUP_MAX_OUT_OF_BOUNDS 16 ++#define DUP_SEQNR_DIFF_HIGH_LIMIT 0x2000 + + struct dup_entry { + struct olsrd_avl_node olsrd_avl; + union olsr_ip_addr ip; + uint16_t seqnr; +- uint16_t too_low_counter; ++ uint16_t out_of_bounds_counter; + uint32_t array; + uint32_t valid_until; + }; diff --git a/net/olsrd/patches/103-make-set-plugin-SONAME-to-the-installed-filename.patch b/net/olsrd/patches/103-make-set-plugin-SONAME-to-the-installed-filename.patch new file mode 100644 index 0000000000000..1ad1127af8271 --- /dev/null +++ b/net/olsrd/patches/103-make-set-plugin-SONAME-to-the-installed-filename.patch @@ -0,0 +1,35 @@ +From 11bf26faef5ee6d62a4641407a2f96a97b59db07 Mon Sep 17 00:00:00 2001 +From: Josef Schlehofer +Date: Thu, 6 Aug 2026 09:56:10 +0200 +Subject: [PATCH] make: set plugin SONAME to the installed filename + +The plugins are linked with SONAME lib$(PLUGIN_NAME).so, but they are +installed as $(PLUGIN_NAME).so.$(PLUGIN_VER) and loaded via dlopen() +using that filename. A library whose SONAME does not match any +installed filename confuses tooling which verifies that a symlink +named after the SONAME exists, for example the OpenWrt CI runtime +tests: + + Library /usr/lib/olsrd_arprefresh.so.0.1 has SONAME + 'libolsrd_arprefresh.so' but no corresponding symlink was found + +Use the full installed filename as SONAME instead. This has no +functional effect on olsrd itself, since the plugins are dlopen()ed +by path and never linked against. + +Signed-off-by: Josef Schlehofer +--- + make/Makefile.linux | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/make/Makefile.linux ++++ b/make/Makefile.linux +@@ -73,7 +73,7 @@ LIBS += -lrt + # CPPFLAGS += -Dlinux -DLINUX_NETLINK_ROUTING -DLINUX_NL80211 + # LIBS += -lnl + +-PLUGIN_SONAME ?= lib$(PLUGIN_NAME).so ++PLUGIN_SONAME ?= $(PLUGIN_FULLNAME) + PLUGIN_FULLNAME ?= $(PLUGIN_NAME).so.$(PLUGIN_VER) + INSTALL_LIB = install -D -m 755 $(PLUGIN_FULLNAME) $(LIBDIR)/$(PLUGIN_FULLNAME); \ + $(LDCONFIG) -n $(LIBDIR) diff --git a/net/olsrd/patches/600-add-ubus-support.patch b/net/olsrd/patches/600-add-ubus-support.patch new file mode 100644 index 0000000000000..f0bd91bb1776f --- /dev/null +++ b/net/olsrd/patches/600-add-ubus-support.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nick Hainke +Date: Sat, 15 Jan 2022 08:37:37 +0100 +Subject: [PATCH] add ubus ipc integration + +--- + +--- a/src/scheduler.c ++++ b/src/scheduler.c +@@ -59,6 +59,8 @@ + #include + #include + ++#include "ubus.h" ++ + #ifdef __MACH__ + #include "mach/clock_gettime.h" + #endif +@@ -363,6 +365,8 @@ poll_sockets(void) + } + OLSR_FOR_ALL_SOCKETS_END(entry); + ++ hfd = olsrd_ubus_add_read_sock(&ibits, hfd); ++ + /* Running select on the FD set */ + do { + n = olsr_select(hfd, fdsets & SP_PR_READ ? &ibits : NULL, fdsets & SP_PR_WRITE ? &obits : NULL, NULL, &tvp); +@@ -395,6 +399,7 @@ poll_sockets(void) + } + } + OLSR_FOR_ALL_SOCKETS_END(entry); ++ olsrd_ubus_receive(&ibits); + } + + static void +--- a/src/main.c ++++ b/src/main.c +@@ -74,6 +74,8 @@ + #include "lock_file.h" + #include "cli.h" + ++#include "ubus.h" ++ + #if defined(__GLIBC__) && defined(__linux__) && !defined(__ANDROID__) && !defined(__UCLIBC__) + #define OLSR_HAVE_EXECINFO_H + #endif +@@ -771,6 +773,9 @@ int main(int argc, char *argv[]) { + signal(SIGUSR2, SIG_IGN); + #endif /* _WIN32 */ + ++ /* Adding ubus */ ++ olsrd_add_ubus(); ++ + /* Starting scheduler */ + olsr_scheduler(); + +--- a/Makefile.inc ++++ b/Makefile.inc +@@ -252,7 +252,7 @@ else + ifeq ($(OS),win32) + LDFLAGS += -Wl,-export-all-symbols + else +- LDFLAGS += -Wl,-export-dynamic ++ LDFLAGS += -Wl,-export-dynamic,-lubus,-lubox + endif + ifeq ($(NORPATH),0) + LDFLAGS += -Wl,-rpath,$(LIBDIR) diff --git a/net/olsrd/src/src/ubus.c b/net/olsrd/src/src/ubus.c new file mode 100644 index 0000000000000..88caed13c418f --- /dev/null +++ b/net/olsrd/src/src/ubus.c @@ -0,0 +1,230 @@ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "defs.h" +#include "ifnet.h" +#include "interfaces.h" +#include "link_set.h" +#include "log.h" +#include "olsr.h" +#include "olsr_cfg.h" + +#include "ubus.h" + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +// Shared state maintained throughout calls to handle ubus messages. +static struct ubus_context *shared_ctx; + +enum { INTERFACE_IFNAME, INTERFACE_LQM, __INTERFACE_MAX }; + +static const struct blobmsg_policy interface_policy[__INTERFACE_MAX] = { + [INTERFACE_IFNAME] = {"ifname", BLOBMSG_TYPE_STRING}, + [INTERFACE_LQM] = {"lqm", BLOBMSG_TYPE_STRING}, +}; + +static int olsrd_ubus_add_interface(struct ubus_context *ctx_local, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, struct blob_attr *msg) { + struct blob_attr *tb[__INTERFACE_MAX]; + struct blob_buf b = {0}; + union olsr_ip_addr addr; + int ret; + char *ifname, *lqm; + + blobmsg_parse(interface_policy, __INTERFACE_MAX, tb, blob_data(msg), + blob_len(msg)); + + if (!tb[INTERFACE_IFNAME]) + return UBUS_STATUS_INVALID_ARGUMENT; + + ifname = blobmsg_get_string(tb[INTERFACE_IFNAME]); + + struct interface_olsr *tmp = if_ifwithname(ifname); + if (tmp != NULL) { + return UBUS_STATUS_PERMISSION_DENIED; + } + + struct olsr_if *temp; + for (temp = olsr_cnf->interfaces; temp != NULL; temp = temp->next) { + if (strcmp(temp->name, ifname) == 0) + return UBUS_STATUS_PERMISSION_DENIED; + } + + struct olsr_if *tmp_ifs = olsr_create_olsrif(ifname, false); + tmp_ifs->cnf = + olsr_malloc(sizeof(struct if_config_options), "Set default config"); + *tmp_ifs->cnf = *olsr_cnf->interface_defaults; + + if (tb[INTERFACE_LQM]) { // add interface lqm + lqm = blobmsg_get_string(tb[INTERFACE_LQM]); + memset(&addr, 0, sizeof(addr)); + + struct olsr_lq_mult *mult = malloc(sizeof(*mult)); + if (mult == NULL) { + olsr_syslog(OLSR_LOG_ERR, "Out of memory (LQ multiplier).\n"); + return UBUS_STATUS_UNKNOWN_ERROR; + } + + double lqm_value = atof(lqm); + mult->addr = addr; + mult->value = (uint32_t)(lqm_value * LINK_LOSS_MULTIPLIER); + mult->next = tmp_ifs->cnf->lq_mult; + tmp_ifs->cnf->lq_mult = mult; + tmp_ifs->cnf->orig_lq_mult_cnt++; + } + + blob_buf_init(&b, 0); + blobmsg_add_string(&b, "adding", ifname); + + ret = ubus_send_reply(ctx_local, req, b.head); + if (ret) + olsr_syslog(OLSR_LOG_ERR, "Failed to send reply: %s\n", ubus_strerror(ret)); + + blob_buf_free(&b); + + return ret; +} + +static int olsrd_ubus_del_interface(struct ubus_context *ctx_local, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, struct blob_attr *msg) { + struct blob_attr *tb[__INTERFACE_MAX]; + struct blob_buf b = {0}; + int ret; + char *ifname; + struct olsr_if *tmp_if, *del_if; + + blobmsg_parse(interface_policy, __INTERFACE_MAX, tb, blob_data(msg), + blob_len(msg)); + + if (!tb[INTERFACE_IFNAME]) + return UBUS_STATUS_INVALID_ARGUMENT; + + ifname = blobmsg_get_string(tb[INTERFACE_IFNAME]); + + struct interface_olsr *tmp = if_ifwithname(ifname); + + if (tmp != NULL) { + + struct olsr_if *temp = olsr_cnf->interfaces, *prev; + if (temp != NULL && (strcmp(temp->name, ifname) == 0)) { + olsr_cnf->interfaces = temp->next; + olsr_remove_interface(temp); + goto send_reply; + } + + while (temp != NULL && (strcmp(temp->name, ifname) != 0)) { + prev = temp; + temp = temp->next; + } + + if (temp == NULL) { + goto send_reply; + } + + prev->next = temp->next; + olsr_remove_interface(temp); + } else { + return UBUS_STATUS_PERMISSION_DENIED; + } + +send_reply: + + blob_buf_init(&b, 0); + blobmsg_add_string(&b, "deleting", ifname); + + ret = ubus_send_reply(ctx_local, req, b.head); + if (ret) + olsr_syslog(OLSR_LOG_ERR, "Failed to send reply: %s\n", ubus_strerror(ret)); + + blob_buf_free(&b); + + return ret; +} + +// List of functions we expose via the ubus bus. +static const struct ubus_method olsrd_methods[] = { + UBUS_METHOD("add_interface", olsrd_ubus_add_interface, interface_policy), + UBUS_METHOD("del_interface", olsrd_ubus_del_interface, interface_policy), +}; + +// Definition of the ubus object type. +static struct ubus_object_type olsrd_object_type = + UBUS_OBJECT_TYPE("olsrd", olsrd_methods); + +// Object we announce via the ubus bus. +static struct ubus_object olsrd_object = { + .name = "olsrd", + .type = &olsrd_object_type, + .methods = olsrd_methods, + .n_methods = ARRAY_SIZE(olsrd_methods), +}; + +// Registers handlers for olsrd methods in the global ubus context. +static bool ubus_init_object() { + int ret; + + ret = ubus_add_object(shared_ctx, &olsrd_object); + if (ret) { + olsr_syslog(OLSR_LOG_ERR, "Failed to add object: %s\n", ubus_strerror(ret)); + return false; + } + + return true; +} + +// Initializes the global ubus context, connecting to the bus to be able to +// receive and send messages. +static bool olsrd_ubus_init(void) { + if (shared_ctx) + return true; + + shared_ctx = ubus_connect(NULL); + if (!shared_ctx) + return false; + + return true; +} + +void olsrd_ubus_receive(fd_set *readfds) { + if (!shared_ctx) + return; + if (FD_ISSET(shared_ctx->sock.fd, readfds)) + ubus_handle_event(shared_ctx); +} + +int olsrd_ubus_add_read_sock(fd_set *readfds, int maxfd) { + if (!shared_ctx) + return maxfd; + + FD_SET(shared_ctx->sock.fd, readfds); + return MAX(maxfd, shared_ctx->sock.fd + 1); +} + +bool olsrd_add_ubus() { + if (!olsrd_ubus_init()) { + olsr_syslog(OLSR_LOG_ERR, "Failed to initialize ubus!\n"); + return false; + } + if (!ubus_init_object()) { + olsr_syslog(OLSR_LOG_ERR, "Failed to add objects to ubus!\n"); + return false; + } + return true; +} diff --git a/net/olsrd/src/src/ubus.h b/net/olsrd/src/src/ubus.h new file mode 100644 index 0000000000000..10bd59f729351 --- /dev/null +++ b/net/olsrd/src/src/ubus.h @@ -0,0 +1,40 @@ +/* + IPC integration of olsrd with OpenWrt. + + The ubus interface offers following functions: + - add_inteface '{"ifname":"wg_51820", "lqm": "0.5"}' + - del_inteface '{"ifname":"wg_51820"}' +*/ + +#include +#include + +/** + * Initialize ubus interface. + * + * Connect to the ubus daemon and expose the ubus functions. + * + * @return if initializing ubus was successful + */ +bool olsrd_add_ubus(); + +/** + * Add ubus socket to given filedescriptor set. + * + * We need to check repeatedly if the ubus socket has something to read. + * The functions allows to add the ubus socket to the normal while(1)-loop of + * olsrd. + * + * @param readfs: the filedescriptor set + * @param maxfd: the current maximum file descriptor + * @return the maximum file descriptor + */ +int olsrd_ubus_add_read_sock(fd_set *readfds, int maxfd); + +/** + * Check and process ubus socket. + * + * If the ubus-socket signals that data is available, the ubus_handle_event is + * called. + */ +void olsrd_ubus_receive(fd_set *readfds); diff --git a/net/olsrd/test-version.sh b/net/olsrd/test-version.sh new file mode 100644 index 0000000000000..581b49176d728 --- /dev/null +++ b/net/olsrd/test-version.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# shellcheck shell=busybox + +case "$PKG_NAME" in +olsrd) + # olsrd leaves through olsr_exit(), which ends the process with + # raise(SIGTERM) even for -v, so the shell reports "Terminated" + # after the banner. The pipeline status comes from grep, so the + # check is unaffected. + olsrd -v 2>&1 | grep -F "$PKG_VERSION" + ;; + +olsrd-mod-*) + # Plugins are libraries and do not provide version information + exit 0 + ;; + +olsrd-utils) + # Shell scripts only, no version information provided + exit 0 + ;; + +*) + echo "Untested package: $PKG_NAME" >&2 + exit 1 + ;; +esac