diff --git a/net/mini_snmpd/Makefile b/net/mini_snmpd/Makefile new file mode 100644 index 000000000..9945b8fa0 --- /dev/null +++ b/net/mini_snmpd/Makefile @@ -0,0 +1,66 @@ +# +# Copyright (C) 2009-2016 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=mini_snmpd +PKG_VERSION:=1.4-rc1 +PKG_RELEASE:=1 +PKG_MAINTAINER:=Luke McKee +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:=COPYING + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/troglobit/mini-snmpd.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=203d92e60ed09466d6676c6ad20ad6cb2ce08a5d +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz + +PKG_FIXUP:=autoreconf +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 +# As warned by upstream maintainer and binutils +# however compiler warnings can be ignored until next binutils release +# https://github.com/wongsyrone/openwrt-1/issues/67 +# PKG_SSP:=0 +# PKG_RELRO:=0 + +include $(INCLUDE_DIR)/package.mk + +define Package/mini_snmpd + SECTION:=net + CATEGORY:=Network + TITLE:=A tiny SNMP server for embedded systems + URL:=http://troglobit.github.io/mini-snmpd.html +# uncomment if you just want the binary, not the init script +# openwrt requires init script runtime dependencies be defined for make menuconfig +# (e.g busybox sysntpd) + DEPENDS:=+jsonfilter +ubus +procd +ubox +endef + +CONFIGURE_ARGS+= \ + $(if $(CONFIG_IPV6),,--disable-ipv6) + +# Configure weirdness - Disabled by default, explicitately disabling turns feature on! +# --disable-debug \ +# --disable-demo - Upstream Github Issue #4 Fixed 20160707 + +define Package/mini_snmpd/install + $(INSTALL_DIR) $(1)/usr/bin + $(CP) $(PKG_INSTALL_DIR)/usr/bin/mini_snmpd $(1)/usr/bin/ + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/mini_snmpd.config $(1)/etc/config/mini_snmpd + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/mini_snmpd.init $(1)/etc/init.d/mini_snmpd +endef + +define Package/mini_snmpd/conffiles +/etc/config/mini_snmpd +endef + +$(eval $(call BuildPackage,mini_snmpd)) diff --git a/net/mini_snmpd/files/mini_snmpd.config b/net/mini_snmpd/files/mini_snmpd.config new file mode 100644 index 000000000..c06f7b190 --- /dev/null +++ b/net/mini_snmpd/files/mini_snmpd.config @@ -0,0 +1,26 @@ +# you may add more than the 'default' mini_snmpd instances provided they all bind to different ports/interfaces +# to get around max 4 interface or mountpoint limit constrained by mini_snmpd's mib +config mini_snmpd 'default' + option enabled 1 + option ipv6 0 + # Verbose flag given to mini_snmpd, extra verbose is only possible with compile time config flags + option debug 0 + # Turn on community authentication (snmp agent must use community name) + option auth 0 + option community 'public' + option contact 'OpenWRT router ' + option location 'Undisclosed' + # to listen on all interfaces you need to set option listen_interface '' + option listen_interface 'lan' + #option udp_port '161' + #option tcp_port '161' + #option vendor_oid '' + option mib_timeout 1 + # enable basic disk usage statistics on specified mountpoint + list disks '/overlay' + list disks '/tmp' + # enable basic network statistics on specified interface + # 4 interfaces maximum per instance, as named in /etc/config/network and luci + # not physical device names + list interfaces 'lan' + list interfaces 'wan' diff --git a/net/mini_snmpd/files/mini_snmpd.init b/net/mini_snmpd/files/mini_snmpd.init new file mode 100644 index 000000000..442e350af --- /dev/null +++ b/net/mini_snmpd/files/mini_snmpd.init @@ -0,0 +1,240 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2009-2016 OpenWrt.org +# Copyright (C) 2016 Luke McKee +# Procd init script reference: http://wiki.prplfoundation.org/wiki/Procd_reference + +START=98 +USE_PROCD=1 +PROG=/usr/bin/mini_snmpd +NAME=mini_snmpd + +_log() { + logger -p daemon.info -t mini_snmpd "$@" +} + +_err() { + logger -p daemon.err -t mini_snmpd "$@" +} + + +# mini_snmpd 1.3+ now starts later in the game. Expects filesystems monitored to be already mounted, or wont pass args to mini_snmpd +# and at least configuration entry for network physical interface defined in /etc/config/network +# It handles network interfaces not yet present (e.g. ppp) but will statfs() the root/wrong filesystem if device not mounted +# Tip: complex scripts run faster without in openwrt if you stop busybox forking and searching for applets. Faster bootups +# CONFIG_BUSYBOX_CONFIG_FEATURE_SH_NOFORK +# CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS +# BUSYBOX_CONFIG_ASH_OPTIMIZE_FOR_SIZE [=n] +# CONFIG_BUSYBOX_CONFIG_ASH_CMDCMD + +mini_snmpd_validation="enabled:bool:0 \ + ipv6:bool:0 \ + debug:bool:0 \ + auth:bool:1 \ + community:rangelength(1,32):public \ + contact:maxlength(255) \ + location:maxlength(255) \ + listen_interface:uciname \ + udp_port:port \ + tcp_port:port \ + vendor_oid:string \ + mib_timeout:and(min(1),uinteger) \ + disks:list(directory) \ + interfaces:list(uciname) \ + respawn_threshold:uinteger respawn_timeout:uinteger respawn_retry:uinteger" +# busybox ash has no array variable support, when put validations in a string be careful to have no spaces in each validate constraint +# this makes it very difficult to use the 'or(uciname, "all")' test, so listen_interface '' or undefined now meands bind to "all". +# this is the sarafice you have to make to avoid typing it all in twice in this script so we can give feedback to user on what's misconfigered +# in syslog + +append_disk() { + local disk="$1" disk_count + [ -z $disk_count ] && disk_count=0 + if grep -qF "$disk" /proc/mounts ; then + # check the fileystem is mountpoint, and directory search permissions available for statfs() + # presence as a directory -d test done is already done by uci_validate_section() + [ -x "$disk" ] || { + _err "$cfg: mountpoint $disk for snmp monitoring EACCES error. Check permissions, ignoring" + return 1 + } + if [ $disk_count -lt 4 ] ; then + append disks_arg "$disk" ',' + disk_count=$((disk_count++)) + else + _err "$cfg: more than 4 mountpoints defined in uci. Disc $disk ignored." + fi + else + _err "$cfg: mountpoint $disk for snmp monitoring not mounted, ignoring." + fi +} + +append_interface() { + local name="$1" netdev netdev_count + [ -z $netdev_count ] && netdev_count=0 + # for the purposes of snmp monitoring it doesn't need to be up, it just needs to exist in /proc/net/dev + netdev=$(ubus -S call network.interface dump|jsonfilter -e "@.interface[@.interface=\"$name\"].device") + if [ -n "$netdev" ] && grep -qF "$netdev" /proc/net/dev ]; then + [ $netdev_count -ge 4 ] && { + _err "$cfg: too many network interfaces configured, ignoring $name" + return + } + netdev_count=$((netdev_count++)) + if [ -n "$interfaces_arg" ]; then + append interfaces_arg "$netdev" ',' + else + append interfaces_arg "$netdev" + fi + else + _err "$cfg: physical interface for network $name not found in uci or kernel so not monitoring" + fi +} + +append_arg() { + local var="$2" + local opt="$1" + [ -n "$var" ] && procd_append_param command $opt "$var" +} + +watch_interfaces() { + local cfg="$1" + local enabled listen_interface # listen_interface_up + config_get_bool enabled "$cfg" "enabled" '1' + [ "$enabled" -gt 0 ] || return 0 + config_get listen_interface "$cfg" listen_interface + # listen_interface_up=$(ubus -S call network.interface dump | jsonfilter -e "@.interface[@.interface=\"$listen_interface\"].up") + # If the interface is up & instance is running we'll watch at the instance level and only restart that instance if it's bound interface changes + # Regardless of ubus knowing about an interface (in the case it's not yet configured) + [ -n "$listen_interface" ] && trigger_interfaces="${listen_interface} ${trigger_interfaces} " +} + +validate_mini_snmpd_section() { + # validate a mini_snmpd instance in uci config file mini_snmpd + # http://luci.subsignal.org/trac/wiki/Documentation/Datatypes ubox/validate/validate.c + uci_validate_section mini_snmpd mini_snmpd "${1}" $mini_snmpd_validation +} + + +service_triggers() { + config_load 'mini_snmpd' + procd_open_trigger + procd_add_config_trigger "config.change" "mini_snmpd" /etc/init.d/mini_snmpd reload + config_foreach watch_interfaces 'mini_snmpd' + # this only watches interfaces for which there is no running instance due to interface down / not in ubus + # hence start not reload, this trigger will not affect running instances as another start will not change their procd command arguments + # or stop the already running process + [ -n "$trigger_interfaces" ] & { + for n in $trigger_interfaces ; do + procd_add_interface_trigger "interface.*" $n /etc/init.d/mini_snmpd start + done + } + procd_close_trigger + procd_add_validation validate_mini_snmpd_section +} + + +start_instance() { + local cfg validation_failed validation_err disks_arg interfaces_arg + cfg="$1" + #uci_validate_section should unset undefined variables from other instances + #however defining uci variables as local will scope them to this instance + #"local variables are also visible to functions called by the parent function" so it's good practice + local enabled ipv6 debug auth community contact location listen_interface \ + udp_port tcp_port vendor_oid mib_timeout + local disks="" interfaces="" + validate_mini_snmpd_section "$cfg" 2>/dev/null || validation_failed=1 + [ "$enabled" == 1 ] || { + _log "instance:$cfg disabled not starting" + return 1 + } + + local listen_interface_json listen_interface_ip listen_interface_device listen_interface_up ubus_exit ubus_err + [ -n "$listen_interface" ] && { + listen_interface_json=$(ubus -S call network.interface.$listen_interface status) + ubus_exit=$? + [ $ubus_exit = 4 ] && { + _err "$cfg: listen_interface $listen_interface not properly configured in ubus network.interface.* not starting this instance " + return 1 + } + [ $ubus_exit = 255 -a -z "$listen_interface_json" ] && { + _log "$cfg: ubusd not yet up, will try to start mini_snmpd shorlty when procd detects $listen_interface comes up" + return 1 + } + [ -z "$listen_interface_json" ] && { + ubus_err=`ubus call network.interface.$listen_interface status 2>&1 >/dev/null` + _err "$cfg: unknown ubus error. exit: $ubus_exit errormsg: $ubus_err " + return 1 + } + listen_interface_up=$(jsonfilter -s "$listen_interface_json" -e '@.up') + if [ "$ipv6" = 1 ]; then + listen_interface_ip=$(jsonfilter -s "$listen_interface_json" -e "@['ipv6-address'][0].address") + else + listen_interface_ip=$(jsonfilter -s "$listen_interface_json" -e "@['ipv4-address'][0].address") + fi + [ -n "$listen_interface_ip" -a "$listen_interface_up" = 'true' ] || { + _log "$cfg:listen interface $listen_interface not up yet / not configured properly" + _log "$cfg:procd will try again when interface state changes" + return 1 + } + listen_interface_device=$(jsonfilter -s "$listen_interface_json" -e '@.l3_device') + } + + [ $validation_failed ] && { + _err "validation of $NAME configuration for $cfg instance failed, all tests should be within constraints" + _err "please edit the configuration values below using [l]uci " + validation_err=`/sbin/validate_data mini_snmpd mini_snmpd "$cfg" $mini_snmpd_validation 2>&1 | sed '/with\ false$/!d;s/validates\ as\ /needs\ to\ be\ /;s/with\ false//' ` + _err "${validation_err}" + return 1 + } + config_list_foreach "$cfg" 'disks' append_disk + config_list_foreach "$cfg" 'interfaces' append_interface + # test if variables are unset or zero length + [ -z "${disks_arg:+1}" -a -z "${interfaces_arg:+1}" ] && { + _err "$cfg: you haven't sucessfully configured any mountpoints or disks for this instance, not starting" + return 1 + } + + procd_open_instance + + procd_set_param command "$PROG" -n + procd_set_param stdout "1" + procd_set_param stderr "1" + # don't the like default respawn values? you can override through uci. + # vars left as global so you only need to do it in the first mini_snmpd instance + procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-10} ${respawn_retry:-1} + # this monitors ubus changes + [ -n "$listen_interface" ] && { + #procd_open_trigger + #procd_add_interface_trigger "interface.*" $listen_interface /etc/init.d/mini_snmpd reload + #procd_close_trigger + procd_add_reload_interface_trigger $listen_interface #or use shorthand of above + } + # this re-starts the daemon if a properly configured network interface is changed whilst it is already running + # igmpproxy has this as well as "procd_set_param netdev" + + append_arg "-c" "$community" + append_arg "-L" "${location}" + append_arg "-C" "${contact}" + append_arg "-p" $udp_port + append_arg "-P" $tcp_port + append_arg "-V" "${vendor_oid}" + append_arg "-t" $mib_timeout + + [ "$ipv6" = 1 ] && procd_append_param command "-6" + [ "$debug" = 1 ] && procd_append_param command "-v" + # uci_validate_section() aka /sbin/validate_data can only cast default values not defined in /etc/config/* to string + # e.g. ="1" however it sets bools defined in /etc/config/* to =1 / =0 + [ "$auth" = 1 -o "$auth" = "1" ] && procd_append_param command "-a" + [ -n "$disks_arg" ] && procd_append_param command "-d $disks_arg" + [ -n "$interfaces_arg" ] && procd_append_param command "-i $interfaces_arg" + [ -n "$listen_interface_device" ] && { + procd_append_param command "-I" "$listen_interface_device" + # and this monitors the hardware device for changes outside of ubus - just a guess + procd_set_param netdev $listen_interface_device + } + procd_close_instance +} + +start_service() { + config_load 'mini_snmpd' + config_foreach start_instance 'mini_snmpd' +} +