Repository
Munin (contrib)
Last change
2020-04-16
Graph Categories
Family
auto
Capabilities
Keywords
Language
Bash
License
GPL-3.0-or-later
Authors

freebox

Name

freebox - Plugin to monitor stats of a Freebox (Free.fr’s custom series of routers)

Magic Markers

#%# family=auto
#%# capabilities=autoconf

Caveat

Only tested on a Freebox v5 with an ADSL uplink.

Author

Olivier Mehani

Copyright (C) 2019 Olivier Mehani <shtrom+munin@ssji.net>

License

SPDX-License-Identifier: GPL-3.0-or-later

#!/bin/bash -u
# -*- sh -*-

: << =cut

=head1 NAME

freebox - Plugin to monitor stats of a Freebox (Free.fr's custom series of routers)

=head1 MAGIC MARKERS

  #%# family=auto
  #%# capabilities=autoconf

=head1 CAVEAT

Only tested on a Freebox v5 with an ADSL uplink.

=head1 AUTHOR

Olivier Mehani

Copyright (C) 2019 Olivier Mehani <shtrom+munin@ssji.net>

=head1 LICENSE

SPDX-License-Identifier: GPL-3.0-or-later

=cut

# shellcheck disable=SC1090
. "${MUNIN_LIBDIR}/plugins/plugin.sh"

if [ "${MUNIN_DEBUG:-0}" = 1 ]; then
    set -x
fi

fbx_info_url="http://mafreebox.free.fr/pub/fbx_info.txt"
#
# Example output (including stray whitespaces):
#

# ______________________________________________________________________
# 
#                       Etat de la Freebox                           
# ______________________________________________________________________
# 
# 
# Informations générales :
# ========================
# 
#   Modèle                         Freebox ADSL            
#   Version du firmware            1.5.26                  
#   Mode de connection             Dégroupé                
#   Temps depuis la mise en route  9 jours, 23 heures, 4 minutes
# 
# 
# Téléphone :
# ===========
# 
#   Etat                           Ok                      
#   Etat du combiné                Raccroché               
#   Sonnerie                       Inactive                
# 
# 
# Adsl :
# ======
# 
#   Etat                           Showtime                
#   Protocole                      ADSL2+                  
#   Mode                           Interleaved             
# 
#                          Descendant         Montant           
#                          --                 --                
#   Débit ATM              1913 kb/s          945 kb/s          
#   Marge de bruit         5.10 dB            5.60 dB           
#   Atténuation            50.00 dB           23.30 dB          
#   FEC                    425249             15503719          
#   CRC                    5489               0                 
#   HEC                    705                4296208           
# 
#  Journal de connexion adsl :
#  ---------------------------
# 
#   Date                         Etat             Débit (kb/s)    
#   --                           --               --              
#   21/05/2019 à 08:35:49        Connexion        1913 / 988      
#   21/05/2019 à 08:34:38        Déconnexion                      
#   20/05/2019 à 21:39:30        Connexion        1156 / 988      
#   20/05/2019 à 21:38:43        Déconnexion                      
#   20/05/2019 à 14:50:52        Connexion        1925 / 985      
#   20/05/2019 à 14:50:05        Déconnexion                      
#   20/05/2019 à 07:14:38        Connexion        206 / 833       
#   20/05/2019 à 07:14:10        Déconnexion                      
#   20/05/2019 à 07:13:50        Connexion        983 / 587       
#   20/05/2019 à 07:12:49        Déconnexion                      
#   20/05/2019 à 07:09:32        Connexion        1113 / 864      
#   20/05/2019 à 07:08:45        Déconnexion                      
#   20/05/2019 à 07:07:22        Connexion        1195 / 826      
#   20/05/2019 à 07:06:59        Déconnexion                      
#   20/05/2019 à 07:06:39        Connexion        1832 / 923      
#   20/05/2019 à 07:05:51        Déconnexion                      
#   20/05/2019 à 06:58:10        Connexion        1238 / 887      
#   20/05/2019 à 06:57:23        Déconnexion                      
#   20/05/2019 à 06:56:46        Connexion        1375 / 935      
#   20/05/2019 à 06:55:58        Déconnexion                      
#   20/05/2019 à 06:55:32        Connexion        1353 / 904      
#   20/05/2019 à 06:54:45        Déconnexion                      
#   20/05/2019 à 06:50:37        Connexion        1380 / 923      
#   20/05/2019 à 06:49:32        Déconnexion                      
# 
# 
# Wifi :
# ======
# 
#   Etat                           Ok                      
#   Modèle                         Ralink RT2880           
#   Canal                          1                       
#   État du réseau                 Activé                  
#   Ssid                           NetSSID 
#   Type de clé                    WPA (TKIP+AES)          
#   FreeWifi                       Désactivé               
#   FreeWifi Secure                Actif                   
# 
# 
# Réseau :
# ========
# 
#   Adresse MAC Freebox            XX:XX:XX:XX:XX:XX
#   Adresse IP                     203.0.113.60            
#   IPv6                           Activé                  
#   Mode routeur                   Activé                  
#   Adresse IP privée              192.0.2.1             
#   Adresse IP DMZ                 192.0.2.2             
#   Adresse IP Freeplayer          192.0.2.0             
#   Réponse au ping                Activé                  
#   Proxy Wake On Lan              Désactivé               
#   Serveur DHCP                   Activé                  
#   Plage d'adresses dynamique     192.0.2.100 - 192.0.2.254
# 
#  Attributions dhcp :
#  -------------------
# 
#   Adresse MAC            Adresse IP                  
#   --                     --                          
#   XX:XX:XX:XX:XX:XX      192.0.2.101               
#   XX:XX:XX:XX:XX:XX      192.0.2.102               
#   XX:XX:XX:XX:XX:XX      192.0.2.103               
#   XX:XX:XX:XX:XX:XX      192.0.2.104               
#   XX:XX:XX:XX:XX:XX      192.0.2.105               
#   XX:XX:XX:XX:XX:XX      192.0.2.100               
#   XX:XX:XX:XX:XX:XX      192.0.2.3                 
# 
#  Redirections de ports :
#  -----------------------
# 
#   Protocole              Port source    Destination    Port destination
#   --                     --             --             --            
#   TCP                    22             192.0.2.3      22            
#   TCP                    2222           192.0.2.100    22            
#   TCP                    1194           192.0.2.3      1194          
#   UDP                    1194           192.0.2.3      1194          
#   TCP                    80             192.0.2.3      80            
# 
#  Interfaces réseau :
#  -------------------
# 
#                          Lien           Débit entrant  Débit sortant 
#                          --             --             --            
#   WAN                    Ok             1 ko/s         1 ko/s        
#   Ethernet                              0 ko/s         0 ko/s        
#   USB                    Non connecté                                
#   Switch                 100baseTX-FD   1 ko/s         1 ko/s        

fetch() {
	# shellcheck disable=SC2154
	curl -s "$@"
}

get_line_column() {
	local key="$1"
	local field_index="$2"
	awk '/'"$key"'/ {
		if ($('"$field_index"') ~ /^[.0-9]+$/) {
			print $('"$field_index"')
		}
	}'
}

get_data() {
	INFO="$(fetch "${fbx_info_url}" | iconv -f latin1 -t utf8)"

	UPTIME_DAYS=$(get_line_column "Temps depuis la mise en route" "NF-5" <<< "${INFO}")
	UPTIME_HOURS=$(get_line_column "Temps depuis la mise en route" "NF-3" <<< "${INFO}")
	UPTIME_MINUTES=$(get_line_column "Temps depuis la mise en route" "NF-1" <<< "${INFO}")

	ATM_DOWN=$(get_line_column "ATM" "NF-3" <<< "${INFO}")
	ATM_UP=$(get_line_column "ATM" "NF-1" <<< "${INFO}")

	NOISE_DOWN=$(get_line_column "bruit" "NF-3" <<< "${INFO}")
	NOISE_UP=$(get_line_column "bruit" "NF-1" <<< "${INFO}")

	ATTENUATION_DOWN=$(get_line_column "Atténuation" "NF-3" <<< "${INFO}")
	ATTENUATION_UP=$(get_line_column "Atténuation" "NF-1" <<< "${INFO}")

	FEC_DOWN=$(get_line_column "FEC" "NF-1" <<< "${INFO}")
	FEC_UP=$(get_line_column "FEC" "NF" <<< "${INFO}")
	CRC_DOWN=$(get_line_column "CRC" "NF-1" <<< "${INFO}")
	CRC_UP=$(get_line_column "CRC" "NF" <<< "${INFO}")
	HEC_DOWN=$(get_line_column "HEC" "NF-1" <<< "${INFO}")
	HEC_UP=$(get_line_column "HEC" "NF" <<< "${INFO}")

	WAN_DOWN=$(get_line_column "WAN" "NF-3" <<< "${INFO}")
	WAN_UP=$(get_line_column "WAN" "NF-1" <<< "${INFO}")
	ETH_DOWN=$(get_line_column "Ethernet" "NF-3" <<< "${INFO}")
	ETH_UP=$(get_line_column "Ethernet" "NF-1" <<< "${INFO}")
	USB_DOWN=$(get_line_column "USB" "NF-3" <<< "${INFO}")
	USB_UP=$(get_line_column "USB" "NF-1" <<< "${INFO}")
	SWITCH_DOWN=$(get_line_column "Switch" "NF-3" <<< "${INFO}")
	SWITCH_UP=$(get_line_column "Switch" "NF-1" <<< "${INFO}")

	DHCP_CLIENTS=$(sed -nE '/Attributions dhcp/,/Redirections de ports/{s/^\s*([0-9A-F:]{17}).*$/\1/p}' <<< "${INFO}" | wc -l)
	REDIRECT_TCP=$(sed -nE '/Redirections de ports/,/Interfaces réseau/{s/^\s*(TCP).*$/\1/p}' <<< "${INFO}" | wc -l)
	REDIRECT_UDP=$(sed -nE '/Redirections de ports/,/Interfaces réseau/{s/^\s*(UDP).*$/\1/p}' <<< "${INFO}" | wc -l)

	if [ -z "${UPTIME_DAYS:-}" ]; then
		UPTIME_DAYS=0
	fi
	if [ -z "${UPTIME_HOURS:-}" ]; then
		UPTIME_HOURS=0
	fi
	if [ -z "${UPTIME_MINUTES:-}" ]; then
		UPTIME_MINUTES=0
	fi
	FREEBOX_UPTIME=$((UPTIME_DAYS*86400+UPTIME_HOURS*3600+UPTIME_MINUTES*60))

	LAST_CONNECT=$(sed -nE '/Journal de connexion adsl/,+5{s#^\s*([0-9]{2})/([0-9]{2})/([0-9]{4})[^0-9]*([0-9]+):([0-9]+):([0-9]+)\s+Connexion.*#\3-\2-\1T\4:\5:\6#p}' <<< "${INFO}")
	CONNECTION_UPTIME=U
	if [ -n "${LAST_CONNECT}" ]; then
		CONNECTION_UPTIME="$(($(date +%s)-$(date -d "${LAST_CONNECT}" +%s)))"

	fi
}

graph_config() {
	graph=""
	if [ -n "${1:-}" ]; then
		graph=".$1"
	fi

	echo "multigraph freebox${graph}"

	case "$graph" in
		.adsl)
			echo "graph_title ADSL characteristics"
			echo 'graph_category network'
			echo 'graph_vlabel dB in (-) / out (+)'
			echo 'graph_order noise_down noise attenuation_down attenuation'

			echo 'noise_down.label Noise down'
			echo 'noise_down.graph no'
			echo 'noise.label Noise'
			echo 'noise.negative noise_down'

			echo 'attenuation_down.label Attenuation down'
			echo 'attenuation_down.graph no'
			echo 'attenuation.label Attenuation'
			echo 'attenuation.negative attenuation_down'
			;;
		.adsl_errors)
			echo 'graph_title ADSL error correction'
			echo 'graph_category network'
			echo 'graph_vlabel errors in (-) / out (+)'
			echo 'graph_order fec_down fec crc_down crc hec_down hec'

			echo 'fec_down.label FEC down'
			echo 'fec_down.type DERIVE'
			echo 'fec_down.min 0'
			echo 'fec_down.graph no'
			echo 'fec.label FEC'
			echo 'fec.type DERIVE'
			echo 'fec.min 0'
			echo 'fec.negative fec_down'

			echo 'crc_down.label CRC down'
			echo 'crc_down.type DERIVE'
			echo 'crc_down.min 0'
			echo 'crc_down.graph no'
			echo 'crc.label CRC'
			echo 'crc.type DERIVE'
			echo 'crc.min 0'
			echo 'crc.negative crc_down'

			echo 'hec_down.label HEC down'
			echo 'hec_down.type DERIVE'
			echo 'hec_down.min 0'
			echo 'hec_down.graph no'
			echo 'hec.label HEC'
			echo 'hec.type DERIVE'
			echo 'hec.min 0'
			echo 'hec.negative hec_down'
			;;
		.traffic)
			echo 'graph_title Traffic'
			echo 'graph_category network'
			echo 'graph_vlabel bits per second in (-) / out (+)'
			echo 'graph_order atm_down atm wan_down wan eth_down eth usb_down usb switch_down switch'

			echo 'atm_down.label ATM down'
			echo 'atm_down.graph no'
			echo 'atm_down.cdef atm_down,1000,*'
			echo 'atm.label ATM sync'
			echo 'atm.negative atm_down'
			echo 'atm.cdef atm,1000,*'

			echo 'wan_down.label WAN down'
			echo 'wan_down.graph no'
			echo 'wan_down.cdef wan_down,8000,*'
			echo 'wan.label WAN'
			echo 'wan.negative wan_down'
			echo 'wan.cdef wan,8000,*'

			echo 'eth_down.label ETH down'
			echo 'eth_down.graph no'
			echo 'eth_down.cdef eth_down,8000,*'
			echo 'eth.label Ethernet'
			echo 'eth.negative eth_down'
			echo 'eth.cdef eth,8000,*'

			echo 'usb_down.label USB down'
			echo 'usb.label USB'
			echo 'usb_down.graph no'
			echo 'usb_down.cdef usb_down,8000,*'
			echo 'usb.negative usb_down'
			echo 'usb.cdef usb,8000,*'

			echo 'switch_down.label Switch down'
			echo 'switch_down.graph no'
			echo 'switch_down.cdef switch_down,8000,*'
			echo 'switch.label Switch'
			echo 'switch.cdef switch,8000,*'
			echo 'switch.negative switch_down'
			;;
		.uptime)
			echo 'graph_title Uptimes'
			echo 'graph_category network'
			echo 'graph_vlabel days'
			echo 'graph_args --logarithmic'

			echo 'freebox.label Freebox'
			echo 'freebox.draw AREA'
			echo 'freebox.cdef freebox,86400,/'

			echo 'connection.label Connection'
			echo 'connection.cdef connection,86400,/'
			;;
		.users)
			echo 'graph_title Network users'
			echo 'graph_category network'
			echo 'graph_vlabel count'

			echo 'dhcp.label DHCP leases'
			echo 'redirect_tcp.label TCP redirections'
			echo 'redirect_udp.label UDP redirections'
			;;
		*)
			echo 'graph_title Uplink traffic'
			echo 'graph_category network'
			echo 'graph_vlabel bits per second in (-) / out (+)'
			echo 'graph_order main_atm_down main_atm main_wan_down main_wan'

			# XXX: summary data similar to (more detailed) traffic
			echo 'main_wan_down.label WAN down'
			echo 'main_wan_down.graph no'
			echo 'main_wan_down.cdef main_wan_down,8000,*'
			echo 'main_wan.label bps'
			echo 'main_wan.negative main_wan_down'
			echo 'main_wan.cdef main_wan,8000,*'

			echo 'main_atm_down.label ATM down'
			echo 'main_atm_down.graph no'
			echo 'main_atm_down.cdef main_atm_down,1000,*'
			echo 'main_atm.label bps (max)'
			echo 'main_atm.negative main_atm_down'
			echo 'main_atm.cdef main_atm,1000,*'
			;;

	esac
	echo
}

graph_data() {
	graph=""
	if [ -n "${1:-}" ]; then
		graph=".$1"
	fi

	echo "multigraph freebox${graph}"
	case "$graph" in
		.adsl)
			echo "noise.value ${NOISE_UP:-U}"
			echo "noise_down.value ${NOISE_DOWN:-U}"

			echo "attenuation.value ${ATTENUATION_UP:-U}"
			echo "attenuation_down.value ${ATTENUATION_DOWN:-U}"
			;;
		.adsl_errors)
			echo "fec.value ${FEC_UP:-U}"
			echo "fec_down.value ${FEC_DOWN:-U}"

			echo "crc.value ${CRC_UP:-U}"
			echo "crc_down.value ${CRC_DOWN:-U}"

			echo "hec.value ${HEC_UP:-U}"
			echo "hec_down.value ${HEC_DOWN:-U}"
			;;
		.traffic)
			echo "atm.value ${ATM_UP:-U}"
			echo "atm_down.value ${ATM_DOWN:-U}"

			echo "wan.value ${WAN_UP:-U}"
			echo "wan_down.value ${WAN_DOWN:-U}"

			echo "eth.value ${ETH_UP:-U}"
			echo "eth_down.value ${ETH_DOWN:-U}"

			echo "usb.value ${USB_UP:-U}"
			echo "usb_down.value ${USB_DOWN:-U}"

			echo "switch.value ${SWITCH_UP:-U}"
			echo "switch_down.value ${SWITCH_DOWN:-U}"
			;;
		.uptime)
			echo "freebox.value ${FREEBOX_UPTIME:-U}"
			echo "connection.value ${CONNECTION_UPTIME:-U}"
			;;
		.users)
			echo "dhcp.value ${DHCP_CLIENTS:-U}"
			echo "redirect_tcp.value ${REDIRECT_TCP:-U}"
			echo "redirect_udp.value ${REDIRECT_UDP:-U}"
			;;
		*)
			echo "main_wan.value ${WAN_UP:-U}"
			echo "main_wan_down.value ${WAN_DOWN:-U}"

			echo "main_atm.value ${ATM_UP:-U}"
			echo "main_atm_down.value ${ATM_DOWN:-U}"

	esac
	echo
}

main() {
	case ${1:-} in
		autoconf)
			for CMD in curl iconv; do
				if ! command -v "${CMD}" >/dev/null; then
					echo "no (${CMD} not found)"
				fi
			done

			if curl --connect-timeout 1 -qso /dev/null "${fbx_info_url}"; then
				echo 'yes'
			else
				echo "no (failed to retrieve ${fbx_info_url})"
			fi
			;;
		config)
			graph_config
			graph_config adsl
			graph_config adsl_errors
			graph_config traffic
			graph_config uptime
			graph_config users
			if [ "${MUNIN_CAP_DIRTYCONFIG:-0}" = "1" ]; then
				main
			fi
			;;
		*)
			get_data
			graph_data
			graph_data adsl
			graph_data adsl_errors
			graph_data traffic
			graph_data uptime
			graph_data users
			;;
	esac
}

main "${1:-}"