En una instalación de collectd con soporte para el plugin iptables, me encontré con un problema de símbolos: "undefined symbol: iptc_strerror". Tal como explica el artículo Recolectar estadísticas de iptables con collectd, el plugin iptables de collectd requiere del paquete iptables-dev, el cual provee la librería libiptc.
En este artículo voy a demostrar cómo es posible depurar errores con símbolos de librerías empleando el utilitario objdump
provisto por el paquete binutils.
El paquete iptables-dev había sido instalado y la configuración del collectd (./configure
) pasó con éxito:
iptables . . . . . . yes
Sin embargo, al iniciar el servicio ocurría el error detallado en el log del sistema Debian (/var/log/syslog
):
root@devuan:~# tail /var/log/syslog
Feb 21 08:57:43 devuan collectd[557]: dlopen("/opt/collectd/lib/collectd/iptables.so") failed: /opt/collectd/lib/collectd/iptables.so: undefined symbol: iptc_strerror. The most common cause for this problem is missing dependencies. Use ldd(1) to check the dependencies of the plugin / shared object.
El plugin iptables de collectd lamentablemente suele traer problemas, tal como aclara la sección de dependencias del mismo en la Wiki oficial:
Linking with the libiptc has not been easy, unfortunately. Because that library used to be meant for internal use only, it was only available as a static library on many distributions.
Los problemas con la libiptc están relacionados a que se trata de una librería pensada para uso interno solamente.
En este sistema Devuan 2.0 ASCII de 64 bit, la librería libiptc queda instalada en el directorio /usr/lib/x86_64-linux-gnu
:
root@devuan:~# find /usr -name "libiptc.so" /usr/lib/x86_64-linux-gnu/libiptc.so
Según el log al iniciar el servicio, el linker falla al incluir la librería de collectd iptables.so
debido a que no se encuentra el símbolo "iptc_strerror" provisto por libiptc. Los símbolos son nombres simbólicos que se asocian a una dirección de memoria para que el linker pueda enlazar a una librería. Típicamente representan la ubicación en memoria (dentro de la librería) de una función o procedimiento.
Veamos qué símbolos provee esta librería. La opción -T
de objdump
permite volcar la tabla de símbolos de una librería:
root@devuan:~# objdump -T /usr/lib/x86_64-linux-gnu/libiptc.so /usr/lib/x86_64-linux-gnu/libiptc.so: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable 0000000000000000 w D *UND* 0000000000000000 __gmon_start__ 0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses 0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable 0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize 0000000000201008 g D .data 0000000000000000 Base _edata 0000000000201010 g D .bss 0000000000000000 Base _end 0000000000201008 g D .bss 0000000000000000 Base __bss_start 00000000000004c0 g DF .init 0000000000000000 Base _init 0000000000000600 g DF .fini 0000000000000000 Base _fini
Tal como se observa, prácticamente no hay símbolos en esta librería, está casi vacía. Esto se debe a que Debian la ha separado en dos librerías independientes específicas para IPv4 e IPv6:
root@devuan:~# ll /usr/lib/x86_64-linux-gnu/libip* lrwxrwxrwx 1 root root 17 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libip4tc.so -> libip4tc.so.0.1.0 lrwxrwxrwx 1 root root 17 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libip4tc.so.0 -> libip4tc.so.0.1.0 -rw-r--r-- 1 root root 27088 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libip4tc.so.0.1.0 lrwxrwxrwx 1 root root 17 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libip6tc.so -> libip6tc.so.0.1.0 lrwxrwxrwx 1 root root 17 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libip6tc.so.0 -> libip6tc.so.0.1.0 -rw-r--r-- 1 root root 31184 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libip6tc.so.0.1.0 lrwxrwxrwx 1 root root 16 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libiptc.so -> libiptc.so.0.0.0 lrwxrwxrwx 1 root root 16 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libiptc.so.0 -> libiptc.so.0.0.0 -rw-r--r-- 1 root root 5832 Apr 12 2017 /usr/lib/x86_64-linux-gnu/libiptc.so.0.0.0
Se trata de libip4tc e libip6tc respectivamente. Es posible comprobar que el símbolo "iptc_strerror", reportado como desconocido por el linker al enlazar dinámicamente, se encuentra en la librería libip4tc:
root@devuan:~# objdump -T /usr/lib/x86_64-linux-gnu/libip4tc.so | grep iptc_strerror 0000000000001a80 g DF .text 00000000000000af Base iptc_strerror
La solución a este error es conocida y fue reportada por primera vez hace bastante tiempo en el repositorio en GitHub de collectd, habiendo ocurrido en un sistema Ubuntu (ver Referencias). Consiste en implementar un wrapper para el binario collectd
que precargue ambas librerías libip4tc y libip6tc:
root@devuan:~# nano /opt/collectd/sbin/collectd.wrapper
#!/bin/sh LIBS="/usr/lib/x86_64-linux-gnu/libip4tc.so /usr/lib/x86_64-linux-gnu/libip6tc.so" export LD_PRELOAD="$LD_PRELOAD $LIBS" exec /opt/collectd/sbin/collectd "$@"
El truco consiste en indicarle al linker, a través de la variable de entorno LD_PRELOAD
, que debe cargar ambas librerías antes que el resto de los objetos. Los ítems en esta variable de entorno pueden estar separados por espacios o comas.
Luego se debe otorgar permisos de ejecución al wrapper:
root@devuan:~# chmod +x /opt/collectd/sbin/collectd.wrapper
Y modificar al script de inicio del servicio para que lance al wrapper en lugar del binario /opt/collectd/sbin/collectd
:
root@devuan:~# nano /etc/init.d/collectd
En el script provisto en mi repositorio de GitHub basta con alterar la variable NAME
de la siguiente forma:
NAME=collectd.wrapper
Al reiniciar collectd, el plugin iptables funciona correctamente y levanta los contadores del firewall con éxito.
Referencias
- Compilar y configurar collectd con InfluxDB en Debian y derivados
- Recolectar estadísticas de iptables con collectd
- iptables plugin not working on Ubuntu >= 11.10 #326
- Librerías compartidas, variables de entorno y permisos en Linux
man ld.so
- Plugin:IPTables - Dependencies