From 7e435e0681fdc8cd6ab68c19ea5005f344eae710 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Thu, 6 Aug 2026 10:08:02 +0200 Subject: [PATCH 1/7] olsrd: add new package olsrd is the olsr.org implementation of the Optimized Link State Routing protocol, together with its plugins packaged as olsrd-mod-* subpackages. Moved from the openwrt/routing feed, as discussed in https://github.com/openwrt/routing/issues/184. Signed-off-by: Josef Schlehofer Co-authored-by: Claude Fable 5 --- net/olsrd/Makefile | 332 +++++++ net/olsrd/files/olsrd-neigh.sh | 109 +++ net/olsrd/files/olsrd.config | 29 + net/olsrd/files/olsrd.pud.position.conf | 51 ++ net/olsrd/files/olsrd.sgw.speed.conf | 14 + net/olsrd/files/olsrd.sh | 852 ++++++++++++++++++ net/olsrd/files/olsrd4.init | 79 ++ net/olsrd/files/olsrd6.config | 16 + net/olsrd/files/olsrd6.init | 79 ++ net/olsrd/files/olsrd_secure_key | 1 + .../102-olsrd-prevent-storm-patches.patch | 83 ++ ...gin-SONAME-to-the-installed-filename.patch | 35 + net/olsrd/patches/600-add-ubus-support.patch | 67 ++ net/olsrd/src/src/ubus.c | 229 +++++ net/olsrd/src/src/ubus.h | 40 + net/olsrd/test-version.sh | 27 + 16 files changed, 2043 insertions(+) create mode 100644 net/olsrd/Makefile create mode 100755 net/olsrd/files/olsrd-neigh.sh create mode 100644 net/olsrd/files/olsrd.config create mode 100644 net/olsrd/files/olsrd.pud.position.conf create mode 100644 net/olsrd/files/olsrd.sgw.speed.conf create mode 100644 net/olsrd/files/olsrd.sh create mode 100644 net/olsrd/files/olsrd4.init create mode 100644 net/olsrd/files/olsrd6.config create mode 100644 net/olsrd/files/olsrd6.init create mode 100644 net/olsrd/files/olsrd_secure_key create mode 100644 net/olsrd/patches/102-olsrd-prevent-storm-patches.patch create mode 100644 net/olsrd/patches/103-make-set-plugin-SONAME-to-the-installed-filename.patch create mode 100644 net/olsrd/patches/600-add-ubus-support.patch create mode 100644 net/olsrd/src/src/ubus.c create mode 100644 net/olsrd/src/src/ubus.h create mode 100644 net/olsrd/test-version.sh diff --git a/net/olsrd/Makefile b/net/olsrd/Makefile new file mode 100644 index 0000000000000..524262075a041 --- /dev/null +++ b/net/olsrd/Makefile @@ -0,0 +1,332 @@ +# 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 + 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 \ + 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..65a32a6b46362 --- /dev/null +++ b/net/olsrd/files/olsrd-neigh.sh @@ -0,0 +1,109 @@ +#!/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" + + # 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) + 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..a20e96728aff1 --- /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..37c2dbf99d1c1 --- /dev/null +++ b/net/olsrd/src/src/ubus.c @@ -0,0 +1,229 @@ +#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); + 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..06024ba79253f --- /dev/null +++ b/net/olsrd/test-version.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# shellcheck shell=busybox + +case "$PKG_NAME" in +olsrd) + # The version of olsrd is derived from the source date and git + # hash, which the binary does not report. Check that the binary + # starts and prints its version banner instead. + olsrd -v 2>&1 | grep -F "olsr.org" + ;; + +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 From c8eebee76c650fb0adcff6f7243aeee3778fda29 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Thu, 6 Aug 2026 12:39:34 +0200 Subject: [PATCH 2/7] olsrd: fix respawn_threshold lookup in the IPv6 init script The UCI option is spelled respawn_threshold, as documented in files/olsrd6.config and as read by files/olsrd4.init, but the IPv6 init script looks up _respawn_threshold. The lookup never matches, so a user-configured value is silently ignored and the built-in default of 3600 is always used. Reported-by: openwrt-ai[bot] Signed-off-by: Josef Schlehofer Co-authored-by: Claude Fable 5 --- net/olsrd/files/olsrd6.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/olsrd/files/olsrd6.init b/net/olsrd/files/olsrd6.init index a20e96728aff1..1b4560f5e119b 100644 --- a/net/olsrd/files/olsrd6.init +++ b/net/olsrd/files/olsrd6.init @@ -46,7 +46,7 @@ start_service() { local _respawn_timeout local _respawn_retry - config_get _respawn_threshold procd _respawn_threshold 3600 + config_get _respawn_threshold procd respawn_threshold 3600 config_get _respawn_timeout procd respawn_timeout 15 config_get _respawn_retry procd respawn_retry 0 From 4d027dbe456040c5ad4d738f803d1859d4e4f2e3 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Thu, 6 Aug 2026 12:39:35 +0200 Subject: [PATCH 3/7] olsrd: add missing jshn dependency to olsrd-utils The only file shipped by olsrd-utils is olsrd-neigh.sh, which sources /usr/share/libubox/jshn.sh on its third line. That file belongs to the jshn package, which is not pulled in by the olsrd -> libubus -> libubox dependency chain, so on a minimal image the utility fails immediately with "not found". Reported-by: openwrt-ai[bot] Signed-off-by: Josef Schlehofer Co-authored-by: Claude Fable 5 --- net/olsrd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/olsrd/Makefile b/net/olsrd/Makefile index 524262075a041..8160b8a2b1e85 100644 --- a/net/olsrd/Makefile +++ b/net/olsrd/Makefile @@ -159,7 +159,7 @@ endef define Package/olsrd-utils $(call Package/olsrd/template) - DEPENDS:=olsrd + DEPENDS:=olsrd +jshn TITLE:=Utils for OLSRD endef From 1d68696ad7dfb96a7b2e4d06be0986484cbddd60 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Thu, 6 Aug 2026 12:39:35 +0200 Subject: [PATCH 4/7] olsrd: initialize the LQ multiplier list pointer in the ubus handler The ubus add_interface handler allocates a struct olsr_lq_mult with malloc() and assigns only ->addr and ->value, leaving ->next uninitialized before the node is published into cnf->lq_mult. olsrd walks that list with for (mult = cnf->lq_mult; mult != NULL; mult = mult->next) so the first traversal follows an indeterminate pointer. Chain the new node onto the existing list, which is what the configuration file parser does for LinkQualityMult in src/cfgparser/oparse.y. This also makes the orig_lq_mult_cnt++ on the next line consistent, since the entry really is prepended to the list instead of replacing it. Reported-by: openwrt-ai[bot] Signed-off-by: Josef Schlehofer Co-authored-by: Claude Fable 5 --- net/olsrd/src/src/ubus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/olsrd/src/src/ubus.c b/net/olsrd/src/src/ubus.c index 37c2dbf99d1c1..88caed13c418f 100644 --- a/net/olsrd/src/src/ubus.c +++ b/net/olsrd/src/src/ubus.c @@ -83,6 +83,7 @@ static int olsrd_ubus_add_interface(struct ubus_context *ctx_local, 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++; } From d47c0f4ffc95de0993cb73dd2cf5d98d0c3051f3 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Thu, 6 Aug 2026 12:39:35 +0200 Subject: [PATCH 5/7] olsrd: reject non-address input before eval in olsrd-neigh.sh olsrd-neigh.sh builds shell variable names from data announced by other nodes in the mesh and passes them through eval: eval IP_${ip//[.:]/_}="$hostname" eval re-parses the string after the quotes have been consumed by the first expansion pass, so a hostname of `x;reboot` announced by a remote node is executed as a command on every node that runs the utility. The values come from the nameservice plugin's hosts file and from the txtinfo plugin, both of which carry unauthenticated remote input. Discard entries containing anything other than the characters that can legitimately appear in an address or hostname before they reach eval, in both places. Reported-by: openwrt-ai[bot] Signed-off-by: Josef Schlehofer Co-authored-by: Claude Fable 5 --- net/olsrd/files/olsrd-neigh.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/olsrd/files/olsrd-neigh.sh b/net/olsrd/files/olsrd-neigh.sh index 65a32a6b46362..bf78f51a5b87c 100755 --- a/net/olsrd/files/olsrd-neigh.sh +++ b/net/olsrd/files/olsrd-neigh.sh @@ -50,6 +50,11 @@ read_hostnames() 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" @@ -89,6 +94,12 @@ for HOST in '127.0.0.1' '::1';do 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%:*}}" From e7f24a2ab5a2a5a08d18629b0cd6970587f64b51 Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Thu, 6 Aug 2026 14:21:13 +0200 Subject: [PATCH 6/7] olsrd: report the packaged version in the binary olsrd builds its version banner from the VERS make variable, which defaults to the upstream development version "pre-0.9.9", so `olsrd -v` never mentioned the version the package was built from. The source tarball carries no git metadata either, so the git hash in that string is always zero: olsr.org - pre-0.9.9-git_0000000-hash_5fd8976... Pass PKG_VERSION as VERS, the same way alfred and batctl already pass REVISION, so the banner identifies the packaged revision. This also lets test-version.sh check the real version instead of merely confirming that the binary starts. Signed-off-by: Josef Schlehofer Co-authored-by: Claude Fable 5 --- net/olsrd/Makefile | 1 + net/olsrd/test-version.sh | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/net/olsrd/Makefile b/net/olsrd/Makefile index 8160b8a2b1e85..f86f3d5936e16 100644 --- a/net/olsrd/Makefile +++ b/net/olsrd/Makefile @@ -177,6 +177,7 @@ endef MAKE_FLAGS+= \ NO_DEBUG_MESSAGES=1 \ + VERS="$(PKG_VERSION)" \ OS="linux" \ DESTDIR="$(PKG_INSTALL_DIR)" \ STRIP="true" \ diff --git a/net/olsrd/test-version.sh b/net/olsrd/test-version.sh index 06024ba79253f..629a619666955 100644 --- a/net/olsrd/test-version.sh +++ b/net/olsrd/test-version.sh @@ -4,10 +4,7 @@ case "$PKG_NAME" in olsrd) - # The version of olsrd is derived from the source date and git - # hash, which the binary does not report. Check that the binary - # starts and prints its version banner instead. - olsrd -v 2>&1 | grep -F "olsr.org" + olsrd -v 2>&1 | grep -F "$PKG_VERSION" ;; olsrd-mod-*) From 605206eac37ddbac1cf4eef439775463659a4e0b Mon Sep 17 00:00:00 2001 From: Josef Schlehofer Date: Mon, 10 Aug 2026 09:56:58 +0200 Subject: [PATCH 7/7] olsrd: record why the version check logs "Terminated" olsrd leaves through olsr_exit(), which ends the process with raise(SIGTERM) rather than returning from main, so the shell reports "Terminated" right after the version banner even for a plain `olsrd -v`. The pipeline status comes from grep, so the check itself is unaffected, but the line in the CI log looks like a failure to anyone reading it. Note it in the script so the next reader does not go hunting. Signed-off-by: Josef Schlehofer Co-authored-by: Claude Fable 5 --- net/olsrd/test-version.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/olsrd/test-version.sh b/net/olsrd/test-version.sh index 629a619666955..581b49176d728 100644 --- a/net/olsrd/test-version.sh +++ b/net/olsrd/test-version.sh @@ -4,6 +4,10 @@ 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" ;;