diff -Nru miniupnpd-2.1/asyncsendto.c miniupnpd-2.2.1/asyncsendto.c --- miniupnpd-2.1/asyncsendto.c 2018-04-12 08:13:00.000000000 +0000 +++ miniupnpd-2.2.1/asyncsendto.c 2020-11-27 18:25:02.000000000 +0000 @@ -1,11 +1,12 @@ -/* $Id: asyncsendto.c,v 1.9 2018/04/12 08:12:31 nanard Exp $ */ +/* $Id: asyncsendto.c,v 1.12 2020/11/11 12:13:26 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2017 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include +#include #include #include #include @@ -21,6 +22,8 @@ #include "asyncsendto.h" #include "upnputils.h" +enum send_state {ESCHEDULED=1, EWAITREADY=2, ESENDNOW=3} state; + /* state diagram for a packet : * * | @@ -33,7 +36,7 @@ struct scheduled_send { LIST_ENTRY(scheduled_send) entries; struct timeval ts; - enum {ESCHEDULED=1, EWAITREADY=2, ESENDNOW=3} state; + enum send_state state; int sockfd; const void * buf; size_t len; @@ -95,7 +98,7 @@ const struct sockaddr_in6 *src_addr, unsigned int delay) { - enum {ESCHEDULED, EWAITREADY, ESENDNOW} state; + enum send_state state; ssize_t n; size_t alloc_len; struct timeval tv; @@ -345,4 +348,3 @@ } } } - diff -Nru miniupnpd-2.1/bsd/getifstats.c miniupnpd-2.2.1/bsd/getifstats.c --- miniupnpd-2.1/bsd/getifstats.c 2018-04-06 09:10:56.000000000 +0000 +++ miniupnpd-2.2.1/bsd/getifstats.c 2020-05-10 22:30:15.000000000 +0000 @@ -19,7 +19,7 @@ #endif #include "../getifstats.h" -#include "../config.h" +#include "config.h" int getifstats(const char *ifname, struct ifdata *data) diff -Nru miniupnpd-2.1/bsd/getroute.c miniupnpd-2.2.1/bsd/getroute.c --- miniupnpd-2.1/bsd/getroute.c 2017-01-30 16:59:50.000000000 +0000 +++ miniupnpd-2.2.1/bsd/getroute.c 2020-05-10 22:30:15.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: getroute.c,v 1.14 2017/01/30 16:59:44 nanard Exp $ */ +/* $Id: getroute.c,v 1.15 2020/05/10 22:24:11 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2017 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -17,7 +17,7 @@ #include #endif -#include "../config.h" +#include "config.h" #include "../upnputils.h" /* SA_SIZE() is a multiple of sizeof(long) with a minimum value of sizeof(long) */ diff -Nru miniupnpd-2.1/bsd/ifacewatcher.c miniupnpd-2.2.1/bsd/ifacewatcher.c --- miniupnpd-2.1/bsd/ifacewatcher.c 2014-04-18 08:23:51.000000000 +0000 +++ miniupnpd-2.2.1/bsd/ifacewatcher.c 2020-05-10 22:30:15.000000000 +0000 @@ -1,12 +1,10 @@ -/* $Id: ifacewatcher.c,v 1.8 2014/04/18 08:23:51 nanard Exp $ */ +/* $Id: ifacewatcher.c,v 1.9 2020/05/10 22:23:56 nanard Exp $ */ /* Project MiniUPnP - * web : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2011 Thomas BERNARD + * web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2011-2020 Thomas BERNARD * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ -#include "../config.h" - #include #include #include @@ -18,6 +16,8 @@ #define SALIGN (sizeof(long) - 1) #define SA_RLEN(sa) (SA_LEN(sa) ? ((SA_LEN(sa) + SALIGN) & ~SALIGN) : (SALIGN + 1)) +#include "config.h" + #include "../upnputils.h" #include "../upnpglobalvars.h" diff -Nru miniupnpd-2.1/Changelog.txt miniupnpd-2.2.1/Changelog.txt --- miniupnpd-2.1/Changelog.txt 2018-05-08 21:34:44.000000000 +0000 +++ miniupnpd-2.2.1/Changelog.txt 2020-10-31 09:16:14.000000000 +0000 @@ -1,4 +1,126 @@ -$Id: Changelog.txt,v 1.441 2018/05/08 21:34:18 nanard Exp $ +$Id: Changelog.txt,v 1.472 2020/10/31 09:16:14 nanard Exp $ + +VERSION 2.2.0 : released on 2020/10/31 + +2020/10/30: + OpenBSD: portinuse.c compatible with OpenBSD 5.5+ + +2020/10/26: + Improve AddAnyPortMapping port selection + +2020/10/22: + netfilter_nft: fix rule-cache update when using the same chain name in + both tables. + +2020/06/20: + -v/-vv to output more log (LOG_INFO / LOG_DEBUG) + AddAnyPortMapping() tries all possible ports + +2020/06/10: + improvements and bug fixes in netfilter_nft/nftnlrdr_misc.c + +2020/06/05: + fix handling of ipv4 M-SEARCH received on ipv6 sockets + numerous fixes in linux/nftables implementation + +2020/06/03: + configure --disable-fork to disable going to background + improve upnp_get_portmapping_number_of_entries() + +2020/05/30: + "IGD2 Port Triggering" pf implementation (adding a nat rule) + +2020/05/07: + Linux: use libcap or libcap-ng to drop unnecessary capabilities + +2020/05/04: + Move configuration detection from Makefiles to configure (was genconfig.sh) + update linux Makefiles + +2020/04/29: + fix for bridges + +2020/04/21: + Remove FW API detecting code from Makefile (BSD). generate bsdmake.inc + netfilter: addmasqueraderule() even if internal/external ports are the same + improve error and debug log in upnpstun.c + +2020/04/20: + Fix "IGD2 Port Triggering" in update_portmapping() + +2020/04/12: + pf: disabled setting dst address in rule by default + +2020/04/09: + Option to disable IPv6 at runtime : -4 / ipv6_disable=yes + +2020/03/29: + Fix FreeBSD build + +2019/12/18: + Fix PCPSendUnsolicitedAnnounce() when IPv6 is not available + +2019/10/05: + Use OpenSSL TLS_server_method() instead of TLSv1_server_method() + Add --version commandline option + +2019/10/03: + Use OpenBSD pledge() + +2019/10/02: + Working NFTables implementation thanks to Paul Chambers + +2019/09/24: + Distinguish between iptables and nftables in genconfig.sh + +2019/09/01: + fix of nftables scripts : https://github.com/miniupnp/miniupnp/pull/395 + +2019/08/24: + Small fixes in netfilter code + +2019/06/25: + Update netfilter nftables code + +2019/05/21: + Allow to use two different network interfaces for IPv4 and IPv6 internet + +2019/05/02: + Fix ssdp notify on unrelated interfaces + +2019/04/09: + Fix buffer over-read in upnpevents.c with urls in the form http://ip:port + +2019/04/05: + Fix memory leak in upnpreplyparse.c with NewPortListing element + +2019/03/22: + netfilter: miniupnpd_functions.sh parsing fix. + fix postrouting chain init. + use iptables -I instead of -A to add rules + +2019/03/09: + check NULL protocol arg in AddAnyPortMapping + +2019/03/07: + Update portinuse code to reflect changes made in FreeBSD 12.0 + +2019/02/12: + linux/getifstats.c: use custom strtoul() implementation to roll over + after 2^32-1 + +2019/02/03: + netfilter: fix build with linux kernel 5.0 + +2018/12/18: + upnp_redirect(): accept NULL desc argument (avoid DOS in AddPortMapping) + upnp_event_prepare(): check the return value of snprintf() + +2018/09/07: + Fix PCP Public address announcement + +2018/07/06: + STUN support VERSION 2.1 : released on 2018/05/08 diff -Nru miniupnpd-2.1/check.mk miniupnpd-2.2.1/check.mk --- miniupnpd-2.1/check.mk 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/check.mk 2020-05-10 16:59:19.000000000 +0000 @@ -0,0 +1,17 @@ +# (c) 2020 Thomas BERNARD + +check: validateupnppermissions validategetifaddr validatessdppktgen \ + validateversion + +validateversion: miniupnpd $(SRCDIR)/VERSION + ./miniupnpd --version + [ "`./miniupnpd --version | head -1 | cut -d' ' -f-2`" = "miniupnpd `cat $(SRCDIR)/VERSION`" ] + touch $@ + +validate%: $(SRCDIR)/test%.sh test% + $(SHELL) $< + touch $@ + +validatessdppktgen: testssdppktgen + ./$< + touch $@ diff -Nru miniupnpd-2.1/commonrdr.h miniupnpd-2.2.1/commonrdr.h --- miniupnpd-2.1/commonrdr.h 2016-02-12 12:36:19.000000000 +0000 +++ miniupnpd-2.2.1/commonrdr.h 2020-12-20 17:50:28.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: commonrdr.h,v 1.10 2016/02/12 12:34:39 nanard Exp $ */ +/* $Id: commonrdr.h,v 1.14 2020/12/20 17:41:46 nanard Exp $ */ /* MiniUPnP project - * (c) 2006-2016 Thomas Bernard - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef COMMONRDR_H_INCLUDED @@ -19,6 +19,11 @@ void shutdown_redirect(void); +/* get_redirect_rule_count() + * return value : -1 for error or the number of redirection rules */ +int +get_redirect_rule_count(const char * ifname); + /* get_redirect_rule() gets internal IP and port from * interface, external port and protocol * return value : @@ -52,16 +57,38 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport, int proto, unsigned int * number); -/* update the port mapping internal port, decription and timestamp */ +/* update the port mapping internal port, description and timestamp */ int update_portmapping(const char * ifname, unsigned short eport, int proto, unsigned short iport, const char * desc, unsigned int timestamp); -/* update the port mapping decription and timestamp */ +/* update the port mapping description and timestamp */ int update_portmapping_desc_timestamp(const char * ifname, unsigned short eport, int proto, const char * desc, unsigned int timestamp); +#if defined(USE_NETFILTER) +/* + * only provided by nftables implementation at the moment. + * Should be implemented for iptables too, for consistency + */ + +typedef enum { + RDR_TABLE_NAME, + RDR_NAT_PREROUTING_CHAIN_NAME, + RDR_NAT_POSTROUTING_CHAIN_NAME, + RDR_FORWARD_CHAIN_NAME, +} rdr_name_type; + +/* + * used by the config file parsing in the core + * to set + */ + +int set_rdr_name( rdr_name_type param, const char * string ); + +#endif + #endif diff -Nru miniupnpd-2.1/configure miniupnpd-2.2.1/configure --- miniupnpd-2.1/configure 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/configure 2020-10-31 09:15:06.000000000 +0000 @@ -0,0 +1,848 @@ +#! /bin/sh +# $Id: configure,v 1.115 2020/10/31 09:14:38 nanard Exp $ +# vim: tabstop=4 shiftwidth=4 noexpandtab +# +# miniupnp daemon +# http://miniupnp.free.fr or https://miniupnp.tuxfamily.org/ +# (c) 2006-2020 Thomas Bernard +# This software is subject to the conditions detailed in the +# LICENCE file provided within the distribution + +# default to UPnP Device Architecture (UDA) v1.1 +# some control points do not like UDA v2.0 +UPNP_VERSION_MAJOR=1 +UPNP_VERSION_MINOR=1 + +# input environment variables : +# IPV6, IGD2, STRICT, DEBUG, LEASFILE, VENDORCFG, PCP_PEER, +# PORTINUSE, DISABLEPPPCONN, FW, IPTABLESPATH, TARGET_OPENWRT, +# PKG_CONFIG, NO_BACKGROUND_NO_PIDFILE + +for argv; do +case "$argv" in + --ipv6) IPV6=1 ;; + --igd2) IGD2=1 ;; + --strict) STRICT=1 ;; + --debug) DEBUG=1 ;; + --leasefile) LEASEFILE=1 ;; + --vendorcfg) VENDORCFG=1 ;; + --pcp-peer) PCP_PEER=1 ;; + --portinuse) PORTINUSE=1 ;; + --uda-version=*) + UPNP_VERSION=$(echo $argv | cut -d= -f2) + UPNP_VERSION_MAJOR=$(echo $UPNP_VERSION | cut -s -d. -f1) + UPNP_VERSION_MINOR=$(echo $UPNP_VERSION | cut -s -d. -f2) + echo "Setting UPnP version major=$UPNP_VERSION_MAJOR minor=$UPNP_VERSION_MINOR" + if [ -z "$UPNP_VERSION_MAJOR" ] || [ -z "$UPNP_VERSION_MINOR" ] ; then + echo "UPnP Version invalid in option $argv" + exit 1 + fi ;; + --disable-pppconn) DISABLEPPPCONN=1 ;; + --disable-fork) NO_BACKGROUND_NO_PIDFILE=1 ;; + --firewall=*) + FW=$(echo $argv | cut -d= -f2) ;; + --iptablespath=*) + IPTABLESPATH=$(echo $argv | cut -d= -f2) ;; + --help|-h) + echo "Usage : $0 [options]" + echo " --ipv6 enable IPv6" + echo " --igd2 build an IGDv2 instead of an IGDv1" + echo " --strict be more strict regarding compliance with UPnP specifications" + echo " --debug #define DEBUG 1" + echo " --leasefile enable lease file" + echo " --vendorcfg enable configuration of manufacturer info" + echo " --pcp-peer enable PCP PEER operation" + echo " --portinuse enable port in use check" + echo " --uda-version=x.x set advertised UPnP version (default to ${UPNP_VERSION_MAJOR}.${UPNP_VERSION_MINOR})" + echo " --disable-pppconn disable WANPPPConnection" + echo " --firewall= force the firewall type (nftables, iptables, pf, ipf, ipfw)" + echo " --iptablespath=/path/to/iptables use a specific version of iptables" + echo " --disable-fork Do not go to background and do not write pid file" + exit 1 + ;; + *) + echo "Option not recognized : $argv" + echo "use -h option to display help" + exit 1 + ;; +esac +done + +echo $* > .configure.cache +BASEDIR=`dirname "$0"` +RM="rm -f" +MV="mv" +CONFIGFILE=`mktemp tmp.config.h.XXXXXXXXXX` +CONFIGFILE_FINAL="config.h" +CONFIGMACRO="CONFIG_H_INCLUDED" +if [ -z "$PKG_CONFIG" ] ; then + PKG_CONFIG=`which pkg-config` +fi + +MINIUPNPD_DATE=`date +"%Y%m%d"` +if [ -n "$SOURCE_DATE_EPOCH" ]; then + MINIUPNPD_DATE=`date --utc --date="@$SOURCE_DATE_EPOCH" +"%Y%m%d"` +fi + +# Facility to syslog +LOG_MINIUPNPD="LOG_DAEMON" + +# detecting the OS name and version +OS_NAME=`uname -s` +OS_VERSION=`uname -r` +OS_MACHINE=`uname -m` +# Makefile to use +MAKEFILE= + +# pfSense special case +if [ -f /etc/platform ]; then + if [ `cat /etc/platform` = "pfSense" ]; then + OS_NAME=pfSense + OS_VERSION=`cat /etc/version` + fi +fi + +# OpenWRT special case +if [ -f ./os.openwrt ]; then + OS_NAME=OpenWRT + OS_VERSION=$(cat ./os.openwrt) +fi + +# AstLinux special case +if [ -f ./os.astlinux ]; then + OS_NAME=AstLinux + OS_VERSION=$(cat ./os.astlinux) +fi + +# Tomato USB special case +if [ -f ../shared/tomato_version ]; then + OS_NAME=Tomato + TOMATO_VER=`cat ../shared/tomato_version | cut -d' ' -f2,3` + OS_VERSION="Tomato $TOMATO_VER" +fi + +# OpenEmbedded special case +if [ -f ./os.openembedded ]; then + OS_NAME=OpenEmbedded + OS_VERSION=$(cat ./os.openembedded) +fi + +${RM} ${CONFIGFILE} + +echo "/* MiniUPnP Project" >> ${CONFIGFILE} +echo " * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/" >> ${CONFIGFILE} +echo " * (c) 2006-2020 Thomas Bernard" >> ${CONFIGFILE} +echo " * generated by $0 on `date`" >> ${CONFIGFILE} +echo " * `uname -a`" >> ${CONFIGFILE} +if [ -z "$*" ] ; then + echo " * using no command line option */" >> ${CONFIGFILE} +else + echo " * using command line options $* */" >> ${CONFIGFILE} +fi +echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE} +echo "#define $CONFIGMACRO" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} +echo "#include " >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} +echo "#define MINIUPNPD_VERSION \"`cat ${BASEDIR}/VERSION`\"" >> ${CONFIGFILE} +echo "#define MINIUPNPD_DATE \"$MINIUPNPD_DATE\"" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +if [ -n "$DEBUG" ] ; then + echo "#define DEBUG 1" >> ${CONFIGFILE} + echo "" >> ${CONFIGFILE} +fi + +cat >> ${CONFIGFILE} <> ${CONFIGFILE} +cat >> ${CONFIGFILE} <> ${CONFIGFILE} + +# OS Specific stuff +case $OS_NAME in + OpenBSD) + MAKEFILE=Makefile.bsd + MAJORVER=`echo $OS_VERSION | cut -d. -f1` + MINORVER=`echo $OS_VERSION | cut -d. -f2` + #echo "OpenBSD majorversion=$MAJORVER minorversion=$MINORVER" + # The pledge() system call first appeared in OpenBSD 5.9. + if [ \( $MAJORVER -ge 6 \) -o \( $MAJORVER -eq 5 -a $MINORVER -ge 9 \) ]; then + # as of writing (OpenBSD 6.7) DIOCGETRULES is not included in the + # operations allowed by the "pf" pledge. + echo "/*#define HAS_PLEDGE*/" >> ${CONFIGFILE} + fi + # rtableid was introduced in OpenBSD 4.0 + if [ $MAJORVER -ge 4 ]; then + echo "#define PFRULE_HAS_RTABLEID" >> ${CONFIGFILE} + fi + # from the 3.8 version, packets and bytes counters are double : in/out + if [ \( $MAJORVER -ge 4 \) -o \( $MAJORVER -eq 3 -a $MINORVER -ge 8 \) ]; then + echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE} + fi + # from the 4.7 version, new pf + if [ \( $MAJORVER -ge 5 \) -o \( $MAJORVER -eq 4 -a $MINORVER -ge 7 \) ]; then + echo "#define PF_NEWSTYLE" >> ${CONFIGFILE} + fi + # onrdomain was introduced in OpenBSD 5.0 + if [ $MAJORVER -ge 5 ]; then + echo "#define PFRULE_HAS_ONRDOMAIN" >> ${CONFIGFILE} + fi + # before OpenBSD 5.5 inpt_queue was CIRCLEQ + if [ $MAJORVER -lt 5 ] || [ $MAJORVER -eq 5 -a $MINORVER -lt 5 ]; then + echo "#define INPT_QUEUE_IS_CIRCLEQ" >> ${CONFIGFILE} + fi + FW=pf + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + OS_URL=http://www.openbsd.org/ + # net.inet6.ip6.v6only has been removed in recent OpenBSD versions + # Default to 1 in that case + if sysctl net.inet6.ip6 | grep net.inet6.ip6.v6only ; then + V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` + else + V6SOCKETS_ARE_V6ONLY=1 + fi + ;; + FreeBSD | GNU/kFreeBSD) + MAKEFILE=Makefile.bsd + VER=`grep '#define __FreeBSD_version' /usr/include/sys/param.h | awk '{print $3}'` + if [ $VER -ge 700049 ]; then + echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE} + fi + HAVE_IP_MREQN=1 + # new way to see which one to use PF or IPF. + # see http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=957 + if [ -z $FW ] && [ -f /etc/rc.subr ] && [ -f /etc/defaults/rc.conf ] ; then + # source file with handy subroutines like checkyesno + . /etc/rc.subr + # source config file so we can probe vars + . /etc/defaults/rc.conf + if [ -f /etc/rc.conf ] ; then + . /etc/rc.conf + fi + if checkyesno ipfilter_enable; then + echo "Using ipf" + FW=ipf + elif checkyesno pf_enable; then + echo "Using pf" + FW=pf + elif checkyesno firewall_enable; then + echo "Using ifpw" + FW=ipfw + fi + fi + if [ -z $FW ] ; then + echo "Could not detect usage of ipf, pf, ipfw. Compiling for pf by default" + FW=pf + fi + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + OS_URL=http://www.freebsd.org/ + V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` + ;; + pfSense) + MAKEFILE=Makefile.bsd + # we need to detect if PFRULE_INOUT_COUNTS macro is needed + FW=pf + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + OS_URL=http://www.pfsense.com/ + V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` + ;; + NetBSD) + MAKEFILE=Makefile.bsd + if [ -z $FW ] && [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then + # source file with handy subroutines like checkyesno + . /etc/rc.subr + # source config file so we can probe vars + . /etc/rc.conf + if checkyesno pf; then + FW=pf + elif checkyesno ipfilter; then + FW=ipf + fi + fi + if [ -z $FW ] ; then + echo "Could not detect ipf nor pf, defaulting to pf." + FW=pf + fi + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + OS_URL=http://www.netbsd.org/ + ;; + DragonFly) + MAKEFILE=Makefile.bsd + if [ -z $FW ] && [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then + # source file with handy subroutines like checkyesno + . /etc/rc.subr + # source config file so we can probe vars + . /etc/rc.conf + if checkyesno pf; then + FW=pf + elif checkyesno ipfilter; then + FW=ipf + fi + fi + if [ -z $FW ] ; then + echo "Could not detect ipf nor pf, defaulting to pf." + FW=pf + fi + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + # PFRULE_INOUT_COUNTS should be set for DragonFly > 2.8 + # version detection is not yet added to this script. + echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE} + # net.inet6.ip6.v6only has been on by default for many years + # and this sysctl node has been removed + V6SOCKETS_ARE_V6ONLY=1 + OS_URL=http://www.dragonflybsd.org/ + ;; + SunOS) + MAKEFILE=Makefile.bsd + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + FW=ipf + echo "#define LOG_PERROR 0" >> ${CONFIGFILE} + echo "#define SOLARIS_KSTATS 1" >> ${CONFIGFILE} + # solaris 10 does not define u_int64_t ? + # but it does define uint64_t + echo "typedef uint64_t u_int64_t;" >> ${CONFIGFILE} + OS_URL=http://www.sun.com/solaris/ + ;; + Linux) + OS_URL=http://www.kernel.org/ + KERNVERA=`echo $OS_VERSION | awk -F. '{print $1}'` + KERNVERB=`echo $OS_VERSION | awk -F. '{print $2}'` + KERNVERC=`echo $OS_VERSION | awk -F. '{print $3}'` + KERNVERD=`echo $OS_VERSION | awk -F. '{print $4}'` + #echo "$KERNVERA.$KERNVERB.$KERNVERC.$KERNVERD" + # from the 2.4 version, struct ip_mreqn instead of struct ip_mreq + if [ \( $KERNVERA -ge 3 \) -o \( $KERNVERA -eq 2 -a $KERNVERB -ge 4 \) ]; then + HAVE_IP_MREQN=1 + fi + # Debian GNU/Linux special case + if [ -f /etc/debian_version ]; then + OS_NAME=Debian + OS_VERSION=`cat /etc/debian_version` + OS_URL=http://www.debian.org/ + fi + # same thing for Gentoo linux + if [ -f /etc/gentoo-release ]; then + OS_NAME=Gentoo + OS_VERSION=`cat /etc/gentoo-release` + OS_URL=http://www.gentoo.org/ + fi + # ClearOS special case + if [ -f /etc/clearos-release ]; then + OS_NAME=ClearOS + OS_VERSION=`grep ^base_version /etc/product | awk '{ print $3 }'` + OS_URL=https://www.clearos.com/ + fi + # use lsb_release (Linux Standard Base) when available + LSB_RELEASE=`which lsb_release` + if [ 0 -eq $? ]; then + OS_NAME=`${LSB_RELEASE} -i -s` + OS_VERSION=`${LSB_RELEASE} -r -s` + case $OS_NAME in + Debian) + OS_URL=http://www.debian.org/ + OS_VERSION=`${LSB_RELEASE} -c -s` + ;; + Ubuntu) + OS_URL=http://www.ubuntu.com/ + OS_VERSION=`${LSB_RELEASE} -c -s` + ;; + Gentoo) + OS_URL=http://www.gentoo.org/ + ;; + arch) + OS_URL=http://www.archlinux.org/ + OS_VERSION=`uname -r` + ;; + esac + fi + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + if [ -z ${FW} ]; then + # test the current environment to determine which to use + # Would be better to check for actual presence of nftable rules, but that requires root privileges + if [ -x "$(command -v nft)" ]; then + FW=nftables + else + FW=iptables + fi + fi + V6SOCKETS_ARE_V6ONLY=`$(find /sbin /bin /usr/sbin /usr/bin -name sysctl) -n net.ipv6.bindv6only` + ;; + OpenWRT) + OS_URL=http://www.openwrt.org/ + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + FW=iptables + ;; + OpenEmbedded) + OS_URL=http://www.openembedded.org/ + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + FW=iptables + ;; + AstLinux) + OS_URL=http://www.astlinux.org/ + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + FW=iptables + ;; + Tomato) + OS_NAME=UPnP + OS_URL=http://tomatousb.org/ + echo "" >> ${CONFIGFILE} + echo "#ifndef TOMATO" >> ${CONFIGFILE} + echo "#define TOMATO" >> ${CONFIGFILE} + echo "#endif" >> ${CONFIGFILE} + echo "" >> ${CONFIGFILE} + echo "#ifdef LINUX26" >> ${CONFIGFILE} + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + echo "#endif" >> ${CONFIGFILE} + echo "#ifdef TCONFIG_IPV6" >> ${CONFIGFILE} + echo "#define ENABLE_IPV6" >> ${CONFIGFILE} + echo "#endif" >> ${CONFIGFILE} + FW=iptables + ;; + Darwin) + MAKEFILE=Makefile.macosx + MAJORVER=`echo $OS_VERSION | cut -d. -f1` + echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} + # OS X switched to pf since 10.7 Lion (Darwin 11.0) + if [ $MAJORVER -ge 11 ] ; then + FW=pf + echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE} + else + FW=ipfw + fi + OS_URL=http://developer.apple.com/macosx + ;; + *) + echo "Unknown OS : $OS_NAME" + echo "Please contact the author at http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/." + exit 1 + ;; +esac + +case $FW in + pf) + echo "#define USE_PF 1" >> ${CONFIGFILE} + ;; + ipf) + echo "#define USE_IPF 1" >> ${CONFIGFILE} + ;; + ipfw) + echo "#define USE_IPFW 1" >> ${CONFIGFILE} + ;; + iptables) + MAKEFILE=Makefile.linux + echo "#define USE_NETFILTER 1" >> ${CONFIGFILE} + echo "#define USE_IPTABLES 1" >> ${CONFIGFILE} + echo "# generated by $0 on `date`" > config.mk + echo "SRCDIR = ${BASEDIR}" >> config.mk + echo "CPPFLAGS += -I." >> config.mk + if [ "$PKG_CONFIG" ] ; then + if ${PKG_CONFIG} --exists libiptc ; then + IPTABLESVERSION=`${PKG_CONFIG} --modversion libiptc` + echo "detected libiptc version $IPTABLESVERSION" + echo "# detected libiptc version $IPTABLESVERSION" >> config.mk + echo "IPTABLES_PCFILE_FOUND = 1" >> config.mk + IPTVER1=`echo $IPTABLESVERSION | cut -d. -f1` + IPTVER2=`echo $IPTABLESVERSION | cut -d. -f2` + IPTVER3=`echo $IPTABLESVERSION | cut -d. -f3` + if [ $IPTVER1 -gt 1 ] || \ + [ \( $IPTVER1 -eq 1 \) -a \( \( $IPTVER2 -gt 4 \) \ + -o \( \( $IPTVER2 -eq 4 \) -a \( $IPTVER3 -ge 3 \) \) \) ] ; then + IPTABLES_143=1 + fi + echo "CFLAGS += `${PKG_CONFIG} --cflags libiptc`" >> config.mk + echo "LDLIBS += `${PKG_CONFIG} --static --libs-only-l libiptc`" >> config.mk + echo "LDFLAGS += `${PKG_CONFIG} --libs-only-L --libs-only-other libiptc`" >> config.mk + fi + if ${PKG_CONFIG} --atleast-version=1.0.2 libnetfilter_conntrack \ + && ${PKG_CONFIG} --atleast-version=1.0.3 libmnl ; then + echo "CPPFLAGS += -DUSE_NFCT" >> config.mk + echo "LDLIBS += `${PKG_CONFIG} --static --libs-only-l libmnl libnetfilter_conntrack`" >> config.mk + fi + fi + if [ "$IPTABLESPATH" ] ; then + echo "CPPFLAGS += -I${IPTABLESPATH}/include/" >> config.mk + echo "LDFLAGS += -L${IPTABLESPATH}/libiptc/" >> config.mk + # to test : change the following test to [ "$OS_NAME" != "OpenWRT" ] + if [ -z "$TARGET_OPENWRT" ] ; then + IPTABLESVERSION=`grep "\#define VERSION" ${IPTABLESPATH}/config.h | tr -d \" |cut -d" " -f3` + echo "detected libiptc version $IPTABLESVERSION" + echo "# detected libiptc version $IPTABLESVERSION" >> config.mk + IPTVER1=`echo $IPTABLESVERSION | cut -d. -f1` + IPTVER2=`echo $IPTABLESVERSION | cut -d. -f2` + IPTVER3=`echo $IPTABLESVERSION | cut -d. -f3` + if [ $IPTVER1 -gt 1 ] || \ + [ \( $IPTVER1 -eq 1 \) -a \( \( $IPTVER2 -gt 4 \) \ + -o \( \( $IPTVER2 -eq 4 \) -a \( $IPTVER3 -ge 3 \) \) \) ] ; then + IPTABLES_143=1 + fi + if [ "$IPTABLES_143" -eq 1 ] ; then + echo "LDLIBS += ${IPTABLESPATH}/libiptc/.libs/libip4tc.o" >> config.mk + else + echo "LDLIBS += ${IPTABLESPATH}/libiptc/libiptc.a" >> config.mk + fi + else + # OpenWRT + # check for system-wide iptables files. Test if iptables version >= 1.4.3 + # the following test has to be verified : + if test -f /usr/include/iptables/internal.h && \ + grep -q "\#define IPTABLES_VERSION" /usr/include/iptables/internal.h ; then + IPTABLES_143=1 + echo "LDLIBS += -liptc" >> config.mk + fi + arch=`echo $OS_MACHINE | grep -q x86_64 && echo 64` + if test -f /usr/lib${arch}/libiptc.a ; then + echo "LDLIBS += -liptc /usr/lib${arch}/libiptc.a" >> config.mk + fi + fi + elif [ -z "${PKG_CONFIG}" ] ; then + # IPTABLESPATH not defined and no pkg-config + if test -f /usr/include/xtables.h && \ + grep -q "XTABLES_VERSION_CODE" /usr/include/xtables.h ; then + IPTABLES_143=1 + echo "LDLIBS += -liptc" >> config.mk + if test -f /lib/libip4tc.so ; then + echo "LDLIBS += -lip4tc" >> config.mk + fi + if test -f /lib/libip6tc.so ; then + echo "LDLIBS += -lip6tc" >> config.mk + fi + fi + fi + echo "/* when IPTABLES_143 is defined, miniupnpd uses the new API" >> ${CONFIGFILE} + echo " * from libiptc 1.4.3+ */ " >> ${CONFIGFILE} + if [ "$IPTABLES_143" -eq 1 ] ; then + echo "#define IPTABLES_143" >> ${CONFIGFILE} + else + echo "#undef IPTABLES_143" >> ${CONFIGFILE} + fi + ;; + nftables) + MAKEFILE=Makefile.linux_nft + echo "#define USE_NETFILTER 1" >> ${CONFIGFILE} + echo "#define USE_NFTABLES 1" >> ${CONFIGFILE} + echo "# generated by $0 on `date`" > config.mk + echo "SRCDIR = ${BASEDIR}" >> config.mk + echo "CPPFLAGS += -I." >> config.mk + ;; + *) + echo "Unknown Firewall/packet filtering software [$FW]" + echo "Please contact the author at http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/." + exit 1 + ;; +esac + +if [ "$FW" = "iptables" ] || [ "$FW" = "nftables" ] ; then + # linux + if [ "$PKG_CONFIG" ] ; then + if ${PKG_CONFIG} --exists libcap-ng ; then + echo "detected libcap-ng `${PKG_CONFIG} --modversion libcap-ng`" + echo "CFLAGS += `${PKG_CONFIG} --cflags libcap-ng`" >> config.mk + echo "LDLIBS += `${PKG_CONFIG} --libs-only-l libcap-ng`" >> config.mk + echo "LDFLAGS += `${PKG_CONFIG} --libs-only-L --libs-only-other libcap-ng`" >> config.mk + echo "#define HAS_LIBCAP_NG" >> ${CONFIGFILE} + elif ${PKG_CONFIG} --exists libcap ; then + echo "detected libcap `${PKG_CONFIG} --modversion libcap`" + echo "CFLAGS += `${PKG_CONFIG} --cflags libcap`" >> config.mk + echo "LDLIBS += `${PKG_CONFIG} --libs-only-l libcap`" >> config.mk + echo "LDFLAGS += `${PKG_CONFIG} --libs-only-L --libs-only-other libcap`" >> config.mk + echo "#define HAS_LIBCAP" >> ${CONFIGFILE} + fi + fi +fi + +if [ "$MAKEFILE" = "Makefile.bsd" ] || [ "$OS_NAME" = "Darwin" ] || [ "$OS_NAME" = "SunOS" ] ; then + echo "FWNAME = $FW" > bsdmake.inc + echo "SRCDIR = ${BASEDIR}" >> bsdmake.inc + echo "CPPFLAGS += -I." >> bsdmake.inc +fi +if [ "$MAKEFILE" ] ; then + cp "${BASEDIR}/${MAKEFILE}" Makefile && echo "${BASEDIR}/${MAKEFILE} -> Makefile" +fi + +# UUID API +case $OS_NAME in + OpenWRT) + echo "#define LIB_UUID" >> ${CONFIGFILE} + ;; + *) + if grep uuid_create /usr/include/uuid.h > /dev/null 2>&1 ; then + echo "#define BSD_UUID" >> ${CONFIGFILE} + fi + if grep uuid_generate /usr/include/uuid/uuid.h > /dev/null 2>&1 ; then + echo "#define LIB_UUID" >> ${CONFIGFILE} + fi + ;; +esac + +# set V6SOCKETS_ARE_V6ONLY to 0 if it was not set above +if [ -z "$V6SOCKETS_ARE_V6ONLY" ] ; then + V6SOCKETS_ARE_V6ONLY=0 +fi + +echo "Configuring compilation for [$OS_NAME] [$OS_VERSION] with [$FW] firewall software." +echo "Please edit config.h for more compilation options." + +# define SUPPORT_REMOTEHOST if the FW related code really supports setting +# a RemoteHost +if [ \( "$FW" = "netfilter" \) -o \( "$FW" = "pf" \) -o \( "$FW" = "ipfw" \) ] ; then + echo "#define SUPPORT_REMOTEHOST" >> ${CONFIGFILE} +fi + +echo "/* Enable IGD2 \"Port Triggering\" as defined in Section 2.5.16" >> ${CONFIGFILE} +echo " * figure 2.2 in UPnP-gw-WANIPConnection-v2-Service.pdf */" >> ${CONFIGFILE} +echo "#define ENABLE_PORT_TRIGGERING" >> ${CONFIGFILE} + +echo "" >> ${CONFIGFILE} +echo "#define OS_NAME \"$OS_NAME\"" >> ${CONFIGFILE} +echo "#define OS_VERSION \"$OS_NAME/$OS_VERSION\"" >> ${CONFIGFILE} +echo "#define OS_URL \"${OS_URL}\"" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* syslog facility to be used by miniupnpd */" >> ${CONFIGFILE} +echo "#define LOG_MINIUPNPD ${LOG_MINIUPNPD}" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Uncomment the following line to allow miniupnpd to be" >> ${CONFIGFILE} +echo " * controlled by miniupnpdctl */" >> ${CONFIGFILE} +echo "/*#define USE_MINIUPNPDCTL*/" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Comment the following line to disable NAT-PMP operations */" >> ${CONFIGFILE} +echo "#define ENABLE_NATPMP" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Comment the following line to disable PCP operations */" >> ${CONFIGFILE} +echo "#define ENABLE_PCP" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "#ifdef ENABLE_PCP" >> ${CONFIGFILE} +if [ -n "$PCP_PEER" ]; then +echo "/* Comment the following line to disable PCP PEER operation */" >> ${CONFIGFILE} +echo "#define PCP_PEER" >> ${CONFIGFILE} +else +echo "/* Uncomment the following line to enable PCP PEER operation */" >> ${CONFIGFILE} +echo "/*#define PCP_PEER*/" >> ${CONFIGFILE} +fi +echo "#ifdef PCP_PEER" >> ${CONFIGFILE} +echo "/*#define PCP_FLOWP*/" >> ${CONFIGFILE} +echo "#endif /*PCP_PEER*/" >> ${CONFIGFILE} +echo "/*#define PCP_SADSCP*/" >> ${CONFIGFILE} +echo "#endif /*ENABLE_PCP*/" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Uncomment the following line to enable generation of" >> ${CONFIGFILE} +echo " * filter rules with pf */" >> ${CONFIGFILE} +echo "/*#define PF_ENABLE_FILTER_RULES*/">> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Uncomment the following line to set dst address in rdr rules with pf." >> ${CONFIGFILE} +echo " * It is disabled by default because of" >> ${CONFIGFILE} +echo " * https://github.com/miniupnp/miniupnp/issues/433 */" >> ${CONFIGFILE} +echo "/*#define PF_SET_DST_ADDR*/">> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Uncomment the following line to enable caching of results of" >> ${CONFIGFILE} +echo " * the getifstats() function */" >> ${CONFIGFILE} +echo "/*#define ENABLE_GETIFSTATS_CACHING*/" >> ${CONFIGFILE} +echo "/* The cache duration is indicated in seconds */" >> ${CONFIGFILE} +echo "#define GETIFSTATS_CACHING_DURATION 2" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Uncomment the following line to enable multiple external ip support */" >> ${CONFIGFILE} +echo "/* note : That is EXPERIMENTAL, do not use that unless you know perfectly what you are doing */" >> ${CONFIGFILE} +echo "/* Dynamic external ip adresses are not supported when this option is enabled." >> ${CONFIGFILE} +echo " * Also note that you would need to configure your .conf file accordingly. */" >> ${CONFIGFILE} +echo "/*#define MULTIPLE_EXTERNAL_IP*/" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Comment the following line to use home made daemonize() func instead" >> ${CONFIGFILE} +echo " * of BSD daemon() */" >> ${CONFIGFILE} +echo "#define USE_DAEMON" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Uncomment the following line to enable lease file support */" >> ${CONFIGFILE} +if [ -n "$LEASEFILE" ] ; then + echo "#define ENABLE_LEASEFILE" >> ${CONFIGFILE} +else + echo "/*#define ENABLE_LEASEFILE*/" >> ${CONFIGFILE} +fi +echo "/* Uncomment the following line to store remaining time in lease file */" >> ${CONFIGFILE} +echo "/*#define LEASEFILE_USE_REMAINING_TIME*/" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Uncomment the following line to enable port in use check */" >> ${CONFIGFILE} +if [ -n "$PORTINUSE" ]; then + echo "#define CHECK_PORTINUSE" >> ${CONFIGFILE} +else + echo "/*#define CHECK_PORTINUSE*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +echo "/* Define one or none of the two following macros in order to make some" >> ${CONFIGFILE} +echo " * clients happy. It will change the XML Root Description of the IGD." >> ${CONFIGFILE} +echo " * Enabling the Layer3Forwarding Service seems to be the more compatible" >> ${CONFIGFILE} +echo " * option. */" >> ${CONFIGFILE} +echo "/*#define HAS_DUMMY_SERVICE*/" >> ${CONFIGFILE} +echo "#define ENABLE_L3F_SERVICE" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* define ADVERTISE_WANPPPCONN to allow buggy Control Point to use" >> ${CONFIGFILE} +echo " * WANPPPConnection instead of WANIPConnection. */" >> ${CONFIGFILE} +if [ -n "$STRICT" ] || [ -n "$DISABLEPPPCONN" ] ; then + echo "/*#define ADVERTISE_WANPPPCONN*/" >> ${CONFIGFILE} +else + echo "#define ADVERTISE_WANPPPCONN" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +echo "/* Enable IP v6 support */" >> ${CONFIGFILE} +if [ -n "$IPV6" ]; then + echo "#define ENABLE_IPV6" >> ${CONFIGFILE} +else + echo "/*#define ENABLE_IPV6*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +echo "/* Define V6SOCKETS_ARE_V6ONLY if AF_INET6 sockets are restricted" >> ${CONFIGFILE} +echo " * to IPv6 communications only. */" >> ${CONFIGFILE} +if [ $V6SOCKETS_ARE_V6ONLY -eq 1 ] ; then + echo "#define V6SOCKETS_ARE_V6ONLY" >> ${CONFIGFILE} +else + echo "/*#define V6SOCKETS_ARE_V6ONLY*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +if [ -n "$HAVE_IP_MREQN" ]; then + echo "#define HAVE_IP_MREQN" >> ${CONFIGFILE} + echo "" >> ${CONFIGFILE} +fi + +echo "/* Enable the support of IGD v2 specification." >> ${CONFIGFILE} +echo " * This is not fully tested yet and can cause incompatibilities with some" >> ${CONFIGFILE} +echo " * control points, so enable with care. */" >> ${CONFIGFILE} +if [ -n "$IGD2" ]; then + echo "#define IGD_V2" >> ${CONFIGFILE} +else + echo "/*#define IGD_V2*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +echo "#ifdef IGD_V2" >> ${CONFIGFILE} +echo "/* Enable DeviceProtection service (IGDv2) */" >> ${CONFIGFILE} +echo "#define ENABLE_DP_SERVICE" >> ${CONFIGFILE} +echo "/*#define ENABLE_HTTPS*/" >> ${CONFIGFILE} +echo "/*#define HTTPS_CERTFILE \"/path/to/certificate.pem\"*/" >> ${CONFIGFILE} +echo "/*#define HTTPS_KEYFILE \"/path/to/private.key\"*/" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} +echo "/* Enable WANIPv6FirewallControl service (IGDv2). needs IPv6 */" >> ${CONFIGFILE} +echo "#ifdef ENABLE_IPV6" >> ${CONFIGFILE} +echo "#define ENABLE_6FC_SERVICE" >> ${CONFIGFILE} +echo "#endif /* ENABLE_IPV6 */" >> ${CONFIGFILE} +echo "#endif /* IGD_V2 */" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* UPnP Events support. Working well enough to be enabled by default." >> ${CONFIGFILE} +echo " * It can be disabled to save a few bytes. */" >> ${CONFIGFILE} +echo "#define ENABLE_EVENTS" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* include interface name in pf and ipf rules */" >> ${CONFIGFILE} +echo "#define USE_IFNAME_IN_RULES" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Experimental NFQUEUE support. */" >> ${CONFIGFILE} +echo "/*#define ENABLE_NFQUEUE*/" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Enable to make MiniUPnPd more strict about UPnP conformance" >> ${CONFIGFILE} +echo " * and the messages it receives from control points */" >> ${CONFIGFILE} +if [ -n "$STRICT" ] ; then + echo "#define UPNP_STRICT" >> ${CONFIGFILE} +else + echo "/*#define UPNP_STRICT*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +echo "/* If SSDP_RESPOND_SAME_VERSION is defined, the M-SEARCH response" >> ${CONFIGFILE} +echo " * include the same device version as was contained in the search" >> ${CONFIGFILE} +echo " * request. It conforms to UPnP DA v1.1 */" >> ${CONFIGFILE} +echo "#define SSDP_RESPOND_SAME_VERSION" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Add the optional Date: header in all HTTP responses */" >> ${CONFIGFILE} +if [ -n "$STRICT" ] ; then + echo "#define ENABLE_HTTP_DATE" >> ${CONFIGFILE} +else + echo "/*#define ENABLE_HTTP_DATE*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +echo "/* Wait a little before answering M-SEARCH request */" >> ${CONFIGFILE} +if [ -n "$STRICT" ] ; then + echo "#define DELAY_MSEARCH_RESPONSE" >> ${CONFIGFILE} +else + echo "/*#define DELAY_MSEARCH_RESPONSE*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +echo "/* disable reading and parsing of config file (miniupnpd.conf) */" >> ${CONFIGFILE} +echo "/*#define DISABLE_CONFIG_FILE*/" >> ${CONFIGFILE} +echo "" >> ${CONFIGFILE} + +echo "/* Uncomment the following line to configure all manufacturer infos through miniupnpd.conf */" >> ${CONFIGFILE} +if [ -n "$VENDORCFG" ] ; then + echo "#define ENABLE_MANUFACTURER_INFO_CONFIGURATION" >> ${CONFIGFILE} +else + echo "/*#define ENABLE_MANUFACTURER_INFO_CONFIGURATION*/" >> ${CONFIGFILE} +fi +echo "" >> ${CONFIGFILE} + +cat >> ${CONFIGFILE} <> ${CONFIGFILE} <> ${CONFIGFILE} <> ${CONFIGFILE} +if [ -n "$NO_BACKGROUND_NO_PIDFILE" ] && [ $NO_BACKGROUND_NO_PIDFILE -eq 1 ] ; then + echo "#define NO_BACKGROUND_NO_PIDFILE" >> ${CONFIGFILE} +else + echo "/*#define NO_BACKGROUND_NO_PIDFILE*/" >> ${CONFIGFILE} +fi + +echo "#endif /* ${CONFIGMACRO} */" >> ${CONFIGFILE} + +${MV} ${CONFIGFILE} ${CONFIGFILE_FINAL} + +exit 0 diff -Nru miniupnpd-2.1/debian/changelog miniupnpd-2.2.1/debian/changelog --- miniupnpd-2.1/debian/changelog 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/changelog 2021-01-04 13:48:54.000000000 +0000 @@ -1,3 +1,24 @@ +miniupnpd (2.2.1-1) unstable; urgency=medium + + * New upstream release + * Upload to unstable + + -- Yangfl Mon, 04 Jan 2021 21:48:54 +0800 + +miniupnpd (2.2.0-1) experimental; urgency=medium + + * New upstream release (Closes: #973511). + - Fix iptables-init.sh for POSTROUTING (Closes: #955779). + * Remove dep of net-tools (Closes: #961701). + * Provide iptables and nftables-backended binaries (Closes: #961723). + * Disable leasefile (Closes: #961877). + * Harden systemd service (Closes: #962088). + * Bump debhelper compat to 13. + * Bump Standards-Version to 4.5.0. + * Add upstream metadata. + + -- Yangfl Tue, 17 Nov 2020 22:17:01 +0800 + miniupnpd (2.1-6.1) unstable; urgency=medium * Non-maintainer upload. diff -Nru miniupnpd-2.1/debian/compat miniupnpd-2.2.1/debian/compat --- miniupnpd-2.1/debian/compat 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -12 diff -Nru miniupnpd-2.1/debian/control miniupnpd-2.2.1/debian/control --- miniupnpd-2.1/debian/control 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/control 2021-01-04 13:48:54.000000000 +0000 @@ -5,29 +5,29 @@ Uploaders: Yangfl , Build-Depends: - debhelper (>= 12~), + debhelper-compat (= 13), libiptc-dev, libxtables-dev, + libnftnl-dev, + libmnl-dev, pkg-config, po-debconf, -Standards-Version: 4.3.0 +Rules-Requires-Root: no +Standards-Version: 4.5.0 Vcs-Browser: https://salsa.debian.org/miniupnp-team/miniupnpd Vcs-Git: https://salsa.debian.org/miniupnp-team/miniupnpd.git Homepage: http://miniupnp.free.fr/ Package: miniupnpd -Architecture: linux-any +Architecture: all Pre-Depends: ${misc:Pre-Depends}, Depends: debconf, - iproute2, - iptables, lsb-base, - net-tools, uuid-runtime, + miniupnpd-nftables | miniupnpd-iptables, ${misc:Depends}, - ${shlibs:Depends}, Description: UPnP and NAT-PMP daemon for gateway routers MiniUPnPd is a small daemon which can be installed on a NAT router to provide UPnP Internet Gateway Device and Port Mapping Protocol services, @@ -35,3 +35,41 @@ compatible with peer-to-peer software, messaging applications, and games consoles that connect to online services (including Xbox LIVE and the PlayStation Network). + +Package: miniupnpd-nftables +Architecture: linux-any +Depends: + ${misc:Depends}, + ${shlibs:Depends}, +Conflicts: miniupnpd-iptables +Breaks: miniupnpd (<< 2.2.0) +Replaces: miniupnpd (<< 2.2.0) +Description: UPnP and NAT-PMP daemon for gateway routers - nftables backend + MiniUPnPd is a small daemon which can be installed on a NAT router to + provide UPnP Internet Gateway Device and Port Mapping Protocol services, + enabling clients on the LAN to ask for port redirections. It is + compatible with peer-to-peer software, messaging applications, and games + consoles that connect to online services (including Xbox LIVE and the + PlayStation Network). + . + This package provides miniupnpd with nftables backend. + +Package: miniupnpd-iptables +Architecture: linux-any +Depends: + iptables, + ${misc:Depends}, + ${shlibs:Depends}, +Conflicts: miniupnpd-nftables +Breaks: miniupnpd (<< 2.2.0) +Replaces: miniupnpd (<< 2.2.0) +Description: UPnP and NAT-PMP daemon for gateway routers - legacy iptables backend + MiniUPnPd is a small daemon which can be installed on a NAT router to + provide UPnP Internet Gateway Device and Port Mapping Protocol services, + enabling clients on the LAN to ask for port redirections. It is + compatible with peer-to-peer software, messaging applications, and games + consoles that connect to online services (including Xbox LIVE and the + PlayStation Network). + . + This package provides miniupnpd with iptables backend. The iptables/xtables + framework has been replaced by nftables. You should consider migrating now. diff -Nru miniupnpd-2.1/debian/examples/miniupnpd.default miniupnpd-2.2.1/debian/examples/miniupnpd.default --- miniupnpd-2.1/debian/examples/miniupnpd.default 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/examples/miniupnpd.default 2021-01-04 13:48:54.000000000 +0000 @@ -5,3 +5,9 @@ # If this option is 1, then the init script will initialize # the ipv6 tables. MiniUPnPd_ip6tables_enable= + +# Customize helper commands; you have to create appropriate chains / do cleanup +# yourself. +# Set to 'true' to disable that stage. +MiniUPnPd_PRESTART_COMMAND= +MiniUPnPd_POSTSTOP_COMMAND= diff -Nru miniupnpd-2.1/debian/gitlab-ci.yml miniupnpd-2.2.1/debian/gitlab-ci.yml --- miniupnpd-2.1/debian/gitlab-ci.yml 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/gitlab-ci.yml 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,3 @@ +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml diff -Nru miniupnpd-2.1/debian/lintian-overrides miniupnpd-2.2.1/debian/lintian-overrides --- miniupnpd-2.1/debian/lintian-overrides 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/lintian-overrides 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -# Second update-rc.d call is to enable the service -duplicate-updaterc.d-calls-in-postinst miniupnpd diff -Nru miniupnpd-2.1/debian/miniupnpd.init miniupnpd-2.2.1/debian/miniupnpd.init --- miniupnpd-2.1/debian/miniupnpd.init 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd.init 2021-01-04 13:48:54.000000000 +0000 @@ -51,39 +51,6 @@ exit 0 fi -if [ -f "${DEFAULT}" ] ; then - . "${DEFAULT}" -else - log_daemon_msg "${DAEMON_NAME}: Default file not found: exiting" - log_end_msg 1 - - exit 0 -fi - -if [ -f "${CONFFILE}" ] ; then - MiniUPnPd_EXTERNAL_INTERFACE=$(read_config "${CONFFILE}" ext_ifname) - #~ MiniUPnPd_LISTENING_IP=$(read_config "${CONFFILE}" listening_ip) -else - log_daemon_msg "${DAEMON_NAME}: Config file not found: exiting" - log_end_msg 1 - - exit 0 -fi - -if [ -z "${MiniUPnPd_EXTERNAL_INTERFACE}" ] ; then - log_daemon_msg "${DAEMON_NAME}: no interface defined: exiting" - log_end_msg 1 - - exit 0 -fi - -#~ if [ -z "${MiniUPnPd_LISTENING_IP}" ] ; then - #~ log_daemon_msg "${DAEMON_NAME}: no listening IP defined: exiting" - #~ log_end_msg 1 - - #~ exit 0 -#~ fi - case "${1}" in start) if [ "${START_DAEMON}" = 0 ] ; then @@ -93,11 +60,10 @@ exit 0 fi - log_daemon_msg "Initializing ${DAEMON_SERVICE_NAME} iptables" "${DAEMON_NAME}" - - "${SCRIPT_DIR}/iptables_init.sh" -i "${MiniUPnPd_EXTERNAL_INTERFACE}" - if [ "${MiniUPnPd_ip6tables_enable}" = 1 ] ; then - "${SCRIPT_DIR}/ip6tables_init.sh" -i "${MiniUPnPd_EXTERNAL_INTERFACE}" + log_daemon_msg "Initializing ${DAEMON_SERVICE_NAME} *tables" "${DAEMON_NAME}" + if ! /usr/libexec/miniupnpd-startstop-helper.sh start ; then + log_end_msg 1 + exit 2 fi start-stop-daemon -q --start --exec "${DAEMON}" -- ${MiniUPnPd_OTHER_OPTIONS} @@ -122,12 +88,8 @@ start-stop-daemon -q --stop --oknodo --pidfile ${PIDFILE} RET="${?}" - log_daemon_msg "Deconfiguring ${DAEMON_SERVICE_NAME} iptables" "${DAEMON_NAME}" - - "${SCRIPT_DIR}/iptables_removeall.sh" -i "${MiniUPnPd_EXTERNAL_INTERFACE}" - if [ "${MiniUPnPd_ip6tables_enable}" = 1 ] ; then - "${SCRIPT_DIR}/ip6tables_removeall.sh" -i "${MiniUPnPd_EXTERNAL_INTERFACE}" - fi + log_daemon_msg "Deconfiguring ${DAEMON_SERVICE_NAME} *tables" "${DAEMON_NAME}" + /usr/libexec/miniupnpd-startstop-helper.sh stop case "${RET}" in 0|1) diff -Nru miniupnpd-2.1/debian/miniupnpd.install miniupnpd-2.2.1/debian/miniupnpd.install --- miniupnpd-2.1/debian/miniupnpd.install 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd.install 2021-01-04 13:48:54.000000000 +0000 @@ -1 +1,3 @@ -miniupnpd /usr/sbin +etc/miniupnpd/miniupnpd* +usr/share/man/ +debian/miniupnpd-startstop-helper.sh usr/libexec/ diff -Nru miniupnpd-2.1/debian/miniupnpd-iptables.install miniupnpd-2.2.1/debian/miniupnpd-iptables.install --- miniupnpd-2.1/debian/miniupnpd-iptables.install 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd-iptables.install 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,2 @@ +netfilter/miniupnpd usr/sbin/ +etc/miniupnpd/ip* diff -Nru miniupnpd-2.1/debian/miniupnpd-iptables.lintian-overrides miniupnpd-2.2.1/debian/miniupnpd-iptables.lintian-overrides --- miniupnpd-2.1/debian/miniupnpd-iptables.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd-iptables.lintian-overrides 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,2 @@ +# In metapackage +no-manual-page usr/sbin/miniupnpd diff -Nru miniupnpd-2.1/debian/miniupnpd.lintian-overrides miniupnpd-2.2.1/debian/miniupnpd.lintian-overrides --- miniupnpd-2.1/debian/miniupnpd.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd.lintian-overrides 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,5 @@ +# Second update-rc.d call is to enable the service +duplicate-updaterc.d-calls-in-postinst miniupnpd + +# In metapackage +spare-manual-page usr/share/man/man8/miniupnpd.8.gz diff -Nru miniupnpd-2.1/debian/miniupnpd.manpages miniupnpd-2.2.1/debian/miniupnpd.manpages --- miniupnpd-2.1/debian/miniupnpd.manpages 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd.manpages 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -miniupnpd.8 diff -Nru miniupnpd-2.1/debian/miniupnpd-nftables.install miniupnpd-2.2.1/debian/miniupnpd-nftables.install --- miniupnpd-2.1/debian/miniupnpd-nftables.install 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd-nftables.install 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,2 @@ +netfilter_nft/miniupnpd usr/sbin/ +etc/miniupnpd/nft* diff -Nru miniupnpd-2.1/debian/miniupnpd-nftables.lintian-overrides miniupnpd-2.2.1/debian/miniupnpd-nftables.lintian-overrides --- miniupnpd-2.1/debian/miniupnpd-nftables.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd-nftables.lintian-overrides 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,2 @@ +# In metapackage +no-manual-page usr/sbin/miniupnpd diff -Nru miniupnpd-2.1/debian/miniupnpd.service miniupnpd-2.2.1/debian/miniupnpd.service --- miniupnpd-2.1/debian/miniupnpd.service 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd.service 2021-01-04 13:48:54.000000000 +0000 @@ -4,16 +4,33 @@ After=network-online.target [Service] -Type=simple +Type=exec EnvironmentFile=-/etc/default/miniupnpd -EnvironmentFile=/etc/miniupnpd/miniupnpd.conf -ExecStartPre=/etc/miniupnpd/iptables_init.sh -i $ext_ifname -ExecStartPre=/bin/sh -c "[ \"$MiniUPnPd_ip6tables_enable\" != 1 ] || /etc/miniupnpd/ip6tables_init.sh -i $ext_ifname" +ExecStartPre=/usr/libexec/miniupnpd-startstop-helper.sh start ExecStart=/usr/sbin/miniupnpd -d -f /etc/miniupnpd/miniupnpd.conf $MiniUPnPd_OTHER_OPTIONS -ExecStopPost=/etc/miniupnpd/iptables_removeall.sh -i $ext_ifname -ExecStopPost=/bin/sh -c "[ \"$MiniUPnPd_ip6tables_enable\" != 1 ] || /etc/miniupnpd/ip6tables_removeall.sh -i $ext_ifname" -PrivateTmp=yes +ExecStopPost=/usr/libexec/miniupnpd-startstop-helper.sh stop PIDFile=/run/miniupnpd.pid +TasksMax=2 #for /etc/miniupnpd/nft_removeall.sh. miniupnpd alone needs only 1. +CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BROADCAST CAP_NET_RAW CAP_SYSLOG +MountAPIVFS=yes +NoNewPrivileges=yes +PrivateMounts=yes +PrivateDevices=yes +PrivateTmp=yes +MemoryDenyWriteExecute=yes +ProtectSystem=full +ProtectHome=yes +ProtectHostname=yes +ProtectClock=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectKernelLogs=yes +ProtectControlGroups=yes +LockPersonality=yes +RestrictRealtime=yes +RestrictNamespaces=yes +RestrictSUIDSGID=yes + [Install] WantedBy=multi-user.target diff -Nru miniupnpd-2.1/debian/miniupnpd-startstop-helper.sh miniupnpd-2.2.1/debian/miniupnpd-startstop-helper.sh --- miniupnpd-2.1/debian/miniupnpd-startstop-helper.sh 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/miniupnpd-startstop-helper.sh 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,72 @@ +#!/bin/sh -e + +DEFAULT=/etc/default/miniupnpd +SCRIPT_DIR=/etc/miniupnpd + + +[ -f "${DEFAULT}" ] && . "${DEFAULT}" + +check_miniupnpd () { + system_backend=$(update-alternatives --query iptables | grep -F Value | grep -qF nft \ + && echo nftables || echo iptables) + if [ -f "${SCRIPT_DIR}/iptables_init.sh" -a "${system_backend}" = nftables -o \ + -f "${SCRIPT_DIR}/nft_init.sh" -a "${system_backend}" = iptables ] ; then + echo "WARNING: Your miniupnpd binary seems to mismatch your *tables backend; refused to start!" + echo "WARNING: You should install 'miniupnpd-${system_backend}' instead" + echo "WARNING: Read /usr/share/doc/miniupnpd/NEWS.Debian.gz for more information" + return 1 + fi +} + +get_ext_ifname () { + if [ -f "${CONFFILE}" ] ; then + ext_ifname=$(read_config "${CONFFILE}" ext_ifname) + ext_ifname6=$(read_config "${CONFFILE}" ext_ifname6) + [ -z "${ext_ifname6}" ] && ext_ifname6="${ext_ifname}" + fi + if [ -z "${ext_ifname}" ] ; then + echo "Warning: no interface defined" + return 1 + fi +} + +case "${1}" in + start) + if [ -n "${MiniUPnPd_PRESTART_COMMAND}" ] ; then + ${MiniUPnPd_PRESTART_COMMAND} + exit $? + fi + check_miniupnpd || exit 2 + if [ "${system_backend}" = nftables ] ; then + "${SCRIPT_DIR}/nft_init.sh" + elif get_ext_ifname ; then + "${SCRIPT_DIR}/iptables_init.sh" -i "${ext_ifname}" + if [ "${MiniUPnPd_ip6tables_enable}" = 1 ] ; then + "${SCRIPT_DIR}/ip6tables_init.sh" -i "${ext_ifname6}" + fi + fi + ;; + + stop) + if [ -n "${MiniUPnPd_POSTSTOP_COMMAND}" ] ; then + ${MiniUPnPd_POSTSTOP_COMMAND} + exit $? + fi + check_miniupnpd || exit 2 + if [ "${system_backend}" = nftables ] ; then + "${SCRIPT_DIR}/nft_removeall.sh" + elif get_ext_ifname ; then + "${SCRIPT_DIR}/iptables_removeall.sh" -i "${ext_ifname}" + if [ "${MiniUPnPd_ip6tables_enable}" = 1 ] ; then + "${SCRIPT_DIR}/ip6tables_removeall.sh" -i "${ext_ifname6}" + fi + fi + ;; + + *) + echo "Usage: ${0} {start|stop}" + exit 1 + ;; +esac + +exit 0 diff -Nru miniupnpd-2.1/debian/NEWS miniupnpd-2.2.1/debian/NEWS --- miniupnpd-2.1/debian/NEWS 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/NEWS 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,10 @@ +miniupnpd (2.2.0-1) experimental; urgency=medium + + miniupnpd now provides two variants: miniupnpd-nftables and + miniupnpd-iptables. Please check manually whether you have installed correct + one according to your *tables backend since it is not possible to do so from + packaging side. + + With Debian default you should choose miniupnpd-nftables. + + -- Yangfl Wed, 18 Nov 2020 10:23:46 +0800 diff -Nru miniupnpd-2.1/debian/not-installed miniupnpd-2.2.1/debian/not-installed --- miniupnpd-2.1/debian/not-installed 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/not-installed 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1 @@ +etc/init.d/ diff -Nru miniupnpd-2.1/debian/patches/CVE-2019-12107_upnp_event_prepare_check_the_return_value_of_snprintf.patch miniupnpd-2.2.1/debian/patches/CVE-2019-12107_upnp_event_prepare_check_the_return_value_of_snprintf.patch --- miniupnpd-2.1/debian/patches/CVE-2019-12107_upnp_event_prepare_check_the_return_value_of_snprintf.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/CVE-2019-12107_upnp_event_prepare_check_the_return_value_of_snprintf.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -Description: CVE-2019-12107: upnp_event_prepare(): check the return value of snprintf() -Author: Thomas Bernard -Date: Tue, 18 Dec 2018 22:37:14 +0100 -Origin: upstream, https://github.com/miniupnp/miniupnp/commit/bec6ccec63cadc95655721bc0e1dd49dac759d94 -Last-Update: 2019-06-07 -Bug-Debian: https://bugs.debian.org/930050 - -diff --git a/miniupnpd/upnpevents.c b/miniupnpd/upnpevents.c -index d96bccbe..3bc402f3 100644 ---- a/upnpevents.c -+++ b/upnpevents.c -@@ -443,19 +443,34 @@ static void upnp_event_prepare(struct upnp_event_notify * obj) - l = 0; - } - obj->buffersize = 1024; -- obj->buffer = malloc(obj->buffersize); -- if(!obj->buffer) { -- syslog(LOG_ERR, "%s: malloc returned NULL", "upnp_event_prepare"); -- if(xml) { -- free(xml); -+ for (;;) { -+ obj->buffer = malloc(obj->buffersize); -+ if(!obj->buffer) { -+ syslog(LOG_ERR, "%s: malloc returned NULL", "upnp_event_prepare"); -+ if(xml) { -+ free(xml); -+ } -+ obj->state = EError; -+ return; - } -- obj->state = EError; -- return; -+ obj->tosend = snprintf(obj->buffer, obj->buffersize, notifymsg, -+ obj->path, obj->addrstr, obj->portstr, l+2, -+ obj->sub->uuid, obj->sub->seq, -+ l, xml); -+ if (obj->tosend < 0) { -+ syslog(LOG_ERR, "%s: snprintf() failed", "upnp_event_prepare"); -+ if(xml) { -+ free(xml); -+ } -+ obj->state = EError; -+ return; -+ } else if (obj->tosend < obj->buffersize) { -+ break; /* the buffer was large enough */ -+ } -+ /* Try again with a buffer big enough */ -+ free(obj->buffer); -+ obj->buffersize = obj->tosend + 1; /* reserve space for the final 0 */ - } -- obj->tosend = snprintf(obj->buffer, obj->buffersize, notifymsg, -- obj->path, obj->addrstr, obj->portstr, l+2, -- obj->sub->uuid, obj->sub->seq, -- l, xml); - if(xml) { - free(xml); - xml = NULL; diff -Nru miniupnpd-2.1/debian/patches/CVE-2019-12108_GetOutboundPinholeTimeout_check_args.patch miniupnpd-2.2.1/debian/patches/CVE-2019-12108_GetOutboundPinholeTimeout_check_args.patch --- miniupnpd-2.1/debian/patches/CVE-2019-12108_GetOutboundPinholeTimeout_check_args.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/CVE-2019-12108_GetOutboundPinholeTimeout_check_args.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -Subject: CVE-2019-12108: GetOutboundPinholeTimeout: check args -Author: Thomas Bernard -Date: Tue, 18 Dec 2018 22:54:51 +0100 -Origin: upstream, https://github.com/miniupnp/miniupnp/commit/13585f15c7f7dc28bbbba1661efb280d530d114c.patch -Last-Update: 2019-06-07 -Bug-Debian: https://bugs.debian.org/930050 - -Index: miniupnpd/upnpsoap.c -=================================================================== ---- miniupnpd.orig/upnpsoap.c -+++ miniupnpd/upnpsoap.c -@@ -1842,6 +1842,13 @@ GetOutboundPinholeTimeout(struct upnphtt - rem_port = GetValueFromNameValueList(&data, "RemotePort"); - protocol = GetValueFromNameValueList(&data, "Protocol"); - -+ if (!int_port || !ext_port || !protocol) -+ { -+ ClearNameValueList(&data); -+ SoapError(h, 402, "Invalid Args"); -+ return; -+ } -+ - rport = (unsigned short)atoi(rem_port); - iport = (unsigned short)atoi(int_port); - /*proto = atoi(protocol);*/ diff -Nru miniupnpd-2.1/debian/patches/CVE-2019-12109_fix_error_from_commit_13585f1.patch miniupnpd-2.2.1/debian/patches/CVE-2019-12109_fix_error_from_commit_13585f1.patch --- miniupnpd-2.1/debian/patches/CVE-2019-12109_fix_error_from_commit_13585f1.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/CVE-2019-12109_fix_error_from_commit_13585f1.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -Subject: CVE-2019-12109 fix error from commit 13585f15c7f7dc28bbbba1661efb280d530d114c -From: Thomas Bernard -Date: Tue, 18 Dec 2018 23:47:54 +0100 -Origin: upstream, https://github.com/miniupnp/miniupnp/commit/86030db849260dd8fb2ed975b9890aef1b62b692.patch -Last-Update: 2019-06-07 -Bug-Debian: https://bugs.debian.org/930050 - -Index: miniupnpd/upnpsoap.c -=================================================================== ---- miniupnpd.orig/upnpsoap.c -+++ miniupnpd/upnpsoap.c -@@ -1842,7 +1842,7 @@ GetOutboundPinholeTimeout(struct upnphtt - rem_port = GetValueFromNameValueList(&data, "RemotePort"); - protocol = GetValueFromNameValueList(&data, "Protocol"); - -- if (!int_port || !ext_port || !protocol) -+ if (!int_port || !rem_port || !protocol) - { - ClearNameValueList(&data); - SoapError(h, 402, "Invalid Args"); diff -Nru miniupnpd-2.1/debian/patches/CVE-2019-12110_upnp_redirect_accept_NULL_desc_argument.patch miniupnpd-2.2.1/debian/patches/CVE-2019-12110_upnp_redirect_accept_NULL_desc_argument.patch --- miniupnpd-2.1/debian/patches/CVE-2019-12110_upnp_redirect_accept_NULL_desc_argument.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/CVE-2019-12110_upnp_redirect_accept_NULL_desc_argument.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Subject: CVE-2019-12110: upnp_redirect(): accept NULL desc argument -Author: Thomas Bernard -Date: Tue, 18 Dec 2018 22:59:18 +0100 -Last-Update: 2019-06-07 -Bug-Debian: https://bugs.debian.org/930050 - -diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c -index 7c179b62..74926f08 100644 ---- a/upnpredirect.c -+++ b/upnpredirect.c -@@ -356,6 +356,10 @@ upnp_redirect(const char * rhost, unsigned short eport, - "%hu->%s:%hu %s", eport, iaddr, iport, protocol); - return -3; - } -+ -+ if (desc == NULL) -+ desc = ""; /* assume empty description */ -+ - /* IGDv1 (WANIPConnection:1 Service Template Version 1.01 / Nov 12, 2001) - * - 2.2.20.PortMappingDescription : - * Overwriting Previous / Existing Port Mappings: diff -Nru miniupnpd-2.1/debian/patches/CVE-2019-12111_pcpserver.c_copyIPv6IfDifferent_check_for_NULL_src_argument.patch miniupnpd-2.2.1/debian/patches/CVE-2019-12111_pcpserver.c_copyIPv6IfDifferent_check_for_NULL_src_argument.patch --- miniupnpd-2.1/debian/patches/CVE-2019-12111_pcpserver.c_copyIPv6IfDifferent_check_for_NULL_src_argument.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/CVE-2019-12111_pcpserver.c_copyIPv6IfDifferent_check_for_NULL_src_argument.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -Subject: CVE-2019-12111 pcpserver.c: copyIPv6IfDifferent() check for NULL src argument -Author: Thomas Bernard -Date: Tue, 18 Dec 2018 23:04:14 +0100 -Origin: https://github.com/miniupnp/miniupnp/commit/cb8a02af7a5677cf608e86d57ab04241cf34e24f.patch -Last-Update: 2019-06-07 -Bug-Debian: https://bugs.debian.org/930050 - -diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c -index 9acfb44f..a964aa9f 100644 ---- a/pcpserver.c -+++ b/pcpserver.c -@@ -177,7 +177,7 @@ static const char * getPCPOpCodeStr(uint8_t opcode) - * buffers are same */ - static void copyIPv6IfDifferent(void * dest, const void * src) - { -- if(dest != src) { -+ if(dest != src && src != NULL) { - memcpy(dest, src, sizeof(struct in6_addr)); - } - } diff -Nru miniupnpd-2.1/debian/patches/makefile-tweak.patch miniupnpd-2.2.1/debian/patches/makefile-tweak.patch --- miniupnpd-2.1/debian/patches/makefile-tweak.patch 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/makefile-tweak.patch 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,54 @@ +diff --git a/Makefile.linux b/Makefile.linux +index 8f16886..f27ccf1 100644 +--- a/Makefile.linux ++++ b/Makefile.linux +@@ -52,7 +52,7 @@ ETCINSTALLDIR = $(PREFIX)/etc/miniupnpd + MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8 + + include config.mk +-include $(SRCDIR)/gitrev.mk ++#include $(SRCDIR)/gitrev.mk + include $(SRCDIR)/objects.mk + + # sources in netfilter/ directory +@@ -129,12 +129,9 @@ clean: + $(RM) validateupnppermissions validategetifaddr validatessdppktgen + $(RM) -r dox/ + +-install: miniupnpd $(SRCDIR)/miniupnpd.8 miniupnpd.conf \ ++install: $(SRCDIR)/miniupnpd.8 miniupnpd.conf \ + $(NETFILTER_SCRIPTS) \ + $(SRCDIR)/linux/miniupnpd.init.d.script +- $(STRIP) miniupnpd +- $(INSTALL) -d $(DESTDIR)$(SBININSTALLDIR) +- $(INSTALL) miniupnpd $(DESTDIR)$(SBININSTALLDIR) + $(INSTALL) -d $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter/iptables_init.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter/iptables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) +diff --git a/Makefile.linux_nft b/Makefile.linux_nft +index e1c517d..786d184 100644 +--- a/Makefile.linux_nft ++++ b/Makefile.linux_nft +@@ -45,7 +45,7 @@ ETCINSTALLDIR = $(PREFIX)/etc/miniupnpd + MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8 + + include config.mk +-include $(SRCDIR)/gitrev.mk ++#include $(SRCDIR)/gitrev.mk + include $(SRCDIR)/objects.mk + + # sources in the netfilter_nft/ directory +@@ -116,12 +116,9 @@ clean: + $(RM) miniupnpdctl.o + $(RM) -r dox/ + +-install: miniupnpd $(SRCDIR)/miniupnpd.8 $(SRCDIR)/miniupnpd.conf \ ++install: $(SRCDIR)/miniupnpd.8 $(SRCDIR)/miniupnpd.conf \ + $(NFT_SCRIPTS) \ + $(SRCDIR)/linux/miniupnpd.init.d.script +- $(STRIP) miniupnpd +- $(INSTALL) -d $(DESTDIR)$(SBININSTALLDIR) +- $(INSTALL) miniupnpd $(DESTDIR)$(SBININSTALLDIR) + $(INSTALL) -d $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter_nft/scripts/nft_init.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter_nft/scripts/nft_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) diff -Nru miniupnpd-2.1/debian/patches/miniupnpd-allow-ipv4-listening-specify.patch miniupnpd-2.2.1/debian/patches/miniupnpd-allow-ipv4-listening-specify.patch --- miniupnpd-2.1/debian/patches/miniupnpd-allow-ipv4-listening-specify.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/miniupnpd-allow-ipv4-listening-specify.patch 2021-01-04 13:48:54.000000000 +0000 @@ -1,9 +1,9 @@ diff --git a/miniupnpd.c b/miniupnpd.c -index 7ae3466..ed6ab08 100644 +index 5a247ca..e0fac04 100644 --- a/miniupnpd.c +++ b/miniupnpd.c -@@ -1001,20 +1001,10 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str) - fprintf(stderr, "Cannot get index for network interface %s", +@@ -1044,20 +1044,10 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str) + fprintf(stderr, "Cannot get index for network interface %s\n", lan_addr->ifname); } -#ifdef ENABLE_IPV6 diff -Nru miniupnpd-2.1/debian/patches/miniupnpd-netfilter-build-with-linux-kernel-5.0.patch miniupnpd-2.2.1/debian/patches/miniupnpd-netfilter-build-with-linux-kernel-5.0.patch --- miniupnpd-2.1/debian/patches/miniupnpd-netfilter-build-with-linux-kernel-5.0.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/miniupnpd-netfilter-build-with-linux-kernel-5.0.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -From: Thomas Bernard -Date: Sun, 3 Feb 2019 13:26:27 +0100 -Subject: miniupnpd/netfilter: build with linux kernel 5.0 - -should fix #346 ---- - netfilter/iptcrdr.c | 38 +++++++++++++++++++++++++++----------- - 1 file changed, 27 insertions(+), 11 deletions(-) - -diff --git a/netfilter/iptcrdr.c b/netfilter/iptcrdr.c -index 48c6dbb..82c5890 100644 ---- a/netfilter/iptcrdr.c -+++ b/netfilter/iptcrdr.c -@@ -1,7 +1,7 @@ - /* $Id: iptcrdr.c,v 1.59 2016/03/08 09:23:52 nanard Exp $ */ - /* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ -- * (c) 2006-2016 Thomas Bernard -+ * (c) 2006-2019 Thomas Bernard - * This software is subject to the conditions detailed - * in the LICENCE file provided within the distribution */ - #include -@@ -1116,9 +1116,11 @@ addnatrule(int proto, unsigned short eport, - } else { - match = get_udp_match(eport, 0); - } -- e->nfcache = NFC_IP_DST_PT; -+ e->nfcache = NFC_UNKNOWN; - target = get_dnat_target(iaddr, iport); -- e->nfcache |= NFC_UNKNOWN; -+#ifdef NFC_IP_DST_PT -+ e->nfcache |= NFC_IP_DST_PT; -+#endif - tmp = realloc(e, sizeof(struct ipt_entry) - + match->u.match_size - + target->u.target_size); -@@ -1186,9 +1188,11 @@ addmasqueraderule(int proto, - } else { - match = get_udp_match(0, iport); - } -- e->nfcache = NFC_IP_DST_PT; -+ e->nfcache = NFC_UNKNOWN; - target = get_masquerade_target(eport); -- e->nfcache |= NFC_UNKNOWN; -+#ifdef NFC_IP_DST_PT -+ e->nfcache |= NFC_IP_DST_PT; -+#endif - tmp = realloc(e, sizeof(struct ipt_entry) - + match->u.match_size - + target->u.target_size); -@@ -1266,9 +1270,14 @@ addpeernatrule(int proto, - } else { - match = get_udp_match(rport, iport); - } -- e->nfcache = NFC_IP_DST_PT | NFC_IP_SRC_PT; -+ e->nfcache = NFC_UNKNOWN; - target = get_snat_target(eaddr, eport); -- e->nfcache |= NFC_UNKNOWN; -+#ifdef NFC_IP_DST_PT -+ e->nfcache |= NFC_IP_DST_PT; -+#endif -+#ifdef NFC_IP_SRC_PT -+ e->nfcache |= NFC_IP_SRC_PT; -+#endif - tmp = realloc(e, sizeof(struct ipt_entry) - + match->u.match_size - + target->u.target_size); -@@ -1337,9 +1346,14 @@ addpeerdscprule(int proto, unsigned char dscp, - } else { - match = get_udp_match(rport, iport); - } -- e->nfcache = NFC_IP_DST_PT | NFC_IP_SRC_PT; -+ e->nfcache = NFC_UNKNOWN; - target = get_dscp_target(dscp); -- e->nfcache |= NFC_UNKNOWN; -+#ifdef NFC_IP_DST_PT -+ e->nfcache |= NFC_IP_DST_PT; -+#endif -+#ifdef NFC_IP_SRC_PT -+ e->nfcache |= NFC_IP_SRC_PT; -+#endif - tmp = realloc(e, sizeof(struct ipt_entry) - + match->u.match_size - + target->u.target_size); -@@ -1420,11 +1434,13 @@ add_filter_rule(int proto, const char * rhost, - } else { - match = get_udp_match(iport,0); - } -- e->nfcache = NFC_IP_DST_PT; - e->ip.dst.s_addr = inet_addr(iaddr); - e->ip.dmsk.s_addr = INADDR_NONE; -+ e->nfcache = NFC_UNKNOWN; - target = get_accept_target(); -- e->nfcache |= NFC_UNKNOWN; -+#ifdef NFC_IP_DST_PT -+ e->nfcache |= NFC_IP_DST_PT; -+#endif - tmp = realloc(e, sizeof(struct ipt_entry) - + match->u.match_size - + target->u.target_size); diff -Nru miniupnpd-2.1/debian/patches/miniupnpd-netfilter-ipctcrdr.c-conditionnaly-use-NFC_UNKN.patch miniupnpd-2.2.1/debian/patches/miniupnpd-netfilter-ipctcrdr.c-conditionnaly-use-NFC_UNKN.patch --- miniupnpd-2.1/debian/patches/miniupnpd-netfilter-ipctcrdr.c-conditionnaly-use-NFC_UNKN.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/miniupnpd-netfilter-ipctcrdr.c-conditionnaly-use-NFC_UNKN.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -From: Thomas Bernard -Date: Sun, 3 Feb 2019 19:04:44 +0100 -Subject: miniupnpd/netfilter/ipctcrdr.c: conditionnally use NFC_UNKNOWN as - well - -fix #346 ---- - netfilter/iptcrdr.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/netfilter/iptcrdr.c b/netfilter/iptcrdr.c -index 82c5890..f40b8a2 100644 ---- a/netfilter/iptcrdr.c -+++ b/netfilter/iptcrdr.c -@@ -1116,7 +1116,9 @@ addnatrule(int proto, unsigned short eport, - } else { - match = get_udp_match(eport, 0); - } -+#ifdef NFC_UNKNOWN - e->nfcache = NFC_UNKNOWN; -+#endif - target = get_dnat_target(iaddr, iport); - #ifdef NFC_IP_DST_PT - e->nfcache |= NFC_IP_DST_PT; -@@ -1188,7 +1190,9 @@ addmasqueraderule(int proto, - } else { - match = get_udp_match(0, iport); - } -+#ifdef NFC_UNKNOWN - e->nfcache = NFC_UNKNOWN; -+#endif - target = get_masquerade_target(eport); - #ifdef NFC_IP_DST_PT - e->nfcache |= NFC_IP_DST_PT; -@@ -1270,7 +1274,9 @@ addpeernatrule(int proto, - } else { - match = get_udp_match(rport, iport); - } -+#ifdef NFC_UNKNOWN - e->nfcache = NFC_UNKNOWN; -+#endif - target = get_snat_target(eaddr, eport); - #ifdef NFC_IP_DST_PT - e->nfcache |= NFC_IP_DST_PT; -@@ -1346,7 +1352,9 @@ addpeerdscprule(int proto, unsigned char dscp, - } else { - match = get_udp_match(rport, iport); - } -+#ifdef NFC_UNKNOWN - e->nfcache = NFC_UNKNOWN; -+#endif - target = get_dscp_target(dscp); - #ifdef NFC_IP_DST_PT - e->nfcache |= NFC_IP_DST_PT; -@@ -1436,7 +1444,9 @@ add_filter_rule(int proto, const char * rhost, - } - e->ip.dst.s_addr = inet_addr(iaddr); - e->ip.dmsk.s_addr = INADDR_NONE; -+#ifdef NFC_UNKNOWN - e->nfcache = NFC_UNKNOWN; -+#endif - target = get_accept_target(); - #ifdef NFC_IP_DST_PT - e->nfcache |= NFC_IP_DST_PT; diff -Nru miniupnpd-2.1/debian/patches/remove-unused-libssl-dep.patch miniupnpd-2.2.1/debian/patches/remove-unused-libssl-dep.patch --- miniupnpd-2.1/debian/patches/remove-unused-libssl-dep.patch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/remove-unused-libssl-dep.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -diff --git a/Makefile.linux b/Makefile.linux -index e4063ac..059a0df 100644 ---- a/Makefile.linux -+++ b/Makefile.linux -@@ -153,8 +153,6 @@ LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libmnl) - LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libnetfilter_conntrack) - endif # ($(TEST),1) - --LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libssl) -- - TEST := $(shell $(PKG_CONFIG) --exists uuid && echo 1) - ifeq ($(TEST),1) - LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l uuid) diff -Nru miniupnpd-2.1/debian/patches/series miniupnpd-2.2.1/debian/patches/series --- miniupnpd-2.1/debian/patches/series 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/patches/series 2021-01-04 13:48:54.000000000 +0000 @@ -1,9 +1,2 @@ +makefile-tweak.patch miniupnpd-allow-ipv4-listening-specify.patch -remove-unused-libssl-dep.patch -CVE-2019-12107_upnp_event_prepare_check_the_return_value_of_snprintf.patch -CVE-2019-12108_GetOutboundPinholeTimeout_check_args.patch -CVE-2019-12109_fix_error_from_commit_13585f1.patch -CVE-2019-12110_upnp_redirect_accept_NULL_desc_argument.patch -CVE-2019-12111_pcpserver.c_copyIPv6IfDifferent_check_for_NULL_src_argument.patch -miniupnpd-netfilter-build-with-linux-kernel-5.0.patch -miniupnpd-netfilter-ipctcrdr.c-conditionnaly-use-NFC_UNKN.patch diff -Nru miniupnpd-2.1/debian/rules miniupnpd-2.2.1/debian/rules --- miniupnpd-2.1/debian/rules 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/rules 2021-01-04 13:48:54.000000000 +0000 @@ -5,38 +5,40 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic -export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed +export DEB_LDFLAGS_MAINT_APPEND = + +export SRCDIR = . %: dh $@ override_dh_auto_clean: - $(MAKE) -f Makefile.linux clean - rm -rf config.h - -override_dh_clean: - if [ -h Makefile ]; then \ - mv Makefile.bsd Makefile; \ - fi - dh_clean + +$(MAKE) -f Makefile.linux clean + rm -f .configure.cache config.mk config.h Makefile netfilter/miniupnpd netfilter_nft/miniupnpd override_dh_auto_configure: - if [ ! -h Makefile ]; then \ - mv Makefile Makefile.bsd; \ - ln -s Makefile.linux Makefile; \ - fi - dh_auto_configure + # skip override_dh_auto_build: - dh_auto_build -- CONFIG_OPTIONS="--igd2 --ipv6 --leasefile --vendorcfg --pcp-peer --portinuse" + ./configure --igd2 --ipv6 --vendorcfg --pcp-peer --portinuse --firewall=iptables + +$(MAKE) -f Makefile.linux miniupnpd + mv miniupnpd netfilter/ + +$(MAKE) -f Makefile.linux clean + ./configure --igd2 --ipv6 --vendorcfg --pcp-peer --portinuse --firewall=nftables + +$(MAKE) -f Makefile.linux_nft miniupnpd + mv miniupnpd netfilter_nft/ override_dh_auto_test: # some test scripts missing from the tarball override_dh_auto_install: - dh_auto_install -- STRIP=echo + +$(MAKE) -f Makefile.linux_nft install STRIP=echo DESTDIR=debian/tmp + +$(MAKE) -f Makefile.linux install STRIP=echo DESTDIR=debian/tmp + # I don't know why + rm debian/tmp/etc/miniupnpd/miniupnpd.conf~ +execute_after_dh_install-indep: # Move the miniupnpd.conf in /usr/share so it's not marked as CONFFILE mkdir -p $(CURDIR)/debian/miniupnpd/usr/share/miniupnpd mv $(CURDIR)/debian/miniupnpd/etc/miniupnpd/miniupnpd.conf $(CURDIR)/debian/miniupnpd/usr/share/miniupnpd/ @@ -52,11 +54,17 @@ # Copy the /etc/default/miniupnpd to /usr/share cp $(CURDIR)/debian/examples/miniupnpd.default $(CURDIR)/debian/miniupnpd/usr/share/miniupnpd/ -override_dh_installinit: - dh_installinit --no-enable --no-start +override_dh_installinit-indep: + dh_installinit -i --no-enable --no-start + +override_dh_installsystemd-indep: + dh_installsystemd -i --no-enable --no-start + -override_dh_installsystemd: - dh_installsystemd --no-enable --no-start +############################################ +### Below is to manage upstream Git repo ### +### and is not used during package build ### +############################################ display-po-stats: cd $(CURDIR)/debian/po ; for i in *.po ; do \ diff -Nru miniupnpd-2.1/debian/tests/unittest.sh miniupnpd-2.2.1/debian/tests/unittest.sh --- miniupnpd-2.1/debian/tests/unittest.sh 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/tests/unittest.sh 2021-01-04 13:48:54.000000000 +0000 @@ -1,6 +1,7 @@ #!/bin/sh set -e +export SRCDIR=. cp debian/tests/testgetifaddr.sh debian/tests/testupnppermissions.sh . make -f Makefile.linux check make -f Makefile.linux clean diff -Nru miniupnpd-2.1/debian/upstream/metadata miniupnpd-2.2.1/debian/upstream/metadata --- miniupnpd-2.1/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/debian/upstream/metadata 2021-01-04 13:48:54.000000000 +0000 @@ -0,0 +1,4 @@ +Bug-Database: https://github.com/miniupnp/miniupnp/issues +Bug-Submit: https://github.com/miniupnp/miniupnp/issues/new +Repository: https://github.com/miniupnp/miniupnp.git +Repository-Browse: https://github.com/miniupnp/miniupnp diff -Nru miniupnpd-2.1/debian/upstream/signing-key.asc miniupnpd-2.2.1/debian/upstream/signing-key.asc --- miniupnpd-2.1/debian/upstream/signing-key.asc 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/upstream/signing-key.asc 2021-01-04 13:48:54.000000000 +0000 @@ -1,51 +1,52 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -mQINBFXbQL4BEADBIKnH+FqvEtMcpWW0x8bVMZaDdGWP0/wgbGblzWQnKNDa6sYr -SoLe5IdEl09U10gvMhHSQfGPR/tjI0iRJj8p9/30yD5QvzphtLcnNhsidhzibOWt -LX33aFW65xlmmXCLOI63E5VRKgza26Kt6LLHicry/UXKrQAQwgjI376uRxv3UMeO -x3eE+deJrsB93rgIVlcma42F8SPebcRPaZTinqmUlVDAvVWRWk7ZKdZpc33gtuHp -Hi/jwtYeQaad9zBT3SLth2Jp/sigslRANxdtLGUKtFaxN8PJly/hjwhptSX2ETWc -Hqhtcd51fNf1lJgLyiln2dsQbsGmGInBMU7Gth/3rrz0cG1ry4iAQETu9xyRC6Sr -CohF1+Fg50h/c1UW8AoO2FPi+Us905SM5vm2vbOeDP8LSgX99QIAp5OJ+cdjUVAF -RmIFIWItnWEiqroqEQCFnqLR+5Jfv+K7elhe1DNz7r/u2QaOV9iTL+0GxA/F1DgF -euRkIFh4cVIZxlo570kZ01lUXpwU4ksnBRCUAj6PAggEdNY7KFhLz62Zcee8OJBL -KDEIz1srmG3+xYbVWVf0jJRuvi3Adiy6MWKkrooOeZrIg/d0elu29lLvH+2J6/1z -5UKyIVo3oroARY73EmcFAO2tqX7ORLeP0kR8rSIU5vvCFpYwdMSj60SGhQARAQAB -tChtaW5pdXBucCAobWluaXVwbnAgISkgPG1pbml1cG5wQGZyZWUuZnI+iQI+BBMB -AgAoBQJV20C+AhsjBQkJZgGABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAP -8RtnpcCGPJX/EACxPzwKuiJUlkue4MHl3L2nVitajz5DCvM2Lw7x/PmKN7jkMCiG -L/NVxkuzzavO/prQsaKy1nbWHlaMppzG7+vcAY43pEBBRU4U+31nAf3QZ4Qwx2Vw -7aLqyatxlsn+vF1p/hUFeCl01B/AylgLe3zXYzuy3aNbZzdErRVQCwM6bsBoy2PC -ANgf8QfJxlwPCyaEAdoyNc+1Q5yZJXLqHvfIZz29weLdVX/7TzXYGu2HuMUqul7g -q2KJzV9/QH7Yyyh3U9h8bhLffBvFbWS/B6Isq11qDq7QQRODfqTUFmwiYUDk/PFC -aI6JDAsKvQXg2sXbr18In3PxNh8Ig1KRnF5FFNlXNbCe7PqLlNb6i4xHMbI5tsJk -b30eEYX5YKeMFtjmTAfkTGdShEVR5ljAcOJeqjUHkHqKaCap76STwtBjQBzKXo90 -794qRARZjK5ExlRN75BlQu4A9XVkNQW9YnyZdirD+KYq7gkVM7ftAJcVwKLK/s0X -h3Fxpo1IftIjBdMru2n8tG4o6HsO4p1OCCC8yIdjICEqTgxHPJZkfdaNRa1o6T05 -hz++la+4yz0lp6r6+JYq5reYXN7VVQWGmfJdfvXLcdWTXNcuDE4b94192CQmWK0s -sbNCg7iq7wRK6Ms/iB0kSFvpTH3ni7iZKDH2NwWROc3ImuAR+26ppzVzGrkCDQRV -20C+ARAAu3mvnRGTdN1nsOG4xNwj6Zcm9gm704Co24/jQzeHycD+oCn/S9yd+qQJ -VWvUaR0zCpKWsk348fAC40HYtUaNior6VZcBNOo9SSrwMDkwQ5i5FH7zl9GzsqQa -1Wyx1rXDa627eZ//W6Gfm2YwOo0qotB0WsWKl3k1EJjV/NSDbZpB6ZBRivGttyhB -+9XcKQzgNmhTy8S4WQGxqSrkWXeIESpRlMIyGN5bRT4CfDQFuVbtwN7wsMLXPhw3 -vLFdJLg30cnM1kkHEdbh2tZanHj2K1/xvq0suhnzsJNS8IrUiPDnmzwWFF/tFp+A -MgOAAeu6UkfVgmr+Vkn/X9ZLP8BThnuJ9HyEKL9FQLVLOHnzKQphWzYFdNQ50hXa -xiaO9Ofk7E3wOJRTKuoXNGloA51F37d5iGBbiTLM2+sxOAfrL6HWIooUaMmDh2Ob -RbdxDQUYZfoHlEFwQaNGQ595q9XNuhNiJejKpaprdRHcEZw8chZwD9A39Cgz9glH -Wo1RnlCY/wk7oeTrAZzhL//6APqh+ruHPQ/LzJGR9jVmGejRM6j2tf+KVSlmS08e -GERos+1mdiW9lQvJPZouH3MoEK5LFYn8Prby+7UHO8CMGcEtUCT7qv6V27x6gued -QCDV/2L1uRSFEi5aPsKlyzMpQjwqbqSY0ZAEmuGpsUrMGVNELO0AEQEAAYkCJQQY -AQIADwUCVdtAvgIbDAUJCWYBgAAKCRAP8RtnpcCGPEk/D/9emYuV2PwxOUZO3UEy -go/cLl/oOk5SG9NwnpbwqvEyTGMHkHSKcRqCcSeywsHz1RsJR2WqKluFKrhLHY/K -EryU0/uJW/1g2H8uJqxNopRr1MOQ/MCafmDH9F7hklzASKId8S7fXItPz7QkouQ4 -DBdF+k+BuODUe73kBsRZlK2tnP/wFeV+WfMAXxc/0gisw0FM6DbzyZx3FcdTrAL3 -zU81NE6RhtMfEatC0YbkKurySHMNZ5zq98bnxhW2LiOgD7YE9WM/8yTHrp26ys9N -WGQL0ebo+M4ESsLNuwOi3fTORDAhGy/SXXlnW/46CN7l8wGz0bWiVfb3wSJoIJca -hK9RMA7ZgqICW1lJlbvl2dPtszWV133cfz911Vo+2TLgs23OGkbKygH9HsvXkMB4 -zzz1G63WE1UzSxdSHovu8+mG0tEppp9TjI4ZEAof4j6ZgVn8W3FNa9NiCYWlyeVJ -/hQoIpbGtm3y1DdiFzNC+kNrgC5PCLy64x61iyYPyf18ulPwb4BhxemtHtk9NY0R -/MkJJBoTCBq1q926Nvn41X9qcwWAIBPp27irdkgI3ImyAWN1TwnQ3xDZnj9iy9w9 -tDrSo77fjfYKlDj05uyASP8yzuT9ZZhKKM3xMRuUZs2ARwYrebv/MVqEkZPsDe7q -ZPvbBkFYl8RQdRZJ3Sh/UiE9MA== -=AKr/ +mQINBF9nX+YBEACgjkJ54yHr9k0RGeHfTyxCy69XhsRdYwOIeWYCL5mEaTHMYg81 +x/E5+q9ENODR0hg3m/bjm4460Q4ZozTuDOesKRvJhD2nTk8rrHcQQLxDqzPcUz34 +5Y4MXr09shkIEf/nuHR+4oZtpc2ysbKYoEEjuA/OFiX5rM/EaIrkR5VsEH5aM77u +UYvJrchlWGedXs0iY/qUvdgjA1Li3C9r5XmvBSDU46FpD4PrH/L5mtQHdwOVAHWA +s+PQBGNDplMc6P7vp7qJo28JULoxgWEbLRupeIPvij6jnSKo+ukqPX2gJQT1JgO3 +S3VK0tc15ZvXjllXRJfU9TxVGKafQk5jOeMLsAIdl2zVBU6fLzuGrnhhTOlZPEz6 +iU9Aoc59pTzFA3eoRZqxRKjz532cQUYBMdoSfT8Bkn30roCGp9PV1wiebjoiT+e5 +Hq6PnjSZFs5GJTu++2sEsPxQP/d/Klja1mSMRKjfwvh/TJjEKQBwt5D6WFnGv6n+ +7vaZsXkowNw20JTEDQpMAB1MIfj7AWyuZ9tl2fRgVsQp5UUF/sFKpFaKB6Pm1UkA +nmNCMNEbd8r+rYrEjkA0oeHv+sBEE//9dAFhzYTrrhZTQfLQaiAErbSGxvh1oPDS +jClNycEOPKmO510sSwo80FpKQmgOEzQyz7qQ4L0UlKdT0AviTkB7VDMcawARAQAB +tBttaW5pdXBucCA8bWluaXVwbnBAZnJlZS5mcj6JAlQEEwEIAD4WIQR1Hp/2lEo7 +NqVDIhbbURBDoxrKrwUCX2df5gIbAwUJEswDAAULCQgHAgYVCgkICwIEFgIDAQIe +AQIXgAAKCRDbURBDoxrKrzhPD/wIKG6TNeUmBf6/5r/Y79R9GNYp3tJ4nOpYPn6B +AXzK7XF7vVKlOb/28sASrEB+wAat/UonCGwI/EWPupbJJ5qjnACO4HVv+eYgvKom +KhFf9ioQ4+KbdHwpXC+fUaT1PuOcACP7IIbZ2g86JzRLONavGbwVoPh3wYWivkHr +xFslF2oxkSFols117joayMSxopJqhx0I/AF6oUGXFDE96zCDGk3fZvwmZU/mTs+a +L0Bg3P9kcY16abk6tIMawxAVinfKfvpRlPQRZgWtFSXbSG/6CpZ1q+8z0K6OydE/ +qMwa3rbwT5b4wQMeFO2McrekWZ+H8NDvzPy4UyeFBA95pva28+sA+krG6V8/usBK +EnoSvsLw18PDduLRuae75XKoJyKnNQhsPiGoSeQHKipx9S9M5+jz/VpuVLizGKDJ +tXXq2EHCZfTOjZf4gJK4Ck8rWs3GOMtBqWYfziJaeBhH1RSNd3RBKSEWwIhmrLFj +cv65+Kz3JT+udmfatyBDGgA3rH+x+rb8G+obKV8xcw/ZJZeamLQyQd13rwvY2eOS +kfYZU8pyKtW44W3WWahMrtyXT0P0KvFqG8M2zkp66jB8+0Nlsrg6+SyO3yYRHcrd +BQGTAlRebhwVU1Om1Pv2p8oMtT1bVi7m3JSeMP/+8G7mrMqjmPU3VSfpxmhX9nue +0Ozjm7kCDQRfZ1/mARAA82/OEc4BgGad9lR8Tjz9bOkllvkIlmmPTuMkjmsvjQ9J +omJXCCDnGmMmONn/Ka7Zxq4QH5f4WzS/n/H2lwOG+W3Whx3z0/RByOU+OWTk2lQ6 +m8PrU+KPajEjxrRbMlBU+BZoyGjjN20prz0UeIvbNSJqrOWzkus5EfqFQQKvtTqF +n1bb4QILPP5S35MByewfKaNXkOnV6c6nt3mU/qnpQtCcRRAuzyyb5FoGcjhr3nod +cXizLY3z6hyeEn7H26S5BHGMt9ftUKjEid5hODJ7upIvl1XT3KmY/CXvfkVxUZTB +eFbUHJULg0W8maLppsZegqWFXygtZ25Abq4WsBynT2zn/woswRj2t4YaJhabJz40 +aJHvQP08rGKiamJEApDtefnDiUm54pxQuJOqoyORHnb7IG7d7rhT8G0339kCAwas +DUevWKBDxJ5iVUmKdq/3+JAfwBmivK43RvgIUdsZAJcxEy6SCPGkDs7LPtUriiSu +NNs6LVwo248NsSPiuQS/RyfV4ZOd74krYC92RrFp32JbzEU8sN4ahpOJaeWeyRyG +dSx3QQmG3qwZIjKVqwWDC7OKDGpp6VJD+wKtGZhLEmfMCuXFC7uY+Qy/gRkCqcp1 +uTILkAiYdw3WBZjz7KgbDB21tiJtsatzbi9OnXY4dLJHBH+bDqPo0PhOBcR3JwkA +EQEAAYkCPAQYAQgAJhYhBHUen/aUSjs2pUMiFttREEOjGsqvBQJfZ1/mAhsMBQkS +zAMAAAoJENtREEOjGsqv9owQAIdRprDKm8FmHvsnpftphKoqWMMBN+MXCYORz9CJ +UgDzZc6ndAYZ9v4vhGlsvFwIgyh3X2AIJ4eDwubY8Vvn/jpvilw5CgXRQSCu5XPa +QeXcs292BiGBqzhixUTfH0MxFl+BavJJVMYByrkbHajYQvLsp4HtTk2meRcuQlqL +zb3ofcWOC2rKfxI2ohD/aa3OUrqnrTnU2U9ieyI6r1ZisUHWDMxSrrXv4x26gJ9w ++uZnki138rSnv5z6fu/f74zza9i3Dr9vdXpmg/Pnd1nVuvnidu7VgA5Jo2e34DYC +cWdtn/DMbRpBYSV9OS1AdHu3IGp1TVSjxMkVMOa/eC/+QyGkAct+WrVqIP99R31j +Orw9iwSH0D1nugI3FGhHM8JNMbTwz9+UC7JsnB1sZYVa8QhVY3hnPoKe5qaG8Q0A +6wucEoP8lvNnM+GkzmpyrvhS/yh6Wet+LffoqqDL8wtwONLgCqlmujhsuw7a7Z66 +hGS5yJ2Ks2eXosp31sRp0uYlmEPtnqx2KGAqJaPJYsj6bvN4g5m7/KSJpgcu3qSO +6KjX1P4lYI8gvIlZrx/C0zes4hyQ5MIW2tjvtnI/46ax3djVskHAqcO7BN9VDM3T ++1241/Vl6QGhGbVQ3uNNHIyt4oWxPagnLygB+0gx1AwP/f8cTMtF/afqDMOWrIOE +QP3d +=bCg1 -----END PGP PUBLIC KEY BLOCK----- diff -Nru miniupnpd-2.1/debian/watch miniupnpd-2.2.1/debian/watch --- miniupnpd-2.1/debian/watch 2020-03-27 13:11:07.000000000 +0000 +++ miniupnpd-2.2.1/debian/watch 2021-01-04 13:48:54.000000000 +0000 @@ -1,3 +1,3 @@ version=4 -opts=filenamemangle=s/.*file=([^&]*)/$1/,pgpsigurlmangle=s%$%.sig% \ - http://miniupnp.free.fr/files/download.php\?file=miniupnpd-(\d\.\d(?:-.*)?).tar.gz +opts=filenamemangle=s/.*file=([^&]*)/$1/,uversionmangle=s/-RC/~rc/,pgpsigurlmangle=s%$%.sig% \ + http://miniupnp.free.fr/files/download.php\?file=miniupnpd-(\d\.\d(?:\.\d)?(?:-.*)?).tar.gz diff -Nru miniupnpd-2.1/genconfig.sh miniupnpd-2.2.1/genconfig.sh --- miniupnpd-2.1/genconfig.sh 2018-05-08 21:34:44.000000000 +0000 +++ miniupnpd-2.2.1/genconfig.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,634 +0,0 @@ -#! /bin/sh -# $Id: genconfig.sh,v 1.97 2018/05/08 21:27:56 nanard Exp $ -# vim: tabstop=4 shiftwidth=4 noexpandtab -# -# miniupnp daemon -# http://miniupnp.free.fr or https://miniupnp.tuxfamily.org/ -# (c) 2006-2018 Thomas Bernard -# This software is subject to the conditions detailed in the -# LICENCE file provided within the distribution - -# default to UPnP Device Architecture (UDA) v1.1 -# some control points do not like UDA v2.0 -UPNP_VERSION_MAJOR=1 -UPNP_VERSION_MINOR=1 - -for argv; do -case "$argv" in - --ipv6) IPV6=1 ;; - --igd2) IGD2=1 ;; - --strict) STRICT=1 ;; - --leasefile) LEASEFILE=1 ;; - --vendorcfg) VENDORCFG=1 ;; - --pcp-peer) PCP_PEER=1 ;; - --portinuse) PORTINUSE=1 ;; - --uda-version=*) - UPNP_VERSION=$(echo $argv | cut -d= -f2) - UPNP_VERSION_MAJOR=$(echo $UPNP_VERSION | cut -s -d. -f1) - UPNP_VERSION_MINOR=$(echo $UPNP_VERSION | cut -s -d. -f2) - echo "Setting UPnP version major=$UPNP_VERSION_MAJOR minor=$UPNP_VERSION_MINOR" - if [ -z "$UPNP_VERSION_MAJOR" ] || [ -z "$UPNP_VERSION_MINOR" ] ; then - echo "UPnP Version invalid in option $argv" - exit 1 - fi ;; - --disable-pppconn) DISABLEPPPCONN=1 ;; - --help|-h) - echo "Usage : $0 [options]" - echo " --ipv6 enable IPv6" - echo " --igd2 build an IGDv2 instead of an IGDv1" - echo " --strict be more strict regarding compliance with UPnP specifications" - echo " --leasefile enable lease file" - echo " --vendorcfg enable configuration of manufacturer info" - echo " --pcp-peer enable PCP PEER operation" - echo " --portinuse enable port in use check" - echo " --uda-version=x.x set advertised UPnP version (default to ${UPNP_VERSION_MAJOR}.${UPNP_VERSION_MINOR})" - echo " --disable-pppconn disable WANPPPConnection" - exit 1 - ;; - *) - echo "Option not recognized : $argv" - echo "use -h option to display help" - exit 1 - ;; -esac -done - -RM="rm -f" -MV="mv" -CONFIGFILE=`mktemp tmp.config.h.XXXXXXXXXX` -CONFIGFILE_FINAL="config.h" -CONFIGMACRO="CONFIG_H_INCLUDED" - -MINIUPNPD_DATE=`date +"%Y%m%d"` -if [ -n "$SOURCE_DATE_EPOCH" ]; then - MINIUPNPD_DATE=`date --utc --date="@$SOURCE_DATE_EPOCH" +"%Y%m%d"` -fi - -# Facility to syslog -LOG_MINIUPNPD="LOG_DAEMON" - -# detecting the OS name and version -OS_NAME=`uname -s` -OS_VERSION=`uname -r` - -# pfSense special case -if [ -f /etc/platform ]; then - if [ `cat /etc/platform` = "pfSense" ]; then - OS_NAME=pfSense - OS_VERSION=`cat /etc/version` - fi -fi - -# OpenWRT special case -if [ -f ./os.openwrt ]; then - OS_NAME=OpenWRT - OS_VERSION=$(cat ./os.openwrt) -fi - -# AstLinux special case -if [ -f ./os.astlinux ]; then - OS_NAME=AstLinux - OS_VERSION=$(cat ./os.astlinux) -fi - -# Tomato USB special case -if [ -f ../shared/tomato_version ]; then - OS_NAME=Tomato - TOMATO_VER=`cat ../shared/tomato_version | cut -d' ' -f2,3` - OS_VERSION="Tomato $TOMATO_VER" -fi - -${RM} ${CONFIGFILE} - -echo "/* MiniUPnP Project" >> ${CONFIGFILE} -echo " * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/" >> ${CONFIGFILE} -echo " * (c) 2006-2018 Thomas Bernard" >> ${CONFIGFILE} -echo " * generated by $0 on `date`" >> ${CONFIGFILE} -echo " * `uname -a`" >> ${CONFIGFILE} -if [ -z "$*" ] ; then - echo " * using no command line option */" >> ${CONFIGFILE} -else - echo " * using command line options $* */" >> ${CONFIGFILE} -fi -echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE} -echo "#define $CONFIGMACRO" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} -echo "#include " >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} -echo "#define MINIUPNPD_VERSION \"`cat VERSION`\"" >> ${CONFIGFILE} -echo "#define MINIUPNPD_DATE \"$MINIUPNPD_DATE\"" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -cat >> ${CONFIGFILE} <> ${CONFIGFILE} -cat >> ${CONFIGFILE} <> ${CONFIGFILE} - -# OS Specific stuff -case $OS_NAME in - OpenBSD) - MAJORVER=`echo $OS_VERSION | cut -d. -f1` - MINORVER=`echo $OS_VERSION | cut -d. -f2` - #echo "OpenBSD majorversion=$MAJORVER minorversion=$MINORVER" - # rtableid was introduced in OpenBSD 4.0 - if [ $MAJORVER -ge 4 ]; then - echo "#define PFRULE_HAS_RTABLEID" >> ${CONFIGFILE} - fi - # from the 3.8 version, packets and bytes counters are double : in/out - if [ \( $MAJORVER -ge 4 \) -o \( $MAJORVER -eq 3 -a $MINORVER -ge 8 \) ]; then - echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE} - fi - # from the 4.7 version, new pf - if [ \( $MAJORVER -ge 5 \) -o \( $MAJORVER -eq 4 -a $MINORVER -ge 7 \) ]; then - echo "#define PF_NEWSTYLE" >> ${CONFIGFILE} - fi - # onrdomain was introduced in OpenBSD 5.0 - if [ $MAJORVER -ge 5 ]; then - echo "#define PFRULE_HAS_ONRDOMAIN" >> ${CONFIGFILE} - fi - FW=pf - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - OS_URL=http://www.openbsd.org/ - V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` - ;; - FreeBSD | GNU/kFreeBSD) - VER=`grep '#define __FreeBSD_version' /usr/include/sys/param.h | awk '{print $3}'` - if [ $VER -ge 700049 ]; then - echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE} - fi - HAVE_IP_MREQN=1 - # new way to see which one to use PF or IPF. - # see http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=957 - if [ -f /etc/rc.subr ] && [ -f /etc/default/rc.conf ] ; then - # source file with handy subroutines like checkyesno - . /etc/rc.subr - # source config file so we can probe vars - . /etc/default/rc.conf - if checkyesno ipfilter_enable; then - echo "Using ipf" - FW=ipf - elif checkyesno pf_enable; then - echo "Using pf" - FW=pf - elif checkyesno firewall_enable; then - echo "Using ifpw" - FW=ipfw - fi - fi - if [ -z $FW ] ; then - echo "Could not detect usage of ipf, pf, ipfw. Compiling for pf by default" - FW=pf - fi - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - OS_URL=http://www.freebsd.org/ - V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` - ;; - pfSense) - # we need to detect if PFRULE_INOUT_COUNTS macro is needed - FW=pf - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - OS_URL=http://www.pfsense.com/ - V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` - ;; - NetBSD) - if [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then - # source file with handy subroutines like checkyesno - . /etc/rc.subr - # source config file so we can probe vars - . /etc/rc.conf - if checkyesno pf; then - FW=pf - elif checkyesno ipfilter; then - FW=ipf - fi - fi - if [ -z $FW ] ; then - echo "Could not detect ipf nor pf, defaulting to pf." - FW=pf - fi - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - OS_URL=http://www.netbsd.org/ - ;; - DragonFly) - if [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then - # source file with handy subroutines like checkyesno - . /etc/rc.subr - # source config file so we can probe vars - . /etc/rc.conf - if checkyesno pf; then - FW=pf - elif checkyesno ipfilter; then - FW=ipf - fi - fi - if [ -z $FW ] ; then - echo "Could not detect ipf nor pf, defaulting to pf." - FW=pf - fi - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - # PFRULE_INOUT_COUNTS should be set for DragonFly > 2.8 - # version detection is not yet added to this script. - echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE} - # net.inet6.ip6.v6only has been on by default for many years - # and this sysctl node has been removed - V6SOCKETS_ARE_V6ONLY=1 - OS_URL=http://www.dragonflybsd.org/ - ;; - SunOS) - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - FW=ipf - echo "#define LOG_PERROR 0" >> ${CONFIGFILE} - echo "#define SOLARIS_KSTATS 1" >> ${CONFIGFILE} - # solaris 10 does not define u_int64_t ? - # but it does define uint64_t - echo "typedef uint64_t u_int64_t;" >> ${CONFIGFILE} - OS_URL=http://www.sun.com/solaris/ - ;; - Linux) - OS_URL=http://www.kernel.org/ - KERNVERA=`echo $OS_VERSION | awk -F. '{print $1}'` - KERNVERB=`echo $OS_VERSION | awk -F. '{print $2}'` - KERNVERC=`echo $OS_VERSION | awk -F. '{print $3}'` - KERNVERD=`echo $OS_VERSION | awk -F. '{print $4}'` - #echo "$KERNVERA.$KERNVERB.$KERNVERC.$KERNVERD" - # from the 2.4 version, struct ip_mreqn instead of struct ip_mreq - if [ \( $KERNVERA -ge 3 \) -o \( $KERNVERA -eq 2 -a $KERNVERB -ge 4 \) ]; then - HAVE_IP_MREQN=1 - fi - # Debian GNU/Linux special case - if [ -f /etc/debian_version ]; then - OS_NAME=Debian - OS_VERSION=`cat /etc/debian_version` - OS_URL=http://www.debian.org/ - fi - # same thing for Gentoo linux - if [ -f /etc/gentoo-release ]; then - OS_NAME=Gentoo - OS_VERSION=`cat /etc/gentoo-release` - OS_URL=http://www.gentoo.org/ - fi - # ClearOS special case - if [ -f /etc/clearos-release ]; then - OS_NAME=ClearOS - OS_VERSION=`grep ^base_version /etc/product | awk '{ print $3 }'` - OS_URL=https://www.clearos.com/ - fi - # use lsb_release (Linux Standard Base) when available - LSB_RELEASE=`which lsb_release` - if [ 0 -eq $? ]; then - OS_NAME=`${LSB_RELEASE} -i -s` - OS_VERSION=`${LSB_RELEASE} -r -s` - case $OS_NAME in - Debian) - OS_URL=http://www.debian.org/ - OS_VERSION=`${LSB_RELEASE} -c -s` - ;; - Ubuntu) - OS_URL=http://www.ubuntu.com/ - OS_VERSION=`${LSB_RELEASE} -c -s` - ;; - Gentoo) - OS_URL=http://www.gentoo.org/ - ;; - arch) - OS_URL=http://www.archlinux.org/ - OS_VERSION=`uname -r` - ;; - esac - fi - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - FW=netfilter - V6SOCKETS_ARE_V6ONLY=`/sbin/sysctl -n net.ipv6.bindv6only` - ;; - OpenWRT) - OS_URL=http://www.openwrt.org/ - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - FW=netfilter - ;; - AstLinux) - OS_URL=http://www.astlinux.org/ - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - FW=netfilter - ;; - Tomato) - OS_NAME=UPnP - OS_URL=http://tomatousb.org/ - echo "" >> ${CONFIGFILE} - echo "#ifndef TOMATO" >> ${CONFIGFILE} - echo "#define TOMATO" >> ${CONFIGFILE} - echo "#endif" >> ${CONFIGFILE} - echo "" >> ${CONFIGFILE} - echo "#ifdef LINUX26" >> ${CONFIGFILE} - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - echo "#endif" >> ${CONFIGFILE} - echo "#ifdef TCONFIG_IPV6" >> ${CONFIGFILE} - echo "#define ENABLE_IPV6" >> ${CONFIGFILE} - echo "#endif" >> ${CONFIGFILE} - FW=netfilter - ;; - Darwin) - MAJORVER=`echo $OS_VERSION | cut -d. -f1` - echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - # OS X switched to pf since 10.7 Lion (Darwin 11.0) - if [ $MAJORVER -ge 11 ] ; then - FW=pf - echo "#define PFRULE_INOUT_COUNTS" >> ${CONFIGFILE} - else - FW=ipfw - fi - OS_URL=http://developer.apple.com/macosx - ;; - *) - echo "Unknown OS : $OS_NAME" - echo "Please contact the author at http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/." - exit 1 - ;; -esac - -case $FW in - pf) - echo "#define USE_PF 1" >> ${CONFIGFILE} - ;; - ipf) - echo "#define USE_IPF 1" >> ${CONFIGFILE} - ;; - ipfw) - echo "#define USE_IPFW 1" >> ${CONFIGFILE} - ;; - netfilter) - echo "#define USE_NETFILTER 1" >> ${CONFIGFILE} - ;; - *) - echo "Unknown Firewall/packet filtering software [$FW]" - echo "Please contact the author at http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/." - exit 1 - ;; -esac - -# UUID API -if grep uuid_create /usr/include/uuid.h > /dev/null 2>&1 ; then - echo "#define BSD_UUID" >> ${CONFIGFILE} -fi -if grep uuid_generate /usr/include/uuid/uuid.h > /dev/null 2>&1 ; then - echo "#define LIB_UUID" >> ${CONFIGFILE} -fi - -# set V6SOCKETS_ARE_V6ONLY to 0 if it was not set above -if [ -z "$V6SOCKETS_ARE_V6ONLY" ] ; then - V6SOCKETS_ARE_V6ONLY=0 -fi - -echo "Configuring compilation for [$OS_NAME] [$OS_VERSION] with [$FW] firewall software." -echo "Please edit config.h for more compilation options." - -# define SUPPORT_REMOTEHOST if the FW related code really supports setting -# a RemoteHost -if [ \( "$FW" = "netfilter" \) -o \( "$FW" = "pf" \) -o \( "$FW" = "ipfw" \) ] ; then - echo "#define SUPPORT_REMOTEHOST" >> ${CONFIGFILE} -fi - -echo "/* Enable IGD2 \"Port Triggering\" as defined in Section 2.5.16" >> ${CONFIGFILE} -echo " * figure 2.2 in UPnP-gw-WANIPConnection-v2-Service.pdf */" >> ${CONFIGFILE} -echo "#define ENABLE_PORT_TRIGGERING" >> ${CONFIGFILE} - -echo "" >> ${CONFIGFILE} -echo "#define OS_NAME \"$OS_NAME\"" >> ${CONFIGFILE} -echo "#define OS_VERSION \"$OS_NAME/$OS_VERSION\"" >> ${CONFIGFILE} -echo "#define OS_URL \"${OS_URL}\"" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* syslog facility to be used by miniupnpd */" >> ${CONFIGFILE} -echo "#define LOG_MINIUPNPD ${LOG_MINIUPNPD}" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Uncomment the following line to allow miniupnpd to be" >> ${CONFIGFILE} -echo " * controlled by miniupnpdctl */" >> ${CONFIGFILE} -echo "/*#define USE_MINIUPNPDCTL*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Comment the following line to disable NAT-PMP operations */" >> ${CONFIGFILE} -echo "#define ENABLE_NATPMP" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Comment the following line to disable PCP operations */" >> ${CONFIGFILE} -echo "#define ENABLE_PCP" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "#ifdef ENABLE_PCP" >> ${CONFIGFILE} -if [ -n "$PCP_PEER" ]; then -echo "/* Comment the following line to disable PCP PEER operation */" >> ${CONFIGFILE} -echo "#define PCP_PEER" >> ${CONFIGFILE} -else -echo "/* Uncomment the following line to enable PCP PEER operation */" >> ${CONFIGFILE} -echo "/*#define PCP_PEER*/" >> ${CONFIGFILE} -fi -echo "#ifdef PCP_PEER" >> ${CONFIGFILE} -echo "/*#define PCP_FLOWP*/" >> ${CONFIGFILE} -echo "#endif /*PCP_PEER*/" >> ${CONFIGFILE} -echo "/*#define PCP_SADSCP*/" >> ${CONFIGFILE} -echo "#endif /*ENABLE_PCP*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Uncomment the following line to enable generation of" >> ${CONFIGFILE} -echo " * filter rules with pf */" >> ${CONFIGFILE} -echo "/*#define PF_ENABLE_FILTER_RULES*/">> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Uncomment the following line to enable caching of results of" >> ${CONFIGFILE} -echo " * the getifstats() function */" >> ${CONFIGFILE} -echo "/*#define ENABLE_GETIFSTATS_CACHING*/" >> ${CONFIGFILE} -echo "/* The cache duration is indicated in seconds */" >> ${CONFIGFILE} -echo "#define GETIFSTATS_CACHING_DURATION 2" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Uncomment the following line to enable multiple external ip support */" >> ${CONFIGFILE} -echo "/* note : That is EXPERIMENTAL, do not use that unless you know perfectly what you are doing */" >> ${CONFIGFILE} -echo "/* Dynamic external ip adresses are not supported when this option is enabled." >> ${CONFIGFILE} -echo " * Also note that you would need to configure your .conf file accordingly. */" >> ${CONFIGFILE} -echo "/*#define MULTIPLE_EXTERNAL_IP*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Comment the following line to use home made daemonize() func instead" >> ${CONFIGFILE} -echo " * of BSD daemon() */" >> ${CONFIGFILE} -echo "#define USE_DAEMON" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Uncomment the following line to enable lease file support */" >> ${CONFIGFILE} -if [ -n "$LEASEFILE" ] ; then - echo "#define ENABLE_LEASEFILE" >> ${CONFIGFILE} -else - echo "/*#define ENABLE_LEASEFILE*/" >> ${CONFIGFILE} -fi -echo "/* Uncomment the following line to store remaining time in lease file */" >> ${CONFIGFILE} -echo "/*#define LEASEFILE_USE_REMAINING_TIME*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Uncomment the following line to enable port in use check */" >> ${CONFIGFILE} -if [ -n "$PORTINUSE" ]; then - echo "#define CHECK_PORTINUSE" >> ${CONFIGFILE} -else - echo "/*#define CHECK_PORTINUSE*/" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -echo "/* Define one or none of the two following macros in order to make some" >> ${CONFIGFILE} -echo " * clients happy. It will change the XML Root Description of the IGD." >> ${CONFIGFILE} -echo " * Enabling the Layer3Forwarding Service seems to be the more compatible" >> ${CONFIGFILE} -echo " * option. */" >> ${CONFIGFILE} -echo "/*#define HAS_DUMMY_SERVICE*/" >> ${CONFIGFILE} -echo "#define ENABLE_L3F_SERVICE" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* define ADVERTISE_WANPPPCONN to allow buggy Control Point to use" >> ${CONFIGFILE} -echo " * WANPPPConnection instead of WANIPConnection. */" >> ${CONFIGFILE} -if [ -n "$STRICT" ] || [ -n "$DISABLEPPPCONN" ] ; then - echo "/*#define ADVERTISE_WANPPPCONN*/" >> ${CONFIGFILE} -else - echo "#define ADVERTISE_WANPPPCONN" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -echo "/* Enable IP v6 support */" >> ${CONFIGFILE} -if [ -n "$IPV6" ]; then - echo "#define ENABLE_IPV6" >> ${CONFIGFILE} -else - echo "/*#define ENABLE_IPV6*/" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -echo "/* Define V6SOCKETS_ARE_V6ONLY if AF_INET6 sockets are restricted" >> ${CONFIGFILE} -echo " * to IPv6 communications only. */" >> ${CONFIGFILE} -if [ $V6SOCKETS_ARE_V6ONLY -eq 1 ] ; then - echo "#define V6SOCKETS_ARE_V6ONLY" >> ${CONFIGFILE} -else - echo "/*#define V6SOCKETS_ARE_V6ONLY*/" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -if [ -n "$HAVE_IP_MREQN" ]; then - echo "#define HAVE_IP_MREQN" >> ${CONFIGFILE} - echo "" >> ${CONFIGFILE} -fi - -echo "/* Enable the support of IGD v2 specification." >> ${CONFIGFILE} -echo " * This is not fully tested yet and can cause incompatibilities with some" >> ${CONFIGFILE} -echo " * control points, so enable with care. */" >> ${CONFIGFILE} -if [ -n "$IGD2" ]; then - echo "#define IGD_V2" >> ${CONFIGFILE} -else - echo "/*#define IGD_V2*/" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -echo "#ifdef IGD_V2" >> ${CONFIGFILE} -echo "/* Enable DeviceProtection service (IGDv2) */" >> ${CONFIGFILE} -echo "#define ENABLE_DP_SERVICE" >> ${CONFIGFILE} -echo "/*#define ENABLE_HTTPS*/" >> ${CONFIGFILE} -echo "/*#define HTTPS_CERTFILE \"/path/to/certificate.pem\"*/" >> ${CONFIGFILE} -echo "/*#define HTTPS_KEYFILE \"/path/to/private.key\"*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} -echo "/* Enable WANIPv6FirewallControl service (IGDv2). needs IPv6 */" >> ${CONFIGFILE} -echo "#ifdef ENABLE_IPV6" >> ${CONFIGFILE} -echo "#define ENABLE_6FC_SERVICE" >> ${CONFIGFILE} -echo "#endif /* ENABLE_IPV6 */" >> ${CONFIGFILE} -echo "#endif /* IGD_V2 */" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* UPnP Events support. Working well enough to be enabled by default." >> ${CONFIGFILE} -echo " * It can be disabled to save a few bytes. */" >> ${CONFIGFILE} -echo "#define ENABLE_EVENTS" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* include interface name in pf and ipf rules */" >> ${CONFIGFILE} -echo "#define USE_IFNAME_IN_RULES" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Experimental NFQUEUE support. */" >> ${CONFIGFILE} -echo "/*#define ENABLE_NFQUEUE*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Enable to make MiniUPnPd more strict about UPnP conformance" >> ${CONFIGFILE} -echo " * and the messages it receives from control points */" >> ${CONFIGFILE} -if [ -n "$STRICT" ] ; then - echo "#define UPNP_STRICT" >> ${CONFIGFILE} -else - echo "/*#define UPNP_STRICT*/" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -echo "/* If SSDP_RESPOND_SAME_VERSION is defined, the M-SEARCH response" >> ${CONFIGFILE} -echo " * include the same device version as was contained in the search" >> ${CONFIGFILE} -echo " * request. It conforms to UPnP DA v1.1 */" >> ${CONFIGFILE} -echo "#define SSDP_RESPOND_SAME_VERSION" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Add the optional Date: header in all HTTP responses */" >> ${CONFIGFILE} -if [ -n "$STRICT" ] ; then - echo "#define ENABLE_HTTP_DATE" >> ${CONFIGFILE} -else - echo "/*#define ENABLE_HTTP_DATE*/" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -echo "/* Wait a little before answering M-SEARCH request */" >> ${CONFIGFILE} -if [ -n "$STRICT" ] ; then - echo "#define DELAY_MSEARCH_RESPONSE" >> ${CONFIGFILE} -else - echo "/*#define DELAY_MSEARCH_RESPONSE*/" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -echo "/* disable reading and parsing of config file (miniupnpd.conf) */" >> ${CONFIGFILE} -echo "/*#define DISABLE_CONFIG_FILE*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} - -echo "/* Uncomment the following line to configure all manufacturer infos through miniupnpd.conf */" >> ${CONFIGFILE} -if [ -n "$VENDORCFG" ] ; then - echo "#define ENABLE_MANUFACTURER_INFO_CONFIGURATION" >> ${CONFIGFILE} -else - echo "/*#define ENABLE_MANUFACTURER_INFO_CONFIGURATION*/" >> ${CONFIGFILE} -fi -echo "" >> ${CONFIGFILE} - -cat >> ${CONFIGFILE} <> ${CONFIGFILE} <> ${CONFIGFILE} <> ${CONFIGFILE} - -${MV} ${CONFIGFILE} ${CONFIGFILE_FINAL} - -exit 0 diff -Nru miniupnpd-2.1/getifaddr.c miniupnpd-2.2.1/getifaddr.c --- miniupnpd-2.1/getifaddr.c 2015-07-15 16:14:01.000000000 +0000 +++ miniupnpd-2.2.1/getifaddr.c 2020-09-28 21:55:14.000000000 +0000 @@ -1,7 +1,8 @@ -/* $Id: getifaddr.c,v 1.24 2015/07/09 12:27:26 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2014 Thomas Bernard +/* $Id: getifaddr.c,v 1.27 2020/09/28 21:32:33 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2019 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -46,7 +47,7 @@ syslog(LOG_ERR, "socket(PF_INET, SOCK_DGRAM): %m"); return -1; } - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); ifr.ifr_name[IFNAMSIZ-1] = '\0'; if(ioctl(s, SIOCGIFFLAGS, &ifr, &ifrlen) < 0) { @@ -60,7 +61,8 @@ close(s); return -1; } - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0) { syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m"); @@ -80,7 +82,8 @@ } if(mask) { - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; if(ioctl(s, SIOCGIFNETMASK, &ifr, &ifrlen) < 0) { syslog(LOG_ERR, "ioctl(s, SIOCGIFNETMASK, ...): %m"); @@ -259,3 +262,43 @@ } #endif +/* List of IP address blocks which are private / reserved and therefore not suitable for public external IP addresses */ +/* If interface has IP address from one of this block, then it is either behind NAT or port forwarding is impossible */ +#define IP(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) +#define MSK(m) (32-(m)) +static const struct { uint32_t address; uint32_t rmask; } reserved[] = { + { IP( 0, 0, 0, 0), MSK( 8) }, /* RFC1122 "This host on this network" */ + { IP( 10, 0, 0, 0), MSK( 8) }, /* RFC1918 Private-Use */ + { IP(100, 64, 0, 0), MSK(10) }, /* RFC6598 Shared Address Space */ + { IP(127, 0, 0, 0), MSK( 8) }, /* RFC1122 Loopback */ + { IP(169, 254, 0, 0), MSK(16) }, /* RFC3927 Link-Local */ + { IP(172, 16, 0, 0), MSK(12) }, /* RFC1918 Private-Use */ + { IP(192, 0, 0, 0), MSK(24) }, /* RFC6890 IETF Protocol Assignments */ + { IP(192, 0, 2, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-1) */ + { IP(192, 31, 196, 0), MSK(24) }, /* RFC7535 AS112-v4 */ + { IP(192, 52, 193, 0), MSK(24) }, /* RFC7450 AMT */ + { IP(192, 88, 99, 0), MSK(24) }, /* RFC7526 6to4 Relay Anycast */ + { IP(192, 168, 0, 0), MSK(16) }, /* RFC1918 Private-Use */ + { IP(192, 175, 48, 0), MSK(24) }, /* RFC7534 Direct Delegation AS112 Service */ + { IP(198, 18, 0, 0), MSK(15) }, /* RFC2544 Benchmarking */ + { IP(198, 51, 100, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-2) */ + { IP(203, 0, 113, 0), MSK(24) }, /* RFC5737 Documentation (TEST-NET-3) */ + { IP(224, 0, 0, 0), MSK( 4) }, /* RFC1112 Multicast */ + { IP(240, 0, 0, 0), MSK( 4) }, /* RFC1112 Reserved for Future Use + RFC919 Limited Broadcast */ +}; +#undef IP +#undef MSK + +int +addr_is_reserved(struct in_addr * addr) +{ + uint32_t address = ntohl(addr->s_addr); + size_t i; + + for (i = 0; i < sizeof(reserved)/sizeof(reserved[0]); ++i) { + if ((address >> reserved[i].rmask) == (reserved[i].address >> reserved[i].rmask)) + return 1; + } + + return 0; +} diff -Nru miniupnpd-2.1/getifaddr.h miniupnpd-2.2.1/getifaddr.h --- miniupnpd-2.1/getifaddr.h 2014-05-06 14:42:49.000000000 +0000 +++ miniupnpd-2.2.1/getifaddr.h 2018-07-06 12:03:21.000000000 +0000 @@ -1,7 +1,8 @@ -/* $Id: getifaddr.h,v 1.10 2014/05/06 14:40:53 nanard Exp $ */ -/* MiniUPnP project +/* $Id: getifaddr.h,v 1.11 2018/07/06 11:47:29 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2018 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -28,5 +29,8 @@ find_ipv6_addr(const char * ifname, char * dst, int n); -#endif +/* check if address is in private / reserved block (e.g. local area network) */ +int +addr_is_reserved(struct in_addr * addr); +#endif diff -Nru miniupnpd-2.1/gitrev.mk miniupnpd-2.2.1/gitrev.mk --- miniupnpd-2.1/gitrev.mk 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/gitrev.mk 2020-11-09 19:43:35.000000000 +0000 @@ -0,0 +1,8 @@ +# (c) 2019-2020 Thomas Bernard +# For GNU Make + +ISGITREPO := $(shell git rev-parse --is-inside-work-tree) +ifeq ($(ISGITREPO),true) +GITREF := $(shell git describe --exact-match --tags 2> /dev/null || echo "`git rev-parse --abbrev-ref HEAD`-`git rev-parse --short HEAD`" ) +CPPFLAGS += -DMINIUPNPD_GIT_REF=\"$(GITREF)\" +endif diff -Nru miniupnpd-2.1/INSTALL miniupnpd-2.2.1/INSTALL --- miniupnpd-2.1/INSTALL 2018-05-03 08:29:25.000000000 +0000 +++ miniupnpd-2.2.1/INSTALL 2020-05-10 18:11:13.000000000 +0000 @@ -1,5 +1,5 @@ MiniUPnP project. -(c) 2006-2017 Thomas Bernard +(c) 2006-2020 Thomas Bernard Homepage : http://miniupnp.free.fr/ Mirror: https://miniupnp.tuxfamily.org/ github: https://github.com/miniupnp/miniupnp @@ -11,12 +11,11 @@ ================================ *BSD/pf ================================= To Build and Install : +- first use ./configure + For more details about options : + > ./configure -h + then edit config.h to fine tune to your preferences. - use BSD make to compile. -- you can first 'make config.h' then edit config.h to your preferences and - finally 'make' - Alternatively to editing config.h, options can be passed to genconfig.sh - For more details : - > ./genconfig.sh -h - add "rdr-anchor miniupnpd" or/and "anchor miniupnpd" lines to /etc/pf.conf (Since OpenBSD 4.7, rdr-anchor lines are no longer used and should be removed, leaving only the anchor lines). @@ -39,9 +38,8 @@ =========================== *BSD,*Solaris/ipf ============================= -genconfig.sh and the Makefile try to detect wether ipf or pf should be -used. If it fails, edit config.h and Makefile by hand. -In Makefile, the FWNAME variable value should be pf or ipf. +configure tries to detect wether ipf or pf should be +used. If it fails, you can use ./configure --firewall=ipf Installation steps are allmost the same as with pf. *Solaris users would be interested in reading informations from : @@ -50,9 +48,8 @@ ============================= Mac OS X/ipfw =============================== - To enable non standard compilation options, - > ./genconfig.sh -h - Or edit config.h after it has been generated by genconfig.sh -- use 'bsdmake' (if available) or 'make -f Makefile.macosx' to build + > ./configure -h +- use either 'bsdmake -f Makefile.bsd' (if available) or 'make' to build ============================== Mac OS X/pf ================================ @@ -61,8 +58,11 @@ Make sure you have installed the Xcode commande line tools (from the Xcode Preferences menu or using 'xcode-select --install' command) -You'll need to download xnu sources : https://github.com/opensource-apple/xnu -> INCLUDES="-I.../xnu/bsd -I.../xnu/libkern" make -f Makefile.macosx +You need to download xnu sources : https://opensource.apple.com/tarballs/xnu/ +- If version of xnu >= 4570, + > ./configure + Then edit config.h, adding line "#define PFVAR_NEW_STYLE" to it. +> INCLUDES="-I.../xnu/bsd -I.../xnu/libkern" make ============================ Linux/netfilter ============================== To Build and install : @@ -77,14 +77,15 @@ This script must allways be run before the daemon to set up initial rules and chains. - Build and edit the config.h file - > make -f Makefile.linux config.h + > ./configure > vi config.h - Build the daemon - > make -f Makefile.linux + > make If not using iptables from your system, - > IPTABLESPATH=/path/to/iptables-1.4.1 make -f Makefile.linux + > ./configure --iptablespath=/path/to/iptables-1.4.1 + > make - install as root using : - > make -f Makefile.linux install + > make install - A miniupnpd script should be installed to /etc/init.d and the configuration files to /etc/miniupnpd - anytime, you can use the netfilter/iptables_flush.sh @@ -108,12 +109,20 @@ > ./configure --enable-static > make - it is now possible to compile miniupnpd using the following command : - > IPTABLESPATH=/path/to/iptables-x.x.x make -f Makefile.linux + > ./configure --iptablespath=/path/to/iptables-x.x.x + > make ======================== Linux/netfilter nftables ========================= -work is in progress. To build : - > make -f Makefile.linux_nft +work is in progress. +install the required development libraries. For debian : + > apt-get install libnftnl-dev libmnl-dev + +To build : + > ./configure --firewall=nftables + > make +(first clean any old config if you built the netfilter/iptables version +previoulsy) see : https://miniupnp.tuxfamily.org/forum/viewtopic.php?p=4370 @@ -140,7 +149,23 @@ names : listening_ip=eth0/24 -Miniupnpd supports some kind of security check for allowing or disallowing +Some users want to use miniupnpd on a NAT router which is connected to the +internet through another NAT router (NAT behind NAT). This kind of setup is +strongly discouraged. miniupnpd will refuses to launch when detecting a +private (RFC1918) "WAN" IP address. The ext_ip option sould be added : +ext_ifname=eth1 # "WAN" network interface, whose IP could be 192.168.1.22 +ext_ip=80.1.2.3 # Real public IP address +listening_ip=eth0 +Please note that miniupnpd doesn't redirect any port on the other NAT router. +UPNP requests forwarding is not implemented. +It is however possible to use STUN. See the ext_perform_stun / ext_stun_host + / ext_stun_port options. + +it is also possible to set a different interface for IPv6 WAN +ext_ifname=eth0 +ext_ifname6=sit0 + +miniupnpd supports some kind of security check for allowing or disallowing redirection to be made. The UPnP permission rules are read from the miniupnpd.conf configuration file. When a new redirection is requested, permission rules are evaluated in @@ -170,8 +195,6 @@ More simple, use the genuuid makefile target : > make genuuid -or -> make -f Makefile.linux genuuid This target is needed by the "install" target, so it is done automatically during install. diff -Nru miniupnpd-2.1/ipf/ipfrdr.c miniupnpd-2.2.1/ipf/ipfrdr.c --- miniupnpd-2.1/ipf/ipfrdr.c 2016-12-16 09:23:44.000000000 +0000 +++ miniupnpd-2.2.1/ipf/ipfrdr.c 2020-12-20 17:50:28.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: ipfrdr.c,v 1.19 2016/12/16 09:11:19 nanard Exp $ */ +/* $Id: ipfrdr.c,v 1.21 2020/12/20 17:43:40 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2007 Darren Reed @@ -59,7 +59,7 @@ #include #include -#include "../config.h" +#include "config.h" #include "netinet/ipl.h" #include "netinet/ip_compat.h" #include "netinet/ip_fil.h" @@ -804,7 +804,7 @@ return array; } -/* update the port mapping internal port, decription and timestamp */ +/* update the port mapping internal port, description and timestamp */ int update_portmapping(const char * ifname, unsigned short eport, int proto, unsigned short iport, const char * desc, @@ -817,7 +817,7 @@ return -1; } -/* update the port mapping decription and timestamp */ +/* update the port mapping description and timestamp */ int update_portmapping_desc_timestamp(const char * ifname, unsigned short eport, int proto, diff -Nru miniupnpd-2.1/ipfw/ipfwrdr.c miniupnpd-2.2.1/ipfw/ipfwrdr.c --- miniupnpd-2.1/ipfw/ipfwrdr.c 2016-02-12 14:58:28.000000000 +0000 +++ miniupnpd-2.2.1/ipfw/ipfwrdr.c 2020-05-10 22:30:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: ipfwrdr.c,v 1.16 2016/02/12 13:44:01 nanard Exp $ */ +/* $Id: ipfwrdr.c,v 1.17 2020/05/10 22:25:45 nanard Exp $ */ /* * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -8,7 +8,7 @@ * in the LICENCE file provided within the distribution */ -#include "../config.h" +#include "config.h" #include "../macros.h" #include diff -Nru miniupnpd-2.1/LICENSE miniupnpd-2.2.1/LICENSE --- miniupnpd-2.1/LICENSE 2017-05-26 11:02:42.000000000 +0000 +++ miniupnpd-2.2.1/LICENSE 2020-11-09 19:43:35.000000000 +0000 @@ -1,5 +1,5 @@ MiniUPnPd -Copyright (c) 2006-2017, Thomas BERNARD +Copyright (c) 2006-2020, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without diff -Nru miniupnpd-2.1/linux/getifstats.c miniupnpd-2.2.1/linux/getifstats.c --- miniupnpd-2.1/linux/getifstats.c 2018-04-06 09:10:55.000000000 +0000 +++ miniupnpd-2.2.1/linux/getifstats.c 2020-05-10 18:11:16.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: getifstats.c,v 1.14 2018/03/13 23:05:21 nanard Exp $ */ +/* $Id: getifstats.c,v 1.16 2020/05/10 17:51:00 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -11,7 +11,7 @@ #include #include -#include "../config.h" +#include "config.h" #include "../getifstats.h" #ifdef GET_WIRELESS_STATS @@ -24,6 +24,51 @@ /* that is the answer */ #define BAUDRATE_DEFAULT 4200000 +/* this custom implementation of strtoul() rollover + * this is needed by the UPnP standard */ +static unsigned long my_strtoul(const char * p, char ** endptr, int base) +{ + unsigned long value; + + if (base == 0) { + /* autodetect base : + * 0xnnnnn is hexadecimal + * 0nnnnnn is octal + * everything else is decimal */ + if (*p == '0') { + p++; + if (*p == 'x') { + p++; + base = 16; + } else { + base = 8; + } + } else { + base = 10; + } + } + + for (value = 0; *p >= '0'; p++) { + value *= (unsigned long)base; + if (*p <= '9') { + if (base < 10 && *p >= ('0' + base)) + break; + value += (unsigned long)(*p - '0'); /* 0-9 */ + } else if (base <= 10 || *p < 'A') { + break; + } else if (*p < ('A' + base - 10)) { + value += (unsigned long)(*p - 'A' + 10); /* A-F */ + } else if (*p >= 'a' && *p < ('a' + base - 10)) { + value += (unsigned long)(*p - 'a' + 10); /* a-f */ + } else { + break; + } + } + if (endptr != NULL) + *endptr = (char *)p; + return value; +} + int getifstats(const char * ifname, struct ifdata * data) { @@ -80,18 +125,18 @@ continue; p++; while(*p==' ') p++; - data->ibytes = strtoul(p, &p, 0); + data->ibytes = my_strtoul(p, &p, 0); while(*p==' ') p++; - data->ipackets = strtoul(p, &p, 0); + data->ipackets = my_strtoul(p, &p, 0); /* skip 6 columns */ for(i=6; i>0 && *p!='\0'; i--) { while(*p==' ') p++; while(*p!=' ' && *p) p++; } while(*p==' ') p++; - data->obytes = strtoul(p, &p, 0); + data->obytes = my_strtoul(p, &p, 0); while(*p==' ') p++; - data->opackets = strtoul(p, &p, 0); + data->opackets = my_strtoul(p, &p, 0); r = 0; break; } diff -Nru miniupnpd-2.1/linux/ifacewatcher.c miniupnpd-2.2.1/linux/ifacewatcher.c --- miniupnpd-2.1/linux/ifacewatcher.c 2018-02-03 22:19:33.000000000 +0000 +++ miniupnpd-2.2.1/linux/ifacewatcher.c 2020-05-10 18:11:16.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: ifacewatcher.c,v 1.9 2018/02/03 22:05:42 nanard Exp $ */ +/* $Id: ifacewatcher.c,v 1.11 2020/05/10 17:50:25 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * * ifacewatcher.c * @@ -48,7 +48,8 @@ #include #include -#include "../config.h" +#include "config.h" +#include "../macros.h" #ifdef USE_IFACEWATCHER @@ -280,6 +281,7 @@ switch(nlhdr->nlmsg_type) { case RTM_DELLINK: is_del = 1; + FALL_THROUGH; case RTM_NEWLINK: #if 0 /* disabled at the moment */ @@ -295,6 +297,7 @@ break; case RTM_DELADDR: is_del = 1; + FALL_THROUGH; case RTM_NEWADDR: /* see /usr/include/linux/netlink.h * and /usr/include/linux/rtnetlink.h */ diff -Nru miniupnpd-2.1/linux/miniupnpd.service miniupnpd-2.2.1/linux/miniupnpd.service --- miniupnpd-2.1/linux/miniupnpd.service 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/linux/miniupnpd.service 2019-10-02 22:21:06.000000000 +0000 @@ -0,0 +1,11 @@ +[Unit] +Description=MiniUPnPD +After=network.target + +[Service] +Type=forking +ExecStart=/usr/sbin/miniupnpd +ExecStop=kill `cat /var/run/miniupnpd.pid` + +[Install] +WantedBy=multi-user.target diff -Nru miniupnpd-2.1/mac/getifstats.c miniupnpd-2.2.1/mac/getifstats.c --- miniupnpd-2.1/mac/getifstats.c 2018-04-06 09:10:55.000000000 +0000 +++ miniupnpd-2.2.1/mac/getifstats.c 2020-05-10 22:30:15.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: getifstats.c,v 1.8 2018/03/13 23:05:21 nanard Exp $ */ +/* $Id: getifstats.c,v 1.9 2020/05/10 22:25:45 nanard Exp $ */ /* * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -19,8 +19,8 @@ #include #include +#include "config.h" #include "../getifstats.h" -#include "../config.h" int getifstats(const char * ifname, struct ifdata * data) { int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(ifname) }; diff -Nru miniupnpd-2.1/macros.h miniupnpd-2.2.1/macros.h --- miniupnpd-2.1/macros.h 2016-12-16 09:23:43.000000000 +0000 +++ miniupnpd-2.2.1/macros.h 2019-09-24 11:51:14.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: macros.h,v 1.4 2016/12/16 09:11:18 nanard Exp $ */ +/* $Id: macros.h,v 1.5 2019/09/24 09:37:52 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2012-2015 Thomas Bernard + * (c) 2012-2019 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -10,6 +10,12 @@ #define UNUSED(arg) (void)(arg) +#if defined(__GNUC__) && (__GNUC__ >= 7) +#define FALL_THROUGH __attribute__((fallthrough)) +#else +#define FALL_THROUGH +#endif + #include #ifndef INLINE diff -Nru miniupnpd-2.1/Makefile miniupnpd-2.2.1/Makefile --- miniupnpd-2.1/Makefile 2017-12-12 11:51:56.000000000 +0000 +++ miniupnpd-2.2.1/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,274 +0,0 @@ -# $Id: Makefile,v 1.90 2017/12/12 11:40:13 nanard Exp $ -# MiniUPnP project -# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ -# Author: Thomas Bernard -# -# Makefile for miniupnpd (MiniUPnP daemon) -# -# This Makefile should work for *BSD and SunOS/Solaris. -# On Mac OS X, use "bsdmake" to build. -# This Makefile is NOT compatible with GNU Make. -# Linux users, please use Makefile.linux : -# make -f Makefile.linux -# -# options can be passed to genconfig.sh through CONFIG_OPTIONS : -# $ CONFIG_OPTIONS="--ipv6 --igd2" make -# - -CFLAGS ?= -pipe -Os -#CFLAGS = -pipe -O -g -DDEBUG -#CFLAGS += -ansi -CFLAGS += -Wall -CFLAGS += -W -CFLAGS += -Wstrict-prototypes -#CFLAGS += -Wdeclaration-after-statement -#CFLAGS += -Wno-missing-field-initializers -CFLAGS += -fno-common -CC ?= gcc -RM = rm -f -MV = mv -INSTALL = install -STRIP = strip - -# OSNAME and FWNAME are used for building OS or FW dependent code. -OSNAME != uname -s -ARCH != uname -m -.ifndef FWNAME -#.if exists(/usr/include/net/pfvar.h) -#FWNAME = pf -#.else -#FWNAME = ipf -#.endif - -.if $(OSNAME) == "OpenBSD" -FWNAME = pf -.endif - -# better way to find if we are using ipf or pf -.if $(OSNAME) == "FreeBSD" -.if exists(/etc/rc.subr) && exists(/etc/default/rc.conf) -FWNAME != . /etc/rc.subr; . /etc/default/rc.conf; \ - if checkyesno ipfilter_enable; then \ - echo "ipf"; elif checkyesno pf_enable; then \ - echo "pf"; elif checkyesno firewall_enable; then \ - echo "ipfw"; else echo "pf"; fi -.else -FWNAME = pf -.endif -.endif - -.if $(OSNAME) == "NetBSD" -.if exists(/etc/rc.subr) && exists(/etc/rc.conf) -FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ - if checkyesno pf; then \ - echo "pf"; elif checkyesno ipfilter; then \ - echo "ipf"; else echo "pf"; fi -.else -FWNAME = pf -.endif -.endif - -.if $(OSNAME) == "DragonFly" -.if exists(/etc/rc.subr) && exists(/etc/rc.conf) -FWNAME != . /etc/rc.subr; . /etc/rc.conf; \ - if checkyesno pf; then \ - echo "pf"; elif checkyesno ipfilter; then \ - echo "ipf"; else echo "pf"; fi -.else -FWNAME = pf -.endif -.endif - -.if $(OSNAME) == "Darwin" -# Firewall is ipfw up to OS X 10.6 Snow Leopard -# and pf since OS X 10.7 Lion (Darwin 11.0) -FWNAME != [ `uname -r | cut -d. -f1` -ge 11 ] && echo "pf" || echo "ipfw" -.endif - -.endif - -# Solaris specific CFLAGS -.if $(OSNAME) == "SunOS" -CFLAGS += -DSOLARIS2=`uname -r | cut -d. -f2` -.if $(ARCH) == "amd64" -CFLAGS += -m64 -mcmodel=kernel -mno-red-zone -ffreestanding -.elif $(ARCH) == "sparc64" -CFLAGS += -m64 -mcmodel=medlow -.endif -.endif - -STDOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ - upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ - options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ - upnpevents.o upnputils.o getconnstatus.o \ - upnppinhole.o asyncsendto.o portinuse.o -BSDOBJS = bsd/getifstats.o bsd/ifacewatcher.o bsd/getroute.o -SUNOSOBJS = solaris/getifstats.o bsd/ifacewatcher.o bsd/getroute.o -MACOBJS = mac/getifstats.o bsd/ifacewatcher.o bsd/getroute.o -PFOBJS = pf/obsdrdr.o pf/pfpinhole.o -IPFOBJS = ipf/ipfrdr.o -IPFWOBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o -MISCOBJS = upnpreplyparse.o minixml.o - -ALLOBJS = $(STDOBJS) $(MISCOBJS) -.if $(OSNAME) == "SunOS" -ALLOBJS += $(SUNOSOBJS) -TESTGETIFSTATSOBJS = testgetifstats.o solaris/getifstats.o -TESTGETROUTEOBJS = testgetroute.o upnputils.o bsd/getroute.o -.elif $(OSNAME) == "Darwin" -ALLOBJS += $(MACOBJS) -TESTGETIFSTATSOBJS = testgetifstats.o mac/getifstats.o -TESTGETROUTEOBJS = testgetroute.o upnputils.o bsd/getroute.o -.else -ALLOBJS += $(BSDOBJS) -TESTGETIFSTATSOBJS = testgetifstats.o bsd/getifstats.o -TESTGETROUTEOBJS = testgetroute.o upnputils.o bsd/getroute.o -.endif - -.if $(FWNAME) == "pf" -ALLOBJS += $(PFOBJS) -.elif $(FWNAME) == "ipfw" -ALLOBJS += $(IPFWOBJS) -.else -ALLOBJS += $(IPFOBJS) -.endif - -TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o -TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o -TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o -MINIUPNPDCTLOBJS = miniupnpdctl.o -TESTASYNCSENDTOOBJS = testasyncsendto.o asyncsendto.o upnputils.o bsd/getroute.o -TESTPORTINUSEOBJS = testportinuse.o portinuse.o getifaddr.o -TESTMINISSDPOBJS = testminissdp.o minissdp.o upnputils.o upnpglobalvars.o \ - asyncsendto.o bsd/getroute.o - -EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ - testupnppermissions miniupnpdctl \ - testgetifaddr testgetroute testasyncsendto \ - testportinuse testssdppktgen testminissdp - -.if $(OSNAME) == "Darwin" -LIBS = -.else -LIBS = -lkvm -.endif -.if $(OSNAME) == "SunOS" -LIBS += -lsocket -lnsl -lkstat -lresolv -.endif - -LIBS += -lssl -lcrypto - -# set PREFIX variable to install in the wanted place - -INSTALLBINDIR = $(PREFIX)/sbin -INSTALLETCDIR = $(PREFIX)/etc -# INSTALLMANDIR = $(PREFIX)/man -INSTALLMANDIR = /usr/share/man - -all: $(EXECUTABLES) - -clean: - $(RM) $(STDOBJS) $(BSDOBJS) $(SUNOSOBJS) $(MACOBJS) $(EXECUTABLES) \ - testupnpdescgen.o \ - $(MISCOBJS) config.h testgetifstats.o testupnppermissions.o \ - miniupnpdctl.o testgetifaddr.o testgetroute.o testasyncsendto.o \ - testportinuse.o \ - $(PFOBJS) $(IPFOBJS) $(IPFWOBJS) - $(RM) validateupnppermissions validategetifaddr validatessdppktgen - -install: miniupnpd genuuid - $(STRIP) miniupnpd - $(INSTALL) -d $(DESTDIR)$(INSTALLBINDIR) - $(INSTALL) -m 755 miniupnpd $(DESTDIR)$(INSTALLBINDIR) - $(INSTALL) -d $(DESTDIR)$(INSTALLETCDIR) - $(INSTALL) -b miniupnpd.conf $(DESTDIR)$(INSTALLETCDIR) - # TODO : install man page correctly -# $(INSTALL) -d $(INSTALLMANDIR) -# $(INSTALL) miniupnpd.8 $(INSTALLMANDIR)/cat8/miniupnpd.0 - -# genuuid is using the uuid cli tool available under OpenBSD 4.0 in -# the uuid-1.5.0 package -# any other cli tool returning a uuid on stdout should work. -UUID != if which uuidgen 2>&1 > /dev/null; then \ - echo `uuidgen` ; \ - elif which uuid 2>&1 > /dev/null; then \ - echo `uuid` ; \ - else echo "00000000-0000-0000-0000-000000000000"; \ - fi - -# bash or ksh -SH != which bash || which ksh - -genuuid: - $(MV) miniupnpd.conf miniupnpd.conf.before - sed -e "s/^uuid=[-0-9a-fA-F]*/uuid=$(UUID)/" miniupnpd.conf.before > miniupnpd.conf - $(RM) miniupnpd.conf.before - -check: validateupnppermissions validategetifaddr validatessdppktgen - -validateupnppermissions: testupnppermissions testupnppermissions.sh - $(SH) ./testupnppermissions.sh - touch $@ - -validategetifaddr: testgetifaddr testgetifaddr.sh - ./testgetifaddr.sh - touch $@ - -validatessdppktgen: testssdppktgen - ./testssdppktgen - touch $@ - -depend: config.h - mkdep $(ALLOBJS:.o=.c) testupnpdescgen.c testgetifstats.c \ - testupnppermissions.c miniupnpdctl.c testgetifaddr.c \ - testgetroute.c testportinuse.c testasyncsendto.c \ - testssdppktgen.c - -miniupnpd: config.h $(ALLOBJS) - $(CC) $(LDFLAGS) -o $@ $(ALLOBJS) $(LIBS) - -# BSDmake : -# $(CC) $(LDFLAGS) -o $@ $> $(LIBS) - -miniupnpdctl: config.h $(MINIUPNPDCTLOBJS) - $(CC) $(LDFLAGS) -o $@ $(MINIUPNPDCTLOBJS) - -testupnpdescgen: config.h $(TESTUPNPDESCGENOBJS) - $(CC) $(LDFLAGS) -o $@ $(TESTUPNPDESCGENOBJS) $(LIBS) - -testgetifstats: config.h $(TESTGETIFSTATSOBJS) - $(CC) $(LDFLAGS) -o $@ $(TESTGETIFSTATSOBJS) $(LIBS) - -testgetifaddr: config.h $(TESTGETIFADDROBJS) - $(CC) $(LDFLAGS) -o $@ $(TESTGETIFADDROBJS) $(LIBS) - -testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS) - $(CC) $(LDFLAGS) -o $@ $(TESTUPNPPERMISSIONSOBJS) $(LIBS) - -testgetroute: config.h $(TESTGETROUTEOBJS) - $(CC) $(LDFLAGS) -o $@ $(TESTGETROUTEOBJS) $(LIBS) - -testasyncsendto: config.h $(TESTASYNCSENDTOOBJS) - $(CC) $(LDFLAGS) -o $@ $(TESTASYNCSENDTOOBJS) - -testportinuse: config.h $(TESTPORTINUSEOBJS) - $(CC) $(LDFLAGS) -o $@ $(TESTPORTINUSEOBJS) $(LIBS) - -testminissdp: config.h $(TESTMINISSDPOBJS) - $(CC) $(LDFLAGS) -o $@ $(TESTMINISSDPOBJS) $(LIBS) - -# gmake : -# $(CC) $(CFLAGS) -o $@ $^ -# BSDmake : -# $(CC) $(CFLAGS) -o $@ $> - -config.h: genconfig.sh VERSION - ./genconfig.sh $(CONFIG_OPTIONS) - -.SUFFIXES: .o .c -.c.o: - $(CC) $(CFLAGS) -c -o $@ $< - -# $(CC) $(CFLAGS) -c -o $(.TARGET) $(.IMPSRC) - - diff -Nru miniupnpd-2.1/Makefile.bsd miniupnpd-2.2.1/Makefile.bsd --- miniupnpd-2.1/Makefile.bsd 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/Makefile.bsd 2020-11-09 19:43:35.000000000 +0000 @@ -0,0 +1,262 @@ +# $Id: Makefile.bsd,v 1.105 2020/10/31 10:10:41 nanard Exp $ +# MiniUPnP project +# http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ +# Author: Thomas Bernard +# +# Makefile for miniupnpd (MiniUPnP daemon) +# +# This Makefile should work for *BSD and SunOS/Solaris. +# On Mac OS X, use "bsdmake" to build. +# This Makefile is NOT compatible with GNU Make. +# Linux users, please use Makefile.linux +# +# options can be passed to configure through CONFIG_OPTIONS : +# $ CONFIG_OPTIONS="--ipv6 --igd2" make +# + +CFLAGS ?= -pipe -Os +#CFLAGS = -pipe -O -g -DDEBUG +#CFLAGS += -ansi +CFLAGS += -Wall +CFLAGS += -W +CFLAGS += -Wstrict-prototypes +#CFLAGS += -Wdeclaration-after-statement +#CFLAGS += -Wno-missing-field-initializers +CFLAGS += -fno-common +CC ?= gcc +RM = rm -f +MV = mv +INSTALL = install +STRIP = strip +DOXYGEN ?= doxygen + +.ifndef CONFIG_OPTIONS +CONFIG_OPTIONS != cat .configure.cache +.endif + +# OSNAME and FWNAME are used for building OS or FW dependent code. +OSNAME != uname -s +ARCH != uname -m + +.ifndef FWNAME +.include "bsdmake.inc" +.endif + +# Solaris specific CFLAGS +.if $(OSNAME) == "SunOS" +CPPFLAGS += -DSOLARIS2=`uname -r | cut -d. -f2` +.if $(ARCH) == "amd64" +CFLAGS += -m64 -mcmodel=kernel -mno-red-zone -ffreestanding +.elif $(ARCH) == "sparc64" +CFLAGS += -m64 -mcmodel=medlow +.endif +.endif + +ISGITREPO != git rev-parse --is-inside-work-tree 2> /dev/null || echo "false" +.if $(ISGITREPO) == "true" +GITREF != git describe --exact-match --tags 2> /dev/null || echo "`git rev-parse --abbrev-ref HEAD`-`git rev-parse --short HEAD`" +CPPFLAGS += -DMINIUPNPD_GIT_REF=\"$(GITREF)\" +.endif + +STDOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ + upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ + options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ + upnpevents.o upnputils.o getconnstatus.o \ + upnpstun.o \ + upnppinhole.o asyncsendto.o portinuse.o +OS_OBJS = getifstats.o ifacewatcher.o getroute.o +PFOBJS = obsdrdr.o pfpinhole.o +IPFOBJS = ipfrdr.o +IPFWOBJS = ipfwrdr.o ipfwaux.o +MISCOBJS = upnpreplyparse.o minixml.o + +ALLOBJS = $(STDOBJS) $(MISCOBJS) +ALLSRCS := $(ALLOBJS:S/^/$(SRCDIR)\//:S/.o$/.c/) + +TESTGETIFSTATSOBJS = testgetifstats.o getifstats.o +TESTGETROUTEOBJS = testgetroute.o upnputils.o getroute.o + +ALLOBJS += $(OS_OBJS) + +.if $(OSNAME) == "SunOS" +ALLSRCS += $(SRCDIR)/solaris/getifstats.c +.elif $(OSNAME) == "Darwin" +ALLSRCS += $(SRCDIR)/mac/getifstats.c +.else +ALLSRCS += $(SRCDIR)/bsd/getifstats.c +.endif +ALLSRCS += $(SRCDIR)/bsd/ifacewatcher.c $(SRCDIR)/bsd/getroute.c + +.if $(FWNAME) == "pf" +ALLOBJS += $(PFOBJS) +ALLSRCS += $(PFOBJS:S/^/$(SRCDIR)\/pf\//:S/.o$/.c/) +.elif $(FWNAME) == "ipfw" +ALLOBJS += $(IPFWOBJS) +ALLSRCS += $(IPFWOBJS:S/^/$(SRCDIR)\/ipfw\//:S/.o$/.c/) +.else +ALLOBJS += $(IPFOBJS) +ALLSRCS += $(IPFOBJS:S/^/$(SRCDIR)\/ipf\//:S/.o$/.c/) +.endif + +TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o +TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o +TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o +MINIUPNPDCTLOBJS = miniupnpdctl.o +TESTASYNCSENDTOOBJS = testasyncsendto.o asyncsendto.o upnputils.o getroute.o +TESTPORTINUSEOBJS = testportinuse.o portinuse.o getifaddr.o +TESTMINISSDPOBJS = testminissdp.o minissdp.o upnputils.o upnpglobalvars.o \ + asyncsendto.o getroute.o + +EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ + testupnppermissions miniupnpdctl \ + testgetifaddr testgetroute testasyncsendto \ + testportinuse testssdppktgen testminissdp + +.if $(OSNAME) == "Darwin" +LIBS = +.else +LIBS = -lkvm +.endif +.if $(OSNAME) == "SunOS" +LIBS += -lsocket -lnsl -lkstat -lresolv +.endif + +LIBS += -lssl -lcrypto + +# set PREFIX variable to install in the wanted place + +INSTALLBINDIR = $(PREFIX)/sbin +INSTALLETCDIR = $(PREFIX)/etc +MANPREFIX ?= $(PREFIX) +INSTALLMANDIR = $(MANPREFIX)/man + +all: $(EXECUTABLES) + +clean: + $(RM) $(ALLOBJS) + $(RM) $(EXECUTABLES) + $(RM) $(TESTUPNPDESCGENOBJS) + $(RM) $(TESTUPNPPERMISSIONSOBJS) + $(RM) $(TESTGETIFADDROBJS) + $(RM) $(MINIUPNPDCTLOBJS) + $(RM) $(TESTASYNCSENDTOOBJS) + $(RM) $(TESTPORTINUSEOBJS) + $(RM) $(TESTMINISSDPOBJS) + $(RM) validateupnppermissions validategetifaddr validatessdppktgen + +install: miniupnpd genuuid + $(STRIP) miniupnpd + $(INSTALL) -d $(DESTDIR)$(INSTALLBINDIR) + $(INSTALL) -m 755 miniupnpd $(DESTDIR)$(INSTALLBINDIR) + $(INSTALL) -d $(DESTDIR)$(INSTALLETCDIR) + $(INSTALL) -b miniupnpd.conf $(DESTDIR)$(INSTALLETCDIR) + $(INSTALL) -d $(DESTDIR)$(INSTALLMANDIR) + $(INSTALL) -m 644 miniupnpd.8 $(DESTDIR)$(INSTALLMANDIR)/man8/miniupnpd.8 + +# genuuid is using the uuid cli tool available under OpenBSD 4.0 in +# the uuid-1.5.0 package +# any other cli tool returning a uuid on stdout should work. +UUID != if which uuidgen 2>&1 > /dev/null; then \ + echo `uuidgen` ; \ + elif which uuid 2>&1 > /dev/null; then \ + echo `uuid` ; \ + else echo "00000000-0000-0000-0000-000000000000"; \ + fi + +genuuid: + $(MV) miniupnpd.conf miniupnpd.conf.before + sed -e "s/^uuid=[-0-9a-fA-F]*/uuid=$(UUID)/" miniupnpd.conf.before > miniupnpd.conf + $(RM) miniupnpd.conf.before + +check: validateupnppermissions validategetifaddr validatessdppktgen + +validateupnppermissions: $(SRCDIR)/testupnppermissions.sh testupnppermissions + $(SRCDIR)/testupnppermissions.sh + touch $@ + +validategetifaddr: $(SRCDIR)/testgetifaddr.sh testgetifaddr + $(SRCDIR)/testgetifaddr.sh + touch $@ + +validatessdppktgen: testssdppktgen + ./testssdppktgen + touch $@ + +depend: $(ALLSRCS) + mkdep $(CPPFLAGS) $(.ALLSRC) + +dox: miniupnpd.doxyconf + $(DOXYGEN) $> + +miniupnpd: $(ALLOBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(ALLOBJS) $(LIBS) + +# BSDmake : +# $(CC) $(LDFLAGS) -o $@ $> $(LIBS) + +miniupnpdctl: config.h $(MINIUPNPDCTLOBJS) + $(CC) $(LDFLAGS) -o $@ $(MINIUPNPDCTLOBJS) + +testupnpdescgen: config.h $(TESTUPNPDESCGENOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTUPNPDESCGENOBJS) $(LIBS) + +testgetifstats: config.h $(TESTGETIFSTATSOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTGETIFSTATSOBJS) $(LIBS) + +testgetifaddr: config.h $(TESTGETIFADDROBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTGETIFADDROBJS) $(LIBS) + +testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTUPNPPERMISSIONSOBJS) $(LIBS) + +testgetroute: config.h $(TESTGETROUTEOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTGETROUTEOBJS) $(LIBS) + +testasyncsendto: config.h $(TESTASYNCSENDTOOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTASYNCSENDTOOBJS) + +testportinuse: config.h $(TESTPORTINUSEOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTPORTINUSEOBJS) $(LIBS) + +testminissdp: config.h $(TESTMINISSDPOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTMINISSDPOBJS) $(LIBS) + +testssdppktgen: testssdppktgen.o + $(CC) $(LDFLAGS) -o $@ $(.ALLSRC) $(LIBS) + +# gmake : +# $(CC) $(CFLAGS) -o $@ $^ +# BSDmake : +# $(CC) $(CFLAGS) -o $@ $> + +config.h: $(SRCDIR)/configure $(SRCDIR)/VERSION + $(SRCDIR)/configure $(CONFIG_OPTIONS) + +$(STDOBJS) $(MISCOBJS): $(SRCDIR)/$(@:.o=.c) +$(PFOBJS): $(SRCDIR)/pf/$(@:.o=.c) +$(IPFOBJS): $(SRCDIR)/ipf/$(@:.o=.c) +$(IPFWOBJS): $(SRCDIR)/ipfw/$(@:.o=.c) + +.if $(OSNAME) == "SunOS" +getifstats.o: $(SRCDIR)/solaris/getifstats.c +.elif $(OSNAME) == "Darwin" +getifstats.o: $(SRCDIR)/mac/getifstats.c +.else +getifstats.o: $(SRCDIR)/bsd/getifstats.c +.endif +ifacewatcher.o getroute.o: $(SRCDIR)/bsd/$(@:.o=.c) + +# make(1) specifies that $ is escaped with a backslash, +# not a preceding $ as usual, but FreeBSD 12.1 make does otherwise +.if $(OSNAME) == "FreeBSD" +$(EXECUTABLES:S/$$/.o/): $(SRCDIR)/$(@:.o=.c) +.else +$(EXECUTABLES:S/\$/.o/): $(SRCDIR)/$(@:.o=.c) +.endif + +.SUFFIXES: .o .c +.c.o: + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +# $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(.TARGET) $(.IMPSRC) + diff -Nru miniupnpd-2.1/Makefile.linux miniupnpd-2.2.1/Makefile.linux --- miniupnpd-2.1/Makefile.linux 2018-04-06 10:53:32.000000000 +0000 +++ miniupnpd-2.2.1/Makefile.linux 2020-06-06 18:02:58.000000000 +0000 @@ -1,82 +1,73 @@ -# $Id: Makefile.linux,v 1.96 2018/04/06 10:17:08 nanard Exp $ +# $Id: Makefile.linux,v 1.108 2020/06/06 17:52:31 nanard Exp $ # MiniUPnP project -# (c) 2006-2017 Thomas Bernard -# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ +# (c) 2006-2020 Thomas Bernard +# http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ # Author : Thomas Bernard # for use with GNU Make # -# options can be passed to genconfig.sh through CONFIG_OPTIONS : -# $ CONFIG_OPTIONS="--ipv6 --igd2" make -f Makefile.linux +# options can be passed to configure through CONFIG_OPTIONS : +# $ CONFIG_OPTIONS="--ipv6 --igd2" make # # To install use : -# $ DESTDIR=/dummyinstalldir make -f Makefile.linux install +# $ DESTDIR=/dummyinstalldir make install # or : -# $ INSTALLPREFIX=/usr/local make -f Makefile.linux install +# $ INSTALLPREFIX=/usr/local make install # or : -# $ make -f Makefile.linux install +# $ make install # (default INSTALLPREFIX is /usr) # # if your system hasn't iptables libiptc headers and binary correctly # installed, you need to get iptables sources from http://netfilter.org/ # ./configure them and build them then miniupnpd will build using : -# $ IPTABLESPATH=/path/to/iptables-1.4.1 make -f Makefile.linux +# $ IPTABLESPATH=/path/to/iptables-1.4.1 make # +CONFIG_OPTIONS ?= $(cat .configure.cache) +CONFIG_OPTIONS += --firewall=iptables #CFLAGS = -O -g -DDEBUG CFLAGS ?= -Os CFLAGS += -fno-strict-aliasing CFLAGS += -fno-common +CFLAGS += -fstack-protector -fPIE +CFLAGS += -D_FORTIFY_SOURCE=2 CPPFLAGS += -D_GNU_SOURCE CFLAGS += -Wall CFLAGS += -Wextra -Wstrict-prototypes -Wdeclaration-after-statement #CFLAGS += -Wno-missing-field-initializers #CFLAGS += -ansi # iptables headers does use typeof which is a gcc extension +LDFLAGS += -Wl,-z,now -Wl,-z,relro -pie CC ?= gcc RM = rm -f INSTALL = install STRIP ?= strip PKG_CONFIG ?= pkg-config CP = cp +DOXYGEN ?= doxygen +DEPFLAGS = -MM -MG -MT $(patsubst %.d,%.o,$@) -MT $@ +# -M : with system headers, -MM : without INSTALLPREFIX ?= $(PREFIX)/usr SBININSTALLDIR = $(INSTALLPREFIX)/sbin ETCINSTALLDIR = $(PREFIX)/etc/miniupnpd MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8 -BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ - upnpreplyparse.o minixml.o portinuse.o \ - upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ - options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ - upnpevents.o upnputils.o getconnstatus.o \ - upnppinhole.o pcplearndscp.o asyncsendto.o +include config.mk +include $(SRCDIR)/gitrev.mk +include $(SRCDIR)/objects.mk -LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o -NETFILTEROBJS = netfilter/iptcrdr.o netfilter/iptpinhole.o netfilter/nfct_get.o +# sources in netfilter/ directory +NETFILTEROBJS = iptcrdr.o iptpinhole.o nfct_get.o ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS) -PCFILE_FOUND := $(shell $(PKG_CONFIG) --exists libiptc; echo $$?) +DEP = $(ALLOBJS:.o=.d) -ifeq (${PCFILE_FOUND},0) +NETFILTER_SCRIPTS = $(addprefix $(SRCDIR)/netfilter/, \ + iptables_init.sh iptables_removeall.sh \ + ip6tables_init.sh ip6tables_removeall.sh \ + miniupnpd_functions.sh) -IPTABLESVERSION := $(shell $(PKG_CONFIG) --modversion libiptc) -IPTVER1 := $(shell echo $(IPTABLESVERSION) | cut -d. -f1 ) -IPTVER2 := $(shell echo $(IPTABLESVERSION) | cut -d. -f2 ) -IPTVER3 := $(shell echo $(IPTABLESVERSION) | cut -d. -f3 ) -# test if iptables version >= 1.4.3 -TEST := $(shell [ $(IPTVER1) -gt 1 ] || \ - [ \( $(IPTVER1) -eq 1 \) -a \ - \( \( $(IPTVER2) -gt 4 \) -o \ - \( \( $(IPTVER2) -eq 4 \) -a \( $(IPTVER3) -ge 3 \) \) \) ] && echo 1 ) -ifeq ($(TEST), 1) -CPPFLAGS += -DIPTABLES_143 -endif - -CFLAGS += $(shell $(PKG_CONFIG) --cflags libiptc) -LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libiptc) -LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L libiptc) -LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-other libiptc) -else +ifneq ($(IPTABLES_PCFILE_FOUND),1) ifeq "$(wildcard /etc/gentoo-release )" "" LDLIBS ?= -liptc @@ -88,71 +79,12 @@ CPPFLAGS := -DIPTABLES_143 $(CPPFLAGS) endif -ARCH ?= $(shell uname -m | grep -q "x86_64" && echo 64) -ifdef IPTABLESPATH -CPPFLAGS := $(CPPFLAGS) -I$(IPTABLESPATH)/include/ -LDFLAGS := $(LDFLAFGS) -L$(IPTABLESPATH)/libiptc/ -# get iptables version and set IPTABLES_143 macro if needed -ifeq ($(TARGET_OPENWRT),) -IPTABLESVERSION := $(shell grep "\#define VERSION" $(IPTABLESPATH)/config.h | tr -d \" |cut -d" " -f3 ) -IPTVER1 := $(shell echo $(IPTABLESVERSION) | cut -d. -f1 ) -IPTVER2 := $(shell echo $(IPTABLESVERSION) | cut -d. -f2 ) -IPTVER3 := $(shell echo $(IPTABLESVERSION) | cut -d. -f3 ) -# test if iptables version >= 1.4.3 -TEST := $(shell [ $(IPTVER1) -gt 1 ] || \ - [ \( $(IPTVER1) -eq 1 \) -a \ - \( \( $(IPTVER2) -gt 4 \) -o \ - \( \( $(IPTVER2) -eq 4 \) -a \( $(IPTVER3) -ge 3 \) \) \) ] && echo 1 ) -ifeq ($(TEST), 1) -CPPFLAGS := $(CPPFLAGS) -DIPTABLES_143 -# the following sucks, but works -LDLIBS = $(IPTABLESPATH)/libiptc/.libs/libip4tc.o -#LDLIBS = $(IPTABLESPATH)/libiptc/.libs/libiptc.a -else # ifeq ($(TEST), 1) -LDLIBS = $(IPTABLESPATH)/libiptc/libiptc.a -endif # ifeq ($(TEST), 1) -else # ($(TARGET_OPENWRT),) -# openWRT : -# check for system-wide iptables files. Test if iptables version >= 1.4.3 -# the following test has to be verified : -TEST := $(shell test -f /usr/include/iptables/internal.h && grep -q "\#define IPTABLES_VERSION" /usr/include/iptables/internal.h && echo 1) -ifeq ($(TEST), 1) -CPPFLAGS := $(CPPFLAGS) -DIPTABLES_143 -LDLIBS = -liptc -endif # ($(TEST), 1) -TEST_LIB := $(shell test -f /usr/lib$(ARCH)/libiptc.a && echo 1) -ifeq ($(TEST_LIB), 1) -LDLIBS = -liptc /usr/lib$(ARCH)/libiptc.a -endif # ($(TEST_LIB), 1) -endif # ($(TARGET_OPENWRT),) -else # ifdef IPTABLESPATH -# IPTABLESPATH not defined -# the following test has to be verified : -TEST := $(shell test -f /usr/include/xtables.h && grep -q "XTABLES_VERSION_CODE" /usr/include/xtables.h && echo 1) -ifeq ($(TEST), 1) -CPPFLAGS := $(CPPFLAGS) -DIPTABLES_143 -LDLIBS = -liptc -TESTIP4TC := $(shell test -f /lib/libip4tc.so && echo 1) -ifeq ($(TESTIP4TC), 1) -LDLIBS := $(LDLIBS) -lip4tc -endif # ($(TESTIP4TC), 1) -TESTIP6TC := $(shell test -f /lib/libip6tc.so && echo 1) -ifeq ($(TESTIP6TC), 1) -LDLIBS := $(LDLIBS) -lip6tc -endif # ($(TESTIP6TC), 1) -endif # ($(TEST), 1) -endif # ifdef IPTABLESPATH -endif # ifdef PCFILE_FOUND +endif # ifneq ($(IPTABLES_PCFILE_FOUND),1) #LDLIBS += -lnfnetlink -TEST := $(shell $(PKG_CONFIG) --atleast-version=1.0.2 libnetfilter_conntrack && $(PKG_CONFIG) --atleast-version=1.0.3 libmnl && echo 1) -ifeq ($(TEST),1) -CPPFLAGS += -DUSE_NFCT -LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libmnl) -LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libnetfilter_conntrack) -endif # ($(TEST),1) - +# OpenWrt packager disables https server for IGD v2 and hardcodes libuuid support +ifeq ($(TARGET_OPENWRT),) LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libssl) TEST := $(shell $(PKG_CONFIG) --exists uuid && echo 1) @@ -161,6 +93,15 @@ else $(info please install uuid-dev package / libuuid) endif # ($(TEST),1) +endif # ($(TARGET_OPENWRT,) + +GLIBC_VERSION := $(shell ldd --version | head -n 1 | sed 's/^.* //') +GLIBC_VERSION_MAJOR = $(shell echo $(GLIBC_VERSION) | cut -f 1 -d . ) +GLIBC_VERSION_MINOR = $(shell echo $(GLIBC_VERSION) | cut -f 2 -d . ) +# clock_gettime() needs -lrt when glibc version < 2.17 +LDLIBS += $(shell if [ $(GLIBC_VERSION_MAJOR) -lt 2 ] \ + || [ \( $(GLIBC_VERSION_MAJOR) -eq 2 \) -a \( $(GLIBC_VERSION_MINOR) -lt 17 \) ] ; \ + then echo "-lrt" ; fi ) TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o @@ -169,175 +110,106 @@ testgetroute testasyncsendto testportinuse \ testssdppktgen testminissdp -.PHONY: all clean install depend genuuid +.PHONY: all clean install depend dox all: $(EXECUTABLES) clean: + $(RM) config.h $(RM) $(ALLOBJS) + $(RM) $(DEP) $(RM) $(EXECUTABLES) $(RM) testupnpdescgen.o testgetifstats.o $(RM) testupnppermissions.o testgetifaddr.o $(RM) testgetroute.o testasyncsendto.o $(RM) testportinuse.o + $(RM) testminissdp.o + $(RM) testssdppktgen.o $(RM) miniupnpdctl.o $(RM) validateupnppermissions validategetifaddr validatessdppktgen + $(RM) -r dox/ -install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \ - netfilter/iptables_init.sh netfilter/iptables_removeall.sh \ - netfilter/ip6tables_init.sh netfilter/ip6tables_removeall.sh \ - netfilter/miniupnpd_functions.sh \ - linux/miniupnpd.init.d.script +install: miniupnpd $(SRCDIR)/miniupnpd.8 miniupnpd.conf \ + $(NETFILTER_SCRIPTS) \ + $(SRCDIR)/linux/miniupnpd.init.d.script $(STRIP) miniupnpd $(INSTALL) -d $(DESTDIR)$(SBININSTALLDIR) $(INSTALL) miniupnpd $(DESTDIR)$(SBININSTALLDIR) $(INSTALL) -d $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/iptables_init.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/iptables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/ip6tables_init.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/ip6tables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/miniupnpd_functions.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) --mode=0644 -b miniupnpd.conf $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter/iptables_init.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter/iptables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter/ip6tables_init.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter/ip6tables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter/miniupnpd_functions.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) --mode=0644 -b $(SRCDIR)/miniupnpd.conf $(DESTDIR)$(ETCINSTALLDIR) $(INSTALL) -d $(DESTDIR)$(PREFIX)/etc/init.d - $(INSTALL) linux/miniupnpd.init.d.script $(DESTDIR)$(PREFIX)/etc/init.d/miniupnpd + $(INSTALL) $(SRCDIR)/linux/miniupnpd.init.d.script $(DESTDIR)$(PREFIX)/etc/init.d/miniupnpd $(INSTALL) -d $(DESTDIR)$(MANINSTALLDIR) - $(INSTALL) --mode=0644 miniupnpd.8 $(DESTDIR)$(MANINSTALLDIR) + $(INSTALL) --mode=0644 $(SRCDIR)/miniupnpd.8 $(DESTDIR)$(MANINSTALLDIR) gzip -f $(DESTDIR)$(MANINSTALLDIR)/miniupnpd.8 # genuuid is using the uuidgen CLI tool which is part of libuuid # from the e2fsprogs # 'cat /proc/sys/kernel/random/uuid' could be also used -genuuid: +miniupnpd.conf: $(SRCDIR)/miniupnpd.conf ifeq ($(TARGET_OPENWRT),) - sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`(genuuid||uuidgen||uuid) 2>/dev/null`/" miniupnpd.conf + sed -e "s/^uuid=[-0-9a-f]*/uuid=`(genuuid||uuidgen||uuid) 2>/dev/null`/" $< > $@.tmp else - sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`($(STAGING_DIR_HOST)/bin/genuuid||$(STAGING_DIR_HOST)/bin/uuidgen||$(STAGING_DIR_HOST)/bin/uuid) 2>/dev/null`/" miniupnpd.conf + sed -e "s/^uuid=[-0-9a-f]*/uuid=`($(STAGING_DIR_HOST)/bin/genuuid||$(STAGING_DIR_HOST)/bin/uuidgen||$(STAGING_DIR_HOST)/bin/uuid) 2>/dev/null`/" $< > $@.tmp endif + mv $@.tmp $@ -check: validateupnppermissions validategetifaddr validatessdppktgen - -validateupnppermissions: testupnppermissions testupnppermissions.sh - ./testupnppermissions.sh - touch $@ - -validategetifaddr: testgetifaddr testgetifaddr.sh - ./testgetifaddr.sh - touch $@ - -validatessdppktgen: testssdppktgen - ./testssdppktgen - touch $@ +include $(SRCDIR)/check.mk miniupnpd: $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS) testupnpdescgen: $(TESTUPNPDESCGENOBJS) -testgetifstats: testgetifstats.o linux/getifstats.o +testgetifstats: testgetifstats.o getifstats.o testupnppermissions: testupnppermissions.o upnppermissions.o testgetifaddr: testgetifaddr.o getifaddr.o -testgetroute: testgetroute.o linux/getroute.o upnputils.o +testgetroute: testgetroute.o getroute.o upnputils.o testssdppktgen: testssdppktgen.o testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o \ - linux/getroute.o + getroute.o testportinuse: testportinuse.o portinuse.o getifaddr.o \ - netfilter/iptcrdr.o + iptcrdr.o testminissdp: testminissdp.o minissdp.o upnputils.o upnpglobalvars.o \ - asyncsendto.o linux/getroute.o + asyncsendto.o getroute.o miniupnpdctl: miniupnpdctl.o -config.h: genconfig.sh VERSION - ./genconfig.sh $(CONFIG_OPTIONS) +config.mk config.h: $(SRCDIR)/configure $(SRCDIR)/VERSION + $(SHELL) $< $(CONFIG_OPTIONS) + +depend: $(DEP) + +%.d: $(SRCDIR)/%.c + $(CC) $(CPPFLAGS) $(DEPFLAGS) -o $@ $< + +dox: $(SRCDIR)/miniupnpd.doxyconf + (cat $< ; echo "INPUT=$(SRCDIR)" ) | $(DOXYGEN) - + +%.o: $(SRCDIR)/%.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ -depend: config.h - makedepend -f$(MAKEFILE_LIST) -Y \ - $(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \ - testgetifstats.c testupnppermissions.c testgetifaddr.c \ - testgetroute.c testasyncsendto.c testportinuse.c \ - miniupnpdctl.c testssdppktgen.c 2>/dev/null - -# DO NOT DELETE - -miniupnpd.o: config.h macros.h upnpglobalvars.h upnppermissions.h -miniupnpd.o: miniupnpdtypes.h upnphttp.h upnpdescgen.h miniupnpdpath.h -miniupnpd.o: getifaddr.h upnpsoap.h options.h minissdp.h upnpredirect.h -miniupnpd.o: upnppinhole.h daemonize.h upnpevents.h asyncsendto.h natpmp.h -miniupnpd.o: pcpserver.h commonrdr.h upnputils.h ifacewatcher.h -upnphttp.o: config.h upnphttp.h upnpdescgen.h miniupnpdpath.h upnpsoap.h -upnphttp.o: upnpevents.h upnputils.h upnpglobalvars.h upnppermissions.h -upnphttp.o: miniupnpdtypes.h -upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h -upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h -upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h -upnpsoap.o: macros.h config.h upnpglobalvars.h upnppermissions.h -upnpsoap.o: miniupnpdtypes.h upnphttp.h upnpsoap.h upnpreplyparse.h -upnpsoap.o: upnpredirect.h upnppinhole.h getifaddr.h getifstats.h -upnpsoap.o: getconnstatus.h upnpurns.h -upnpreplyparse.o: upnpreplyparse.h minixml.h -minixml.o: minixml.h -portinuse.o: macros.h config.h upnpglobalvars.h upnppermissions.h -portinuse.o: miniupnpdtypes.h getifaddr.h portinuse.h netfilter/iptcrdr.h -portinuse.o: commonrdr.h -upnpredirect.o: macros.h config.h upnpredirect.h upnpglobalvars.h -upnpredirect.o: upnppermissions.h miniupnpdtypes.h upnpevents.h portinuse.h -upnpredirect.o: netfilter/iptcrdr.h commonrdr.h -getifaddr.o: config.h getifaddr.h -daemonize.o: daemonize.h config.h -upnpglobalvars.o: config.h upnpglobalvars.h upnppermissions.h -upnpglobalvars.o: miniupnpdtypes.h upnpdescstrings.h -options.o: config.h options.h upnppermissions.h upnpglobalvars.h -options.o: miniupnpdtypes.h -upnppermissions.o: config.h upnppermissions.h -minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h -minissdp.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h minissdp.h -minissdp.o: upnputils.h getroute.h asyncsendto.h codelength.h macros.h -natpmp.o: macros.h config.h natpmp.h upnpglobalvars.h upnppermissions.h -natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h -natpmp.o: portinuse.h asyncsendto.h -pcpserver.o: config.h pcpserver.h macros.h upnpglobalvars.h upnppermissions.h -pcpserver.o: miniupnpdtypes.h pcplearndscp.h upnpredirect.h commonrdr.h -pcpserver.o: getifaddr.h asyncsendto.h pcp_msg_struct.h netfilter/iptcrdr.h -pcpserver.o: commonrdr.h -upnpevents.o: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h -upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h -upnputils.o: config.h upnputils.h upnpglobalvars.h upnppermissions.h -upnputils.o: miniupnpdtypes.h getroute.h -getconnstatus.o: getconnstatus.h getifaddr.h -upnppinhole.o: macros.h config.h upnpredirect.h upnpglobalvars.h -upnppinhole.o: upnppermissions.h miniupnpdtypes.h upnpevents.h upnppinhole.h -upnppinhole.o: netfilter/iptpinhole.h -pcplearndscp.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h -pcplearndscp.o: pcplearndscp.h -asyncsendto.o: asyncsendto.h upnputils.h -linux/getifstats.o: config.h getifstats.h -linux/ifacewatcher.o: config.h ifacewatcher.h config.h minissdp.h -linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h -linux/ifacewatcher.o: upnppermissions.h natpmp.h -linux/getroute.o: getroute.h upnputils.h -netfilter/iptcrdr.o: macros.h config.h netfilter/iptcrdr.h commonrdr.h -netfilter/iptcrdr.o: config.h upnpglobalvars.h upnppermissions.h -netfilter/iptcrdr.o: miniupnpdtypes.h -netfilter/iptpinhole.o: config.h netfilter/iptpinhole.h upnpglobalvars.h -netfilter/iptpinhole.o: upnppermissions.h config.h miniupnpdtypes.h -testupnpdescgen.o: macros.h config.h upnpdescgen.h upnpdescstrings.h -testupnpdescgen.o: getifaddr.h -upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h -upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h -upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h -testgetifstats.o: getifstats.h -testupnppermissions.o: upnppermissions.h config.h -testgetifaddr.o: config.h getifaddr.h -testgetroute.o: getroute.h upnputils.h upnpglobalvars.h upnppermissions.h -testgetroute.o: config.h miniupnpdtypes.h -testasyncsendto.o: miniupnpdtypes.h config.h upnputils.h asyncsendto.h -testportinuse.o: macros.h config.h portinuse.h -miniupnpdctl.o: macros.h -testssdppktgen.o: macros.h config.h miniupnpdpath.h upnphttp.h +%.o: $(SRCDIR)/linux/%.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ + +%.o: $(SRCDIR)/netfilter/%.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ + +print-%: + @echo "$* = $($*)" + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEP) +endif diff -Nru miniupnpd-2.1/Makefile.linux_nft miniupnpd-2.2.1/Makefile.linux_nft --- miniupnpd-2.1/Makefile.linux_nft 2018-04-06 10:53:32.000000000 +0000 +++ miniupnpd-2.2.1/Makefile.linux_nft 2020-06-06 18:02:58.000000000 +0000 @@ -1,35 +1,42 @@ # MiniUPnP project +# (c) 2018-2020 Thomas Bernard # (c) 2015 Tomofumi Hayashi -# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ +# http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ # Author : Tomofumi Hayashi # for use with GNU Make # -# options can be passed to genconfig.sh through CONFIG_OPTIONS : -# $ CONFIG_OPTIONS="--ipv6 --igd2" make -f Makefile.linux +# options can be passed to configure through CONFIG_OPTIONS : +# $ CONFIG_OPTIONS="--ipv6 --igd2" make # # To install use : -# $ DESTDIR=/dummyinstalldir make -f Makefile.linux_nft install +# $ DESTDIR=/dummyinstalldir make install # or : -# $ INSTALLPREFIX=/usr/local make -f Makefile.linux_nft install +# $ INSTALLPREFIX=/usr/local make install # or : -# $ make -f Makefile.linux install +# $ make install # (default INSTALLPREFIX is /usr) # # -CFLAGS = -O -g #-DDEBUG +CONFIG_OPTIONS ?= $(cat .configure.cache) +CONFIG_OPTIONS += --firewall=nftables +#CFLAGS = -O -g #-DDEBUG CFLAGS ?= -Os CFLAGS += -fno-strict-aliasing CFLAGS += -fno-common +CFLAGS += -fstack-protector -fPIE +CFLAGS += -D_FORTIFY_SOURCE=2 CPPFLAGS += -D_GNU_SOURCE CFLAGS += -Wall CFLAGS += -Wextra -Wstrict-prototypes -Wdeclaration-after-statement #CFLAGS += -Wno-missing-field-initializers +LDFLAGS += -Wl,-z,now -Wl,-z,relro -pie CC ?= gcc RM = rm -f INSTALL = install STRIP ?= strip PKG_CONFIG ?= pkg-config CP = cp +DOXYGEN ?= doxygen INSTALLPREFIX ?= $(PREFIX)/usr @@ -37,18 +44,20 @@ ETCINSTALLDIR = $(PREFIX)/etc/miniupnpd MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8 -BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ - upnpreplyparse.o minixml.o portinuse.o \ - upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ - options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ - upnpevents.o upnputils.o getconnstatus.o \ - upnppinhole.o pcplearndscp.o asyncsendto.o +include config.mk +include $(SRCDIR)/gitrev.mk +include $(SRCDIR)/objects.mk -LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o -NETFILTEROBJS = netfilter_nft/nftnlrdr.o netfilter_nft/nfct_get.o netfilter_nft/nftnlrdr_misc.o +# sources in the netfilter_nft/ directory +NETFILTEROBJS = nftnlrdr.o nftpinhole.o nfct_get.o nftnlrdr_misc.o ALLOBJS = $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS) +DEP = $(ALLOBJS:o=.d) + +NFT_SCRIPTS = $(addprefix $(SRCDIR)/netfilter_nft/scripts/, \ + nft_init.sh nft_removeall.sh nft_flush.sh nft_delete_chain.sh) + PCFILE_FOUND := $(shell $(PKG_CONFIG) --exists libnftnl; echo $$?) ifeq (${PCFILE_FOUND},0) @@ -60,31 +69,44 @@ LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-other $(PKG_CONFIG_LIBS)) else -ARCH ?= $(shell uname -m | grep -q "x86_64" && echo 64) endif # ifdef PCFILE_FOUND #LDLIBS += -lnfnetlink -TEST := $(shell $(PKG_CONFIG) --atleast-version=1.0.2 libnetfilter_conntrack && $(PKG_CONFIG) --atleast-version=1.0.3 libmnl && echo 1) +LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libssl) + +TEST := $(shell $(PKG_CONFIG) --exists uuid && echo 1) ifeq ($(TEST),1) -CPPFLAGS += -DUSE_NFCT -LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libmnl) -LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libnetfilter_conntrack) +LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l uuid) +else +$(info please install uuid-dev package / libuuid) endif # ($(TEST),1) -LDLIBS += $(shell $(PKG_CONFIG) --static --libs-only-l libssl) +# genuuid uses the uuidgen CLI tool which is part of libuuid +# from the e2fsprogs +# 'cat /proc/sys/kernel/random/uuid' could be also used +# +ifeq ($(TARGET_OPENWRT),) + UUIDEXECDIR='' +else + UUIDEXECDIR="$(STAGING_DIR_HOST)/bin/" +endif +UUID=$(shell ($(UUIDEXECDIR)genuuid || $(UUIDEXECDIR)uuidgen || $(UUIDEXECDIR)uuid) 2> /dev/null ) + TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o -EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ - testupnppermissions miniupnpdctl testgetifaddr \ +EXECUTABLES = miniupnpd miniupnpdctl \ + testupnpdescgen testgetifstats \ + testupnppermissions testgetifaddr \ testgetroute testasyncsendto testportinuse -.PHONY: all clean install depend genuuid +.PHONY: all clean install depend dox all: $(EXECUTABLES) clean: + $(RM) config.h $(RM) $(ALLOBJS) $(RM) $(EXECUTABLES) $(RM) testupnpdescgen.o testgetifstats.o @@ -92,140 +114,72 @@ $(RM) testgetroute.o testasyncsendto.o $(RM) testportinuse.o $(RM) miniupnpdctl.o + $(RM) -r dox/ -install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \ - netfilter/iptables_init.sh netfilter/iptables_removeall.sh \ - netfilter/ip6tables_init.sh netfilter/ip6tables_removeall.sh \ - netfilter/miniupnpd_functions.sh \ - linux/miniupnpd.init.d.script +install: miniupnpd $(SRCDIR)/miniupnpd.8 $(SRCDIR)/miniupnpd.conf \ + $(NFT_SCRIPTS) \ + $(SRCDIR)/linux/miniupnpd.init.d.script $(STRIP) miniupnpd $(INSTALL) -d $(DESTDIR)$(SBININSTALLDIR) $(INSTALL) miniupnpd $(DESTDIR)$(SBININSTALLDIR) $(INSTALL) -d $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/iptables_init.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/iptables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/ip6tables_init.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/ip6tables_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) netfilter/miniupnpd_functions.sh $(DESTDIR)$(ETCINSTALLDIR) - $(INSTALL) --mode=0644 -b miniupnpd.conf $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter_nft/scripts/nft_init.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter_nft/scripts/nft_removeall.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter_nft/scripts/nft_flush.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) $(SRCDIR)/netfilter_nft/scripts/nft_delete_chain.sh $(DESTDIR)$(ETCINSTALLDIR) + $(INSTALL) --mode=0644 -b $(SRCDIR)/miniupnpd.conf $(DESTDIR)$(ETCINSTALLDIR) + sed -i -e "s/^uuid=[-0-9a-f]*/uuid=$(UUID)/" $(DESTDIR)$(ETCINSTALLDIR)/miniupnpd.conf $(INSTALL) -d $(DESTDIR)$(PREFIX)/etc/init.d - $(INSTALL) linux/miniupnpd.init.d.script $(DESTDIR)$(PREFIX)/etc/init.d/miniupnpd + $(INSTALL) $(SRCDIR)/linux/miniupnpd.init.d.script $(DESTDIR)$(PREFIX)/etc/init.d/miniupnpd $(INSTALL) -d $(DESTDIR)$(MANINSTALLDIR) $(INSTALL) --mode=0644 miniupnpd.8 $(DESTDIR)$(MANINSTALLDIR) gzip -f $(DESTDIR)$(MANINSTALLDIR)/miniupnpd.8 -# genuuid is using the uuidgen CLI tool which is part of libuuid -# from the e2fsprogs -# 'cat /proc/sys/kernel/random/uuid' could be also used -genuuid: -ifeq ($(TARGET_OPENWRT),) - sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`(genuuid||uuidgen||uuid) 2>/dev/null`/" miniupnpd.conf -else - sed -i -e "s/^uuid=[-0-9a-f]*/uuid=`($(STAGING_DIR_HOST)/bin/genuuid||$(STAGING_DIR_HOST)/bin/uuidgen||$(STAGING_DIR_HOST)/bin/uuid) 2>/dev/null`/" miniupnpd.conf -endif +include $(SRCDIR)/check.mk miniupnpd: $(BASEOBJS) $(LNXOBJS) $(NETFILTEROBJS) testupnpdescgen: $(TESTUPNPDESCGENOBJS) -testgetifstats: testgetifstats.o linux/getifstats.o +testgetifstats: testgetifstats.o getifstats.o testupnppermissions: testupnppermissions.o upnppermissions.o testgetifaddr: testgetifaddr.o getifaddr.o -testgetroute: testgetroute.o linux/getroute.o upnputils.o +testgetroute: testgetroute.o getroute.o upnputils.o testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o \ - linux/getroute.o + getroute.o testportinuse: testportinuse.o portinuse.o getifaddr.o \ - netfilter_nft/nftnlrdr.o netfilter_nft/nftnlrdr_misc.o + nftnlrdr.o nftnlrdr_misc.o miniupnpdctl: miniupnpdctl.o -config.h: genconfig.sh VERSION - ./genconfig.sh $(CONFIG_OPTIONS) +config.mk config.h: $(SRCDIR)/configure $(SRCDIR)/VERSION + $(SHELL) $< $(CONFIG_OPTIONS) + +depend: $(DEP) + +%.d: $(SRCDIR)/%.c + $(CC) $(CPPFLAGS) $(DEPFLAGS) -o $@ $< -depend: config.h - makedepend -f$(MAKEFILE_LIST) -Y \ - $(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \ - testgetifstats.c testupnppermissions.c testgetifaddr.c \ - testgetroute.c testasyncsendto.c testportinuse.c \ - miniupnpdctl.c 2>/dev/null - -# DO NOT DELETE - -miniupnpd.o: config.h macros.h upnpglobalvars.h upnppermissions.h -miniupnpd.o: miniupnpdtypes.h upnphttp.h upnpdescgen.h miniupnpdpath.h -miniupnpd.o: getifaddr.h upnpsoap.h options.h minissdp.h upnpredirect.h -miniupnpd.o: upnppinhole.h daemonize.h upnpevents.h asyncsendto.h natpmp.h -miniupnpd.o: pcpserver.h commonrdr.h upnputils.h ifacewatcher.h -upnphttp.o: config.h upnphttp.h upnpdescgen.h miniupnpdpath.h upnpsoap.h -upnphttp.o: upnpevents.h upnputils.h -upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h -upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h -upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h -upnpsoap.o: macros.h config.h upnpglobalvars.h upnppermissions.h -upnpsoap.o: miniupnpdtypes.h upnphttp.h upnpsoap.h upnpreplyparse.h -upnpsoap.o: upnpredirect.h upnppinhole.h getifaddr.h getifstats.h -upnpsoap.o: getconnstatus.h upnpurns.h -upnpreplyparse.o: upnpreplyparse.h minixml.h -minixml.o: minixml.h -portinuse.o: macros.h config.h upnpglobalvars.h upnppermissions.h -portinuse.o: miniupnpdtypes.h getifaddr.h portinuse.h netfilter_nft/nftnlrdr.h -portinuse.o: commonrdr.h -upnpredirect.o: macros.h config.h upnpredirect.h upnpglobalvars.h -upnpredirect.o: upnppermissions.h miniupnpdtypes.h upnpevents.h portinuse.h -upnpredirect.o: netfilter_nft/nftnlrdr.h commonrdr.h -getifaddr.o: config.h getifaddr.h -daemonize.o: daemonize.h config.h -upnpglobalvars.o: config.h upnpglobalvars.h upnppermissions.h -upnpglobalvars.o: miniupnpdtypes.h upnpdescstrings.h -options.o: config.h options.h upnppermissions.h upnpglobalvars.h -options.o: miniupnpdtypes.h -upnppermissions.o: config.h upnppermissions.h -minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h -minissdp.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h minissdp.h -minissdp.o: upnputils.h getroute.h asyncsendto.h codelength.h -natpmp.o: macros.h config.h natpmp.h upnpglobalvars.h upnppermissions.h -natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h -natpmp.o: portinuse.h asyncsendto.h -pcpserver.o: config.h pcpserver.h macros.h upnpglobalvars.h upnppermissions.h -pcpserver.o: miniupnpdtypes.h pcplearndscp.h upnpredirect.h commonrdr.h -pcpserver.o: getifaddr.h asyncsendto.h pcp_msg_struct.h netfilter_nft/nftnlrdr.h -pcpserver.o: commonrdr.h -upnpevents.o: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h -upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h -upnputils.o: config.h upnputils.h upnpglobalvars.h upnppermissions.h -upnputils.o: miniupnpdtypes.h getroute.h -getconnstatus.o: getconnstatus.h getifaddr.h -upnppinhole.o: macros.h config.h upnpredirect.h upnpglobalvars.h -upnppinhole.o: upnppermissions.h miniupnpdtypes.h upnpevents.h -#upnppinhole.o: netfilter/iptpinhole.h -pcplearndscp.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h -pcplearndscp.o: pcplearndscp.h -asyncsendto.o: asyncsendto.h -linux/getifstats.o: config.h getifstats.h -linux/ifacewatcher.o: config.h ifacewatcher.h config.h minissdp.h -linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h -linux/ifacewatcher.o: upnppermissions.h natpmp.h -linux/getroute.o: getroute.h upnputils.h -netfilter_nft/nftnlrdr.o: macros.h config.h netfilter_nft/nftnlrdr.h commonrdr.h -netfilter_nft/nftnlrdr.o: config.h upnpglobalvars.h upnppermissions.h -netfilter_nft/nftnlrdr.o: miniupnpdtypes.h -netfilter_nft/iptpinhole.o: config.h netfilter_nft/iptpinhole.h upnpglobalvars.h -netfilter_nft/iptpinhole.o: upnppermissions.h config.h miniupnpdtypes.h -testupnpdescgen.o: macros.h config.h upnpdescgen.h upnpdescstrings.h -testupnpdescgen.o: getifaddr.h -upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h -upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h -upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h -testgetifstats.o: getifstats.h -testupnppermissions.o: upnppermissions.h config.h -testgetifaddr.o: config.h getifaddr.h -testgetroute.o: getroute.h upnputils.h upnpglobalvars.h upnppermissions.h -testgetroute.o: config.h miniupnpdtypes.h -testasyncsendto.o: miniupnpdtypes.h config.h upnputils.h asyncsendto.h -testportinuse.o: macros.h config.h portinuse.h -miniupnpdctl.o: macros.h +dox: $(SRCDIR)/miniupnpd.doxyconf + (cat $< ; echo "INPUT=$(SRCDIR)" ) | $(DOXYGEN) - + +%.o: $(SRCDIR)/%.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ + +%.o: $(SRCDIR)/linux/%.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ + +%.o: $(SRCDIR)/netfilter_nft/%.c + $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ + +print-%: + @echo "$* = $($*)" + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEP) +endif diff -Nru miniupnpd-2.1/Makefile.macosx miniupnpd-2.2.1/Makefile.macosx --- miniupnpd-2.1/Makefile.macosx 2014-06-30 12:03:05.000000000 +0000 +++ miniupnpd-2.2.1/Makefile.macosx 2020-05-10 18:11:13.000000000 +0000 @@ -1,5 +1,5 @@ # MiniUPnP project -# http://miniupnp.free.fr/ +# http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ # Author: Thomas Bernard # This Makefile should work for MacOSX # @@ -31,6 +31,7 @@ upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ options.o upnppermissions.o minissdp.o natpmp.o \ upnpevents.o getconnstatus.o upnputils.o \ + upnpstun.o \ upnppinhole.o asyncsendto.o portinuse.o pcpserver.o MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o bsd/getroute.o IPFW_OBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o @@ -123,8 +124,8 @@ testportinuse: config.h $(TEST_PORTINUSE_OBJS) $(CC) $(CFLAGS) -o $@ $(TEST_PORTINUSE_OBJS) -config.h: genconfig.sh - ./genconfig.sh +config.h: configure VERSION + ./configure .SUFFIXES: .o .c .c.o: diff -Nru miniupnpd-2.1/Makefile.sunos miniupnpd-2.2.1/Makefile.sunos --- miniupnpd-2.1/Makefile.sunos 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/Makefile.sunos 2020-05-10 18:11:13.000000000 +0000 @@ -0,0 +1,203 @@ +# $Id: Makefile.sunos,v 1.2 2020/05/10 16:51:52 nanard Exp $ +# MiniUPnP project +# http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ +# Author: Thomas Bernard +# +# Makefile for miniupnpd (MiniUPnP daemon) +# +# This Makefile should work for SunOS/Solaris. +# This Makefile is NOT compatible with GNU Make. +# Linux users, please use Makefile.linux : +# make -f Makefile.linux +# +# options can be passed to configure through CONFIG_OPTIONS : +# $ CONFIG_OPTIONS="--ipv6 --igd2" make +# + +CFLAGS = -pipe -Os +#CFLAGS = -pipe -O -g -DDEBUG +#CFLAGS += -ansi +CFLAGS += -Wall +CFLAGS += -W +CFLAGS += -Wstrict-prototypes +#CFLAGS += -Wdeclaration-after-statement +#CFLAGS += -Wno-missing-field-initializers +CFLAGS += -fno-common +CFLAGS += -D_XOPEN_SOURCE +CFLAGS += -D_XOPEN_SOURCE_EXTENDED=1 +CFLAGS += -D__EXTENSIONS__ +CC = gcc +RM = rm -f +MV = mv +INSTALL = install +STRIP = strip + +# OSNAME and FWNAME are used for building OS or FW dependent code. +OSNAME :sh = uname -s +ARCH :sh = uname -m + +FWNAME = ipf + +# Solaris specific CFLAGS +CFLAGS :sh += echo "-DSOLARIS2=`uname -r | cut -d. -f2`" +# "amd64" +CFLAGS += -m64 -mcmodel=kernel -mno-red-zone -ffreestanding +# "sparc64" +#CFLAGS += -m64 -mcmodel=medlow +LDFLAGS += -m64 + +STDOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ + upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ + options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ + upnpevents.o upnputils.o getconnstatus.o \ + upnpstun.o \ + upnppinhole.o asyncsendto.o portinuse.o +BSDOBJS = bsd/getifstats.o bsd/ifacewatcher.o bsd/getroute.o +SUNOSOBJS = solaris/getifstats.o bsd/ifacewatcher.o bsd/getroute.o +MACOBJS = mac/getifstats.o bsd/ifacewatcher.o bsd/getroute.o +PFOBJS = pf/obsdrdr.o pf/pfpinhole.o +IPFOBJS = ipf/ipfrdr.o +IPFWOBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o +MISCOBJS = upnpreplyparse.o minixml.o + +ALLOBJS = $(STDOBJS) $(MISCOBJS) +ALLOBJS += $(SUNOSOBJS) +TESTGETIFSTATSOBJS = testgetifstats.o solaris/getifstats.o +TESTGETROUTEOBJS = testgetroute.o upnputils.o bsd/getroute.o + +#.if $(FWNAME) == "pf" +#ALLOBJS += $(PFOBJS) +#.elif $(FWNAME) == "ipfw" +#ALLOBJS += $(IPFWOBJS) +#.else +ALLOBJS += $(IPFOBJS) +#.endif + +TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o +TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o +TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o +MINIUPNPDCTLOBJS = miniupnpdctl.o +TESTASYNCSENDTOOBJS = testasyncsendto.o asyncsendto.o upnputils.o bsd/getroute.o +TESTPORTINUSEOBJS = testportinuse.o portinuse.o getifaddr.o + +EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ + testupnppermissions miniupnpdctl \ + testgetifaddr testgetroute testasyncsendto \ + testportinuse testssdppktgen + +LIBS += -lsocket -lnsl -lkstat -lresolv +LIBS += -luuid + +LIBS += -lssl -lcrypto + +# set PREFIX variable to install in the wanted place + +INSTALLBINDIR = $(PREFIX)/sbin +INSTALLETCDIR = $(PREFIX)/etc +# INSTALLMANDIR = $(PREFIX)/man +INSTALLMANDIR = /usr/share/man + +all: $(EXECUTABLES) + +clean: + $(RM) $(STDOBJS) $(BSDOBJS) $(SUNOSOBJS) $(MACOBJS) $(EXECUTABLES) \ + testupnpdescgen.o \ + $(MISCOBJS) config.h testgetifstats.o testupnppermissions.o \ + miniupnpdctl.o testgetifaddr.o testgetroute.o testasyncsendto.o \ + testportinuse.o \ + $(PFOBJS) $(IPFOBJS) $(IPFWOBJS) + $(RM) validateupnppermissions validategetifaddr validatessdppktgen + +install: miniupnpd genuuid + $(STRIP) miniupnpd + $(INSTALL) -d $(DESTDIR)$(INSTALLBINDIR) + $(INSTALL) -m 755 miniupnpd $(DESTDIR)$(INSTALLBINDIR) + $(INSTALL) -d $(DESTDIR)$(INSTALLETCDIR) + $(INSTALL) -b miniupnpd.conf $(DESTDIR)$(INSTALLETCDIR) + # TODO : install man page correctly +# $(INSTALL) -d $(INSTALLMANDIR) +# $(INSTALL) miniupnpd.8 $(INSTALLMANDIR)/cat8/miniupnpd.0 + +# genuuid is using the uuid cli tool available under OpenBSD 4.0 in +# the uuid-1.5.0 package +# any other cli tool returning a uuid on stdout should work. +UUID :sh = if which uuidgen 2>&1 > /dev/null; then \ + echo `uuidgen` ; \ + elif which uuid 2>&1 > /dev/null; then \ + echo `uuid` ; \ + else echo "00000000-0000-0000-0000-000000000000"; \ + fi + +# bash or ksh +SH :sh = which bash || which ksh + +genuuid: + $(MV) miniupnpd.conf miniupnpd.conf.before + sed -e "s/^uuid=[-0-9a-fA-F]*/uuid=$(UUID)/" miniupnpd.conf.before > miniupnpd.conf + $(RM) miniupnpd.conf.before + +check: validateupnppermissions validategetifaddr validatessdppktgen + +validateupnppermissions: testupnppermissions testupnppermissions.sh + $(SH) ./testupnppermissions.sh + touch $@ + +validategetifaddr: testgetifaddr testgetifaddr.sh + ./testgetifaddr.sh + touch $@ + +validatessdppktgen: testssdppktgen + ./testssdppktgen + touch $@ + +depend: config.h + mkdep $(ALLOBJS:.o=.c) testupnpdescgen.c testgetifstats.c \ + testupnppermissions.c miniupnpdctl.c testgetifaddr.c \ + testgetroute.c testportinuse.c testasyncsendto.c \ + testssdppktgen.c + +miniupnpd: config.h $(ALLOBJS) + $(CC) $(LDFLAGS) -o $@ $(ALLOBJS) $(LIBS) + +# BSDmake : +# $(CC) $(LDFLAGS) -o $@ $> $(LIBS) + +miniupnpdctl: config.h $(MINIUPNPDCTLOBJS) + $(CC) $(LDFLAGS) -o $@ $(MINIUPNPDCTLOBJS) -lsocket + +testupnpdescgen: config.h $(TESTUPNPDESCGENOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTUPNPDESCGENOBJS) $(LIBS) + +testgetifstats: config.h $(TESTGETIFSTATSOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTGETIFSTATSOBJS) $(LIBS) + +testgetifaddr: config.h $(TESTGETIFADDROBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTGETIFADDROBJS) $(LIBS) + +testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTUPNPPERMISSIONSOBJS) $(LIBS) + +testgetroute: config.h $(TESTGETROUTEOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTGETROUTEOBJS) $(LIBS) + +testasyncsendto: config.h $(TESTASYNCSENDTOOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTASYNCSENDTOOBJS) -lsocket -lnsl + +testportinuse: config.h $(TESTPORTINUSEOBJS) + $(CC) $(LDFLAGS) -o $@ $(TESTPORTINUSEOBJS) $(LIBS) + +# gmake : +# $(CC) $(CFLAGS) -o $@ $^ +# BSDmake : +# $(CC) $(CFLAGS) -o $@ $> + +config.h: configure VERSION + ./configure $(CONFIG_OPTIONS) + +.SUFFIXES: .o .c +.c.o: + $(CC) $(CFLAGS) -c -o $@ $< + +# $(CC) $(CFLAGS) -c -o $(.TARGET) $(.IMPSRC) + + diff -Nru miniupnpd-2.1/minissdp.c miniupnpd-2.2.1/minissdp.c --- miniupnpd-2.1/minissdp.c 2018-04-22 19:44:41.000000000 +0000 +++ miniupnpd-2.2.1/minissdp.c 2020-06-06 18:02:58.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: minissdp.c,v 1.93 2018/04/22 19:36:58 nanard Exp $ */ +/* $Id: minissdp.c,v 1.101 2020/06/06 17:56:17 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -65,33 +65,29 @@ struct ip_mreqn imr; /* Ip multicast membership */ #endif /* HAVE_IP_MREQN */ - /* setting up imr structure */ - imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR); - /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/ + /* setting up imr structure */ + imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR); + /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/ #ifndef HAVE_IP_MREQN imr.imr_interface.s_addr = lan_addr->addr.s_addr; #else /* HAVE_IP_MREQN */ - imr.imr_address.s_addr = lan_addr->addr.s_addr; + imr.imr_address.s_addr = lan_addr->addr.s_addr; #ifndef MULTIPLE_EXTERNAL_IP #ifdef ENABLE_IPV6 imr.imr_ifindex = lan_addr->index; #else /* ENABLE_IPV6 */ - imr.imr_ifindex = if_nametoindex(lan_addr->ifname); + imr.imr_ifindex = if_nametoindex(lan_addr->ifname); #endif /* ENABLE_IPV6 */ #else /* MULTIPLE_EXTERNAL_IP */ - imr.imr_ifindex = 0; + imr.imr_ifindex = 0; #endif /* MULTIPLE_EXTERNAL_IP */ #endif /* HAVE_IP_MREQN */ -#ifndef HAVE_IP_MREQN - if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0) -#else /* HAVE_IP_MREQN */ - if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreqn)) < 0) -#endif /* HAVE_IP_MREQN */ + if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(imr)) < 0) { - syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m"); + syslog(LOG_ERR, "setsockopt(udp, IP_ADD_MEMBERSHIP): %m"); return -1; - } + } return 0; } @@ -209,8 +205,7 @@ syslog(LOG_WARNING, "setsockopt(udp, IP_RECVIF): %m"); } } -#endif /* IP_RECVIF */ -#ifdef IP_PKTINFO +#elif defined(IP_PKTINFO) /* IP_RECVIF */ /* Linux */ if(!ipv6) { if(setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) @@ -289,7 +284,7 @@ /* open the UDP socket used to send SSDP notifications to * the multicast group reserved for them */ static int -OpenAndConfSSDPNotifySocket(in_addr_t addr) +OpenAndConfSSDPNotifySocket(struct lan_addr_s * lan_addr) { int s; unsigned char loopchar = 0; @@ -298,7 +293,11 @@ The TTL for the IP packet SHOULD default to 2 and SHOULD be configurable. */ /* TODO: Make TTL be configurable */ +#ifndef HAVE_IP_MREQN struct in_addr mc_if; +#else /* HAVE_IP_MREQN */ + struct ip_mreqn mc_if; +#endif /* HAVE_IP_MREQN */ struct sockaddr_in sockname; if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) @@ -307,7 +306,16 @@ return -1; } - mc_if.s_addr = addr; /*inet_addr(addr);*/ +#ifndef HAVE_IP_MREQN + mc_if.s_addr = lan_addr->addr.s_addr; /*inet_addr(addr);*/ +#else /* HAVE_IP_MREQN */ + mc_if.imr_address.s_addr = lan_addr->addr.s_addr; /*inet_addr(addr);*/ +#ifdef ENABLE_IPV6 + mc_if.imr_ifindex = lan_addr->index; +#else /* ENABLE_IPV6 */ + mc_if.imr_ifindex = if_nametoindex(lan_addr->ifname); +#endif /* ENABLE_IPV6 */ +#endif /* HAVE_IP_MREQN */ if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopchar, sizeof(loopchar)) < 0) { @@ -340,15 +348,15 @@ * an unbound socket) * here it is used to se a specific sending address */ memset(&sockname, 0, sizeof(struct sockaddr_in)); - sockname.sin_family = AF_INET; - sockname.sin_addr.s_addr = addr; /*inet_addr(addr);*/ + sockname.sin_family = AF_INET; + sockname.sin_addr.s_addr = lan_addr->addr.s_addr; /*inet_addr(addr);*/ - if (bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0) + if (bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0) { syslog(LOG_ERR, "bind(udp_notify): %m"); close(s); return -1; - } + } return s; } @@ -357,7 +365,7 @@ /* open the UDP socket used to send SSDP notifications to * the multicast group reserved for them. IPv6 */ static int -OpenAndConfSSDPNotifySocketIPv6(unsigned int if_index) +OpenAndConfSSDPNotifySocketIPv6(struct lan_addr_s * lan_addr) { int s; unsigned int loop = 0; @@ -372,9 +380,9 @@ syslog(LOG_ERR, "socket(udp_notify IPv6): %m"); return -1; } - if(setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_index, sizeof(if_index)) < 0) + if(setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &lan_addr->index, sizeof(lan_addr->index)) < 0) { - syslog(LOG_ERR, "setsockopt(udp_notify IPv6, IPV6_MULTICAST_IF, %u): %m", if_index); + syslog(LOG_ERR, "setsockopt(udp_notify IPv6, IPV6_MULTICAST_IF, %u): %m", lan_addr->index); close(s); return -1; } @@ -423,7 +431,7 @@ lan_addr != NULL; lan_addr = lan_addr->list.le_next) { - sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr->addr.s_addr); + sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr); if(sockets[i] < 0) goto error; i++; @@ -434,7 +442,7 @@ } else { - sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index); + sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr); if(sockets[i] < 0) goto error; } @@ -790,7 +798,8 @@ known_service_types[i].s, /* ver_str, USN: */ lifetime); /* for devices, also send NOTIFY on the uuid */ - if(0==memcmp(known_service_types[i].s, + if(i > 0 && /* only known_service_types[0].s is shorter than "urn:schemas-upnp-org:device" */ + 0==memcmp(known_service_types[i].s, "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) { SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str, host, http_port, @@ -858,24 +867,12 @@ struct sockaddr_in sendername; #endif int source_ifindex = -1; -#ifdef IP_PKTINFO - char cmbuf[CMSG_SPACE(sizeof(struct in_pktinfo))]; - struct iovec iovec = { - .iov_base = bufr, - .iov_len = sizeof(bufr) - }; - struct msghdr mh = { - .msg_name = &sendername, - .msg_namelen = sizeof(sendername), - .msg_iov = &iovec, - .msg_iovlen = 1, - .msg_control = cmbuf, - .msg_controllen = sizeof(cmbuf) - }; - struct cmsghdr *cmptr; -#endif /* IP_PKTINFO */ +#if defined(IP_RECVIF) || defined(IP_PKTINFO) #ifdef IP_RECVIF char cmbuf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; +#else /* IP_PKTINFO */ + char cmbuf[CMSG_SPACE(sizeof(struct in_pktinfo))]; +#endif struct iovec iovec = { .iov_base = bufr, .iov_len = sizeof(bufr) @@ -889,9 +886,7 @@ .msg_controllen = sizeof(cmbuf) }; struct cmsghdr *cmptr; -#endif /* IP_RECVIF */ -#if defined(IP_RECVIF) || defined(IP_PKTINFO) n = recvmsg(s, &mh, 0); #else socklen_t len_r; @@ -916,7 +911,15 @@ for(cmptr = CMSG_FIRSTHDR(&mh); cmptr != NULL; cmptr = CMSG_NXTHDR(&mh, cmptr)) { syslog(LOG_DEBUG, "level=%d type=%d", cmptr->cmsg_level, cmptr->cmsg_type); -#ifdef IP_PKTINFO +#ifdef IP_RECVIF + if(cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) + { + struct sockaddr_dl *sdl; /* fields : len, family, index, type, nlen, alen, slen, data */ + sdl = (struct sockaddr_dl *)CMSG_DATA(cmptr); + syslog(LOG_DEBUG, "sdl_index = %d %s", sdl->sdl_index, link_ntoa(sdl)); + source_ifindex = sdl->sdl_index; + } +#elif defined(IP_PKTINFO) /* IP_RECVIF */ if(cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO) { struct in_pktinfo * pi; /* fields : ifindex, spec_dst, addr */ @@ -934,15 +937,6 @@ source_ifindex = pi6->ipi6_ifindex; } #endif /* defined(ENABLE_IPV6) && defined(IPV6_RECVPKTINFO) */ -#ifdef IP_RECVIF - if(cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) - { - struct sockaddr_dl *sdl; /* fields : len, family, index, type, nlen, alen, slen, data */ - sdl = (struct sockaddr_dl *)CMSG_DATA(cmptr); - syslog(LOG_DEBUG, "sdl_index = %d %s", sdl->sdl_index, link_ntoa(sdl)); - source_ifindex = sdl->sdl_index; - } -#endif /* IP_RECVIF */ } #endif /* defined(IP_RECVIF) || defined(IP_PKTINFO) */ #ifdef ENABLE_HTTPS @@ -998,11 +992,16 @@ /* get the string representation of the sender address */ sockaddr_to_string(sender, sender_str, sizeof(sender_str)); lan_addr = get_lan_for_peer(sender); - if(source_if >= 0) + if(source_if > 0) { if(lan_addr != NULL) { +#ifndef MULTIPLE_EXTERNAL_IP + if(lan_addr->index != (unsigned)source_if && lan_addr->index != 0 + && !(lan_addr->add_indexes & (1UL << (source_if - 1)))) +#else if(lan_addr->index != (unsigned)source_if && lan_addr->index != 0) +#endif { syslog(LOG_WARNING, "interface index not matching %u != %d", lan_addr->index, source_if); } @@ -1043,7 +1042,7 @@ { st = bufr+i+3; st_len = 0; - while((*st == ' ' || *st == '\t') && (st < bufr + n)) + while((st < bufr + n) && (*st == ' ' || *st == '\t')) st++; while((st + st_len < bufr + n) && (st[st_len]!='\r' && st[st_len]!='\n')) @@ -1079,7 +1078,7 @@ #endif /* defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE) */ #if defined(UPNP_STRICT) /* Fix UDA-1.2.10 Man header empty or invalid */ - else if((i < n - 4) && (strncasecmp(bufr+i, "man:", 3) == 0)) + else if((i < n - 4) && (strncasecmp(bufr+i, "man:", 4) == 0)) { const char * man; int man_len; @@ -1127,7 +1126,13 @@ syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s", sender_str, st_len, st); /* find in which sub network the client is */ +#ifdef ENABLE_IPV6 + if((sender->sa_family == AF_INET) || + (sender->sa_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sender)->sin6_addr))) +#else if(sender->sa_family == AF_INET) +#endif { if (lan_addr == NULL) { @@ -1139,7 +1144,7 @@ announced_host = lan_addr->str; } #ifdef ENABLE_IPV6 - else + else if(sender->sa_family == AF_INET6) { /* IPv6 address with brackets */ #ifdef UPNP_STRICT @@ -1179,6 +1184,13 @@ #endif } #endif + else + { + syslog(LOG_ERR, + "Unknown address family %d for client %s", + sender->sa_family, sender_str); + return; + } /* Responds to request with a device as ST header */ for(i = 0; known_service_types[i].s; i++) { @@ -1405,10 +1417,10 @@ int ret = 0; const char * dest_str; - memset(&sockname4, 0, sizeof(struct sockaddr_in)); - sockname4.sin_family = AF_INET; - sockname4.sin_port = htons(SSDP_PORT); - sockname4.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); + memset(&sockname4, 0, sizeof(struct sockaddr_in)); + sockname4.sin_family = AF_INET; + sockname4.sin_port = htons(SSDP_PORT); + sockname4.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); #ifdef ENABLE_IPV6 memset(&sockname6, 0, sizeof(struct sockaddr_in6)); sockname6.sin6_family = AF_INET6; @@ -1450,7 +1462,8 @@ known_service_types[i].s, ver_str, /* NT: */ known_service_types[i].uuid, "::", known_service_types[i].s); /* ver_str, USN: */ - if(0==memcmp(known_service_types[i].s, + if(i > 0 && /* only known_service_types[0].s is shorter than "urn:schemas-upnp-org:device" */ + 0==memcmp(known_service_types[i].s, "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) { ret += SendSSDPbyebye(sockets[j], @@ -1463,7 +1476,7 @@ known_service_types[i].uuid, "", /* NT: */ known_service_types[i].uuid, "", ""); /* ver_str, USN: */ } - } + } } return ret; } diff -Nru miniupnpd-2.1/miniupnpd.8 miniupnpd-2.2.1/miniupnpd.8 --- miniupnpd-2.1/miniupnpd.8 2018-02-22 13:19:38.000000000 +0000 +++ miniupnpd-2.2.1/miniupnpd.8 2019-10-05 20:09:29.000000000 +0000 @@ -3,7 +3,8 @@ miniupnpd \- UPnP Internet Gateway Device Daemon .SH SYNOPSIS .B miniupnpd -.RB [ "\-f \fIconfig_file" "] [" "\-i \fIext_ifname" "] [" "\-o \fIext_ip" ] +.RB [--version] +.RB [ "\-f \fIconfig_file" "] [" "\-i \fIext_ifname" "] [" "\-I \fIext_ifname6" "] [" "\-o \fIext_ip" ] .RB [ "\-a \fIlistening_ip" "] [" "\-p \fIport" "] [" \-d "] [" \-U "] [" \-S "] [" \-N ] .RB [ "\-u \fIuuid" "] [" "\-s \fIserial" "] [" "\-m \fImodel_number" ] .RB [ "\-t \fInotify_interval" "] [" "\-P \fIpid_filename" ] diff -Nru miniupnpd-2.1/miniupnpd.c miniupnpd-2.2.1/miniupnpd.c --- miniupnpd-2.1/miniupnpd.c 2018-05-08 21:34:44.000000000 +0000 +++ miniupnpd-2.2.1/miniupnpd.c 2020-10-30 21:38:06.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: miniupnpd.c,v 1.230 2018/05/08 21:28:28 nanard Exp $ */ +/* $Id: miniupnpd.c,v 1.248 2020/10/30 21:31:08 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -44,11 +44,20 @@ /* for BSD's sysctl */ #include #endif +#ifdef HAS_LIBCAP +#include +#endif +#ifdef HAS_LIBCAP_NG +#include +#endif /* unix sockets */ #ifdef USE_MINIUPNPDCTL #include #endif +#ifdef ENABLE_HTTPS +#include +#endif #ifdef TOMATO #include @@ -64,6 +73,7 @@ #include "minissdp.h" #include "upnpredirect.h" #include "upnppinhole.h" +#include "upnpstun.h" #include "miniupnpdtypes.h" #include "daemonize.h" #include "upnpevents.h" @@ -380,7 +390,7 @@ #if defined(SO_BINDTODEVICE) && !defined(MULTIPLE_EXTERNAL_IP) /* One and only one LAN interface */ if(lan_addrs.lh_first != NULL && lan_addrs.lh_first->list.le_next == NULL - && strlen(lan_addrs.lh_first->ifname) > 0) + && lan_addrs.lh_first->ifname[0] != '\0') { if(setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, lan_addrs.lh_first->ifname, @@ -908,7 +918,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str) { const char * p; - int n; + unsigned int n; char tmp[16]; memset(lan_addr, 0, sizeof(struct lan_addr_s)); @@ -954,7 +964,7 @@ while(*p && (*p=='.' || isdigit(*p))) p++; n = p - q; - if(n>15) + if(n >= sizeof(tmp)) goto parselan_error; memcpy(tmp, q, n); tmp[n] = '\0'; @@ -990,15 +1000,48 @@ if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) { /* error */ fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str); + return -1; + } + if(addr_is_reserved(&lan_addr->ext_ip_addr)) { + /* error */ + fprintf(stderr, "Error: option ext_ip address contains reserved / private address : %s\n", lan_addr->ext_ip_str); + return -1; } } } +#else + while(*p) { + /* skip spaces */ + while(*p && isspace(*p)) + p++; + if(*p) { + unsigned int index; + n = 0; + while(p[n] && !isspace(p[n]) && n < sizeof(tmp)) { + tmp[n] = p[n]; + n++; + } + if(n >= sizeof(tmp)) { + fprintf(stderr, "Cannot parse '%s'\n", p); + break; + } + tmp[n] = '\0'; + index = if_nametoindex(tmp); + if(index == 0) { + fprintf(stderr, "Cannot get index for network interface %s\n", + tmp); + } else { + lan_addr->add_indexes |= (1UL << (index - 1)); + } + p += n; + } + } #endif if(lan_addr->ifname[0] != '\0') { lan_addr->index = if_nametoindex(lan_addr->ifname); if(lan_addr->index == 0) - fprintf(stderr, "Cannot get index for network interface %s", + fprintf(stderr, "Cannot get index for network interface %s\n", lan_addr->ifname); } #ifdef ENABLE_IPV6 @@ -1022,6 +1065,45 @@ return -1; } +static char ext_addr_str[INET_ADDRSTRLEN]; + +int update_ext_ip_addr_from_stun(int init) +{ + struct in_addr if_addr, ext_addr; + int restrictive_nat; + char if_addr_str[INET_ADDRSTRLEN]; + + syslog(LOG_INFO, "STUN: Performing with host=%s and port=%u ...", ext_stun_host, (unsigned)ext_stun_port); + + if (getifaddr(ext_if_name, if_addr_str, INET_ADDRSTRLEN, &if_addr, NULL) < 0) { + syslog(LOG_ERR, "STUN: Cannot get IP address for ext interface %s", ext_if_name); + return 1; + } + if (perform_stun(ext_if_name, if_addr_str, ext_stun_host, ext_stun_port, &ext_addr, &restrictive_nat) != 0) { + syslog(LOG_ERR, "STUN: Performing STUN failed: %s", strerror(errno)); + return 1; + } + if (!inet_ntop(AF_INET, &ext_addr, ext_addr_str, sizeof(ext_addr_str))) { + syslog(LOG_ERR, "STUN: Function inet_ntop for IP address returned by STUN failed: %s", strerror(errno)); + return 1; + } + + if ((init || disable_port_forwarding) && !restrictive_nat) { + if (addr_is_reserved(&if_addr)) + syslog(LOG_INFO, "STUN: ext interface %s with IP address %s is now behind unrestricted NAT 1:1 with public IP address %s: Port forwarding is now enabled", ext_if_name, if_addr_str, ext_addr_str); + else + syslog(LOG_INFO, "STUN: ext interface %s has now public IP address %s: Port forwarding is now enabled", ext_if_name, if_addr_str); + } else if ((init || !disable_port_forwarding) && restrictive_nat) { + syslog(LOG_WARNING, "STUN: ext interface %s with IP address %s is now behind restrictive NAT with public IP address %s: Port forwarding is now impossible", ext_if_name, if_addr_str, ext_addr_str); + } else { + syslog(LOG_INFO, "STUN: ... done"); + } + + use_ext_ip_addr = ext_addr_str; + disable_port_forwarding = restrictive_nat; + return 0; +} + /* fill uuidvalue_wan and uuidvalue_wcd based on uuidvalue_igd */ void complete_uuidvalues(void) { @@ -1067,9 +1149,13 @@ init(int argc, char * * argv, struct runtime_vars * v) { int i; +#ifndef NO_BACKGROUND_NO_PIDFILE int pid; +#endif int debug_flag = 0; + int verbosity_level = 0; /* for determining setlogmask() */ int openlog_option; + struct in_addr addr; struct sigaction sa; /*const char * logfilename = 0;*/ const char * presurl = 0; @@ -1083,7 +1169,7 @@ /* only print usage if -h is used */ for(i=1; iport = atoi(ary_options[i].value); @@ -1206,15 +1311,15 @@ #endif /* ENABLE_MANUFACTURER_INFO_CONFIGURATION */ #ifdef USE_NETFILTER case UPNPFORWARDCHAIN: - miniupnpd_forward_chain = ary_options[i].value; + set_rdr_name(RDR_FORWARD_CHAIN_NAME, ary_options[i].value); break; case UPNPNATCHAIN: - miniupnpd_nat_chain = ary_options[i].value; + set_rdr_name(RDR_NAT_PREROUTING_CHAIN_NAME, ary_options[i].value); break; case UPNPNATPOSTCHAIN: - miniupnpd_nat_postrouting_chain = ary_options[i].value; + set_rdr_name(RDR_NAT_POSTROUTING_CHAIN_NAME, ary_options[i].value); break; -#endif /* USE_NETFILTER */ +#endif /* USE_NETFILTER */ case UPNPNOTIFY_INTERVAL: v->notify_interval = atoi(ary_options[i].value); break; @@ -1330,6 +1435,10 @@ return 1; } #endif /* ENABLE_PCP */ + if (GETFLAG(PERFORMSTUNMASK) && !ext_stun_host) { + fprintf(stderr, "You must specify ext_stun_host= when ext_perform_stun=yes\n"); + return 1; + } } #endif /* DISABLE_CONFIG_FILE */ @@ -1342,6 +1451,18 @@ } else switch(argv[i][1]) { + case 'v': + { + int j; + for (j = 1; argv[i][j] != '\0'; j++) + verbosity_level++; + } + break; +#ifdef ENABLE_IPV6 + case '4': + SETFLAG(IPV6DISABLEDMASK); + break; +#endif #ifdef IGD_V2 case '1': SETFLAG(FORCEIGDDESCV1MASK); @@ -1354,9 +1475,20 @@ fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'o': - if(i+1 < argc) - use_ext_ip_addr = argv[++i]; - else + if(i+1 < argc) { + i++; + if (0 == strncasecmp(argv[i], "STUN:", 5)) { + char *ptr; + SETFLAG(PERFORMSTUNMASK); + ext_stun_host = argv[i] + 5; + ptr = strchr(ext_stun_host, ':'); + if (ptr) { + ext_stun_port = atoi(ptr+1); + *ptr = 0; + } + } else + use_ext_ip_addr = argv[i]; + } else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 't': @@ -1429,6 +1561,14 @@ else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; +#ifdef ENABLE_IPV6 + case 'I': + if(i+1 < argc) + ext_if_name6 = argv[++i]; + else + fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); + break; +#endif #ifdef USE_PF case 'q': if(i+1 < argc) @@ -1479,12 +1619,14 @@ } break; #endif /* ENABLE_NFQUEUE */ +#ifndef NO_BACKGROUND_NO_PIDFILE case 'P': if(i+1 < argc) pidfilename = argv[++i]; else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; +#endif case 'd': debug_flag = 1; break; @@ -1600,12 +1742,34 @@ fprintf(stderr, "Unknown option: %s\n", argv[i]); } } - if(!ext_if_name || !lan_addrs.lh_first) - { + if(!ext_if_name || !lan_addrs.lh_first) { /* bad configuration */ goto print_usage; } + /* IPv6 ifname is defaulted to same as IPv4 */ +#ifdef ENABLE_IPV6 + if(!ext_if_name6) + ext_if_name6 = ext_if_name; +#endif + + if (use_ext_ip_addr && GETFLAG(PERFORMSTUNMASK)) { + fprintf(stderr, "Error: options ext_ip= and ext_perform_stun=yes cannot be specified together\n"); + return 1; + } + + if (use_ext_ip_addr) { + if (inet_pton(AF_INET, use_ext_ip_addr, &addr) != 1) { + fprintf(stderr, "Error: option ext_ip contains invalid address %s\n", use_ext_ip_addr); + return 1; + } + if (addr_is_reserved(&addr)) { + fprintf(stderr, "Error: option ext_ip contains reserved / private address %s, not public routable\n", use_ext_ip_addr); + return 1; + } + } + +#ifndef NO_BACKGROUND_NO_PIDFILE if(debug_flag) { pid = getpid(); @@ -1621,6 +1785,7 @@ pid = daemonize(); #endif } +#endif openlog_option = LOG_PID|LOG_CONS; if(debug_flag) @@ -1632,15 +1797,28 @@ if(!debug_flag) { - /* speed things up and ignore LOG_INFO and LOG_DEBUG */ - setlogmask(LOG_UPTO(LOG_NOTICE)); + switch (verbosity_level) + { + case 0: + /* speed things up and ignore LOG_INFO and LOG_DEBUG */ + setlogmask(LOG_UPTO(LOG_NOTICE)); + break; + case 1: + /* ignore LOG_DEBUG */ + setlogmask(LOG_UPTO(LOG_INFO)); + break; + case 2: + setlogmask(LOG_UPTO(LOG_DEBUG)); + } } +#ifndef NO_BACKGROUND_NO_PIDFILE if(checkforrunning(pidfilename) < 0) { syslog(LOG_ERR, "MiniUPnPd is already running. EXITING"); return 1; } +#endif #ifdef TOMATO syslog(LOG_NOTICE, "version " MINIUPNPD_VERSION " started"); @@ -1717,8 +1895,10 @@ #endif #endif +#ifndef NO_BACKGROUND_NO_PIDFILE if(writepidfile(pidfilename, pid) < 0) pidfilename = NULL; +#endif #ifdef ENABLE_LEASEFILE /*remove(lease_file);*/ @@ -1733,11 +1913,17 @@ return 0; print_usage: fprintf(stderr, "Usage:\n\t" + "%s --version\n\t" + "%s --help\n\t" "%s " #ifndef DISABLE_CONFIG_FILE "[-f config_file] " #endif - "[-i ext_ifname] [-o ext_ip]\n" + "[-i ext_ifname] " +#ifdef ENABLE_IPV6 + "[-I ext_ifname6] [-4] " +#endif + "[-o ext_ip]\n" #ifndef MULTIPLE_EXTERNAL_IP "\t\t[-a listening_ip]" #else @@ -1746,7 +1932,7 @@ #ifdef ENABLE_HTTPS " [-H https_port]" #endif - " [-p port] [-d]" + " [-p port] [-d] [-v]" #if defined(USE_PF) || defined(USE_IPF) " [-L]" #endif @@ -1757,7 +1943,10 @@ "\n" /*"[-l logfile] " not functionnal */ "\t\t[-u uuid] [-s serial] [-m model_number] \n" - "\t\t[-t notify_interval] [-P pid_filename] " + "\t\t[-t notify_interval] " +#ifndef NO_BACKGROUND_NO_PIDFILE + "[-P pid_filename] " +#endif #ifdef ENABLE_MANUFACTURER_INFO_CONFIGURATION "[-z fiendly_name]" #endif @@ -1775,9 +1964,15 @@ "\n" "\nNotes:\n\tThere can be one or several listening_ips.\n" "\tNotify interval is in seconds. Default is 30 seconds.\n" +#ifndef NO_BACKGROUND_NO_PIDFILE "\tDefault pid file is '%s'.\n" +#endif "\tDefault config file is '%s'.\n" "\tWith -d miniupnpd will run as a standard program.\n" + "\t-o argument is either an IPv4 address or \"STUN:host[:port]\".\n" +#ifdef ENABLE_IPV6 + "\t-4 disable IPv6\n" +#endif #if defined(USE_PF) || defined(USE_IPF) "\t-L sets packet log in pf and ipf on.\n" #endif @@ -1806,8 +2001,13 @@ #ifdef IGD_V2 "\t-1 force reporting IGDv1 in rootDesc *use with care*\n" #endif - "\t-h prints this help and quits.\n" - "", argv[0], pidfilename, DEFAULT_CONFIG); + "\t-v enables LOG_INFO messages, -vv LOG_DEBUG as well (default with -d)\n" + "\t-h / --help prints this help and quits.\n" + "", argv[0], argv[0], argv[0], +#ifndef NO_BACKGROUND_NO_PIDFILE + pidfilename, +#endif + DEFAULT_CONFIG); return 1; } @@ -1868,6 +2068,39 @@ unsigned int next_pinhole_ts; #endif + for(i = 0; i < argc; i++) { + if(strcmp(argv[i], "version") == 0 || strcmp(argv[i], "--version") == 0) { + puts("miniupnpd " MINIUPNPD_VERSION +#ifdef MINIUPNPD_GIT_REF + " " MINIUPNPD_GIT_REF +#endif + " " __DATE__ ); +#ifdef USE_PF + puts("using pf backend"); +#endif +#ifdef USE_IPF + puts("using ipf backend"); +#endif +#ifdef USE_IPFW + puts("using ipfw backend"); +#endif +#ifdef USE_IPTABLES + puts("using netfilter(iptables) backend"); +#endif +#ifdef USE_NFTABLES + puts("using netfilter(nftables) backend"); +#endif +#ifdef ENABLE_HTTPS +#ifdef OPENSSL_VERSION + puts(OpenSSL_version(OPENSSL_VERSION)); +#else + puts(SSLeay_version(SSLEAY_VERSION)); +#endif +#endif + return 0; + } + } + memset(&v, 0, sizeof(v)); if(init(argc, argv, &v) != 0) return 1; #ifdef ENABLE_HTTPS @@ -1922,6 +2155,32 @@ #endif GETFLAG(ENABLEUPNPMASK) ? "UPnP-IGD " : "", ext_if_name, upnp_bootid); +#ifdef ENABLE_IPV6 + if (ext_if_name6 != ext_if_name) { + syslog(LOG_INFO, "specific IPv6 ext if %s", ext_if_name6); + } +#endif + + if(GETFLAG(PERFORMSTUNMASK)) + { + if (update_ext_ip_addr_from_stun(1) != 0) { + syslog(LOG_ERR, "Performing STUN failed. EXITING"); + return 1; + } + } + else if (!use_ext_ip_addr) + { + char if_addr[INET_ADDRSTRLEN]; + struct in_addr addr; + if (getifaddr(ext_if_name, if_addr, INET_ADDRSTRLEN, &addr, NULL) < 0) { + syslog(LOG_WARNING, "Cannot get IP address for ext interface %s. Network is down", ext_if_name); + } else if (addr_is_reserved(&addr)) { + syslog(LOG_INFO, "Reserved / private IP address %s on ext interface %s: Port forwarding is impossible", if_addr, ext_if_name); + syslog(LOG_INFO, "You are probably behind NAT, enable option ext_perform_stun=yes to detect public IP address"); + syslog(LOG_INFO, "Or use ext_ip= / -o option to declare public IP address"); + disable_port_forwarding = 1; + } + } if(GETFLAG(ENABLEUPNPMASK)) { @@ -1929,7 +2188,7 @@ listen_port = (v.port > 0) ? v.port : 0; /* open socket for HTTP connections. Listen on the 1st LAN address */ #ifdef ENABLE_IPV6 - shttpl = OpenAndConfHTTPSocket(&listen_port, 1); + shttpl = OpenAndConfHTTPSocket(&listen_port, !GETFLAG(IPV6DISABLEDMASK)); #else /* ENABLE_IPV6 */ shttpl = OpenAndConfHTTPSocket(&listen_port); #endif /* ENABLE_IPV6 */ @@ -1955,11 +2214,11 @@ /* https */ listen_port = (v.https_port > 0) ? v.https_port : 0; #ifdef ENABLE_IPV6 - shttpsl = OpenAndConfHTTPSocket(&listen_port, 1); + shttpsl = OpenAndConfHTTPSocket(&listen_port, !GETFLAG(IPV6DISABLEDMASK)); #else /* ENABLE_IPV6 */ shttpsl = OpenAndConfHTTPSocket(&listen_port); #endif /* ENABLE_IPV6 */ - if(shttpl < 0) + if(shttpsl < 0) { syslog(LOG_ERR, "Failed to open socket for HTTPS. EXITING"); return 1; @@ -2093,6 +2352,69 @@ } #endif + /* drop privileges */ +#ifdef HAS_PLEDGE + /* mcast ? unix ? */ + if (pledge("stdio inet pf", NULL) < 0) { + syslog(LOG_ERR, "pledge(): %m"); + return 1; + } +#endif /* HAS_PLEDGE */ +#ifdef HAS_LIBCAP + { + cap_t caps = cap_get_proc(); + if (caps == NULL) { + syslog(LOG_ERR, "cap_get_proc(): %m"); + } else { + static const cap_value_t cap_list[3] = { CAP_NET_BROADCAST, CAP_NET_ADMIN, CAP_NET_RAW }; + char * txt_caps = cap_to_text(caps, NULL); + if (txt_caps == NULL) { + syslog(LOG_ERR, "cap_to_text(): %m"); + } else { + syslog(LOG_DEBUG, "capabilities %s", txt_caps); + if (cap_free(txt_caps) < 0) { + syslog(LOG_ERR, "cap_free(): %m"); + } + } + if (cap_clear(caps) < 0) { + syslog(LOG_ERR, "cap_clear(): %m"); + } + if (cap_set_flag(caps, CAP_PERMITTED, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_SET) < 0) { + syslog(LOG_ERR, "cap_set_flag(): %m"); + } + if (cap_set_flag(caps, CAP_EFFECTIVE, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_SET) < 0) { + syslog(LOG_ERR, "cap_set_flag(): %m"); + } + txt_caps = cap_to_text(caps, NULL); + if (txt_caps == NULL) { + syslog(LOG_ERR, "cap_to_text(): %m"); + } else { + syslog(LOG_DEBUG, "capabilities %s", txt_caps); + if (cap_free(txt_caps) < 0) { + syslog(LOG_ERR, "cap_free(): %m"); + } + } + if (cap_set_proc(caps) < 0) { + syslog(LOG_ERR, "cap_set_proc(): %m"); + } + if (cap_free(caps) < 0) { + syslog(LOG_ERR, "cap_free(): %m"); + } + } + } +#endif /* HAS_LIBCAP */ +#ifdef HAS_LIBCAP_NG + capng_setpid(getpid()); + capng_clear(CAPNG_SELECT_BOTH); + if (capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_BROADCAST, CAP_NET_ADMIN, CAP_NET_RAW, -1) < 0) { + syslog(LOG_ERR, "capng_updatev() failed"); + } else { + if (capng_apply(CAPNG_SELECT_BOTH) < 0) { + syslog(LOG_ERR, "capng_apply() failed"); + } + } +#endif /* HAS_LIBCAP_NG */ + /* main loop */ while(!quitting) { @@ -2114,6 +2436,23 @@ if(should_send_public_address_change_notif) { syslog(LOG_INFO, "should send external iface address change notification(s)"); + if(GETFLAG(PERFORMSTUNMASK)) + update_ext_ip_addr_from_stun(0); + if (!use_ext_ip_addr) + { + char if_addr[INET_ADDRSTRLEN]; + struct in_addr addr; + if (getifaddr(ext_if_name, if_addr, INET_ADDRSTRLEN, &addr, NULL) == 0) { + int reserved = addr_is_reserved(&addr); + if (disable_port_forwarding && !reserved) { + syslog(LOG_INFO, "Public IP address %s on ext interface %s: Port forwarding is enabled", if_addr, ext_if_name); + } else if (!disable_port_forwarding && reserved) { + syslog(LOG_INFO, "Reserved / private IP address %s on ext interface %s: Port forwarding is impossible", if_addr, ext_if_name); + syslog(LOG_INFO, "You are probably behind NAT, enable option ext_perform_stun=yes to detect public IP address"); + } + disable_port_forwarding = reserved; + } + } #ifdef ENABLE_NATPMP if(GETFLAG(ENABLENATPMPMASK)) SendNATPMPPublicAddressChangeNotification(snatpmp, addr_count); @@ -2723,10 +3062,12 @@ } /* remove pidfile */ +#ifndef NO_BACKGROUND_NO_PIDFILE if(pidfilename && (unlink(pidfilename) < 0)) { syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename); } +#endif /* delete lists */ while(lan_addrs.lh_first != NULL) @@ -2743,11 +3084,14 @@ free(snatpmp); #endif free(snotify); - closelog(); + + shutdown_redirect(); + #ifndef DISABLE_CONFIG_FILE + /* in some case shutdown_redirect() may need the option values */ freeoptions(); #endif - + closelog(); return 0; } diff -Nru miniupnpd-2.1/miniupnpd.conf miniupnpd-2.2.1/miniupnpd.conf --- miniupnpd-2.1/miniupnpd.conf 2018-02-22 13:19:38.000000000 +0000 +++ miniupnpd-2.2.1/miniupnpd.conf 2020-05-10 18:11:14.000000000 +0000 @@ -1,9 +1,33 @@ # WAN network interface #ext_ifname=eth1 #ext_ifname=xl1 +# if the WAN network interface for IPv6 is different than for IPv4, +# set ext_ifname6 +#ext_ifname6=eth2 # If the WAN interface has several IP addresses, you -# can specify the one to use below +# can specify the one to use below. +# Setting ext_ip is also useful in double NAT setup, you can declare here +# the public IP address. #ext_ip= +# WAN interface must have public IP address. Otherwise it is behind NAT +# and port forwarding is impossible. In some cases WAN interface can be +# behind unrestricted NAT 1:1 when all incoming traffic is NAT-ed and +# routed to WAN interfaces without any filtering. In this cases miniupnpd +# needs to know public IP address and it can be learnt by asking external +# server via STUN protocol. Following option enable retrieving external +# public IP address from STUN server and detection of NAT type. You need +# to specify also external STUN server in stun_host option below. +# This option is disabled by default. +#ext_perform_stun=yes +# Specify STUN server, either hostname or IP address +# Some public STUN servers: +# stun.stunprotocol.org +# stun.sipgate.net +# stun.xten.com +# stun.l.google.com (on non standard port 19302) +#ext_stun_host=stun.stunprotocol.org +# Specify STUN UDP port, by default it is standard port 3478. +#ext_stun_port=3478 # LAN network interfaces IPs / networks # There can be multiple listening IPs for SSDP traffic, in that case @@ -14,6 +38,9 @@ # When MULTIPLE_EXTERNAL_IP is enabled, the external IP # address associated with the subnet follows. For example: # listening_ip=192.168.0.1/24 88.22.44.13 +# When MULTIPLE_EXTERNAL_IP is disabled, you can list associated network +# interfaces (for bridges) +# listening_ip=bridge0 em0 wlan0 #listening_ip=192.168.0.1/24 #listening_ip=10.5.0.0/16 #listening_ip=eth0 @@ -31,6 +58,9 @@ # default is /var/run/minissdpd.sock #minissdpdsocket=/var/run/minissdpd.sock +# Disable IPv6 (default is no : IPv6 enabled if enabled at build time) +#ipv6_disable=yes + # Enable NAT-PMP support (default is no) #enable_natpmp=yes diff -Nru miniupnpd-2.1/miniupnpdtypes.h miniupnpd-2.2.1/miniupnpdtypes.h --- miniupnpd-2.1/miniupnpdtypes.h 2017-05-24 22:29:00.000000000 +0000 +++ miniupnpd-2.2.1/miniupnpdtypes.h 2020-05-10 18:11:16.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: miniupnpdtypes.h,v 1.6 2017/05/24 22:28:40 nanard Exp $ */ +/* $Id: miniupnpdtypes.h,v 1.7 2020/05/10 17:54:35 nanard Exp $ */ /* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #ifndef MINIUPNPDTYPES_H_INCLUDED @@ -22,6 +22,8 @@ #ifdef MULTIPLE_EXTERNAL_IP char ext_ip_str[16]; struct in_addr ext_ip_addr; +#else + unsigned long add_indexes; /* mask of indexes of associated interfaces */ #endif LIST_ENTRY(lan_addr_s) list; }; diff -Nru miniupnpd-2.1/minixml.h miniupnpd-2.2.1/minixml.h --- miniupnpd-2.1/minixml.h 2012-10-04 22:34:08.000000000 +0000 +++ miniupnpd-2.2.1/minixml.h 2019-02-10 12:30:19.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ +/* $Id: minixml.h,v 1.8 2019/02/10 12:29:25 nanard Exp $ */ /* minimal xml parser * * Project : miniupnp @@ -10,7 +10,7 @@ * */ #ifndef MINIXML_H_INCLUDED #define MINIXML_H_INCLUDED -#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) +#define IS_WHITE_SPACE(c) ((c)==' ' || (c)=='\t' || (c)=='\r' || (c)=='\n') /* if a callback function pointer is set to NULL, * the function is not called */ diff -Nru miniupnpd-2.1/natpmp.c miniupnpd-2.2.1/natpmp.c --- miniupnpd-2.1/natpmp.c 2018-03-13 10:27:01.000000000 +0000 +++ miniupnpd-2.2.1/natpmp.c 2019-09-24 11:51:14.000000000 +0000 @@ -1,6 +1,6 @@ -/* $Id: natpmp.c,v 1.55 2018/03/12 22:41:54 nanard Exp $ */ +/* $Id: natpmp.c,v 1.57 2019/09/24 11:48:01 nanard Exp $ */ /* MiniUPnP project - * (c) 2007-2017 Thomas Bernard + * (c) 2007-2019 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -94,6 +94,7 @@ static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr) { #ifndef MULTIPLE_EXTERNAL_IP + struct in_addr addr; char tmp[16]; UNUSED(senderaddr); @@ -103,10 +104,13 @@ if(!ext_if_name || ext_if_name[0]=='\0') { resp[3] = 3; /* Network Failure (e.g. NAT box itself * has not obtained a DHCP lease) */ - } else if(getifaddr(ext_if_name, tmp, INET_ADDRSTRLEN, NULL, NULL) < 0) { + } else if(getifaddr(ext_if_name, tmp, INET_ADDRSTRLEN, &addr, NULL) < 0) { syslog(LOG_ERR, "Failed to get IP for interface %s", ext_if_name); resp[3] = 3; /* Network Failure (e.g. NAT box itself * has not obtained a DHCP lease) */ + } else if (addr_is_reserved(&addr)) { + resp[3] = 3; /* Network Failure, box has not obtained + public IP address */ } else { inet_pton(AF_INET, tmp, resp+8); /* ok */ } diff -Nru miniupnpd-2.1/netfilter/ip6tables_init.sh miniupnpd-2.2.1/netfilter/ip6tables_init.sh --- miniupnpd-2.1/netfilter/ip6tables_init.sh 2018-04-06 10:53:32.000000000 +0000 +++ miniupnpd-2.2.1/netfilter/ip6tables_init.sh 2019-04-03 16:28:01.000000000 +0000 @@ -1,21 +1,25 @@ #! /bin/sh -# $Id: ip6tables_init.sh,v 1.2 2018/04/06 09:21:11 nanard Exp $ +# $Id: ip6tables_init.sh,v 1.3 2019/04/03 16:25:55 nanard Exp $ # Improved Miniupnpd iptables init script. # Checks for state of filter before doing anything.. IPV6=1 EXT=1 . $(dirname "$0")/miniupnpd_functions.sh +# -I inserts the rule at the head of the chain, +# -A appends the rule at the end of the chain +ADDCMD=-I +#ADDCMD=-A if [ "$FDIRTY" = "${CHAIN}Chain" ]; then echo "Filter table dirty; Cleaning..." elif [ "$FDIRTY" = "Chain" ]; then echo "Dirty filter chain but no reference..? Fixing..." - $IPTABLES -t filter -A FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN + $IPTABLES -t filter $ADDCMD FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN else echo "Filter table clean..initalizing.." $IPTABLES -t filter -N $CHAIN - $IPTABLES -t filter -A FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN + $IPTABLES -t filter $ADDCMD FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN fi if [ "$CLEAN" = "yes" ]; then $IPTABLES -t filter -F $CHAIN diff -Nru miniupnpd-2.1/netfilter/iptables_init.sh miniupnpd-2.2.1/netfilter/iptables_init.sh --- miniupnpd-2.1/netfilter/iptables_init.sh 2018-04-06 10:53:32.000000000 +0000 +++ miniupnpd-2.2.1/netfilter/iptables_init.sh 2019-04-03 16:28:00.000000000 +0000 @@ -1,37 +1,73 @@ #! /bin/sh -# $Id: iptables_init.sh,v 1.11 2018/04/06 10:17:09 nanard Exp $ +# $Id: iptables_init.sh,v 1.12 2019/04/03 16:25:55 nanard Exp $ # Improved Miniupnpd iptables init script. # Checks for state of filter before doing anything.. EXT=1 . $(dirname "$0")/miniupnpd_functions.sh +# -I inserts the rule at the head of the chain, +# -A appends the rule at the end of the chain +ADDCMD=-I +#ADDCMD=-A +# MINIUPNPD chain for nat if [ "$NDIRTY" = "${CHAIN}Chain" ]; then echo "Nat table dirty; Cleaning..." elif [ "$NDIRTY" = "Chain" ]; then echo "Dirty NAT chain but no reference..? Fixing..." - #$IPTABLES -t nat -A PREROUTING -d $EXTIP -i $EXTIF -j $CHAIN - $IPTABLES -t nat -A PREROUTING -i $EXTIF -j $CHAIN + #$IPTABLES -t nat $ADDCMD PREROUTING -d $EXTIP -i $EXTIF -j $CHAIN + $IPTABLES -t nat $ADDCMD PREROUTING -i $EXTIF -j $CHAIN else echo "NAT table clean..initalizing.." $IPTABLES -t nat -N $CHAIN - #$IPTABLES -t nat -A PREROUTING -d $EXTIP -i $EXTIF -j $CHAIN - $IPTABLES -t nat -A PREROUTING -i $EXTIF -j $CHAIN + #$IPTABLES -t nat $ADDCMD PREROUTING -d $EXTIP -i $EXTIF -j $CHAIN + $IPTABLES -t nat $ADDCMD PREROUTING -i $EXTIF -j $CHAIN fi if [ "$CLEAN" = "yes" ]; then $IPTABLES -t nat -F $CHAIN fi +# MINIUPNPD chain for mangle +if [ "$MDIRTY" = "${CHAIN}Chain" ]; then + echo "Mangle table dirty; Cleaning..." +elif [ "$MDIRTY" = "Chain" ]; then + echo "Dirty Mangle chain but no reference..? Fixing..." + $IPTABLES -t mangle $ADDCMD PREROUTING -i $EXTIF -j $CHAIN +else + echo "Mangle table clean..initializing..." + $IPTABLES -t mangle -N $CHAIN + $IPTABLES -t mangle $ADDCMD PREROUTING -i $EXTIF -j $CHAIN +fi +if [ "$CLEAN" = "yes" ]; then + $IPTABLES -t mangle -F $CHAIN +fi + +# MINIUPNPD chain for filter if [ "$FDIRTY" = "${CHAIN}Chain" ]; then echo "Filter table dirty; Cleaning..." elif [ "$FDIRTY" = "Chain" ]; then echo "Dirty filter chain but no reference..? Fixing..." - $IPTABLES -t filter -A FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN + $IPTABLES -t filter $ADDCMD FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN else echo "Filter table clean..initalizing.." $IPTABLES -t filter -N MINIUPNPD - $IPTABLES -t filter -A FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN + $IPTABLES -t filter $ADDCMD FORWARD -i $EXTIF ! -o $EXTIF -j $CHAIN fi if [ "$CLEAN" = "yes" ]; then $IPTABLES -t filter -F $CHAIN fi + +# MINIUPNPD-POSTROUTING chain (for nat) +if [ "$NPDIRTY" = "${CHAIN}-POSTROUTINGChain" ]; then + echo "Postrouting Nat table dirty; Cleaning..." +elif [ "$NPDIRTY" = "Chain" ]; then + echo "Dirty POSTROUTING NAT chain but no reference..? Fixing..." + $IPTABLES -t nat $ADDCMD POSTROUTING -o $EXTIF -j $CHAIN-POSTROUTING +else + echo "POSTROUTING NAT table clean..initalizing.." + $IPTABLES -t nat -N $CHAIN-POSTROUTING + $IPTABLES -t nat $ADDCMD POSTROUTING -o $EXTIF -j $CHAIN-POSTROUTING +fi +if [ "$CLEAN" = "yes" ]; then + $IPTABLES -t nat -F $CHAIN-POSTROUTING +fi diff -Nru miniupnpd-2.1/netfilter/iptcrdr.c miniupnpd-2.2.1/netfilter/iptcrdr.c --- miniupnpd-2.1/netfilter/iptcrdr.c 2016-04-19 21:01:06.000000000 +0000 +++ miniupnpd-2.2.1/netfilter/iptcrdr.c 2020-11-27 18:25:04.000000000 +0000 @@ -1,14 +1,15 @@ -/* $Id: iptcrdr.c,v 1.59 2016/03/08 09:23:52 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2016 Thomas Bernard +/* $Id: iptcrdr.c,v 1.67 2020/11/11 12:09:05 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #include #include -#include +#include #include #include #include @@ -19,7 +20,9 @@ #include -#if IPTABLES_143 +#include "config.h" + +#ifdef IPTABLES_143 /* IPTABLES API version >= 1.4.3 */ /* added in order to compile on gentoo : @@ -58,10 +61,53 @@ #endif #include "../macros.h" -#include "../config.h" #include "iptcrdr.h" #include "../upnpglobalvars.h" +/* chain names to use in the nat and filter tables. */ + +/* iptables -t nat -N MINIUPNPD + * iptables -t nat -A PREROUTING -i -j MINIUPNPD */ +static const char * miniupnpd_nat_chain = "MINIUPNPD"; + +/* iptables -t nat -N MINIUPNPD-POSTROUTING + * iptables -t nat -A POSTROUTING -o -j MINIUPNPD-POSTROUTING */ +static const char * miniupnpd_nat_postrouting_chain = "MINIUPNPD-POSTROUTING"; + +/* iptables -t filter -N MINIUPNPD + * iptables -t filter -A FORWARD -i ! -o -j MINIUPNPD */ +static const char * miniupnpd_forward_chain = "MINIUPNPD"; + +/** + * used by the core to override default chain names if specified in config file + * @param param which string to set + * @param string the new name to use. Do not dispose after setting (i.e. use strdup if not static). + * @return 0 if successful + */ +int +set_rdr_name(rdr_name_type param, const char *string) +{ + if (string == NULL || strlen(string) > 30 || string[0] == '\0') { + syslog(LOG_ERR, "%s(): invalid string argument '%s'", "set_rdr_name", string); + return -1; + } + switch (param) { + case RDR_NAT_PREROUTING_CHAIN_NAME: + miniupnpd_nat_chain = string; + break; + case RDR_NAT_POSTROUTING_CHAIN_NAME: + miniupnpd_nat_postrouting_chain = string; + break; + case RDR_FORWARD_CHAIN_NAME: + miniupnpd_forward_chain = string; + break; + default: + syslog(LOG_ERR, "%s(): tried to set invalid string parameter: %d", "set_rdr_name", param); + return -2; + } + return 0; +} + /* local functions declarations */ static int addnatrule(int proto, unsigned short eport, @@ -223,17 +269,13 @@ if(r >= 0) { add_redirect_desc(eport, proto, desc, timestamp); #ifdef ENABLE_PORT_TRIGGERING - /* http://www.netfilter.org/documentation/HOWTO/NAT-HOWTO-6.html#ss6.3 - * The default behavior is to alter the connection as little - * as possible, within the constraints of the rule given by - * the user. - * This means we won't remap ports unless we have to. */ - if(iport != eport) { - /* TODO : check if this should be done only with UDP */ - r = addmasqueraderule(proto, eport, iaddr, iport, rhost/*, ifname*/); - if(r < 0) { - syslog(LOG_NOTICE, "add_redirect_rule2(): addmasqueraderule returned %d", r); - } + /* we now always setup SNAT to support bidirectional mapping + * we cannot expect that iport == eport on all the firewall. + */ + /* TODO : check if this should be done only with UDP */ + r = addmasqueraderule(proto, eport, iaddr, iport, rhost/*, ifname*/); + if(r < 0) { + syslog(LOG_NOTICE, "add_redirect_rule2(): addmasqueraderule returned %d", r); } #endif /* ENABLE_PORT_TRIGGERING */ } @@ -621,6 +663,69 @@ return r; } +/* delete_filter_rule() + */ +int +delete_filter_rule(const char * ifname, unsigned short port, int proto) +{ + int r = -1; + unsigned index = 0; + unsigned i = 0; + IPTC_HANDLE h; + const struct ipt_entry * e; + const struct ipt_entry_match *match; + UNUSED(ifname); + + if((h = iptc_init("filter"))) + { + i = 0; + /* we must find the right index for the filter rule */ +#ifdef IPTABLES_143 + for(e = iptc_first_rule(miniupnpd_forward_chain, h); + e; + e = iptc_next_rule(e, h), i++) +#else + for(e = iptc_first_rule(miniupnpd_forward_chain, &h); + e; + e = iptc_next_rule(e, &h), i++) +#endif + { + if(proto==e->ip.proto) + { + match = (const struct ipt_entry_match *)&e->elems; + /*syslog(LOG_DEBUG, "filter rule #%u: %s %s", + i, match->u.user.name, inet_ntoa(e->ip.dst));*/ + if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) + { + const struct ipt_tcp * info; + info = (const struct ipt_tcp *)match->data; + if(port != info->dpts[0]) + continue; + } + else + { + const struct ipt_udp * info; + info = (const struct ipt_udp *)match->data; + if(port != info->dpts[0]) + continue; + } + index = i; + /*syslog(LOG_INFO, "Trying to delete filter rule at index %u", index);*/ + r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule"); + h = NULL; + break; + } + } + } + if(h) +#ifdef IPTABLES_143 + iptc_free(h); +#else + iptc_free(&h); +#endif + return r; +} + /* delete_redirect_and_filter_rules() */ int @@ -794,7 +899,7 @@ { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; - iport = info->dpts[0]; + iport = info->spts[0]; } index = i; @@ -1116,9 +1221,13 @@ } else { match = get_udp_match(eport, 0); } - e->nfcache = NFC_IP_DST_PT; +#ifdef NFC_UNKNOWN + e->nfcache = NFC_UNKNOWN; +#endif target = get_dnat_target(iaddr, iport); - e->nfcache |= NFC_UNKNOWN; +#ifdef NFC_IP_DST_PT + e->nfcache |= NFC_IP_DST_PT; +#endif tmp = realloc(e, sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size); @@ -1186,9 +1295,13 @@ } else { match = get_udp_match(0, iport); } - e->nfcache = NFC_IP_DST_PT; +#ifdef NFC_UNKNOWN + e->nfcache = NFC_UNKNOWN; +#endif target = get_masquerade_target(eport); - e->nfcache |= NFC_UNKNOWN; +#ifdef NFC_IP_DST_PT + e->nfcache |= NFC_IP_DST_PT; +#endif tmp = realloc(e, sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size); @@ -1266,9 +1379,16 @@ } else { match = get_udp_match(rport, iport); } - e->nfcache = NFC_IP_DST_PT | NFC_IP_SRC_PT; +#ifdef NFC_UNKNOWN + e->nfcache = NFC_UNKNOWN; +#endif target = get_snat_target(eaddr, eport); - e->nfcache |= NFC_UNKNOWN; +#ifdef NFC_IP_DST_PT + e->nfcache |= NFC_IP_DST_PT; +#endif +#ifdef NFC_IP_SRC_PT + e->nfcache |= NFC_IP_SRC_PT; +#endif tmp = realloc(e, sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size); @@ -1337,9 +1457,16 @@ } else { match = get_udp_match(rport, iport); } - e->nfcache = NFC_IP_DST_PT | NFC_IP_SRC_PT; +#ifdef NFC_UNKNOWN + e->nfcache = NFC_UNKNOWN; +#endif target = get_dscp_target(dscp); - e->nfcache |= NFC_UNKNOWN; +#ifdef NFC_IP_DST_PT + e->nfcache |= NFC_IP_DST_PT; +#endif +#ifdef NFC_IP_SRC_PT + e->nfcache |= NFC_IP_SRC_PT; +#endif tmp = realloc(e, sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size); @@ -1420,11 +1547,15 @@ } else { match = get_udp_match(iport,0); } - e->nfcache = NFC_IP_DST_PT; e->ip.dst.s_addr = inet_addr(iaddr); e->ip.dmsk.s_addr = INADDR_NONE; +#ifdef NFC_UNKNOWN + e->nfcache = NFC_UNKNOWN; +#endif target = get_accept_target(); - e->nfcache |= NFC_UNKNOWN; +#ifdef NFC_IP_DST_PT + e->nfcache |= NFC_IP_DST_PT; +#endif tmp = realloc(e, sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size); @@ -1527,6 +1658,9 @@ { unsigned short * tmp; /* need to increase the capacity of the array */ + capacity += 128; + if (capacity <= *number) + capacity = *number + 1; tmp = realloc(array, sizeof(unsigned short)*capacity); if(!tmp) { @@ -1620,7 +1754,7 @@ const struct ipt_entry * e; struct ipt_entry * new_e = NULL; size_t entry_len; - const struct ipt_entry_target * target; + struct ipt_entry_target * target; struct ip_nat_multi_range * mr; const struct ipt_entry_match *match; uint32_t iaddr = 0; @@ -1763,6 +1897,10 @@ r = -1; } else { memcpy(new_e, e, entry_len); + target = (void *)new_e + new_e->target_offset; + if (target->u.user.name[0] == '\0' && iptc_get_target(e, h)) { + strncpy(target->u.user.name, iptc_get_target(e, h), sizeof(target->u.user.name)); + } } break; } @@ -1794,6 +1932,105 @@ if(r < 0) return r; +#ifdef ENABLE_PORT_TRIGGERING + /* update snat rule */ + h = iptc_init("nat"); + if(!h) + { + syslog(LOG_ERR, "%s() : iptc_init() failed : %s", + "update_portmapping", iptc_strerror(errno)); + goto skip; + } + i = 0; found = 0; + if(!iptc_is_chain(miniupnpd_nat_postrouting_chain, h)) + { + syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_postrouting_chain); + } + else + { + /* we must find the right index for the filter rule */ +#ifdef IPTABLES_143 + for(e = iptc_first_rule(miniupnpd_nat_postrouting_chain, h); + e; + e = iptc_next_rule(e, h), i++) +#else + for(e = iptc_first_rule(miniupnpd_nat_postrouting_chain, &h); + e; + e = iptc_next_rule(e, &h), i++) +#endif + { + if(proto==e->ip.proto) + { + target = (void *)e + e->target_offset; + mr = (struct ip_nat_multi_range *)&target->data[0]; + syslog(LOG_DEBUG, "postrouting rule #%u: %s %s %hu", + i, target->u.user.name, inet_ntoa(e->ip.src), ntohs(mr->range[0].min.all)); + /* target->u.user.name SNAT / MASQUERADE */ + if (eport != ntohs(mr->range[0].min.all)) { + continue; + } + match = (const struct ipt_entry_match *)&e->elems; + if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) + { + const struct ipt_tcp * info; + info = (const struct ipt_tcp *)match->data; + if(old_iport != info->spts[0]) + continue; + } + else + { + const struct ipt_udp * info; + info = (const struct ipt_udp *)match->data; + if(old_iport != info->spts[0]) + continue; + } + if (iaddr != e->ip.src.s_addr) { + continue; + } + index = i; + found = 1; + entry_len = sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size; + new_e = malloc(entry_len); + if(new_e == NULL) { + syslog(LOG_ERR, "%s: malloc(%u) error", + "update_portmapping", (unsigned)entry_len); + r = -1; + } else { + memcpy(new_e, e, entry_len); + } + break; + } + } + } +#ifdef IPTABLES_143 + iptc_free(h); +#else + iptc_free(&h); +#endif + if(!found || r < 0) + goto skip; + + syslog(LOG_INFO, "Trying to update snat rule at index %u", index); + match = (struct ipt_entry_match *)&new_e->elems; + if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) + { + struct ipt_tcp * info; + info = (struct ipt_tcp *)match->data; + info->spts[0] = info->spts[1] = iport; + } + else + { + struct ipt_udp * info; + info = (struct ipt_udp *)match->data; + info->spts[0] = info->spts[1] = iport; + } + r = update_rule_and_commit("nat", miniupnpd_nat_postrouting_chain, index, new_e); + free(new_e); new_e = NULL; + if(r < 0) + syslog(LOG_INFO, "Trying to update snat rule at index %u fail!", index); + +skip: +#endif /* ENABLE_PORT_TRIGGERING */ return update_portmapping_desc_timestamp(ifname, eport, proto, desc, timestamp); } diff -Nru miniupnpd-2.1/netfilter/iptcrdr.h miniupnpd-2.2.1/netfilter/iptcrdr.h --- miniupnpd-2.1/netfilter/iptcrdr.h 2014-03-28 12:03:37.000000000 +0000 +++ miniupnpd-2.2.1/netfilter/iptcrdr.h 2018-07-06 12:03:21.000000000 +0000 @@ -1,7 +1,8 @@ -/* $Id: iptcrdr.h,v 1.21 2014/03/28 12:03:37 nanard Exp $ */ -/* MiniUPnP project +/* $Id: iptcrdr.h,v 1.22 2018/07/06 12:00:10 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2011 Thomas Bernard + * (c) 2006-2018 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -33,6 +34,9 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto); int +delete_filter_rule(const char * ifname, unsigned short port, int proto); + +int add_peer_dscp_rule2(const char * ifname, const char * rhost, unsigned short rport, unsigned char dscp, diff -Nru miniupnpd-2.1/netfilter/iptpinhole.c miniupnpd-2.2.1/netfilter/iptpinhole.c --- miniupnpd-2.1/netfilter/iptpinhole.c 2018-04-22 19:44:43.000000000 +0000 +++ miniupnpd-2.2.1/netfilter/iptpinhole.c 2020-09-28 21:55:15.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: iptpinhole.c,v 1.19 2018/04/22 19:36:58 nanard Exp $ */ +/* $Id: iptpinhole.c,v 1.22 2020/09/28 21:35:04 nanard Exp $ */ /* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2012-2018 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2012-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -12,7 +12,7 @@ #include #include -#include "../config.h" +#include "config.h" #include "../macros.h" #include "iptpinhole.h" #include "../upnpglobalvars.h" @@ -28,6 +28,8 @@ static int next_uid = 1; +static const char * miniupnpd_v6_filter_chain = "MINIUPNPD"; + static LIST_HEAD(pinhole_list_t, pinhole_t) pinhole_list; static struct pinhole_t * @@ -186,6 +188,7 @@ syslog(LOG_ERR, "ip6tc_commit() error : %s", ip6tc_strerror(errno)); goto error; } + ip6tc_free(h); return 0; /* ok */ error: ip6tc_free(h); diff -Nru miniupnpd-2.1/netfilter/Makefile miniupnpd-2.2.1/netfilter/Makefile --- miniupnpd-2.1/netfilter/Makefile 2016-02-09 09:39:02.000000000 +0000 +++ miniupnpd-2.2.1/netfilter/Makefile 2020-03-29 09:08:55.000000000 +0000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.8 2016/02/09 09:36:30 nanard Exp $ +# $Id: Makefile,v 1.9 2020/03/22 22:47:19 nanard Exp $ CFLAGS?=-Wall -g -D_GNU_SOURCE -DDEBUG -Wstrict-prototypes -Wdeclaration-after-statement CC = gcc @@ -8,7 +8,7 @@ ARCH := $(shell uname -m | grep -q "x86_64" && echo 64) ifdef IPTABLESPATH CFLAGS := $(CFLAGS) -I$(IPTABLESPATH)/include/ -LDFLAGS := $(LDFLAFGS) -L$(IPTABLESPATH)/libiptc/ +LDFLAGS := $(LDFLAGS) -L$(IPTABLESPATH)/libiptc/ # get iptables version and set IPTABLES_143 macro if needed IPTABLESVERSION := $(shell grep "\#define VERSION" $(IPTABLESPATH)/config.h | tr -d \" |cut -d" " -f3 ) IPTABLESVERSION1 := $(shell echo $(IPTABLESVERSION) | cut -d. -f1 ) diff -Nru miniupnpd-2.1/netfilter/miniupnpd_functions.sh miniupnpd-2.2.1/netfilter/miniupnpd_functions.sh --- miniupnpd-2.1/netfilter/miniupnpd_functions.sh 2018-04-06 09:21:11.000000000 +0000 +++ miniupnpd-2.2.1/netfilter/miniupnpd_functions.sh 2019-04-03 16:28:02.000000000 +0000 @@ -1,5 +1,5 @@ #! /bin/sh -# $Id: miniupnpd_functions.sh,v 1.1 2018/04/06 09:21:11 nanard Exp $ +# $Id: miniupnpd_functions.sh,v 1.3 2019/04/03 16:25:55 nanard Exp $ IP=$(which ip) || { echo "Can't find ip" >&2 @@ -18,6 +18,7 @@ } IP="$IP -6" fi +IPTABLES="$IPTABLES -w" CHAIN=MINIUPNPD CLEAN= @@ -56,9 +57,9 @@ #fi fi -FDIRTY=$(LC_ALL=C $IPTABLES -t filter -L -n | awk "/$CHAIN/ {printf \$1}") +FDIRTY=$(LC_ALL=C $IPTABLES -t filter -L -n | awk "/$CHAIN / {printf \$1}") if [ -z "$IPV6" ]; then - NDIRTY=$(LC_ALL=C $IPTABLES -t nat -L -n | awk "/$CHAIN/ {printf \$1}") - MDIRTY=$(LC_ALL=C $IPTABLES -t mangle -L -n | awk "/$CHAIN/ {printf \$1}") - NPDIRTY=$(LC_ALL=C $IPTABLES -t nat -L -n | awk "/$CHAIN-POSTROUTING/ {printf \$1}") + NDIRTY=$(LC_ALL=C $IPTABLES -t nat -L -n | awk "/$CHAIN / {printf \$1}") + MDIRTY=$(LC_ALL=C $IPTABLES -t mangle -L -n | awk "/$CHAIN / {printf \$1}") + NPDIRTY=$(LC_ALL=C $IPTABLES -t nat -L -n | awk "/$CHAIN-POSTROUTING / {printf \$1}") fi diff -Nru miniupnpd-2.1/netfilter_nft/Makefile miniupnpd-2.2.1/netfilter_nft/Makefile --- miniupnpd-2.1/netfilter_nft/Makefile 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/Makefile 2020-10-30 21:23:38.000000000 +0000 @@ -1,19 +1,28 @@ -CFLAGS?=-Wall -g -D_GNU_SOURCE -DDEBUG -Wstrict-prototypes -Wdeclaration-after-statement +CFLAGS?=-Wall -g -Wstrict-prototypes -Wdeclaration-after-statement +CPPFLAGS += -I. +CPPFLAGS += -D_GNU_SOURCE -DDEBUG +CPPFLAGS += -DUSE_NETFILTER -DUSE_NFTABLES +CPPFLAGS += -DENABLE_UPNPPINHOLE +CPPFLAGS += -DUSE_NFCT CC = gcc LIBS = -lnftnl -lmnl ARCH := $(shell uname -m | grep -q "x86_64" && echo 64) -all: test_nfct_get testnftnlrdr +all: test_nfct_get testnftnlrdr testnftpinhole clean: - $(RM) *.o testnftnlcrdr testnftnlpinhole testnftnlrdr_peer \ + $(RM) *.o config.h testnftnlcrdr testnftpinhole testnftnlrdr_peer \ test_nfct_get testnftnlrdr -testnftnlrdr: nftnlrdr.o nftnlrdr_misc.o testnftnlrdr.o upnpglobalvars.o $(LIBS) +config.h: + touch $@ -testiptpinhole: testiptpinhole.o iptpinhole.o upnpglobalvars.o $(LIBS) +testnftnlrdr: nftnlrdr.o nftnlrdr_misc.o testnftnlrdr.o $(LIBS) + +testnftpinhole: nftpinhole.o nftnlrdr_misc.o testnftpinhole.o \ + ../upnputils.o ../linux/getroute.o $(LIBS) test_nfct_get: test_nfct_get.o test_nfct_get.o -lmnl -lnetfilter_conntrack @@ -23,11 +32,12 @@ testnftnlrdr_dscp.o: testnftnlrdr_dscp.c -nftnlrdr.o: nftnlrdr.c nftnlrdr.h +nftnlrdr.o: nftnlrdr.c nftnlrdr.h config.h nftnlrdr_misc.o: nftnlrdr_misc.c -iptpinhole.o: iptpinhole.c iptpinhole.h +nftpinhole.o: nftpinhole.c nftpinhole.h config.h + +testnftnlrdr.o: config.h nftnlrdr.h nftnlrdr_misc.h -upnpglobalvars.o: ../upnpglobalvars.c ../upnpglobalvars.h - $(CC) -c -o $@ $< +testnftpinhole.o: config.h nftpinhole.h diff -Nru miniupnpd-2.1/netfilter_nft/nftnlrdr.c miniupnpd-2.2.1/netfilter_nft/nftnlrdr.c --- miniupnpd-2.1/netfilter_nft/nftnlrdr.c 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/nftnlrdr.c 2020-11-27 18:25:04.000000000 +0000 @@ -1,8 +1,12 @@ -/* +/* $Id: nftnlrdr.c,v 1.10 2020/11/11 12:08:43 nanard Exp $ + * vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * (c) 2015 Tomofumi Hayashi - * + * (c) 2019 Sven Auhagen + * (c) 2019 Paul Chambers + * (c) 2020 Thomas Bernard + * * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution. */ @@ -11,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -19,23 +23,27 @@ #include #include #include +#include #include #include +#include #include #include #include +#include +#include #include #include #include "tiny_nf_nat.h" +#include "config.h" #include "../macros.h" -#include "../config.h" +#include "../commonrdr.h" #include "nftnlrdr.h" -#include "../upnpglobalvars.h" #include "nftnlrdr_misc.h" @@ -45,17 +53,195 @@ #define d_printf(x) #endif -/* dummy init and shutdown functions */ -int init_redirect(void) +/* list to keep timestamps for port mappings having a lease duration */ +struct timestamp_entry { + struct timestamp_entry * next; + unsigned int timestamp; + unsigned short eport; + short protocol; +}; + +static struct timestamp_entry * timestamp_list = NULL; + +#define NAT_CHAIN_TYPE "nat" +#define FILTER_CHAIN_TYPE "filter" + +/* init and shutdown functions */ +int +init_redirect(void) +{ + int result; + + /* requires elevated privileges */ + result = nft_mnl_connect(); + + /* 'inet' family */ + if (result == 0) { + result = table_op(NFT_MSG_NEWTABLE, NFPROTO_INET, nft_table); + } + if (result == 0) { + result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_INET, nft_table, + nft_forward_chain, FILTER_CHAIN_TYPE, NF_INET_FORWARD, NF_IP_PRI_FILTER - 25); + } + + /* 'ip' family */ + if (result == 0) { + result = table_op(NFT_MSG_NEWTABLE, NFPROTO_IPV4, nft_table); + } + if (result == 0) { + result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV4, nft_table, + nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST); + } + if (result == 0) { + result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV4, nft_table, + nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC); + } + + /* 'ip6' family */ + if (result == 0) { + result = table_op(NFT_MSG_NEWTABLE, NFPROTO_IPV6, nft_table); + } + if (result == 0) { + result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV6, nft_table, + nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST); + } + if (result == 0) { + result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV6, nft_table, + nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC); + } + + return result; +} + +void +shutdown_redirect(void) { + int result; + + /* 'inet' family */ + result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_INET, nft_table, + nft_forward_chain, FILTER_CHAIN_TYPE, NF_INET_FORWARD, NF_IP_PRI_FILTER - 25); + if (result == 0) { + result = table_op(NFT_MSG_DELTABLE, NFPROTO_INET, nft_table); + } + + /* 'ip' family */ + result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV4, nft_table, + nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST); + if (result == 0) { + result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV4, nft_table, + nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC); + } + if (result == 0) { + result = table_op(NFT_MSG_DELTABLE, NFPROTO_IPV4, nft_table); + } + + /* 'ip6' family */ + if (result == 0) { + result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV6, nft_table, + nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST); + } + if (result == 0) { + result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV6, nft_table, + nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC); + } + if (result == 0) { + result = table_op(NFT_MSG_DELTABLE, NFPROTO_IPV6, nft_table); + } + + nft_mnl_disconnect(); +} + +/** + * used by the core to override default chain names if specified in config file + * @param param which string to set + * @param string the new name to use. Do not dispose after setting (i.e. use strdup if not static). + * @return 0 if successful + */ +int +set_rdr_name(rdr_name_type param, const char *string) +{ + if (string == NULL || strlen(string) > 30 || string[0] == '\0') { + syslog(LOG_ERR, "%s(): invalid string argument '%s'", "set_rdr_name", string); + return -1; + } + switch (param) { + case RDR_TABLE_NAME: + nft_table = string; + break; + case RDR_NAT_PREROUTING_CHAIN_NAME: + nft_prerouting_chain = string; + break; + case RDR_NAT_POSTROUTING_CHAIN_NAME: + nft_postrouting_chain = string; + break; + case RDR_FORWARD_CHAIN_NAME: + nft_forward_chain = string; + break; + default: + syslog(LOG_ERR, "%s(): tried to set invalid string parameter: %d", "set_rdr_name", param); + return -2; + } return 0; } -void shutdown_redirect(void) +static unsigned int +get_timestamp(unsigned short eport, int proto) { - return; + struct timestamp_entry * e; + e = timestamp_list; + while(e) { + if(e->eport == eport && e->protocol == (short)proto) { + syslog(LOG_DEBUG, "timestamp entry found (%hu, %d, %u)", eport, proto, e->timestamp); + return e->timestamp; + } + e = e->next; + } + syslog(LOG_WARNING, "get_timestamp(%hu, %d) no entry found", eport, proto); + return 0; } +static void +remove_timestamp_entry(unsigned short eport, int proto) +{ + struct timestamp_entry * e; + struct timestamp_entry * * p; + p = ×tamp_list; + e = *p; + while(e) { + if(e->eport == eport && e->protocol == (short)proto) { + syslog(LOG_DEBUG, "timestamp entry removed (%hu, %d, %u)", eport, proto, e->timestamp); + /* remove the entry */ + *p = e->next; + free(e); + return; + } + p = &(e->next); + e = *p; + } + syslog(LOG_WARNING, "remove_timestamp_entry(%hu, %d) no entry found", eport, proto); +} + +static void +add_timestamp_entry(unsigned short eport, int proto, unsigned timestamp) +{ + struct timestamp_entry * tmp; + tmp = malloc(sizeof(struct timestamp_entry)); + if(tmp) + { + tmp->next = timestamp_list; + tmp->timestamp = timestamp; + tmp->eport = eport; + tmp->protocol = (short)proto; + timestamp_list = tmp; + syslog(LOG_DEBUG, "timestamp entry added (%hu, %d, %u)", eport, proto, timestamp); + } + else + { + syslog(LOG_ERR, "add_timestamp_entry() malloc(%lu) error", + sizeof(struct timestamp_entry)); + } +} int add_redirect_rule2(const char * ifname, @@ -63,21 +249,28 @@ const char * iaddr, unsigned short iport, int proto, const char * desc, unsigned int timestamp) { - struct nft_rule *r; + int ret; + struct nftnl_rule *r; UNUSED(rhost); - UNUSED(timestamp); - d_printf(("add redirect rule2(%s, %s, %u, %s, %u, %d, %s)!\n", + + d_printf(("add redirect rule2(%s, %s, %u, %s, %u, %d, %s)!\n", ifname, rhost, eport, iaddr, iport, proto, desc)); + r = rule_set_dnat(NFPROTO_IPV4, ifname, proto, - 0, eport, - inet_addr(iaddr), iport, desc, NULL); - return nft_send_request(r, NFT_MSG_NEWRULE); + 0, eport, + inet_addr(iaddr), iport, desc, NULL); + + ret = nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_REDIRECT); + if (ret >= 0) { + add_timestamp_entry(eport, proto, timestamp); + } + return ret; } /* - * This function submit the rule as following: - * nft add rule nat miniupnpd-pcp-peer ip - * saddr ip daddr tcp sport + * This function submit the rule as following: + * nft add rule nat miniupnpd-pcp-peer ip + * saddr ip daddr tcp sport * tcp dport snat : */ int @@ -87,23 +280,24 @@ const char * iaddr, unsigned short iport, int proto, const char * desc, unsigned int timestamp) { - struct nft_rule *r; + struct nftnl_rule *r; UNUSED(ifname); UNUSED(timestamp); - d_printf(("add peer redirect rule2()!\n")); - r = rule_set_snat(NFPROTO_IPV4, proto, - inet_addr(rhost), rport, - inet_addr(eaddr), eport, - inet_addr(iaddr), iport, desc, NULL); + d_printf(("add peer redirect rule2()!\n")); - return nft_send_request(r, NFT_MSG_NEWRULE); + r = rule_set_snat(NFPROTO_IPV4, proto, + inet_addr(rhost), rport, + inet_addr(eaddr), eport, + inet_addr(iaddr), iport, desc, NULL); + + return nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_PEER); } /* - * This function submit the rule as following: - * nft add rule filter miniupnpd + * This function submit the rule as following: + * nft add rule filter miniupnpd * ip daddr tcp dport accept - * + * */ int add_filter_rule2(const char * ifname, @@ -111,18 +305,21 @@ unsigned short eport, unsigned short iport, int proto, const char * desc) { - struct nft_rule *r = NULL; + struct nftnl_rule *r = NULL; in_addr_t rhost_addr = 0; d_printf(("add_filter_rule2(%s, %s, %s, %d, %d, %d, %s)\n", ifname, rhost, iaddr, eport, iport, proto, desc)); - if (rhost != NULL && strcmp(rhost, "") != 0) { - rhost_addr = inet_addr(rhost); - } - r = rule_set_filter(NFPROTO_IPV4, ifname, proto, - rhost_addr, inet_addr(iaddr), eport, iport, - desc, 0); - return nft_send_request(r, NFT_MSG_NEWRULE); + + if (rhost != NULL && strcmp(rhost, "") != 0 && strcmp(rhost, "*") != 0) { + rhost_addr = inet_addr(rhost); + } + r = rule_set_filter(NFPROTO_INET, ifname, proto, + rhost_addr, inet_addr(iaddr), + eport, iport, 0, + desc, 0); + + return nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_FILTER); } /* @@ -136,13 +333,32 @@ const char * iaddr, unsigned short iport, int proto, const char * desc, unsigned int timestamp) { - UNUSED(ifname); UNUSED(rhost); UNUSED(rport); + UNUSED(ifname); UNUSED(rhost); UNUSED(rport); UNUSED(dscp); UNUSED(iaddr); UNUSED(iport); UNUSED(proto); UNUSED(desc); UNUSED(timestamp); syslog(LOG_ERR, "add_peer_dscp_rule2: not supported"); return 0; } +int +delete_filter_rule(const char * ifname, unsigned short port, int proto) +{ + rule_t *p; + struct nftnl_rule *r; + UNUSED(ifname); + + refresh_nft_cache_filter(); + LIST_FOREACH(p, &head_filter, entry) { + if (p->eport == port && p->proto == proto && p->type == RULE_FILTER) { + r = rule_del_handle(p); + nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); + break; + } + } + + return 0; +} + /* * Clear all rules corresponding eport/proto */ @@ -150,45 +366,78 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto) { rule_t *p; - struct nft_rule *r = NULL; - in_addr_t iaddr = 0; - uint16_t iport = 0; - extern void print_rule(rule_t *r) ; + struct nftnl_rule *r = NULL; + in_addr_t iaddr = 0; + uint16_t iport = 0; d_printf(("delete_redirect_and_filter_rules(%d %d)\n", eport, proto)); - reflesh_nft_cache(NFPROTO_IPV4); - LIST_FOREACH(p, &head, entry) { - if (p->eport == eport && p->proto == proto && - (p->type == RULE_NAT || p->type == RULE_SNAT)) { + refresh_nft_cache_redirect(); + + // Delete Redirect Rule + LIST_FOREACH(p, &head_redirect, entry) { + if (p->eport == eport && p->proto == proto && + (p->type == RULE_NAT && p->nat_type == NFT_NAT_DNAT)) { iaddr = p->iaddr; iport = p->iport; r = rule_del_handle(p); /* Todo: send bulk request */ - nft_send_request(r, NFT_MSG_DELRULE); + nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_REDIRECT); break; } } - if (iaddr == 0 && iport == 0) { - return -1; + if (iaddr != 0 && iport != 0) { + refresh_nft_cache_filter(); + // Delete Forward Rule + LIST_FOREACH(p, &head_filter, entry) { + if (p->eport == iport && + p->iaddr == iaddr && p->type == RULE_FILTER) { + r = rule_del_handle(p); + /* Todo: send bulk request */ + nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); + break; + } + } } - reflesh_nft_cache(NFPROTO_IPV4); - LIST_FOREACH(p, &head, entry) { - if (p->eport == iport && - p->iaddr == iaddr && p->type == RULE_FILTER) { + + iaddr = 0; + iport = 0; + + refresh_nft_cache_peer(); + // Delete Peer Rule + LIST_FOREACH(p, &head_peer, entry) { + if (p->eport == eport && p->proto == proto && + (p->type == RULE_NAT && p->nat_type == NFT_NAT_SNAT)) { + iaddr = p->iaddr; + iport = p->iport; + r = rule_del_handle(p); /* Todo: send bulk request */ - nft_send_request(r, NFT_MSG_DELRULE); + nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_PEER); break; } } + if (iaddr != 0 && iport != 0) { + refresh_nft_cache_filter(); + // Delete Forward Rule + LIST_FOREACH(p, &head_filter, entry) { + if (p->eport == iport && + p->iaddr == iaddr && p->type == RULE_FILTER) { + r = rule_del_handle(p); + /* Todo: send bulk request */ + nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); + break; + } + } + } + return 0; } -/* - * get peer by index as array. +/* + * get peer by index as array. * return -1 when not found. */ int @@ -200,62 +449,79 @@ unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) { - int i; - struct in_addr addr; - char *addr_str; rule_t *r; - UNUSED(timestamp); UNUSED(packets); UNUSED(bytes); + int i = 0; - d_printf(("get_peer_rule_by_index()\n")); - reflesh_nft_cache(NFPROTO_IPV4); - if (peer_cache == NULL) { - return -1; - } + d_printf(("get_peer_rule_by_index()\n")); + refresh_nft_cache_peer(); - for (i = 0; peer_cache[i] != NULL; i++) { - if (index == i) { - r = peer_cache[i]; + LIST_FOREACH(r, &head_peer, entry) { + if (i++ == index) { if (ifname != NULL) { if_indextoname(r->ingress_ifidx, ifname); } + if (eport != NULL) { *eport = r->eport; } + if (iaddr != NULL) { - addr.s_addr = r->iaddr; - addr_str = inet_ntoa(addr); - strncpy(iaddr , addr_str, iaddrlen); + if (inet_ntop(AF_INET, &r->iaddr, iaddr, iaddrlen) == NULL) { + syslog(LOG_ERR, "%s: inet_ntop: %m", + "get_peer_rule_by_index"); + } } + if (iport != NULL) { *iport = r->iport; } + if (proto != NULL) { *proto = r->proto; } + if (rhost != NULL) { - addr.s_addr = r->rhost; - addr_str = inet_ntoa(addr); - strncpy(iaddr , addr_str, rhostlen); + if (r->rhost) { + if (inet_ntop(AF_INET, &r->rhost, rhost, rhostlen) == NULL) { + syslog(LOG_ERR, "%s: inet_ntop: %m", + "get_peer_rule_by_index"); + } + } else { + rhost[0] = '\0'; + } } + if (rport != NULL) { *rport = r->rport; } + if (desc != NULL) { strncpy(desc, r->desc, desclen); } - /* - * TODO: Implement counter in case of add {nat,filter} + if (packets) { + *packets = r->packets; + } + if (bytes) { + *bytes = r->bytes; + } + + if (timestamp) { + *timestamp = get_timestamp(r->eport, r->proto); + } + /* + * TODO: Implement counter in case of add {nat,filter} */ return 0; } } + return -1; } -/* +/* * get_redirect_rule() - * returns -1 if the rule is not found + * returns -1 if the rule is not found */ int get_redirect_rule(const char * ifname, unsigned short eport, int proto, @@ -265,7 +531,7 @@ unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) { - return get_nat_redirect_rule(NFT_TABLE_NAT, + return get_nat_redirect_rule(nft_prerouting_chain, ifname, eport, proto, iaddr, iaddrlen, iport, desc, desclen, @@ -273,9 +539,25 @@ timestamp, packets, bytes); } +/* get_redirect_rule_count() + * return value : -1 for error or the number of redirection rules */ +int +get_redirect_rule_count(const char * ifname) +{ + rule_t *r; + int n = 0; + UNUSED(ifname); + + refresh_nft_cache_redirect(); + LIST_FOREACH(r, &head_redirect, entry) { + n++; + } + return n; +} + /* * get_redirect_rule_by_index() - * return -1 when the rule was not found + * return -1 when the rule was not found */ int get_redirect_rule_by_index(int index, @@ -286,53 +568,70 @@ unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) { - int i; - struct in_addr addr; - char *addr_str; rule_t *r; - UNUSED(timestamp); UNUSED(packets); UNUSED(bytes); + int i = 0; - d_printf(("get_redirect_rule_by_index()\n")); - reflesh_nft_cache(NFPROTO_IPV4); - if (redirect_cache == NULL) { - return -1; - } + d_printf(("get_redirect_rule_by_index()\n")); + refresh_nft_cache_redirect(); - for (i = 0; redirect_cache[i] != NULL; i++) { - if (index == i) { - r = redirect_cache[i]; + LIST_FOREACH(r, &head_redirect, entry) { + if (i++ == index) { if (ifname != NULL) { if_indextoname(r->ingress_ifidx, ifname); } + if (eport != NULL) { *eport = r->eport; } + if (iaddr != NULL) { - addr.s_addr = r->iaddr; - addr_str = inet_ntoa(addr); - strncpy(iaddr , addr_str, iaddrlen); + if (inet_ntop(AF_INET, &r->iaddr, iaddr, iaddrlen) == NULL) { + syslog(LOG_ERR, "%s: inet_ntop: %m", + "get_redirect_rule_by_index"); + } } + if (iport != NULL) { *iport = r->iport; } + if (proto != NULL) { *proto = r->proto; } + if (rhost != NULL) { - addr.s_addr = r->rhost; - addr_str = inet_ntoa(addr); - strncpy(iaddr , addr_str, rhostlen); + if (r->rhost) { + if (inet_ntop(AF_INET, &r->rhost, rhost, rhostlen) == NULL) { + syslog(LOG_ERR, "%s: inet_ntop: %m", + "get_redirect_rule_by_index"); + } + } else { + rhost[0] = '\0'; + } } + if (desc != NULL && r->desc) { strncpy(desc, r->desc, desclen); } - /* + if (timestamp != NULL) { + *timestamp = get_timestamp(*eport, *proto); + } + + if (packets || bytes) { + if (packets) + *packets = r->packets; + if (bytes) + *bytes = r->bytes; + } + + /* * TODO: Implement counter in case of add {nat,filter} */ return 0; } } + return -1; } @@ -351,30 +650,37 @@ { rule_t *p; struct in_addr addr; - char *addr_str; UNUSED(nat_chain_name); UNUSED(ifname); - UNUSED(iaddrlen); - UNUSED(timestamp); UNUSED(packets); UNUSED(bytes); + UNUSED(rhost); + UNUSED(rhostlen); - d_printf(("get_nat_redirect_rule()\n")); - reflesh_nft_cache(NFPROTO_IPV4); + refresh_nft_cache_redirect(); - LIST_FOREACH(p, &head, entry) { + LIST_FOREACH(p, &head_redirect, entry) { if (p->proto == proto && p->eport == eport) { - if (p->rhost && rhost) { - addr.s_addr = p->rhost; - addr_str = inet_ntoa(addr); - strncpy(iaddr , addr_str, rhostlen); + if (p->iaddr && iaddr) { + addr.s_addr = p->iaddr; + if (inet_ntop(AF_INET, &addr, iaddr, iaddrlen) == NULL) { + syslog(LOG_ERR, "%s: inet_ntop: %m", + "get_nat_redirect_rule"); + } } + if (desc != NULL && p->desc) { strncpy(desc, p->desc, desclen); } - *iport = p->iport; + + if (iport) + *iport = p->iport; + + if(timestamp != NULL) + *timestamp = get_timestamp(eport, proto); + return 0; } } @@ -382,9 +688,9 @@ return -1; } -/* +/* * return an (malloc'ed) array of "external" port for which there is - * a port mapping. number is the size of the array + * a port mapping. number is the size of the array */ unsigned short * get_portmappings_in_range(unsigned short startport, unsigned short endport, @@ -395,7 +701,8 @@ unsigned short *array; unsigned short *tmp; - d_printf(("get_portmappings_in_range()\n")); + d_printf(("get_portmappings_in_range()\n")); + *number = 0; capacity = 128; array = calloc(capacity, sizeof(unsigned short)); @@ -405,13 +712,15 @@ return NULL; } - LIST_FOREACH(p, &head, entry) { + refresh_nft_cache_redirect(); + + LIST_FOREACH(p, &head_redirect, entry) { if (p->proto == proto && - startport <= p->eport && + startport <= p->eport && p->eport <= endport) { if (*number >= capacity) { - tmp = realloc(array, + tmp = realloc(array, sizeof(unsigned short)*capacity); if (tmp == NULL) { syslog(LOG_ERR, @@ -420,7 +729,7 @@ (unsigned)sizeof(unsigned short)*capacity); *number = 0; free(array); - return NULL; + return NULL; } array = tmp; } @@ -431,69 +740,42 @@ return array; } -/* for debug */ -/* read the "filter" and "nat" tables */ int -list_redirect_rule(const char * ifname) +update_portmapping_desc_timestamp(const char * ifname, + unsigned short eport, int proto, + const char * desc, unsigned int timestamp) { - rule_t *p; UNUSED(ifname); + UNUSED(desc); + remove_timestamp_entry(eport, proto); + add_timestamp_entry(eport, proto, timestamp); + return 0; +} - reflesh_nft_cache(NFPROTO_IPV4); +int +update_portmapping(const char * ifname, unsigned short eport, int proto, + unsigned short iport, const char * desc, + unsigned int timestamp) +{ + char iaddr_str[INET_ADDRSTRLEN]; + char rhost[INET_ADDRSTRLEN]; + int r; - LIST_FOREACH(p, &head, entry) { - print_rule(p); - } + d_printf(("update_portmapping()\n")); - return -1; - return 0; -} + if (get_redirect_rule(NULL, eport, proto, iaddr_str, INET_ADDRSTRLEN, NULL, NULL, 0, rhost, INET_ADDRSTRLEN, NULL, 0, 0) < 0) + return -1; + r = delete_redirect_and_filter_rules(eport, proto); + if (r < 0) + return -1; -#if 0 -/* delete_rule_and_commit() : - * subfunction used in delete_redirect_and_filter_rules() */ -static int -delete_rule_and_commit(unsigned int index, IPTC_HANDLE h, - const char * miniupnpd_chain, - const char * logcaller) -{ -/* TODO: Implement it */ -} + if (add_redirect_rule2(ifname, rhost, eport, iaddr_str, iport, proto, + desc, timestamp) < 0) + return -1; -/* TODO: Implement it */ -static void -print_iface(const char * iface, const unsigned char * mask, int invert) -{ - unsigned i; - if(mask[0] == 0) - return; - if(invert) - printf("! "); - for(i=0; i> 24, (ip >> 16) & 0xff, - (ip >> 8) & 0xff, ip & 0xff); + return 0; } -#endif - -#endif /* if 0 */ diff -Nru miniupnpd-2.1/netfilter_nft/nftnlrdr.h miniupnpd-2.2.1/netfilter_nft/nftnlrdr.h --- miniupnpd-2.1/netfilter_nft/nftnlrdr.h 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/nftnlrdr.h 2019-10-06 20:54:10.000000000 +0000 @@ -2,6 +2,7 @@ * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2015 Tomofumi Hayashi + * (c) 2019 Paul Chambers * * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution. @@ -11,6 +12,7 @@ #define NFTNLRDR_H_INCLUDED #include "../commonrdr.h" + int init_redirect(void); void shutdown_redirect(void); @@ -37,6 +39,9 @@ delete_redirect_and_filter_rules(unsigned short eport, int proto); int +delete_filter_rule(const char * ifname, unsigned short port, int proto); + +int add_peer_dscp_rule2(const char * ifname, const char * rhost, unsigned short rport, unsigned char dscp, @@ -76,9 +81,4 @@ int get_nat_ext_addr(struct sockaddr* src, struct sockaddr *dst, uint8_t proto, struct sockaddr* ret_ext); -/* for debug */ -int -list_redirect_rule(const char * ifname); - #endif - diff -Nru miniupnpd-2.1/netfilter_nft/nftnlrdr_misc.c miniupnpd-2.2.1/netfilter_nft/nftnlrdr_misc.c --- miniupnpd-2.1/netfilter_nft/nftnlrdr_misc.c 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/nftnlrdr_misc.c 2020-10-30 21:23:38.000000000 +0000 @@ -1,8 +1,11 @@ -/* +/* $Id: nftnlrdr_misc.c,v 1.13 2020/10/30 21:23:16 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * (c) 2015 Tomofumi Hayashi - * + * (c) 2019 Paul Chambers + * (c) 2019-2020 Thomas Bernard + * * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution. */ @@ -27,14 +30,18 @@ #include #include #include +#include #include +#include +#include #include #include +#include "../commonrdr.h" #include "nftnlrdr_misc.h" #include "../macros.h" -#include "../upnpglobalvars.h" + #ifdef DEBUG #define d_printf(x) do { printf x; } while (0) @@ -42,153 +49,116 @@ #define d_printf(x) #endif -#define RULE_CACHE_INVALID 0 -#define RULE_CACHE_VALID 1 - -const char * miniupnpd_nft_nat_chain = "miniupnpd"; -const char * miniupnpd_nft_peer_chain = "miniupnpd-pcp-peer"; -const char * miniupnpd_nft_forward_chain = "miniupnpd"; +#if defined(DEBUG) && (__STDC_VERSION__ >= 199901L) && (__GNUC__ >= 3) +/* disambiguate log messages by adding position in source. GNU C99 or later. Pesky trailing comma... */ +#define log_error( msg, ...) syslog(LOG_ERR, "%s[%d]: " msg, __func__, __LINE__, ##__VA_ARGS__ ) +#define log_debug( msg, ...) syslog(LOG_DEBUG, "%s[%d]: " msg, __func__, __LINE__, ##__VA_ARGS__ ) +#else +/* original style */ +#define log_error(args...) syslog(LOG_ERR, args) +#define log_debug(args...) syslog(LOG_DEBUG, args) +#endif -static struct mnl_socket *nl = NULL; -struct rule_list head = LIST_HEAD_INITIALIZER(head); -static uint32_t rule_list_validate = RULE_CACHE_INVALID; -uint32_t rule_list_length = 0; -uint32_t rule_list_peer_length = 0; +#define RULE_CACHE_INVALID 0 +#define RULE_CACHE_VALID 1 -rule_t **redirect_cache; -rule_t **peer_cache; +const char * nft_table = "miniupnpd"; +const char * nft_prerouting_chain = "prerouting"; +const char * nft_postrouting_chain = "postrouting"; +const char * nft_forward_chain = "forward"; + +static struct mnl_socket *mnl_sock = NULL; +static uint32_t mnl_portid = 0; +static uint32_t mnl_seq = 0; + +// FILTER +struct rule_list head_filter = LIST_HEAD_INITIALIZER(head_filter); +// DNAT +struct rule_list head_redirect = LIST_HEAD_INITIALIZER(head_redirect); +// SNAT +struct rule_list head_peer = LIST_HEAD_INITIALIZER(head_peer); + +static uint32_t rule_list_filter_validate = RULE_CACHE_INVALID; +static uint32_t rule_list_redirect_validate = RULE_CACHE_INVALID; +static uint32_t rule_list_peer_validate = RULE_CACHE_INVALID; -static const char * -get_family_string(uint32_t family) +/* + * return : 0 for OK, -1 for error + */ +int +nft_mnl_connect(void) { - switch (family) { - case NFPROTO_IPV4: - return "ipv4"; + mnl_sock = mnl_socket_open(NETLINK_NETFILTER); + if (mnl_sock == NULL) { + log_error("mnl_socket_open() FAILED: %m"); + return -1; } - return "unknown family"; + if (mnl_socket_bind(mnl_sock, 0, MNL_SOCKET_AUTOPID) < 0) { + log_error("mnl_socket_bind() FAILED: %m"); + return -1; + } + mnl_portid = mnl_socket_get_portid(mnl_sock); + syslog(LOG_INFO, "mnl_socket bound, port_id=%u", mnl_portid); + return 0; } -static const char * -get_proto_string(uint32_t proto) +void +nft_mnl_disconnect(void) { - switch (proto) { - case IPPROTO_TCP: - return "tcp"; - case IPPROTO_UDP: - return "udp"; + if (mnl_sock != NULL) { + mnl_socket_close(mnl_sock); + mnl_sock = NULL; } - return "unknown proto"; } -static const char * -get_verdict_string(uint32_t val) +#ifdef DEBUG +void +print_rule(const char *func, int line, const struct nftnl_rule *rule) { - switch (val) { - case NF_ACCEPT: - return "accept"; - case NF_DROP: - return "drop"; - default: - return "unknown verdict"; - } + fprintf(stdout, "%s[%d]: ", func, line); + nftnl_rule_fprintf(stdout, rule, NFTNL_OUTPUT_DEFAULT, 0); } -void -print_rule(rule_t *r) +void +print_rule_t(const char *func, int line, const rule_t *r) { - struct in_addr addr; - char *iaddr_str = NULL, *rhost_str = NULL, *eaddr_str = NULL; - char ifname_buf[IF_NAMESIZE]; + fprintf(stdout, "%s[%d]: ", func, line); + printf("%s %s %d %hu => %hu\n", r->table, r->chain, (int)r->type, + r->eport, r->iport); +} - switch (r->type) { - case RULE_NAT: - if (r->iaddr != 0) { - addr.s_addr = r->iaddr; - iaddr_str = strdupa(inet_ntoa(addr)); - } - if (r->rhost != 0) { - addr.s_addr = r->rhost; - rhost_str = strdupa(inet_ntoa(addr)); - } - if (r->eaddr != 0) { - addr.s_addr = r->eaddr; - eaddr_str = strdupa(inet_ntoa(addr)); - } - if (r->nat_type == NFT_NAT_DNAT) { - printf("%"PRIu64":[%s/%s] iif %s, %s/%s, %d -> " - "%s:%d (%s)\n", - r->handle, - r->table, r->chain, - if_indextoname(r->ingress_ifidx, ifname_buf), - get_family_string(r->family), - get_proto_string(r->proto), r->eport, - iaddr_str, r->iport, - r->desc); - } else if (r->nat_type == NFT_NAT_SNAT) { - printf("%"PRIu64":[%s/%s] " - "nat type:%d, family:%d, ifidx: %d, " - "eaddr: %s, eport:%d, " - "proto:%d, iaddr: %s, " - "iport:%d, rhost:%s rport:%d (%s)\n", - r->handle, r->table, r->chain, - r->nat_type, r->family, r->ingress_ifidx, - eaddr_str, r->eport, - r->proto, iaddr_str, r->iport, - rhost_str, r->rport, - r->desc); - } else { - printf("%"PRIu64":[%s/%s] " - "nat type:%d, family:%d, ifidx: %d, " - "eaddr: %s, eport:%d, " - "proto:%d, iaddr: %s, iport:%d, rhost:%s (%s)\n", - r->handle, r->table, r->chain, - r->nat_type, r->family, r->ingress_ifidx, - eaddr_str, r->eport, - r->proto, iaddr_str, r->iport, rhost_str, - r->desc); - } - break; - case RULE_FILTER: - if (r->iaddr != 0) { - addr.s_addr = r->iaddr; - iaddr_str = strdupa(inet_ntoa(addr)); - } - if (r->rhost != 0) { - addr.s_addr = r->rhost; - rhost_str = strdupa(inet_ntoa(addr)); - } - printf("%"PRIu64":[%s/%s] %s/%s, %s %s:%d: %s (%s)\n", - r->handle, r->table, r->chain, - get_family_string(r->family), get_proto_string(r->proto), - rhost_str, - iaddr_str, r->eport, - get_verdict_string(r->filter_action), - r->desc); - break; - case RULE_COUNTER: - if (r->iaddr != 0) { - addr.s_addr = r->iaddr; - iaddr_str = strdupa(inet_ntoa(addr)); - } - if (r->rhost != 0) { - addr.s_addr = r->iaddr; - rhost_str = strdupa(inet_ntoa(addr)); - } - printf("%"PRIu64":[%s/%s] %s/%s, %s:%d: " - "packets:%"PRIu64", bytes:%"PRIu64"\n", - r->handle, r->table, r->chain, - get_family_string(r->family), get_proto_string(r->proto), - iaddr_str, r->eport, r->packets, r->bytes); - break; - default: - printf("nftables: unknown type: %d\n", r->type); +/* print out the "filter" and "nat" tables */ +void +print_redirect_rules(const char * ifname) +{ + rule_t *p; + int i; + UNUSED(ifname); + + refresh_nft_cache_filter(); + i = 1; + LIST_FOREACH(p, &head_filter, entry) { + print_rule_t("filter", i++, p); + } + + refresh_nft_cache_redirect(); + i = 1; + LIST_FOREACH(p, &head_redirect, entry) { + print_rule_t("redirect", i++, p); + } + + refresh_nft_cache_peer(); + i = 1; + LIST_FOREACH(p, &head_peer, entry) { + print_rule_t("peer", 0, p); } } +#endif static enum rule_reg_type * -get_reg_type_ptr(rule_t *r, uint32_t dreg) +get_reg_type_ptr(rule_t *r, uint32_t dreg) { switch (dreg) { case NFT_REG_1: @@ -201,7 +171,7 @@ } static uint32_t * -get_reg_val_ptr(rule_t *r, uint32_t dreg) +get_reg_val_ptr(rule_t *r, uint32_t dreg) { switch (dreg) { case NFT_REG_1: @@ -231,233 +201,279 @@ r->filter_action = val; } } else { - syslog(LOG_ERR, "%s: unknown reg:%d", "set_reg", dreg); + log_error("unknown reg:%d", dreg); } return ; } -static inline void -parse_rule_immediate(struct nft_rule_expr *e, rule_t *r) +static void +parse_rule_immediate(struct nftnl_expr *e, rule_t *r) { uint32_t dreg, reg_val, reg_len; - dreg = nft_rule_expr_get_u32(e, NFT_EXPR_IMM_DREG); + dreg = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_DREG); if (dreg == NFT_REG_VERDICT) { - reg_val = nft_rule_expr_get_u32(e, NFT_EXPR_IMM_VERDICT); + reg_val = nftnl_expr_get_u32(e, NFTNL_EXPR_IMM_VERDICT); } else { - reg_val = *(uint32_t *)nft_rule_expr_get(e, - NFT_EXPR_IMM_DATA, + reg_val = *(uint32_t *)nftnl_expr_get(e, + NFTNL_EXPR_IMM_DATA, ®_len); } set_reg(r, dreg, RULE_REG_IMM_VAL, reg_val); - return; } -static inline void -parse_rule_counter(struct nft_rule_expr *e, rule_t *r) +static void +parse_rule_counter(struct nftnl_expr *e, rule_t *r) { r->type = RULE_COUNTER; - r->bytes = nft_rule_expr_get_u64(e, NFT_EXPR_CTR_BYTES); - r->packets = nft_rule_expr_get_u64(e, NFT_EXPR_CTR_PACKETS); - - return; + r->bytes = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_BYTES); + r->packets = nftnl_expr_get_u64(e, NFTNL_EXPR_CTR_PACKETS); } -static inline void -parse_rule_meta(struct nft_rule_expr *e, rule_t *r) +static void +parse_rule_meta(struct nftnl_expr *e, rule_t *r) { - uint32_t key = nft_rule_expr_get_u32(e, NFT_EXPR_META_KEY); - uint32_t dreg = nft_rule_expr_get_u32(e, NFT_EXPR_META_DREG); + uint32_t key = nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY); + uint32_t dreg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG); enum rule_reg_type reg_type; + /* ToDo: body of both cases are identical - bug? */ switch (key) { case NFT_META_IIF: reg_type = RULE_REG_IIF; set_reg(r, dreg, reg_type, 0); - return ; - + break; case NFT_META_OIF: reg_type = RULE_REG_IIF; set_reg(r, dreg, reg_type, 0); - return ; - + break; + default: + log_debug("parse_rule_meta :Not support key %d\n", key); + break; } - syslog(LOG_DEBUG, "parse_rule_meta :Not support key %d\n", key); - - return; } -static inline void -parse_rule_nat(struct nft_rule_expr *e, rule_t *r) +static void +parse_rule_nat(struct nftnl_expr *e, rule_t *r) { uint32_t addr_min_reg, addr_max_reg, proto_min_reg, proto_max_reg; - uint16_t proto_min_val; + uint16_t proto_min_val = 0; + uint32_t * reg_val_ptr; r->type = RULE_NAT; - r->nat_type = nft_rule_expr_get_u32(e, NFT_EXPR_NAT_TYPE); - r->family = nft_rule_expr_get_u32(e, NFT_EXPR_NAT_FAMILY); - addr_min_reg = nft_rule_expr_get_u32(e, NFT_EXPR_NAT_REG_ADDR_MIN); - addr_max_reg = nft_rule_expr_get_u32(e, NFT_EXPR_NAT_REG_ADDR_MAX); - proto_min_reg = nft_rule_expr_get_u32(e, NFT_EXPR_NAT_REG_PROTO_MIN); - proto_max_reg = nft_rule_expr_get_u32(e, NFT_EXPR_NAT_REG_PROTO_MAX); + r->nat_type = nftnl_expr_get_u32(e, NFTNL_EXPR_NAT_TYPE); + r->family = nftnl_expr_get_u32(e, NFTNL_EXPR_NAT_FAMILY); + addr_min_reg = nftnl_expr_get_u32(e, NFTNL_EXPR_NAT_REG_ADDR_MIN); + addr_max_reg = nftnl_expr_get_u32(e, NFTNL_EXPR_NAT_REG_ADDR_MAX); + proto_min_reg = nftnl_expr_get_u32(e, NFTNL_EXPR_NAT_REG_PROTO_MIN); + proto_max_reg = nftnl_expr_get_u32(e, NFTNL_EXPR_NAT_REG_PROTO_MAX); if (addr_min_reg != addr_max_reg || proto_min_reg != proto_max_reg) { - syslog(LOG_ERR, "Unsupport proto/addr range for NAT"); + log_error( "Unsupport proto/addr range for NAT"); } - proto_min_val = htons((uint16_t)*get_reg_val_ptr(r, proto_min_reg)); - if (r->nat_type == NFT_NAT_DNAT) { - r->iaddr = (in_addr_t)*get_reg_val_ptr(r, addr_min_reg); - r->iport = proto_min_val; - } else if (r->nat_type == NFT_NAT_SNAT) { - r->eaddr = (in_addr_t)*get_reg_val_ptr(r, addr_min_reg); - if (proto_min_reg == NFT_REG_1) { - r->eport = proto_min_val; + reg_val_ptr = get_reg_val_ptr(r, proto_min_reg); + if (reg_val_ptr != NULL) { + proto_min_val = htons((uint16_t)*reg_val_ptr); + } else { + syslog(LOG_ERR, "%s: invalid proto_min_reg %u", "parse_rule_nat", proto_min_reg); + } + reg_val_ptr = get_reg_val_ptr(r, addr_min_reg); + if (reg_val_ptr != NULL) { + if (r->nat_type == NFT_NAT_DNAT) { + r->iaddr = (in_addr_t)*reg_val_ptr; + r->iport = proto_min_val; + } else if (r->nat_type == NFT_NAT_SNAT) { + r->eaddr = (in_addr_t)*reg_val_ptr; + if (proto_min_reg == NFT_REG_1) { + r->eport = proto_min_val; + } } + } else { + syslog(LOG_ERR, "%s: invalid addr_min_reg %u", "parse_rule_nat", addr_min_reg); } set_reg(r, NFT_REG_1, RULE_REG_NONE, 0); set_reg(r, NFT_REG_2, RULE_REG_NONE, 0); - return; } -static inline void -parse_rule_payload(struct nft_rule_expr *e, rule_t *r) +static void +parse_rule_payload(struct nftnl_expr *e, rule_t *r) { uint32_t base, dreg, offset, len; - uint32_t *regptr; + uint32_t *regptr; - dreg = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_DREG); - base = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_BASE); - offset = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_OFFSET); - len = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_LEN); + dreg = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG); + base = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE); + offset = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET); + len = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN); regptr = get_reg_type_ptr(r, dreg); + if (regptr == NULL) { + syslog(LOG_ERR, "%s: unsupported dreg %u", "parse_rule_payload", dreg); + return; + } switch (base) { case NFT_PAYLOAD_NETWORK_HEADER: if (offset == offsetof(struct iphdr, daddr) && len == sizeof(in_addr_t)) { *regptr = RULE_REG_IP_DEST_ADDR; - return; } else if (offset == offsetof(struct iphdr, saddr) && len == sizeof(in_addr_t)) { *regptr = RULE_REG_IP_SRC_ADDR; - return; } else if (offset == offsetof(struct iphdr, saddr) && len == sizeof(in_addr_t) * 2) { *regptr = RULE_REG_IP_SD_ADDR; - return; } else if (offset == offsetof(struct iphdr, protocol) && len == sizeof(uint8_t)) { *regptr = RULE_REG_IP_PROTO; - return; + } else if (offset == offsetof(struct ipv6hdr, nexthdr) && + len == sizeof(uint8_t)) { + *regptr = RULE_REG_IP6_PROTO; + } else if (offset == offsetof(struct ipv6hdr, daddr) && + len == sizeof(struct in6_addr)) { + *regptr = RULE_REG_IP6_DEST_ADDR; + } else if (offset == offsetof(struct ipv6hdr, saddr) && + len == sizeof(struct in6_addr)) { + *regptr = RULE_REG_IP6_SRC_ADDR; + } else if (offset == offsetof(struct ipv6hdr, saddr) && + len == sizeof(struct in6_addr) * 2) { + *regptr = RULE_REG_IP6_SD_ADDR; } + break; case NFT_PAYLOAD_TRANSPORT_HEADER: if (offset == offsetof(struct tcphdr, dest) && len == sizeof(uint16_t)) { *regptr = RULE_REG_TCP_DPORT; - return; } else if (offset == offsetof(struct tcphdr, source) && len == sizeof(uint16_t) * 2) { *regptr = RULE_REG_TCP_SD_PORT; - return; } + break; + default: + syslog(LOG_WARNING, + "%s: Unsupported payload: (dreg:%u, base:%u, offset:%u, len:%u)", + "parse_rule_payload", dreg, base, offset, len); + break; } - syslog(LOG_DEBUG, - "Unsupport payload: (dreg:%d, base:%d, offset:%d, len:%d)", - dreg, base, offset, len); - return; + } /* * * Note: Currently support only NFT_REG_1 */ -static inline void -parse_rule_cmp(struct nft_rule_expr *e, rule_t *r) { - uint32_t data_len; - void *data_val; +static void +parse_rule_cmp(struct nftnl_expr *e, rule_t *r) +{ + uint32_t data_len = 0; + const void *data_val; uint32_t op, sreg; - uint16_t *ports; - in_addr_t *addrp; - data_val = (void *)nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &data_len); - sreg = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_SREG); - op = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + + if (op != NFT_CMP_EQ) { + /* not a cmp expression, so bail out early */ + return; + } + + sreg = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_SREG); if (sreg != NFT_REG_1) { - syslog(LOG_ERR, "parse_rule_cmp: Unsupport reg:%d", sreg); + log_error( "parse_rule_cmp: Unsupport reg:%d", sreg); + return; + } + + data_val = nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &data_len); + if (data_val == NULL) { + log_error( "parse_rule_cmp: nftnl_expr_get(NFTNL_EXPR_CMP_DATA) returned NULL"); return; } switch (r->reg1_type) { case RULE_REG_IIF: - if (data_len == sizeof(uint32_t) && op == NFT_CMP_EQ) { - r->ingress_ifidx = *(uint32_t *)data_val; - r->reg1_type = RULE_REG_NONE; - return; + if (data_len == sizeof(uint32_t)) { + r->ingress_ifidx = *(const uint32_t *)data_val; } + break; case RULE_REG_IP_SRC_ADDR: - if (data_len == sizeof(in_addr_t) && op == NFT_CMP_EQ) { - r->rhost = *(in_addr_t *)data_val; - r->reg1_type = RULE_REG_NONE; - return; + if (data_len == sizeof(in_addr_t)) { + r->rhost = *(const in_addr_t *)data_val; + } + break; + case RULE_REG_IP6_SRC_ADDR: + if (data_len == sizeof(struct in6_addr)) { + r->rhost6 = *(const struct in6_addr *)data_val; } + break; case RULE_REG_IP_DEST_ADDR: - if (data_len == sizeof(in_addr_t) && op == NFT_CMP_EQ) { + if (data_len == sizeof(in_addr_t)) { if (r->type == RULE_FILTER) { - r->iaddr = *(in_addr_t *)data_val; + r->iaddr = *(const in_addr_t *)data_val; } else { - r->rhost = *(in_addr_t *)data_val; + r->rhost = *(const in_addr_t *)data_val; } - r->reg1_type = RULE_REG_NONE; - return; } + break; + case RULE_REG_IP6_DEST_ADDR: + if (data_len == sizeof(struct in6_addr)) { + if (r->type == RULE_FILTER) { + r->iaddr6 = *(const struct in6_addr *)data_val; + } else { + r->rhost6 = *(const struct in6_addr *)data_val; + } + } + break; case RULE_REG_IP_SD_ADDR: - if (data_len == sizeof(in_addr_t) * 2 && op == NFT_CMP_EQ) { - addrp = (in_addr_t *)data_val; + if (data_len == sizeof(in_addr_t) * 2) { + const in_addr_t *addrp = (const in_addr_t *)data_val; r->iaddr = addrp[0]; r->rhost = addrp[1]; - r->reg1_type = RULE_REG_NONE; - return; } + break; + case RULE_REG_IP6_SD_ADDR: + if (data_len == sizeof(struct in6_addr) * 2) { + const struct in6_addr *addrp6 = (const struct in6_addr *)data_val; + r->iaddr6 = addrp6[0]; + r->rhost6 = addrp6[1]; + } + break; case RULE_REG_IP_PROTO: - if (data_len == sizeof(uint8_t) && op == NFT_CMP_EQ) { - r->proto = *(uint8_t *)data_val; - r->reg1_type = RULE_REG_NONE; - return; + case RULE_REG_IP6_PROTO: + if (data_len == sizeof(uint8_t)) { + r->proto = *(const uint8_t *)data_val; } + break; case RULE_REG_TCP_DPORT: - if (data_len == sizeof(uint16_t) && op == NFT_CMP_EQ) { - r->eport = ntohs(*(uint16_t *)data_val); - r->reg1_type = RULE_REG_NONE; - return; + if (data_len == sizeof(uint16_t)) { + r->eport = ntohs(*(const uint16_t *)data_val); } + break; case RULE_REG_TCP_SD_PORT: - if (data_len == sizeof(uint16_t) * 2 && op == NFT_CMP_EQ) { - ports = (uint16_t *)data_val; - r->iport = ntohs(ports[0]); + if (data_len == sizeof(uint16_t) * 2) { + const uint16_t * ports = (const uint16_t *)data_val; + r->eport = ntohs(ports[0]); r->rport = ntohs(ports[1]); - r->reg1_type = RULE_REG_NONE; - return; } - default: break; + default: + log_debug("Unknown cmp (r1type:%d, data_len:%d, op:%d)", + r->reg1_type, data_len, op); + /* return early - don't modify r->reg1_type */ + return; } - syslog(LOG_DEBUG, "Unknown cmp (r1type:%d, data_len:%d, op:%d)", - r->reg1_type, data_len, op); + + r->reg1_type = RULE_REG_NONE; return; } static int -rule_expr_cb(struct nft_rule_expr *e, void *data) +rule_expr_cb(struct nftnl_expr *e, rule_t *r) { - rule_t *r = data; - const char *attr_name = nft_rule_expr_get_str(e, - NFT_RULE_EXPR_ATTR_NAME); + const char *attr_name = nftnl_expr_get_str(e, NFTNL_EXPR_NAME); if (strncmp("cmp", attr_name, sizeof("cmp")) == 0) { parse_rule_cmp(e, r); @@ -472,380 +488,377 @@ } else if (strncmp("immediate", attr_name, sizeof("immediate")) == 0) { parse_rule_immediate(e, r); } else { - syslog(LOG_ERR, "unknown attr: %s\n", attr_name); - } + log_debug("unknown attr: %s\n", attr_name); + } + return MNL_CB_OK; } - +struct table_cb_data { + const char * table; + const char * chain; + enum rule_type type; +}; + +/* callback. + * return values : + * MNL_CB_ERROR : an error has occurred. Stop callback runqueue. + * MNL_CB_STOP : top callback runqueue. + * MNL_CB_OK : no problems has occurred. + */ static int table_cb(const struct nlmsghdr *nlh, void *data) { - struct nft_rule *t; - uint32_t len; - struct nft_rule_expr *expr; - struct nft_rule_expr_iter *itr; - rule_t *r; - char *chain; - UNUSED(data); - - r = malloc(sizeof(rule_t)); - - memset(r, 0, sizeof(rule_t)); - t = nft_rule_alloc(); - if (t == NULL) { - perror("OOM"); - goto err; - } - - if (nft_rule_nlmsg_parse(nlh, t) < 0) { - perror("nft_rule_nlmsg_parse"); - goto err_free; - } - - chain = (char *)nft_rule_attr_get_data(t, NFT_RULE_ATTR_CHAIN, &len); - if (strcmp(chain, miniupnpd_nft_nat_chain) != 0 && - strcmp(chain, miniupnpd_nft_peer_chain) != 0 && - strcmp(chain, miniupnpd_nft_forward_chain) != 0) { - goto rule_skip; - } - - r->table = strdup( - (char *)nft_rule_attr_get_data(t, NFT_RULE_ATTR_TABLE, &len)); - r->chain = strdup(chain); - r->family = *(uint32_t*)nft_rule_attr_get_data(t, NFT_RULE_ATTR_FAMILY, - &len); - r->desc = (char *)nft_rule_attr_get_data(t, NFT_RULE_ATTR_USERDATA, - &len); - r->handle = *(uint32_t*)nft_rule_attr_get_data(t, - NFT_RULE_ATTR_HANDLE, - &len); - if (strcmp(r->table, NFT_TABLE_NAT) == 0) { - r->type = RULE_NAT; - } else if (strcmp(r->table, NFT_TABLE_FILTER) == 0) { - r->type = RULE_FILTER; - } - if (strcmp(r->chain, miniupnpd_nft_peer_chain) == 0) { - rule_list_peer_length++; - } + int result = MNL_CB_OK; + struct nftnl_rule *rule; + struct nftnl_expr_iter *itr; +#define CB_DATA(field) ((struct table_cb_data *)data)->field + + syslog(LOG_DEBUG, "table_cb(%p, %p) %s %s %d", nlh, data, CB_DATA(table), CB_DATA(chain), CB_DATA(type)); + rule = nftnl_rule_alloc(); + if (rule == NULL) { + log_error("nftnl_rule_alloc() FAILED"); + return MNL_CB_ERROR; + } + if (nftnl_rule_nlmsg_parse(nlh, rule) < 0) { + log_error("nftnl_rule_nlmsg_parse FAILED"); + result = MNL_CB_ERROR; + } else { + rule_t *r = malloc(sizeof(rule_t)); + if (r == NULL) { + syslog(LOG_ERR, "%s: failed to allocate %u bytes", + "table_cb", (unsigned)sizeof(rule_t)); + result = MNL_CB_ERROR; + } else { + const char *chain; + uint32_t len; - itr = nft_rule_expr_iter_create(t); + memset(r, 0, sizeof(rule_t)); - while ((expr = nft_rule_expr_iter_next(itr)) != NULL) { - rule_expr_cb(expr, r); + chain = (const char *) nftnl_rule_get_data(rule, NFTNL_RULE_CHAIN, &len); + if (strcmp(chain, nft_prerouting_chain) == 0 || + strcmp(chain, nft_postrouting_chain) == 0 || + strcmp(chain, nft_forward_chain) == 0) { + r->table = strdup((const char *) nftnl_rule_get_data(rule, NFTNL_RULE_TABLE, &len)); + r->chain = strdup(chain); + r->family = *(uint32_t *) nftnl_rule_get_data(rule, NFTNL_RULE_FAMILY, + &len); + if (nftnl_rule_is_set(rule, NFTNL_RULE_USERDATA)) { + const char *descr; + descr = (const char *) nftnl_rule_get_data(rule, NFTNL_RULE_USERDATA, + &r->desc_len); + if (r->desc_len > 0) { + r->desc = malloc(r->desc_len + 1); + if (r->desc != NULL) { + memcpy(r->desc, descr, r->desc_len); + r->desc[r->desc_len] = '\0'; + } else { + syslog(LOG_ERR, "failed to allocate %u bytes for desc", r->desc_len); + } + } + } + + r->handle = *(uint32_t *) nftnl_rule_get_data(rule, + NFTNL_RULE_HANDLE, + &len); + r->type = CB_DATA(type); + + itr = nftnl_expr_iter_create(rule); + if (itr == NULL) { + syslog(LOG_ERR, "%s: nftnl_expr_iter_create() FAILED", + "table_cb"); + } else { + struct nftnl_expr *expr; + + while ((expr = nftnl_expr_iter_next(itr)) != NULL) { + rule_expr_cb(expr, r); + } + nftnl_expr_iter_destroy(itr); + } + + switch (r->type) { + case RULE_NAT: + switch (r->nat_type) { + case NFT_NAT_SNAT: + LIST_INSERT_HEAD(&head_peer, r, entry); + r = NULL; + break; + case NFT_NAT_DNAT: + LIST_INSERT_HEAD(&head_redirect, r, entry); + r = NULL; + break; + default: + syslog(LOG_WARNING, "unknown nat type %d", r->nat_type); + } + break; + + case RULE_FILTER: + LIST_INSERT_HEAD(&head_filter, r, entry); + r = NULL; + break; + + default: + syslog(LOG_WARNING, "unknown rule type %d", r->type); + break; + } + } else { + syslog(LOG_WARNING, "unknown chain '%s'", chain); + } + if (r != NULL) { + free(r); + } + } } + nftnl_rule_free(rule); + return result; +} +#undef CB_DATA - if (r->type == RULE_NONE) { - free(r); - } else { - LIST_INSERT_HEAD(&head, r, entry); - rule_list_length++; +int +refresh_nft_cache_filter(void) +{ + if (rule_list_filter_validate != RULE_CACHE_VALID) { + if (refresh_nft_cache(&head_filter, nft_table, nft_forward_chain, NFPROTO_INET, RULE_FILTER) < 0) + return -1; + rule_list_filter_validate = RULE_CACHE_VALID; } - -rule_skip: -err_free: - nft_rule_free(t); -err: - return MNL_CB_OK; + return 0; } -void -reflesh_nft_redirect_cache(void) +int +refresh_nft_cache_peer(void) { - rule_t *p; - int i; - uint32_t len; - - if (redirect_cache != NULL) { - free(redirect_cache); + if (rule_list_peer_validate != RULE_CACHE_VALID) { + if (refresh_nft_cache(&head_peer, nft_table, nft_postrouting_chain, NFPROTO_IPV4, RULE_NAT) < 0) + return -1; + rule_list_peer_validate = RULE_CACHE_VALID; } - len = rule_list_length - rule_list_peer_length; - if (len == 0) { - redirect_cache = NULL; - return; - } - - redirect_cache = (rule_t **)malloc(sizeof(rule_t *) * len); - bzero(redirect_cache, sizeof(rule_t *) * len); + return 0; +} - i = 0; - LIST_FOREACH(p, &head, entry) { - if (strcmp(p->chain, miniupnpd_nft_nat_chain) == 0 && - (p->type == RULE_NAT || p->type == RULE_SNAT)) { - redirect_cache[i] = p; - i++; - } +int +refresh_nft_cache_redirect(void) +{ + if (rule_list_redirect_validate != RULE_CACHE_VALID) { + if (refresh_nft_cache(&head_redirect, nft_table, nft_prerouting_chain, NFPROTO_IPV4, RULE_NAT) < 0) + return -1; + rule_list_redirect_validate = RULE_CACHE_VALID; } - - return; + return 0; } void -reflesh_nft_peer_cache(void) +flush_nft_cache(struct rule_list *head) { - rule_t *p; - int i; + rule_t *p1, *p2; - if (peer_cache != NULL) { - free(peer_cache); - } - if (rule_list_peer_length == 0) { - peer_cache = NULL; - return; - } - peer_cache = (rule_t **)malloc( - sizeof(rule_t *) * rule_list_peer_length); - bzero(peer_cache, sizeof(rule_t *) * rule_list_peer_length); - - i = 0; - LIST_FOREACH(p, &head, entry) { - if (strcmp(p->chain, miniupnpd_nft_peer_chain) == 0) { - peer_cache[i] = p; - i++; + p1 = LIST_FIRST(head); + while (p1 != NULL) { + p2 = (rule_t *)LIST_NEXT(p1, entry); + if (p1->desc != NULL) { + free(p1->desc); + } + if (p1->table != NULL) { + free(p1->table); + } + if (p1->chain != NULL) { + free(p1->chain); } + free(p1); + p1 = p2; } - - return; + LIST_INIT(head); } -void -reflesh_nft_cache(uint32_t family) +/* + * return -1 in case of error, 0 if OK + */ +int +refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, uint32_t family, enum rule_type type) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; - uint32_t portid, seq, type = NFT_OUTPUT_DEFAULT; - struct nft_rule *t; - rule_t *p1, *p2; + struct table_cb_data data; + struct nftnl_rule *rule; int ret; + ssize_t n; - if (rule_list_validate == RULE_CACHE_VALID) { - return; - } - - t = NULL; - p1 = LIST_FIRST(&head); - if (p1 != NULL) { - while(p1 != NULL) { - p2 = (rule_t *)LIST_NEXT(p1, entry); - if (p1->desc != NULL) { - free(p1->desc); - } - if (p1->table != NULL) { - free(p1->table); - } - if (p1->chain != NULL) { - free(p1->chain); - } - free(p1); - p1 = p2; - } + if (mnl_sock == NULL) { + log_error("netlink not connected"); + return -1; } - LIST_INIT(&head); + flush_nft_cache(head); - t = nft_rule_alloc(); - if (t == NULL) { - perror("OOM"); - exit(EXIT_FAILURE); + rule = nftnl_rule_alloc(); + if (rule == NULL) { + log_error("nftnl_rule_alloc() FAILED"); + return -1; } - seq = time(NULL); - nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, - NLM_F_DUMP, seq); - nft_rule_nlmsg_build_payload(nlh, t); - nft_rule_free(t); + mnl_seq = time(NULL); + nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, + NLM_F_DUMP, mnl_seq); + nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, table); + nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, chain); + nftnl_rule_nlmsg_build_payload(nlh, rule); + nftnl_rule_free(rule); - if (nl == NULL) { - nl = mnl_socket_open(NETLINK_NETFILTER); - if (nl == NULL) { - perror("mnl_socket_open"); - exit(EXIT_FAILURE); - } - - if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { - perror("mnl_socket_bind"); - exit(EXIT_FAILURE); - } - } - portid = mnl_socket_get_portid(nl); - - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { - perror("mnl_socket_send"); - exit(EXIT_FAILURE); + if (mnl_socket_sendto(mnl_sock, nlh, nlh->nlmsg_len) < 0) { + log_error("mnl_socket_sendto() FAILED: %m"); + return -1; } - rule_list_peer_length = 0; - rule_list_length = 0; - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - while (ret > 0) { - ret = mnl_cb_run(buf, ret, seq, portid, table_cb, &type); - if (ret <= 0) + data.table = table; + data.chain = chain; + data.type = type; + do { + n = mnl_socket_recvfrom(mnl_sock, buf, sizeof(buf)); + if (n < 0) { + syslog(LOG_ERR, "%s: mnl_socket_recvfrom: %m", + "refresh_nft_cache"); + return -1; + } else if (n == 0) { break; - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - } - if (ret == -1) { - perror("error"); - exit(EXIT_FAILURE); - } - /* mnl_socket_close(nl); */ - - reflesh_nft_peer_cache(); - reflesh_nft_redirect_cache(); - rule_list_validate = RULE_CACHE_VALID; - return; -} - -static void -expr_add_payload(struct nft_rule *r, uint32_t base, uint32_t dreg, - uint32_t offset, uint32_t len) -{ - struct nft_rule_expr *e; - - e = nft_rule_expr_alloc("payload"); - if (e == NULL) { - perror("expr payload oom"); - exit(EXIT_FAILURE); - } - - nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_BASE, base); - nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_DREG, dreg); - nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_OFFSET, offset); - nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_LEN, len); + } + ret = mnl_cb_run(buf, n, mnl_seq, mnl_portid, table_cb, &data); + if (ret <= -1 /*== MNL_CB_ERROR*/) { + syslog(LOG_ERR, "%s: mnl_cb_run returned %d", + "refresh_nft_cache", ret); + return -1; + } + } while(ret >= 1 /*== MNL_CB_OK*/); + /* ret == MNL_CB_STOP */ - nft_rule_add_expr(r, e); + return 0; } -#if 0 static void -expr_add_bitwise(struct nft_rule *r, uint32_t sreg, uint32_t dreg, - uint32_t len, uint32_t mask, uint32_t xor) +expr_add_payload(struct nftnl_rule *r, uint32_t base, uint32_t dreg, + uint32_t offset, uint32_t len) { - struct nft_rule_expr *e; + struct nftnl_expr *e; - e = nft_rule_expr_alloc("bitwise"); + e = nftnl_expr_alloc("payload"); if (e == NULL) { - perror("expr cmp bitwise"); - exit(EXIT_FAILURE); + log_error("nftnl_expr_alloc(\"%s\") FAILED", "payload"); + return; } - nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_SREG, sreg); - nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_DREG, dreg); - nft_rule_expr_set_u32(e, NFT_EXPR_BITWISE_LEN, len); - nft_rule_expr_set(e, NFT_EXPR_BITWISE_MASK, &mask, sizeof(mask)); - nft_rule_expr_set(e, NFT_EXPR_BITWISE_XOR, &xor, sizeof(xor)); + nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base); + nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg); + nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset); + nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len); - nft_rule_add_expr(r, e); + nftnl_rule_add_expr(r, e); } -#endif static void -expr_add_cmp(struct nft_rule *r, uint32_t sreg, uint32_t op, +expr_add_cmp(struct nftnl_rule *r, uint32_t sreg, uint32_t op, const void *data, uint32_t data_len) { - struct nft_rule_expr *e; + struct nftnl_expr *e; - e = nft_rule_expr_alloc("cmp"); + e = nftnl_expr_alloc("cmp"); if (e == NULL) { - perror("expr cmp oom"); - exit(EXIT_FAILURE); + log_error("nftnl_expr_alloc(\"%s\") FAILED", "cmp"); + return; } - nft_rule_expr_set_u32(e, NFT_EXPR_CMP_SREG, sreg); - nft_rule_expr_set_u32(e, NFT_EXPR_CMP_OP, op); - nft_rule_expr_set(e, NFT_EXPR_CMP_DATA, data, data_len); + nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_SREG, sreg); + nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_OP, op); + nftnl_expr_set(e, NFTNL_EXPR_CMP_DATA, data, data_len); - nft_rule_add_expr(r, e); + nftnl_rule_add_expr(r, e); } static void -expr_add_meta(struct nft_rule *r, uint32_t meta_key, uint32_t dreg) +expr_add_meta(struct nftnl_rule *r, uint32_t meta_key, uint32_t dreg) { - struct nft_rule_expr *e; + struct nftnl_expr *e; - e = nft_rule_expr_alloc("meta"); + e = nftnl_expr_alloc("meta"); if (e == NULL) { - perror("expr meta oom"); - exit(EXIT_FAILURE); + log_error("nftnl_expr_alloc(\"%s\") FAILED", "meta"); + return; } - nft_rule_expr_set_u32(e, NFT_EXPR_META_KEY, meta_key); - nft_rule_expr_set_u32(e, NFT_EXPR_META_DREG, dreg); + nftnl_expr_set_u32(e, NFTNL_EXPR_META_KEY, meta_key); + nftnl_expr_set_u32(e, NFTNL_EXPR_META_DREG, dreg); - nft_rule_add_expr(r, e); + nftnl_rule_add_expr(r, e); } static void -expr_set_reg_val_u32(struct nft_rule *r, enum nft_registers dreg, uint32_t val) +expr_set_reg_val_u32(struct nftnl_rule *r, enum nft_registers dreg, uint32_t val) { - struct nft_rule_expr *e; - e = nft_rule_expr_alloc("immediate"); + struct nftnl_expr *e; + e = nftnl_expr_alloc("immediate"); if (e == NULL) { - perror("expr dreg oom"); - exit(EXIT_FAILURE); + log_error("nftnl_expr_alloc(\"%s\") FAILED", "immediate"); + return; } - nft_rule_expr_set_u32(e, NFT_EXPR_IMM_DREG, dreg); - nft_rule_expr_set_u32(e, NFT_EXPR_IMM_DATA, val); - nft_rule_add_expr(r, e); + nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, dreg); + nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DATA, val); + nftnl_rule_add_expr(r, e); } static void -expr_set_reg_val_u16(struct nft_rule *r, enum nft_registers dreg, uint32_t val) +expr_set_reg_val_u16(struct nftnl_rule *r, enum nft_registers dreg, uint32_t val) { - struct nft_rule_expr *e; - e = nft_rule_expr_alloc("immediate"); + struct nftnl_expr *e; + e = nftnl_expr_alloc("immediate"); if (e == NULL) { - perror("expr dreg oom"); - exit(EXIT_FAILURE); + log_error("nftnl_expr_alloc(\"%s\") FAILED", "immediate"); + return; } - nft_rule_expr_set_u32(e, NFT_EXPR_IMM_DREG, dreg); - nft_rule_expr_set_u16(e, NFT_EXPR_IMM_DATA, val); - nft_rule_add_expr(r, e); + nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, dreg); + nftnl_expr_set_u16(e, NFTNL_EXPR_IMM_DATA, val); + nftnl_rule_add_expr(r, e); } static void -expr_set_reg_verdict(struct nft_rule *r, uint32_t val) +expr_set_reg_verdict(struct nftnl_rule *r, uint32_t val) { - struct nft_rule_expr *e; - e = nft_rule_expr_alloc("immediate"); + struct nftnl_expr *e; + e = nftnl_expr_alloc("immediate"); if (e == NULL) { - perror("expr dreg oom"); - exit(EXIT_FAILURE); + log_error("nftnl_expr_alloc(\"%s\") FAILED", "immediate"); + return; } - nft_rule_expr_set_u32(e, NFT_EXPR_IMM_DREG, NFT_REG_VERDICT); - nft_rule_expr_set_u32(e, NFT_EXPR_IMM_VERDICT, val); - nft_rule_add_expr(r, e); + nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT); + nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_VERDICT, val); + nftnl_rule_add_expr(r, e); } static void -expr_add_nat(struct nft_rule *r, uint32_t t, uint32_t family, +expr_add_nat(struct nftnl_rule *r, uint32_t t, uint32_t family, in_addr_t addr_min, uint32_t proto_min, uint32_t flags) { - struct nft_rule_expr *e; + struct nftnl_expr *e; UNUSED(flags); - e = nft_rule_expr_alloc("nat"); + e = nftnl_expr_alloc("nat"); if (e == NULL) { - perror("expr nat oom"); - exit(EXIT_FAILURE); + log_error("nftnl_expr_alloc(\"%s\") FAILED", "nat"); + return; } - nft_rule_expr_set_u32(e, NFT_EXPR_NAT_TYPE, t); - nft_rule_expr_set_u32(e, NFT_EXPR_NAT_FAMILY, family); + nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_TYPE, t); + nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_FAMILY, family); + /* To IP Address */ expr_set_reg_val_u32(r, NFT_REG_1, (uint32_t)addr_min); - nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1); - nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MAX, NFT_REG_1); + nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1); + nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_ADDR_MAX, NFT_REG_1); + /* To Port */ expr_set_reg_val_u16(r, NFT_REG_2, proto_min); - nft_rule_expr_set_u16(e, NFT_EXPR_NAT_REG_PROTO_MIN, NFT_REG_2); - nft_rule_expr_set_u16(e, NFT_EXPR_NAT_REG_PROTO_MAX, NFT_REG_2); + nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_PROTO_MIN, NFT_REG_2); + nftnl_expr_set_u32(e, NFTNL_EXPR_NAT_REG_PROTO_MAX, NFT_REG_2); - nft_rule_add_expr(r, e); + nftnl_rule_add_expr(r, e); } - -/* - * Todo: add expr for rhost - */ -struct nft_rule * +struct nftnl_rule * rule_set_snat(uint8_t family, uint8_t proto, in_addr_t rhost, unsigned short rport, in_addr_t ehost, unsigned short eport, @@ -853,158 +866,251 @@ const char *descr, const char *handle) { - struct nft_rule *r = NULL; - uint32_t destport; - in_addr_t addr[2]; - uint16_t port[2]; - uint32_t descr_len; + struct nftnl_rule *r = NULL; + uint16_t dport, sport; UNUSED(handle); - r = nft_rule_alloc(); + r = nftnl_rule_alloc(); if (r == NULL) { - perror("OOM"); - exit(EXIT_FAILURE); + log_error("nftnl_rule_alloc() FAILED"); + return NULL; } - nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, NFT_TABLE_NAT); - nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, miniupnpd_nft_peer_chain); - if (descr != NULL) { - descr_len = strlen(descr); - nft_rule_attr_set_data(r, NFT_RULE_ATTR_USERDATA, - descr, descr_len); + nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); + nftnl_rule_set_str(r, NFTNL_RULE_TABLE, nft_table); + nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, nft_postrouting_chain); + + if (descr != NULL && *descr != '\0') { + nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, + descr, strlen(descr)); } - nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FAMILY, family); - addr[0] = ihost; - addr[1] = rhost; + /* Destination IP */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, daddr), sizeof(uint32_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &ihost, sizeof(uint32_t)); + + /* Source IP */ expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, saddr), sizeof(uint32_t)*2); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, addr, sizeof(uint32_t)*2); + offsetof(struct iphdr, saddr), sizeof(in_addr_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &rhost, sizeof(in_addr_t)); + /* Protocol */ expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, protocol), sizeof(uint8_t)); + offsetof(struct iphdr, protocol), sizeof(uint8_t)); expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); - port[0] = htons(iport); - port[1] = htons(rport); + /* Source and Destination Port of Protocol */ if (proto == IPPROTO_TCP) { + /* Destination Port */ + dport = htons(iport); expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct tcphdr, source), - sizeof(uint32_t)); + offsetof(struct tcphdr, dest), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); + + /* Source Port */ + sport = htons(rport); + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct tcphdr, source), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t)); } else if (proto == IPPROTO_UDP) { + /* Destination Port */ + dport = htons(iport); expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct udphdr, source), - sizeof(uint32_t)); + offsetof(struct udphdr, dest), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); + + /* Source Port */ + sport = htons(rport); + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct udphdr, source), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t)); } - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, port, sizeof(uint32_t)); - destport = htons(eport); - expr_add_nat(r, NFT_NAT_SNAT, AF_INET, ehost, destport, 0); + expr_add_nat(r, NFT_NAT_SNAT, family, ehost, htons(eport), 0); + + debug_rule(r); return r; } -/* - * Todo: add expr for rhost - */ -struct nft_rule * +struct nftnl_rule * rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto, in_addr_t rhost, unsigned short eport, in_addr_t ihost, uint32_t iport, const char *descr, const char *handle) { - struct nft_rule *r = NULL; + struct nftnl_rule *r = NULL; uint16_t dport; uint64_t handle_num; uint32_t if_idx; - uint32_t descr_len; UNUSED(handle); - UNUSED(rhost); - r = nft_rule_alloc(); + r = nftnl_rule_alloc(); if (r == NULL) { - perror("OOM"); - exit(EXIT_FAILURE); + log_error("nftnl_rule_alloc() FAILED"); + return NULL; } - nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, NFT_TABLE_NAT); - nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, miniupnpd_nft_nat_chain); - nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FAMILY, family); - if (descr != NULL) { - descr_len = strlen(descr); - nft_rule_attr_set_data(r, NFT_RULE_ATTR_USERDATA, - descr, descr_len); + nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); + nftnl_rule_set_str(r, NFTNL_RULE_TABLE, nft_table); + nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, nft_prerouting_chain); + + if (descr != NULL && *descr != '\0') { + nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, + descr, strlen(descr)); } if (handle != NULL) { handle_num = atoll(handle); - nft_rule_attr_set_u64(r, NFT_RULE_ATTR_POSITION, handle_num); + nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle_num); } if (ifname != NULL) { if_idx = (uint32_t)if_nametoindex(ifname); expr_add_meta(r, NFT_META_IIF, NFT_REG_1); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &if_idx, + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &if_idx, sizeof(uint32_t)); } + /* Source IP */ + if (rhost != 0) { + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, saddr), sizeof(in_addr_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &rhost, sizeof(in_addr_t)); + } + + /* Protocol */ expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, protocol), sizeof(uint8_t)); + offsetof(struct iphdr, protocol), sizeof(uint8_t)); expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); if (proto == IPPROTO_TCP) { dport = htons(eport); expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct tcphdr, dest), - sizeof(uint16_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, - sizeof(uint16_t)); + offsetof(struct tcphdr, dest), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); } else if (proto == IPPROTO_UDP) { dport = htons(eport); expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct udphdr, dest), - sizeof(uint16_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, - sizeof(uint16_t)); + offsetof(struct udphdr, dest), sizeof(uint16_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); } - expr_add_nat(r, NFT_NAT_DNAT, AF_INET, ihost, htons(iport), 0); + expr_add_nat(r, NFT_NAT_DNAT, family, ihost, htons(iport), 0); + + debug_rule(r); return r; } -struct nft_rule * +struct nftnl_rule * rule_set_filter(uint8_t family, const char * ifname, uint8_t proto, - in_addr_t rhost, in_addr_t iaddr, unsigned short eport, - unsigned short iport, const char *descr, const char *handle) + in_addr_t rhost, in_addr_t iaddr, + unsigned short eport, unsigned short iport, + unsigned short rport, const char *descr, const char *handle) { - struct nft_rule *r = NULL; - uint16_t dport; - uint64_t handle_num; - uint32_t if_idx; - uint32_t descr_len; + struct nftnl_rule *r = NULL; UNUSED(eport); - r = nft_rule_alloc(); + r = nftnl_rule_alloc(); if (r == NULL) { - perror("OOM"); - exit(EXIT_FAILURE); + log_error("nftnl_rule_alloc() FAILED"); + return NULL; } - nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, NFT_TABLE_FILTER); - nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, miniupnpd_nft_forward_chain); - nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FAMILY, family); - if (descr != NULL) { - descr_len = strlen(descr); - nft_rule_attr_set_data(r, NFT_RULE_ATTR_USERDATA, - descr, descr_len); + r = rule_set_filter_common(r, family, ifname, proto, eport, iport, rport, descr, handle); + + /* Destination IP */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, daddr), sizeof(uint32_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &iaddr, sizeof(uint32_t)); + + /* Source IP */ + if (rhost != 0) { + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, saddr), sizeof(in_addr_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &rhost, + sizeof(in_addr_t)); + } + + /* Protocol */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct iphdr, protocol), sizeof(uint8_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); + + expr_set_reg_verdict(r, NF_ACCEPT); + + debug_rule(r); + + return r; +} + +struct nftnl_rule * +rule_set_filter6(uint8_t family, const char * ifname, uint8_t proto, + struct in6_addr *rhost6, struct in6_addr *iaddr6, + unsigned short eport, unsigned short iport, + unsigned short rport, const char *descr, const char *handle) +{ + struct nftnl_rule *r = NULL; + UNUSED(eport); + + r = nftnl_rule_alloc(); + if (r == NULL) { + log_error("nftnl_rule_alloc() FAILED"); + return NULL; + } + + r = rule_set_filter_common(r, family, ifname, proto, eport, iport, rport, descr, handle); + + /* Destination IP */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct ipv6hdr, daddr), sizeof(struct in6_addr)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, iaddr6, sizeof(struct in6_addr)); + + /* Source IP */ + if (rhost6) { + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct ipv6hdr, saddr), sizeof(struct in6_addr)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, rhost6, sizeof(struct in6_addr)); + } + + /* Protocol */ + expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, + offsetof(struct ipv6hdr, nexthdr), sizeof(uint8_t)); + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); + + expr_set_reg_verdict(r, NF_ACCEPT); + + debug_rule(r); + + return r; +} + +struct nftnl_rule * +rule_set_filter_common(struct nftnl_rule *r, uint8_t family, const char * ifname, + uint8_t proto, unsigned short eport, unsigned short iport, + unsigned short rport, const char *descr, const char *handle) +{ + uint16_t dport, sport; + uint64_t handle_num; + uint32_t if_idx; + UNUSED(eport); + + nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family); + nftnl_rule_set_str(r, NFTNL_RULE_TABLE, nft_table); + nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, nft_forward_chain); + + if (descr != NULL && *descr != '\0') { + nftnl_rule_set_data(r, NFTNL_RULE_USERDATA, + descr, strlen(descr)); } if (handle != NULL) { handle_num = atoll(handle); - nft_rule_attr_set_u64(r, NFT_RULE_ATTR_POSITION, handle_num); + nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle_num); } if (ifname != NULL) { @@ -1014,47 +1120,48 @@ sizeof(uint32_t)); } - expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, daddr), sizeof(uint32_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &iaddr, sizeof(uint32_t)); - - expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, protocol), sizeof(uint8_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &proto, sizeof(uint8_t)); - + /* Destination Port */ dport = htons(iport); - expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, - offsetof(struct tcphdr, dest), sizeof(uint16_t)); + if (proto == IPPROTO_TCP) { + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct tcphdr, dest), sizeof(uint16_t)); + } else if (proto == IPPROTO_UDP) { + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct udphdr, dest), sizeof(uint16_t)); + } expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &dport, sizeof(uint16_t)); - if (rhost != 0) { - expr_add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, - offsetof(struct iphdr, saddr), - sizeof(in_addr_t)); - expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &rhost, - sizeof(in_addr_t)); + /* Source Port */ + if (rport != 0) { + sport = htons(rport); + if (proto == IPPROTO_TCP) { + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct tcphdr, source), sizeof(uint16_t)); + } else if (proto == IPPROTO_UDP) { + expr_add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + offsetof(struct udphdr, source), sizeof(uint16_t)); + } + expr_add_cmp(r, NFT_REG_1, NFT_CMP_EQ, &sport, sizeof(uint16_t)); } - expr_set_reg_verdict(r, NF_ACCEPT); - return r; } -struct nft_rule * +struct nftnl_rule * rule_del_handle(rule_t *rule) { - struct nft_rule *r = NULL; + struct nftnl_rule *r = NULL; - r = nft_rule_alloc(); + r = nftnl_rule_alloc(); if (r == NULL) { - perror("OOM"); - exit(EXIT_FAILURE); + log_error("nftnl_rule_alloc() FAILED"); + return NULL; } - nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, rule->table); - nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, rule->chain); - nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FAMILY, rule->family); - nft_rule_attr_set_u64(r, NFT_RULE_ATTR_HANDLE, rule->handle); + nftnl_rule_set_str(r, NFTNL_RULE_TABLE, rule->table); + nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, rule->chain); + nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, rule->family); + nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, rule->handle); return r; } @@ -1077,69 +1184,224 @@ } int -nft_send_request(struct nft_rule * rule, uint16_t cmd) +nft_send_rule(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type chain_type) { + int result = -1; struct nlmsghdr *nlh; struct mnl_nlmsg_batch *batch; - char buf[MNL_SOCKET_BUFFER_SIZE]; - uint32_t seq = time(NULL); - int ret; + char buf[MNL_SOCKET_BUFFER_SIZE*2]; - rule_list_validate = RULE_CACHE_INVALID; - if (nl == NULL) { - nl = mnl_socket_open(NETLINK_NETFILTER); - if (nl == NULL) { - perror("mnl_socket_open"); - return -1; + batch = start_batch(buf, MNL_SOCKET_BUFFER_SIZE); + if (batch != NULL) + { + switch (chain_type) { + case RULE_CHAIN_FILTER: + rule_list_filter_validate = RULE_CACHE_INVALID; + break; + case RULE_CHAIN_PEER: + rule_list_peer_validate = RULE_CACHE_INVALID; + break; + case RULE_CHAIN_REDIRECT: + rule_list_redirect_validate = RULE_CACHE_INVALID; + break; + } + nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), + cmd, + nftnl_rule_get_u32(rule, NFTNL_RULE_FAMILY), + NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, + mnl_seq++); + + nftnl_rule_nlmsg_build_payload(nlh, rule); + nftnl_rule_free(rule); + + result = send_batch(batch); + if (result < 0) { + syslog(LOG_ERR, "%s(%p, %d, %d) send_batch failed %d", + "nft_send_rule", rule, (int)cmd, (int)chain_type, result); } + } - if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { - perror("mnl_socket_bind"); - return -1; + return result; +} + +int +table_op( enum nf_tables_msg_types op, uint16_t family, const char * name) +{ + int result; + struct nlmsghdr *nlh; + struct mnl_nlmsg_batch *batch; + char buf[MNL_SOCKET_BUFFER_SIZE*2]; + + struct nftnl_table *table; + + // log_debug("(%d, %d, %s)", op, family, name); + + table = nftnl_table_alloc(); + if (table == NULL) { + log_error("out of memory: %m"); + result = -1; + } else { + nftnl_table_set_u32(table, NFTNL_TABLE_FAMILY, family); + nftnl_table_set_str(table, NFTNL_TABLE_NAME, name); + + batch = start_batch(buf, MNL_SOCKET_BUFFER_SIZE); + if (batch == NULL) { + log_error("out of memory: %m"); + result = -2; + } else { + nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), + op, family, + (op == NFT_MSG_NEWTABLE ? NLM_F_CREATE : 0) | NLM_F_ACK, + mnl_seq++); + nftnl_table_nlmsg_build_payload(nlh, table); + + result = send_batch(batch); + if (result < 0) { + syslog(LOG_ERR, "%s(%d, %d, %s) send_batch failed %d", + "table_op", (int)op, (int)family, name, result); + } } + nftnl_table_free(table); } + return result; +} - batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); +/* + * return values : + * -2 : out of memory (nftnl_chain_alloc) + * -3 : out of memory (start batch) + * -4 : failed to build header + */ +int +chain_op(enum nf_tables_msg_types op, uint16_t family, const char * table, + const char * name, const char * type, uint32_t hooknum, signed int priority ) +{ + int result = -1; + struct nlmsghdr *nlh; + struct mnl_nlmsg_batch *batch; + char buf[MNL_SOCKET_BUFFER_SIZE*2]; - nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), - NFNL_MSG_BATCH_BEGIN, seq++); - mnl_nlmsg_batch_next(batch); + struct nftnl_chain *chain; - nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), - cmd, - nft_rule_attr_get_u32(rule, NFT_RULE_ATTR_FAMILY), - NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, - seq++); + // log_debug("(%d, %d, %s, %s, %s, %d, %d)", op, family, table, name, type, hooknum, priority); - nft_rule_nlmsg_build_payload(nlh, rule); - nft_rule_free(rule); - mnl_nlmsg_batch_next(batch); + chain = nftnl_chain_alloc(); + if (chain == NULL) { + log_error("out of memory: %m"); + result = -2; + } else { + nftnl_chain_set_u32(chain, NFTNL_CHAIN_FAMILY, family); + nftnl_chain_set_str(chain, NFTNL_CHAIN_TABLE, table); + nftnl_chain_set_str(chain, NFTNL_CHAIN_NAME, name); + if (op == NFT_MSG_NEWCHAIN) { + nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, type); + nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, hooknum); + nftnl_chain_set_s32(chain, NFTNL_CHAIN_PRIO, priority); + } - nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, - seq++); - mnl_nlmsg_batch_next(batch); + batch = start_batch(buf, MNL_SOCKET_BUFFER_SIZE); + if (batch == NULL) { + log_error("out of memory: %m"); + result = -3; + } else { + nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), + op, family, + (op == NFT_MSG_NEWCHAIN ? NLM_F_CREATE : 0) | NLM_F_ACK, + mnl_seq++); + if (nlh == NULL) + { + log_error("failed to build header: %m"); + result = -4; + } else { + nftnl_chain_nlmsg_build_payload(nlh, chain); - ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), - mnl_nlmsg_batch_size(batch)); - if (ret == -1) { - perror("mnl_socket_sendto"); - return -1; + result = send_batch(batch); + if (result < 0) { + syslog(LOG_ERR, "%s(%d, %d, %s, %s, %s, %u, %d) send_batch failed %d", + "chain_op", (int)op, (int)family, table, name, type, + hooknum, priority, result); + } + } + } + nftnl_chain_free(chain); } + return result; +} - mnl_nlmsg_batch_stop(batch); +/** + * the buffer that you have to use to store the batch must be double + * of MNL_SOCKET_BUFFER_SIZE + * @see https://www.netfilter.org/projects/libmnl/doxygen/html/group__batch.html + */ +struct mnl_nlmsg_batch * +start_batch(char *buf, size_t buf_size) +{ + struct mnl_nlmsg_batch *result; + mnl_seq = time(NULL); - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) { - perror("mnl_socket_recvfrom"); - return -1; + if (mnl_sock == NULL) { + log_error("netlink not connected"); + result = NULL; + } else { + result = mnl_nlmsg_batch_start(buf, buf_size); + if (result != NULL) { + nft_mnl_batch_put(mnl_nlmsg_batch_current(result), + NFNL_MSG_BATCH_BEGIN, mnl_seq++); + mnl_nlmsg_batch_next(result); + } } - ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL); - if (ret < 0) { - perror("mnl_cb_run"); - return -1; + return result; +} + +/** + * return codes : + * 0 : OK + * -1 : netlink not connected + * -2 : mnl_socket_sendto() error + * -3 : mnl_socket_recvfrom() error + * -4 : mnl_cb_run() error + */ +int +send_batch(struct mnl_nlmsg_batch *batch) +{ + int ret; + ssize_t n; + char buf[MNL_SOCKET_BUFFER_SIZE]; + + mnl_nlmsg_batch_next(batch); + + nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, mnl_seq++); + mnl_nlmsg_batch_next(batch); + + if (mnl_sock == NULL) { + log_error("netlink not connected"); + return -1; + } + + n = mnl_socket_sendto(mnl_sock, mnl_nlmsg_batch_head(batch), + mnl_nlmsg_batch_size(batch)); + if (n == -1) { + log_error("mnl_socket_sendto() FAILED: %m"); + return -2; } + mnl_nlmsg_batch_stop(batch); - /* mnl_socket_close(nl); */ + do { + n = mnl_socket_recvfrom(mnl_sock, buf, sizeof(buf)); + if (n == -1) { + log_error("mnl_socket_recvfrom() FAILED: %m"); + return -3; + } else if (n == 0) { + break; + } + ret = mnl_cb_run(buf, n, 0, mnl_portid, NULL, NULL); + if (ret <= -1 /*== MNL_CB_ERROR*/) { + syslog(LOG_ERR, "%s: mnl_cb_run returned %d", + "send_batch", ret); + return -4; + } + } while (ret >= 1 /*== MNL_CB_OK*/); + /* ret == MNL_CB_STOP */ return 0; } diff -Nru miniupnpd-2.1/netfilter_nft/nftnlrdr_misc.h miniupnpd-2.2.1/netfilter_nft/nftnlrdr_misc.h --- miniupnpd-2.1/netfilter_nft/nftnlrdr_misc.h 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/nftnlrdr_misc.h 2020-10-30 21:23:38.000000000 +0000 @@ -2,14 +2,20 @@ * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2015 Tomofumi Hayashi - * + * (c) 2019 Paul Chambers + * (c) 2020 Thomas Bernard + * * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution. */ #include -#define NFT_TABLE_NAT "nat" -#define NFT_TABLE_FILTER "filter" +extern const char * nft_table; +extern const char * nft_prerouting_chain; +extern const char * nft_postrouting_chain; +extern const char * nft_forward_chain; + +#define NFT_DESCR_SIZE 1024 enum rule_reg_type { RULE_REG_NONE, @@ -18,22 +24,31 @@ RULE_REG_IP_SRC_ADDR, RULE_REG_IP_DEST_ADDR, RULE_REG_IP_SD_ADDR, /* source & dest */ + RULE_REG_IP6_SRC_ADDR, + RULE_REG_IP6_DEST_ADDR, + RULE_REG_IP6_SD_ADDR, /* source & dest */ RULE_REG_IP_PROTO, + RULE_REG_IP6_PROTO, RULE_REG_TCP_DPORT, RULE_REG_TCP_SD_PORT, /* source & dest */ - RULE_REG_IMM_VAL, + RULE_REG_IMM_VAL, /* immediate */ RULE_REG_MAX, }; enum rule_type { RULE_NONE, RULE_NAT, - RULE_SNAT, RULE_FILTER, RULE_COUNTER, }; -typedef struct rule_ { +enum rule_chain_type { + RULE_CHAIN_FILTER, + RULE_CHAIN_PEER, + RULE_CHAIN_REDIRECT, +}; + +typedef struct rule_t { LIST_ENTRY(rule_t) entry; char * table; char * chain; @@ -47,6 +62,8 @@ in_addr_t eaddr; in_addr_t iaddr; in_addr_t rhost; + struct in6_addr iaddr6; + struct in6_addr rhost6; uint16_t eport; uint16_t iport; uint16_t rport; @@ -57,35 +74,79 @@ uint32_t reg2_val; uint64_t packets; uint64_t bytes; - char *desc; + char * desc; + uint32_t desc_len; } rule_t; -LIST_HEAD(rule_list, rule_); -extern struct rule_list head; -extern rule_t **peer_cache; -extern rule_t **redirect_cache; +LIST_HEAD(rule_list, rule_t); +extern struct rule_list head_filter; +extern struct rule_list head_redirect; +extern struct rule_list head_peer; +/** called at initialization. + * establishes persistent connection to mnl/netfilter socket, needs elevated privilege */ int -nft_send_request(struct nft_rule * rule, uint16_t cmd); -struct nft_rule * +nft_mnl_connect(void); + +/** called at shutdown, to release the mnl/netfilter socket */ +void +nft_mnl_disconnect(void); + +#ifdef DEBUG +void +print_rule(const char *func, int line, const struct nftnl_rule *rule); + +void +print_redirect_rules(const char * ifname); + +#define debug_rule(rule) do { print_rule(__func__, __LINE__, rule); } while (0) + +#else +#define debug_rule(rule) +#endif + +int +nft_send_rule(struct nftnl_rule * rule, uint16_t cmd, enum rule_chain_type type); +struct nftnl_rule * rule_set_dnat(uint8_t family, const char * ifname, uint8_t proto, in_addr_t rhost, unsigned short eport, in_addr_t ihost, uint32_t iport, const char *descr, const char *handle); -struct nft_rule * +struct nftnl_rule * rule_set_snat(uint8_t family, uint8_t proto, in_addr_t rhost, unsigned short rport, in_addr_t ehost, unsigned short eport, in_addr_t ihost, unsigned short iport, const char *descr, const char *handle); -struct nft_rule * +struct nftnl_rule * rule_set_filter(uint8_t family, const char * ifname, uint8_t proto, - in_addr_t rhost, in_addr_t iaddr, unsigned short eport, - unsigned short iport, const char * descr, const char *handle); -struct nft_rule * -rule_del_handle(rule_t *r); -void -reflesh_nft_cache(uint32_t family); -void print_rule(rule_t *r); + in_addr_t rhost, in_addr_t iaddr, + unsigned short eport, unsigned short iport, + unsigned short rport, const char * descr, const char *handle); +struct nftnl_rule * +rule_set_filter6(uint8_t family, const char * ifname, uint8_t proto, + struct in6_addr *rhost6, struct in6_addr *iaddr6, + unsigned short eport, unsigned short iport, + unsigned short rport, const char *descr, const char *handle); +struct nftnl_rule * +rule_set_filter_common(struct nftnl_rule *r, uint8_t family, const char * ifname, + uint8_t proto, unsigned short eport, unsigned short iport, + unsigned short rport, const char *descr, const char *handle); +struct nftnl_rule *rule_del_handle(rule_t *r); +int refresh_nft_cache_filter(void); +int refresh_nft_cache_redirect(void); +int refresh_nft_cache_peer(void); +int refresh_nft_cache(struct rule_list *head, const char *table, const char *chain, uint32_t family, enum rule_type type); + +int +table_op(enum nf_tables_msg_types op, uint16_t family, const char * name); +int +chain_op(enum nf_tables_msg_types op, uint16_t family, const char * table, + const char * name, const char * type, uint32_t hooknum, signed int priority ); + +struct mnl_nlmsg_batch * +start_batch( char *buf, size_t buf_size); +int +send_batch(struct mnl_nlmsg_batch * batch); diff -Nru miniupnpd-2.1/netfilter_nft/nftpinhole.c miniupnpd-2.2.1/netfilter_nft/nftpinhole.c --- miniupnpd-2.1/netfilter_nft/nftpinhole.c 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/nftpinhole.c 2020-11-27 18:25:04.000000000 +0000 @@ -0,0 +1,470 @@ +/* $Id: nftpinhole.c,v 1.7 2020/11/11 12:08:43 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2012-2020 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../upnputils.h" +#include "nftpinhole.h" + +#include + +#include +#include +#include + +#include +#include +#include + +#include "tiny_nf_nat.h" + +#include "config.h" +#include "../macros.h" +#include "nftnlrdr.h" +#include "../upnpglobalvars.h" + +#include "nftnlrdr_misc.h" + +#ifdef DEBUG +#define d_printf(x) do { printf x; } while (0) +#else +#define d_printf(x) +#endif + +#ifdef ENABLE_UPNPPINHOLE + +static int next_uid = 1; + +#define PINEHOLE_LABEL_FORMAT "pinhole-%d ts-%u: %s" +#define PINEHOLE_LABEL_FORMAT_SKIPDESC "pinhole-%d ts-%u: %*s" + +void init_iptpinhole(void) +{ + return; +} + +void shutdown_iptpinhole(void) +{ + return; +} + +/* +ip saddr ip daddr tcp sport tcp dport +*/ +int add_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, const char * desc, unsigned int timestamp) +{ + int uid, res; + char comment[NFT_DESCR_SIZE]; + + struct nftnl_rule *r = NULL; + struct in6_addr rhost_addr, ihost_addr; + struct in6_addr *rhost_addr_p; + + uid = next_uid; + + d_printf(("add_pinhole(%s, %s, %s, %d, %d, %d, %s)\n", + ifname, rem_host, int_client, rem_port, int_port, proto, desc)); + + if (rem_host && rem_host[0] != '\0' && rem_host[0] != '*') { + inet_pton(AF_INET6, rem_host, &rhost_addr); + rhost_addr_p = &rhost_addr; + } else { + rhost_addr_p = NULL; + } + + inet_pton(AF_INET6, int_client, &ihost_addr); + + snprintf(comment, NFT_DESCR_SIZE, + PINEHOLE_LABEL_FORMAT, uid, timestamp, desc); + + r = rule_set_filter6(NFPROTO_INET, ifname, proto, + rhost_addr_p, &ihost_addr, + 0, int_port, rem_port, comment, 0); + + res = nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_FILTER); + + if (res < 0) + return -1; + + if (++next_uid >= 65535) { + next_uid = 1; + } + + return uid; +} + +int +find_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, + char *desc, int desc_len, unsigned int * timestamp) +{ + rule_t *p; + struct in6_addr saddr; + struct in6_addr daddr; + int uid; + unsigned int ts; + UNUSED(ifname); + + if (rem_host && rem_host[0] != '\0' && rem_host[0] != '*') { + inet_pton(AF_INET6, rem_host, &saddr); + } else { + memset(&saddr, 0, sizeof(struct in6_addr)); + } + inet_pton(AF_INET6, int_client, &daddr); + + d_printf(("find_pinhole()\n")); + refresh_nft_cache_filter(); + + LIST_FOREACH(p, &head_filter, entry) { + + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + if ((proto == p->proto) && (rem_port == p->rport) + && (0 == memcmp(&saddr, &p->rhost6, sizeof(struct in6_addr))) + && (int_port == p->eport) && + (0 == memcmp(&daddr, &p->iaddr6, sizeof(struct in6_addr)))) { + + if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) { + syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc); + continue; + } + + if (timestamp) + *timestamp = ts; + + if (desc) { + char * pd = strchr(p->desc, ':'); + if(pd) { + pd += 2; + strncpy(desc, pd, desc_len); + } + } + + return uid; + } + } + + return -2; /* not found */ +} + +int +delete_pinhole(unsigned short uid) +{ + rule_t *p; + struct nftnl_rule *r; + char label_start[NFT_DESCR_SIZE]; + char tmp_label[NFT_DESCR_SIZE]; + + snprintf(label_start, sizeof(label_start), + "pinhole-%hu", uid); + + d_printf(("delete_pinhole()\n")); + refresh_nft_cache_filter(); + + LIST_FOREACH(p, &head_filter, entry) { + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + strncpy(tmp_label, p->desc, p->desc_len); + strtok(tmp_label, " "); + if (0 == strcmp(tmp_label, label_start)) { + r = rule_del_handle(p); + nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); + return 0; + } + } + + return -2; +} + +int +update_pinhole(unsigned short uid, unsigned int timestamp) +{ +#ifdef DEBUG + char iaddr[INET6_ADDRSTRLEN]; +#endif + char raddr[INET6_ADDRSTRLEN]; + char label_start[NFT_DESCR_SIZE]; + char tmp_label[NFT_DESCR_SIZE]; + char desc[NFT_DESCR_SIZE]; + char ifname[IFNAMSIZ]; + char comment[NFT_DESCR_SIZE]; + char * tmp_p; + uint32_t ext_if_indx; + int proto, res; + unsigned short iport, rport; + rule_t *p; + struct in6_addr rhost_addr, ihost_addr; + struct in6_addr * rhost_addr_p; + struct nftnl_rule *r; + + d_printf(("update_pinhole()\n")); + + snprintf(label_start, sizeof(label_start), + "pinhole-%hu", uid); + + refresh_nft_cache_filter(); + + proto = -1; + memset(&rhost_addr, 0, sizeof(struct in6_addr)); + + LIST_FOREACH(p, &head_filter, entry) { + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + strncpy(tmp_label, p->desc, p->desc_len); + strtok(tmp_label, " "); + if (0 == strcmp(tmp_label, label_start)) { + /* Source IP Address */ + // Check if empty + if (0 == memcmp(&rhost_addr, &p->rhost6, sizeof(struct in6_addr))) { + rhost_addr_p = NULL; + raddr[0] = '*'; + raddr[1] = '\0'; + } else { + rhost_addr_p = &p->rhost6; + inet_ntop(AF_INET6, rhost_addr_p, raddr, INET6_ADDRSTRLEN); + } + + /* Source Port */ + rport = p->iport; + + /* Destination IP Address */ + ihost_addr = p->iaddr6; + + /* Destination Port */ + iport = p->eport; + + proto = p->proto; + + ext_if_indx = p->ingress_ifidx; + if_indextoname(ext_if_indx, ifname); + + tmp_p = tmp_label; + strsep(&tmp_p, " "); + if (tmp_p) { + strncpy(desc, tmp_p, NFT_DESCR_SIZE); + } else { + desc[0] = '\0'; + } + + break; + } + } + + if (proto == -1) + return -2; + + // Delete rule + r = rule_del_handle(p); + res = nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); + + if (res < 0) + return -1; + + // readd rule with new timestamp + snprintf(comment, NFT_DESCR_SIZE, + PINEHOLE_LABEL_FORMAT, uid, timestamp, desc); + + d_printf(("update add_pinhole(%s, %s, %s, %d, %d, %d, %s)\n", + ifname, raddr, inet_ntop(AF_INET6, &ihost_addr, iaddr, INET6_ADDRSTRLEN), rport, iport, proto, comment)); + + r = rule_set_filter6(NFPROTO_INET, ifname, proto, + rhost_addr_p, &ihost_addr, + 0, iport, rport, comment, 0); + + res = nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_FILTER); + + if (res < 0) + return -1; + + return 0; +} + +int +get_pinhole_info(unsigned short uid, + char * rem_host, int rem_hostlen, + unsigned short * rem_port, + char * int_client, int int_clientlen, + unsigned short * int_port, + int * proto, char * desc, int desclen, + unsigned int * timestamp, + u_int64_t * packets, u_int64_t * bytes) +{ + rule_t *p; + unsigned int ts; + char label_start[NFT_DESCR_SIZE]; + char tmp_label[NFT_DESCR_SIZE]; + + snprintf(label_start, sizeof(label_start), + "pinhole-%hu", uid); + + d_printf(("get_pinhole_info()\n")); + refresh_nft_cache_filter(); + + LIST_FOREACH(p, &head_filter, entry) { + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + strncpy(tmp_label, p->desc, p->desc_len); + strtok(tmp_label, " "); + if (0 == strcmp(tmp_label, label_start)) { + /* Source IP Address */ + if (rem_host && (rem_host[0] != '\0')) { + if(inet_ntop(AF_INET6, &p->rhost6, rem_host, rem_hostlen) == NULL) + return -1; + } + + /* Source Port */ + if (rem_port) + *rem_port = p->rport; + + /* Destination IP Address */ + if (int_client) { + if(inet_ntop(AF_INET6, &p->iaddr6, int_client, int_clientlen) == NULL) + return -1; + } + + /* Destination Port */ + if (int_port) + *int_port = p->eport; + + if (proto) + *proto = p->proto; + + if (timestamp) { + int uid_temp; + if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid_temp, &ts) != 2) { + syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc); + continue; + } + + *timestamp = ts; + } + + if (desc) + strncpy(desc, p->desc, desclen); + + if (packets || bytes) { + if (packets) + *packets = p->packets; + if (bytes) + *bytes = p->bytes; + } + + break; + } + } + + d_printf(("end_pinhole_info()\n")); + + return 0; +} + +int get_pinhole_uid_by_index(int index) +{ + UNUSED(index); + return -42; +} + +int +clean_pinhole_list(unsigned int * next_timestamp) +{ + rule_t *p; + struct nftnl_rule *r; + time_t current_time; + unsigned int ts; + int uid; + unsigned int min_ts = UINT_MAX; + int min_uid = INT_MAX, max_uid = -1; + int n = 0; + + current_time = upnp_time(); + + d_printf(("clean_pinhole_list()\n")); + refresh_nft_cache_filter(); + + LIST_FOREACH(p, &head_filter, entry) { + // Only forward entries + if (p->type != RULE_FILTER) + continue; + + if (p->desc_len == 0) + continue; + + if (sscanf(p->desc, PINEHOLE_LABEL_FORMAT_SKIPDESC, &uid, &ts) != 2) { + syslog(LOG_DEBUG, "rule with label '%s' is not a IGD pinhole", p->desc); + continue; + } + + if (ts <= (unsigned int)current_time) { + syslog(LOG_INFO, "removing expired pinhole '%s'", p->desc); + r = rule_del_handle(p); + nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER); + n++; + } else { + if (uid > max_uid) + max_uid = uid; + else if (uid < min_uid) + min_uid = uid; + if (ts < min_ts) + min_ts = ts; + } + } + + if (next_timestamp && (min_ts != UINT_MAX)) + *next_timestamp = min_ts; + + if (max_uid > 0) { + if (((min_uid - 32000) <= next_uid) && (next_uid <= max_uid)) { + next_uid = max_uid + 1; + } + + if (next_uid >= 65535) { + next_uid = 1; + } + } + + return n; /* number of rules removed */ +} + +#endif /* ENABLE_UPNPPINHOLE */ diff -Nru miniupnpd-2.1/netfilter_nft/nftpinhole.h miniupnpd-2.2.1/netfilter_nft/nftpinhole.h --- miniupnpd-2.1/netfilter_nft/nftpinhole.h 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/nftpinhole.h 2019-06-25 21:27:57.000000000 +0000 @@ -0,0 +1,43 @@ +/* $Id: nftpinhole.h,v 1.1 2019/06/25 21:27:57 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2012-2016 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#ifndef NFTPINHOLE_H_INCLUDED +#define NFTPINHOLE_H_INCLUDED + +#ifdef ENABLE_UPNPPINHOLE +#include + +int find_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, + char *desc, int desc_len, unsigned int * timestamp); + +int add_pinhole(const char * ifname, + const char * rem_host, unsigned short rem_port, + const char * int_client, unsigned short int_port, + int proto, const char *desc, unsigned int timestamp); + +int update_pinhole(unsigned short uid, unsigned int timestamp); + +int delete_pinhole(unsigned short uid); + +int +get_pinhole_info(unsigned short uid, + char * rem_host, int rem_hostlen, unsigned short * rem_port, + char * int_client, int int_clientlen, + unsigned short * int_port, + int * proto, char * desc, int desclen, + unsigned int * timestamp, + u_int64_t * packets, u_int64_t * bytes); + +int get_pinhole_uid_by_index(int index); + +int clean_pinhole_list(unsigned int * next_timestamp); + +#endif /* ENABLE_UPNPPINHOLE */ + +#endif diff -Nru miniupnpd-2.1/netfilter_nft/scripts/nft_delete_chain.sh miniupnpd-2.2.1/netfilter_nft/scripts/nft_delete_chain.sh --- miniupnpd-2.1/netfilter_nft/scripts/nft_delete_chain.sh 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_delete_chain.sh 2019-06-25 21:30:54.000000000 +0000 @@ -1,5 +1,5 @@ -#! /sbin/nft -f +#!/bin/sh -delete chain nat miniupnpd -delete chain nat miniupnpd-pcp-peer -delete chain filter miniupnpd +nft delete chain nat MINIUPNPD +nft delete chain nat MINIUPNPD-POSTROUTING +nft delete chain filter MINIUPNPD diff -Nru miniupnpd-2.1/netfilter_nft/scripts/nft_display.sh miniupnpd-2.2.1/netfilter_nft/scripts/nft_display.sh --- miniupnpd-2.1/netfilter_nft/scripts/nft_display.sh 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_display.sh 2019-06-25 21:26:46.000000000 +0000 @@ -0,0 +1,8 @@ +#!/bin/sh + +# Prerouting +nft list chain ip nat MINIUPNPD +# Postrouting +nft list chain ip nat MINIUPNPD-POSTROUTING +# Filter +nft list chain inet filter MINIUPNPD diff -Nru miniupnpd-2.1/netfilter_nft/scripts/nft_flush.sh miniupnpd-2.2.1/netfilter_nft/scripts/nft_flush.sh --- miniupnpd-2.1/netfilter_nft/scripts/nft_flush.sh 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_flush.sh 2019-06-25 21:30:54.000000000 +0000 @@ -1,5 +1,5 @@ -#! /sbin/nft -f +#!/bin/sh -flush chain ip nat miniupnpd -flush chain ip nat miniupnpd-pcp-peer -flush chain ip filter miniupnpd +nft flush chain ip nat MINIUPNPD +nft flush chain ip nat MINIUPNPD-POSTROUTING +nft flush chain inet filter MINIUPNPD diff -Nru miniupnpd-2.1/netfilter_nft/scripts/nft_init.sh miniupnpd-2.2.1/netfilter_nft/scripts/nft_init.sh --- miniupnpd-2.1/netfilter_nft/scripts/nft_init.sh 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_init.sh 2019-09-01 23:02:26.000000000 +0000 @@ -1,47 +1,23 @@ -#! /bin/sh +#!/bin/sh +# +# establish the chains that miniupnpd will update dynamically +# +# 'add' doesn't raise an error if the object already exists. 'create' does. +# -nft list table nat > /dev/null -nft_nat_exists=$? -nft list table filter > /dev/null -nft_filter_exists=$? -nft list table mangle > /dev/null -nft_mangle_exists=$? - -if [ $nft_nat_exists -eq "1" ]; then - echo "create nat" - nft "add table nat" -fi -if [ $nft_filter_exists -eq "1" ]; then - echo "create filter" - nft "add table filter" -fi -if [ $nft_mangle_exists -eq "1" ]; then - echo "create mangle" - nft "add table mangle" -fi - -nft list chain nat miniupnpd > /dev/null -nft_nat_miniupnpd_exists=$? -nft list chain nat miniupnpd-pcp-peer > /dev/null -nft_nat_miniupnpd_pcp_peer_exists=$? -nft list chain filter miniupnpd > /dev/null -nft_filter_miniupnpd_exists=$? -nft list chain mangle miniupnpd > /dev/null -nft_mangle_miniupnpd_exists=$? - -if [ $nft_nat_miniupnpd_exists -eq "1" ]; then - echo "create chain in nat" - nft "add chain nat miniupnpd" -fi -if [ $nft_nat_miniupnpd_pcp_peer_exists -eq "1" ]; then - echo "create pcp peer chain in nat" - nft "add chain nat miniupnpd-pcp-peer" -fi -if [ $nft_filter_miniupnpd_exists -eq "1" ]; then - echo "create chain in filter " - nft "add chain filter miniupnpd" -fi -if [ $nft_mangle_miniupnpd_exists -eq "1" ]; then - echo "create chain in mangle" - nft "add chain mangle miniupnpd" -fi +#opts="--echo" + +echo "create nat table" +nft ${opts} add table nat + +echo "create chain in nat table" +nft ${opts} add chain nat MINIUPNPD + +echo "create pcp peer chain in nat table" +nft ${opts} add chain nat MINIUPNPD-POSTROUTING + +echo "create filter table" +nft ${opts} add table inet filter + +echo "create chain in filter table" +nft ${opts} add chain inet filter MINIUPNPD diff -Nru miniupnpd-2.1/netfilter_nft/scripts/nft_removeall.sh miniupnpd-2.2.1/netfilter_nft/scripts/nft_removeall.sh --- miniupnpd-2.1/netfilter_nft/scripts/nft_removeall.sh 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/scripts/nft_removeall.sh 2019-09-01 23:02:26.000000000 +0000 @@ -1,5 +1,44 @@ -#! /sbin/nft -f +#!/bin/sh +# +# Undo the things nft_init.sh did +# +# Do not disturb other existing structures in nftables, e.g. those created by firewalld +# -delete rule nat miniupnpd -delete rule nat miniupnpd-pcp-peer -delete rule filter miniupnpd +nft --check list table nat > /dev/null 2>&1 +if [ $? -eq "0" ]; then +{ + # nat table exists, so first remove the chains we added + nft --check list chain nat MINIUPNPD > /dev/null 2>&1 + if [ $? -eq "0" ]; then + echo "Remove chain from nat table" + nft delete chain nat MINIUPNPD + fi + + nft --check list chain nat MINIUPNPD-POSTROUTING > /dev/null 2>&1 + if [ $? -eq "0" ]; then + echo "Remove pcp peer chain from nat table" + nft delete chain nat MINIUPNPD-POSTROUTING + fi + + # then remove the table itself + echo "Remove nat table" + nft delete table nat +} +fi + +nft --check list table inet filter > /dev/null 2>&1 +if [ $? -eq "0" ]; then +{ + # filter table exists, so first remove the chain we added + nft --check list chain inet filter MINIUPNPD > /dev/null 2>&1 + if [ $? -eq "0" ]; then + echo "Remove chain from filter table" + nft delete chain inet filter MINIUPNPD + fi + + # then remove the table itself + echo "Remove filter table" + nft delete table inet filter +} +fi diff -Nru miniupnpd-2.1/netfilter_nft/test_nfct_get.c miniupnpd-2.2.1/netfilter_nft/test_nfct_get.c --- miniupnpd-2.1/netfilter_nft/test_nfct_get.c 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/test_nfct_get.c 2019-06-30 20:27:11.000000000 +0000 @@ -1,3 +1,6 @@ +/* $Id: test_nfct_get.c,v 1.2 2019/06/30 19:49:18 nanard Exp $ */ +#include +#include #include "nfct_get.c" int main(int argc, char *argv[]) @@ -5,8 +8,12 @@ struct sockaddr_storage src, dst, ext; char buff[INET6_ADDRSTRLEN]; - if (argc!=5) - return 0; + if (argc!=5) { + fprintf(stderr, "Usage: %s SRC_IP SRC_PORT DST_IP DST_PORT\n", argv[0]); + return 1; + } + + openlog("test_nfct_get", LOG_PERROR|LOG_CONS, LOG_LOCAL0); if (1 != inet_pton(AF_INET, argv[1], &((struct sockaddr_in*)&src)->sin_addr)) { diff -Nru miniupnpd-2.1/netfilter_nft/testnftnlrdr.c miniupnpd-2.2.1/netfilter_nft/testnftnlrdr.c --- miniupnpd-2.1/netfilter_nft/testnftnlrdr.c 2015-04-30 09:05:08.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/testnftnlrdr.c 2020-10-30 21:23:38.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: testnftnlrdr.c,v 1.1 2015/04/30 09:05:08 nanard Exp $ */ +/* $Id: testnftnlrdr.c,v 1.4 2020/10/30 21:23:16 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -9,8 +9,17 @@ #include #include #include +/* for PRIu64 */ +#include + +#include +#include +#include +#include +#include #include "nftnlrdr.h" +#include "nftnlrdr_misc.h" #include "../commonrdr.h" #ifndef PRIu64 @@ -43,6 +52,10 @@ return -1; } openlog("testnftnlrdr", LOG_PERROR|LOG_CONS, LOG_LOCAL0); + if (init_redirect() < 0) { + fprintf(stderr, "init_redirect() FAILED\n"); + return -1; + } eport = (unsigned short)atoi(argv[1]); iaddr = argv[2]; iport = (unsigned short)atoi(argv[3]); @@ -84,8 +97,9 @@ printf("test\n"); } printf("trying to list nat rules :\n"); - list_redirect_rule(argv[1]); + print_redirect_rules(argv[1]); printf("deleting\n"); delete_redirect_and_filter_rules(eport, IPPROTO_TCP); + shutdown_redirect(); return 0; } diff -Nru miniupnpd-2.1/netfilter_nft/testnftpinhole.c miniupnpd-2.2.1/netfilter_nft/testnftpinhole.c --- miniupnpd-2.1/netfilter_nft/testnftpinhole.c 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/netfilter_nft/testnftpinhole.c 2020-10-30 21:23:38.000000000 +0000 @@ -0,0 +1,33 @@ +/* $Id: testnftpinhole.c,v 1.3 2020/10/30 21:23:16 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2012-2020 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include +#include + +#include "config.h" +#include "../miniupnpdtypes.h" +#include "nftpinhole.h" +#include "../commonrdr.h" +#include "../upnputils.h" + +struct lan_addr_list lan_addrs; +time_t startup_time = 0; + +int main(int argc, char * * argv) +{ + int uid; + + openlog("testnftpinhole", LOG_PERROR|LOG_CONS, LOG_LOCAL0); + + uid = add_pinhole("eth0", NULL, 0, "ff::123", 54321, IPPROTO_TCP, + "dummy description", upnp_time() + 60 /* timestamp */); + syslog(LOG_INFO, "uid=%d", uid); + return 0; +} + diff -Nru miniupnpd-2.1/objects.mk miniupnpd-2.2.1/objects.mk --- miniupnpd-2.1/objects.mk 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/objects.mk 2020-05-10 16:59:19.000000000 +0000 @@ -0,0 +1,9 @@ +BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ + upnpreplyparse.o minixml.o portinuse.o \ + upnpredirect.o getifaddr.o daemonize.o \ + options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ + upnpglobalvars.o upnpevents.o upnputils.o getconnstatus.o \ + upnpstun.o upnppinhole.o pcplearndscp.o asyncsendto.o + +# sources in linux/ directory +LNXOBJS = getifstats.o ifacewatcher.o getroute.o diff -Nru miniupnpd-2.1/options.c miniupnpd-2.2.1/options.c --- miniupnpd-2.1/options.c 2018-04-22 19:44:42.000000000 +0000 +++ miniupnpd-2.2.1/options.c 2020-05-10 18:11:16.000000000 +0000 @@ -1,8 +1,9 @@ -/* $Id: options.c,v 1.35 2018/04/22 19:36:58 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ +/* $Id: options.c,v 1.39 2020/04/09 18:40:42 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * author: Ryan Wagoner - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -29,10 +30,17 @@ const char * name; } optionids[] = { { UPNPEXT_IFNAME, "ext_ifname" }, +#ifdef ENABLE_IPV6 + { UPNPEXT_IFNAME6, "ext_ifname6" }, +#endif { UPNPEXT_IP, "ext_ip" }, + { UPNPEXT_PERFORM_STUN, "ext_perform_stun" }, + { UPNPEXT_STUN_HOST, "ext_stun_host" }, + { UPNPEXT_STUN_PORT, "ext_stun_port" }, { UPNPLISTENING_IP, "listening_ip" }, #ifdef ENABLE_IPV6 { UPNPIPV6_LISTENING_IP, "ipv6_listening_ip" }, + { UPNPIPV6_DISABLE, "ipv6_disable" }, #endif /* ENABLE_IPV6 */ { UPNPPORT, "port" }, { UPNPPORT, "http_port" }, /* "port" and "http_port" are synonims */ diff -Nru miniupnpd-2.1/options.h miniupnpd-2.2.1/options.h --- miniupnpd-2.1/options.h 2018-02-22 13:19:38.000000000 +0000 +++ miniupnpd-2.2.1/options.h 2020-05-10 18:11:16.000000000 +0000 @@ -1,8 +1,9 @@ -/* $Id: options.h,v 1.28 2018/02/22 13:18:58 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ +/* $Id: options.h,v 1.32 2020/04/09 18:40:42 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * author: Ryan Wagoner - * (c) 2006-2014 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -16,10 +17,17 @@ enum upnpconfigoptions { UPNP_INVALID = 0, UPNPEXT_IFNAME = 1, /* ext_ifname */ +#ifdef ENABLE_IPV6 + UPNPEXT_IFNAME6, /* ext_ifname6 */ +#endif UPNPEXT_IP, /* ext_ip */ + UPNPEXT_PERFORM_STUN, /* ext_perform_stun */ + UPNPEXT_STUN_HOST, /* ext_stun_host */ + UPNPEXT_STUN_PORT, /* ext_stun_port */ UPNPLISTENING_IP, /* listening_ip */ #ifdef ENABLE_IPV6 UPNPIPV6_LISTENING_IP, /* listening address for IPv6 */ + UPNPIPV6_DISABLE, /* ipv6_disable */ #endif /* ENABLE_IPV6 */ UPNPPORT, /* "port" / "http_port" */ #ifdef ENABLE_HTTPS @@ -95,4 +103,3 @@ #endif /* DISABLE_CONFIG_FILE */ #endif /* OPTIONS_H_INCLUDED */ - diff -Nru miniupnpd-2.1/pcpserver.c miniupnpd-2.2.1/pcpserver.c --- miniupnpd-2.1/pcpserver.c 2018-05-08 21:34:45.000000000 +0000 +++ miniupnpd-2.2.1/pcpserver.c 2020-06-06 18:02:59.000000000 +0000 @@ -1,6 +1,7 @@ -/* $Id: pcpserver.c,v 1.48 2018/05/08 21:28:28 nanard Exp $ */ -/* MiniUPnP project - * Website : http://miniupnp.free.fr/ +/* $Id: pcpserver.c,v 1.53 2020/06/06 17:47:38 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project + * Website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Peter Tatrai Copyright (c) 2013 by Cisco Systems, Inc. @@ -177,7 +178,7 @@ * buffers are same */ static void copyIPv6IfDifferent(void * dest, const void * src) { - if(dest != src) { + if(dest != src && src != NULL) { memcpy(dest, src, sizeof(struct in6_addr)); } } @@ -590,6 +591,17 @@ pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE; return -1; } +#ifdef ENABLE_IPV6 + } else if ((af == AF_INET6) && (ext_if_name6 != ext_if_name)) { + if(!ext_if_name6 || ext_if_name6[0]=='\0') { + pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE; + return -1; + } + if(getifaddr_in6(ext_if_name6, af, &external_addr) < 0) { + pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE; + return -1; + } +#endif } else { if(!ext_if_name || ext_if_name[0]=='\0') { pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE; @@ -686,6 +698,7 @@ char peerip_s[INET6_ADDRSTRLEN], extip_s[INET6_ADDRSTRLEN]; time_t timestamp = upnp_time() + pcp_msg_info->lifetime; int r; + const char * ext_if = ext_if_name; FillSA((struct sockaddr*)&intip, pcp_msg_info->mapped_ip, pcp_msg_info->int_port); @@ -718,9 +731,14 @@ eport = pcp_msg_info->int_port; } +#ifdef ENABLE_IPV6 + if (ret_extip.ss_family == AF_INET6) { + ext_if = ext_if_name6; + } +#endif #ifdef PCP_FLOWP if (pcp_msg_info->flowp_present && pcp_msg_info->dscp_up) { - if (add_peer_dscp_rule2(ext_if_name, peerip_s, + if (add_peer_dscp_rule2(ext_if, peerip_s, pcp_msg_info->peer_port, pcp_msg_info->dscp_up, pcp_msg_info->mapped_str, pcp_msg_info->int_port, proto, pcp_msg_info->desc, timestamp) < 0 ) { @@ -735,7 +753,7 @@ } if (pcp_msg_info->flowp_present && pcp_msg_info->dscp_down) { - if (add_peer_dscp_rule2(ext_if_name, pcp_msg_info->mapped_str, + if (add_peer_dscp_rule2(ext_if, pcp_msg_info->mapped_str, pcp_msg_info->int_port, pcp_msg_info->dscp_down, peerip_s, pcp_msg_info->peer_port, proto, pcp_msg_info->desc, timestamp) < 0 ) { @@ -751,7 +769,7 @@ } #endif - r = add_peer_redirect_rule2(ext_if_name, + r = add_peer_redirect_rule2(ext_if, peerip_s, pcp_msg_info->peer_port, extip_s, @@ -1434,7 +1452,7 @@ } -static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info) +static void createPCPResponse(unsigned char *response, const pcp_info_t *pcp_msg_info) { response[2] = 0; /* reserved */ memset(response + 12, 0, 12); /* reserved */ @@ -1445,7 +1463,7 @@ response[0] = pcp_msg_info->version; } - response[1] |= 0x80; /* r_opcode */ + response[1] = pcp_msg_info->opcode | 0x80; /* r_opcode */ response[3] = pcp_msg_info->result_code; if(epoch_origin == 0) { epoch_origin = startup_time; @@ -1664,19 +1682,24 @@ addr.sin_addr.s_addr = inet_addr("224.0.0.1"); addr.sin_port = htons(5350); for(i = 0; i < n_sockets; i++) { + if (sockets[i] < 0) { + continue; + } len = sendto_or_schedule(sockets[i], buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); if( len < 0 ) { - syslog(LOG_ERR, "PCPSendUnsolicitedAnnounce() sendto(): %m"); + syslog(LOG_ERR, "PCPSendUnsolicitedAnnounce(sockets[%d]) sendto(): %m", i); } } #ifdef ENABLE_IPV6 - memset(&addr6, 0, sizeof(struct sockaddr_in6)); - addr6.sin6_family = AF_INET6; - inet_pton(AF_INET6, "FF02::1", &(addr6.sin6_addr)); - addr6.sin6_port = htons(5350); - len = sendto_or_schedule(socket6, buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)); - if( len < 0 ) { - syslog(LOG_ERR, "PCPSendUnsolicitedAnnounce() IPv6 sendto(): %m"); + if (socket6 >= 0) { + memset(&addr6, 0, sizeof(struct sockaddr_in6)); + addr6.sin6_family = AF_INET6; + inet_pton(AF_INET6, "FF02::1", &(addr6.sin6_addr)); + addr6.sin6_port = htons(5350); + len = sendto_or_schedule(socket6, buff, PCP_MIN_LEN, 0, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)); + if( len < 0 ) { + syslog(LOG_ERR, "PCPSendUnsolicitedAnnounce() IPv6 sendto(): %m"); + } } #endif /* ENABLE_IPV6 */ } diff -Nru miniupnpd-2.1/pf/Makefile miniupnpd-2.2.1/pf/Makefile --- miniupnpd-2.1/pf/Makefile 2018-04-12 09:08:10.000000000 +0000 +++ miniupnpd-2.2.1/pf/Makefile 2020-10-31 09:20:00.000000000 +0000 @@ -1,7 +1,8 @@ -# $Id: Makefile,v 1.5 2016/01/19 10:03:30 nanard Exp $ +# $Id: Makefile,v 1.7 2020/05/21 00:10:56 nanard Exp $ # made for GNU Make (and BSD make) CFLAGS = -Wall -g -DTEST CFLAGS += -Wextra +CFLAGS += -I.. EXECUTABLES = testobsdrdr testpfpinhole all: $(EXECUTABLES) @@ -9,10 +10,10 @@ clean: rm -f *.o $(EXECUTABLES) -testobsdrdr: testobsdrdr.o obsdrdr.o +testobsdrdr: testobsdrdr.o obsdrdr.o getifaddr.o $(CC) $(CFLAGS) -o $@ $> -testpfpinhole: testpfpinhole.o obsdrdr.o pfpinhole.o +testpfpinhole: testpfpinhole.o obsdrdr.o pfpinhole.o getifaddr.o $(CC) $(CFLAGS) -o $@ $> obsdrdr.o: obsdrdr.c obsdrdr.h @@ -23,3 +24,4 @@ testpfpinhole.o: testpfpinhole.c pfpinhole.h +getifaddr.o: ../getifaddr.c diff -Nru miniupnpd-2.1/pf/obsdrdr.c miniupnpd-2.2.1/pf/obsdrdr.c --- miniupnpd-2.1/pf/obsdrdr.c 2018-04-22 19:44:43.000000000 +0000 +++ miniupnpd-2.2.1/pf/obsdrdr.c 2020-12-20 17:50:29.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: obsdrdr.c,v 1.89 2018/04/22 19:30:49 nanard Exp $ */ +/* $Id: obsdrdr.c,v 1.100 2020/12/20 17:43:40 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -64,9 +64,10 @@ #include #include "../macros.h" -#include "../config.h" +#include "config.h" #include "obsdrdr.h" #include "../upnpglobalvars.h" +#include "../getifaddr.h" #ifndef USE_PF #error "USE_PF macro is undefined, check consistency between config.h and Makefile" @@ -135,6 +136,7 @@ } /* /dev/pf when opened */ +extern int dev; /* global also used in pfpinhole.c */ int dev = -1; /* shutdown_redirect() : @@ -244,6 +246,260 @@ return -1; #endif } + +int +clear_nat_rules(void) +{ + struct pfioc_trans io; + struct pfioc_trans_e ioe; + if(dev<0) { + syslog(LOG_ERR, "pf device is not open"); + return -1; + } + memset(&ioe, 0, sizeof(ioe)); + io.size = 1; + io.esize = sizeof(ioe); + io.array = &ioe; +#ifndef PF_NEWSTYLE + ioe.rs_num = PF_RULESET_NAT; +#else + /* ? */ + ioe.type = PF_TRANS_RULESET; +#endif + strlcpy(ioe.anchor, anchor_name, MAXPATHLEN); + if(ioctl(dev, DIOCXBEGIN, &io) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCXBEGIN, ...): %m"); + goto error; + } + if(ioctl(dev, DIOCXCOMMIT, &io) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCXCOMMIT, ...): %m"); + goto error; + } + return 0; +error: + return -1; +} +#endif + +#ifdef ENABLE_PORT_TRIGGERING +/* add_nat_rule() + * nat on re0 inet proto udp from 192.168.1.49 port 3074 to any -> (re0) port 3148 + * is ext_if, (re0) is ext_ip + * should be created when a port mapping (3148 => 192.168.1.49:3074 UDP) is created. + * for symetric NAT / UPnP IGD NAT Port Triggering */ +int add_nat_rule(const char * ifname, + const char * rhost, unsigned short eport, + const char * iaddr, unsigned short iport, int proto, + const char * desc) +{ + int r; + struct pfioc_rule pcr; +#ifndef PF_NEWSTYLE + struct pfioc_pooladdr pp; + struct pf_pooladdr *a; +#endif + const char * extaddr; + char extaddr_buf[INET_ADDRSTRLEN]; + + if(dev<0) { + syslog(LOG_ERR, "pf device is not open"); + return -1; + } + if(use_ext_ip_addr && use_ext_ip_addr[0] != '\0') { + extaddr = use_ext_ip_addr; + } else { + if(getifaddr(ifname, extaddr_buf, INET_ADDRSTRLEN, NULL, NULL) < 0) { + syslog(LOG_WARNING, "failed to get address for interface %s", ifname); + return -1; + } + extaddr = extaddr_buf; + } + syslog(LOG_DEBUG, "use external ip %s", extaddr); + r = 0; + memset(&pcr, 0, sizeof(pcr)); + strlcpy(pcr.anchor, anchor_name, MAXPATHLEN); + +#ifndef PF_NEWSTYLE + memset(&pp, 0, sizeof(pp)); + strlcpy(pp.anchor, anchor_name, MAXPATHLEN); + if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m"); + r = -1; + } + else + { + pcr.pool_ticket = pp.ticket; +#else + { + pcr.rule.nat.addr.type = PF_ADDR_ADDRMASK; + pcr.rule.rdr.addr.type = PF_ADDR_NONE; +#endif + /*pcr.rule.src.addr.type = PF_ADDR_NONE;*/ + pcr.rule.src.addr.type = PF_ADDR_ADDRMASK; + pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK; + + pcr.rule.action = PF_NAT; + pcr.rule.af = AF_INET; +#ifdef USE_IFNAME_IN_RULES + if(ifname) + strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ); +#endif + pcr.rule.proto = proto; + pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0; /*logpackets;*/ +#ifdef PFRULE_HAS_RTABLEID + pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */ +#endif +#ifdef PFRULE_HAS_ONRDOMAIN + pcr.rule.onrdomain = -1; /* first appeared in OpenBSD 5.0 */ +#endif + pcr.rule.quick = 1; + pcr.rule.keep_state = PF_STATE_NORMAL; + if(tag) + strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE); + strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE); +#ifdef PFVAR_NEW_STYLE + inet_pton(AF_INET, iaddr, &pcr.rule.src.addr.v.a.addr.v4addr.s_addr); + pcr.rule.src.addr.v.a.mask.v4addr.s_addr = htonl(INADDR_NONE); +#else + inet_pton(AF_INET, iaddr, &pcr.rule.src.addr.v.a.addr.v4.s_addr); + pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); +#endif +#ifdef __APPLE__ + pcr.rule.src.xport.range.op = PF_OP_EQ; + pcr.rule.src.xport.range.port[0] = htons(iport); + pcr.rule.src.xport.range.port[1] = htons(iport); +#else + pcr.rule.src.port_op = PF_OP_EQ; + pcr.rule.src.port[0] = htons(iport); + pcr.rule.src.port[1] = htons(iport); +#endif + if(rhost && rhost[0] != '\0' && rhost[0] != '*') + { +#ifdef PFVAR_NEW_STYLE + inet_pton(AF_INET, rhost, &pcr.rule.dst.addr.v.a.addr.v4addr.s_addr); + pcr.rule.dst.addr.v.a.mask.v4addr.s_addr = htonl(INADDR_NONE); +#else + inet_pton(AF_INET, rhost, &pcr.rule.dst.addr.v.a.addr.v4.s_addr); + pcr.rule.dst.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); +#endif + } +#ifdef __APPLE__ + pcr.rule.dst.xport.range.op = PF_OP_NONE; +#else + pcr.rule.dst.port_op = PF_OP_NONE; +#endif + /* -> xxx.xxx.xxx.xxx port 1234 */ +#ifndef PF_NEWSTYLE + pcr.rule.rpool.proxy_port[0] = eport; + pcr.rule.rpool.proxy_port[1] = eport; + TAILQ_INIT(&pcr.rule.rpool.list); + a = calloc(1, sizeof(struct pf_pooladdr)); +#ifdef PFVAR_NEW_STYLE + inet_pton(AF_INET, extaddr, &a->addr.v.a.addr.v4addr.s_addr); + a->addr.v.a.mask.v4addr.s_addr = htonl(INADDR_NONE); +#else + inet_pton(AF_INET, extaddr, &a->addr.v.a.addr.v4.s_addr); + a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); +#endif + TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries); + + memcpy(&pp.addr, a, sizeof(struct pf_pooladdr)); + if(ioctl(dev, DIOCADDADDR, &pp) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m"); + r = -1; + } + else + { +#else + pcr.rule.nat.proxy_port[0] = eport; + pcr.rule.nat.proxy_port[1] = eport; + inet_pton(AF_INET, extaddr, &pcr.rule.nat.addr.v.a.addr.v4.s_addr); + pcr.rule.nat.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); + { +#endif /* PF_NEWSTYLE */ + pcr.action = PF_CHANGE_GET_TICKET; + if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m"); + r = -1; + } + else + { + pcr.action = PF_CHANGE_ADD_TAIL; + if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m"); + r = -1; + } + } + } +#ifndef PF_NEWSTYLE + free(a); +#endif + } + return r; +} + +static int +delete_nat_rule(const char * ifname, unsigned short iport, int proto, in_addr_t iaddr) +{ + int i, n; + struct pfioc_rule pr; + UNUSED(ifname); + if(dev<0) { + syslog(LOG_ERR, "pf device is not open"); + return -1; + } + memset(&pr, 0, sizeof(pr)); + strlcpy(pr.anchor, anchor_name, MAXPATHLEN); + pr.rule.action = PF_NAT; + if(ioctl(dev, DIOCGETRULES, &pr) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m"); + goto error; + } + n = pr.nr; + for(i=0; iaddr.v.a.addr.v4addr.s_addr); + a->addr.v.a.mask.v4addr.s_addr = htonl(INADDR_NONE); +#else inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr); a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); +#endif TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries); memcpy(&pp.addr, a, sizeof(struct pf_pooladdr)); @@ -367,9 +643,9 @@ { #endif pcr.action = PF_CHANGE_GET_TICKET; - if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) + if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) { - syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m"); + syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m"); r = -1; } else @@ -388,6 +664,13 @@ } if(r == 0 && timestamp > 0) add_timestamp_entry(eport, proto, timestamp); +#ifdef ENABLE_PORT_TRIGGERING + if(r == 0 && proto == IPPROTO_UDP) + { + add_nat_rule(ifname, rhost, eport, iaddr, iport, proto, desc); + /* TODO check error */ + } +#endif return r; } @@ -502,6 +785,31 @@ #endif } +/* get_redirect_rule_count() + * return value : -1 for error or the number of rdr rules */ +int +get_redirect_rule_count(const char * ifname) +{ + struct pfioc_rule pr; + UNUSED(ifname); + + if(dev<0) { + syslog(LOG_ERR, "pf device is not open"); + return -1; + } + memset(&pr, 0, sizeof(pr)); + strlcpy(pr.anchor, anchor_name, MAXPATHLEN); +#ifndef PF_NEWSTYLE + pr.rule.action = PF_RDR; +#endif + if(ioctl(dev, DIOCGETRULES, &pr) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m"); + return -1; + } + return pr.nr; +} + /* get_redirect_rule() * return value : 0 success (found) * -1 = error or rule not found */ @@ -592,22 +900,36 @@ syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m"); goto error; } +#ifdef PFVAR_NEW_STYLE + inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4addr.s_addr, + iaddr, iaddrlen); +#else inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr, iaddr, iaddrlen); +#endif #else inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, iaddr, iaddrlen); #endif if(rhost && rhostlen > 0) { +#ifdef PFVAR_NEW_STYLE + if (pr.rule.src.addr.v.a.addr.v4addr.s_addr == 0) +#else if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0) +#endif { rhost[0] = '\0'; /* empty string */ } else { +#ifdef PFVAR_NEW_STYLE + inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4addr.s_addr, + rhost, rhostlen); +#else inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, rhost, rhostlen); +#endif } } if(timestamp) @@ -698,7 +1020,11 @@ syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m"); goto error; } +#ifdef PFVAR_NEW_STYLE + *iaddr = pp.addr.addr.v.a.addr.v4addr.s_addr; +#else *iaddr = pp.addr.addr.v.a.addr.v4.s_addr; +#endif } #else if(iport) *iport = pr.rule.rdr.proxy_port[0]; @@ -710,11 +1036,20 @@ #endif if(rhost && rhostlen > 0) { +#ifdef PFVAR_NEW_STYLE + if (pr.rule.src.addr.v.a.addr.v4addr.s_addr == 0) +#else if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0) +#endif rhost[0] = '\0'; /* empty string */ else +#ifdef PFVAR_NEW_STYLE + inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4addr.s_addr, + rhost, rhostlen); +#else inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, rhost, rhostlen); +#endif } if(check_desc) { if((desc == NULL && pr.rule.label[0] == '\0') || @@ -739,6 +1074,7 @@ return 0; } } + syslog(LOG_NOTICE, "could not find redirect rule to delete eport=%hu", eport); error: return -1; } @@ -790,7 +1126,7 @@ #endif if( (iport == ntohs(pr.rule.dst.port[0])) && (pr.rule.proto == proto) && - (iaddr == pr.rule.dst.addr.v.a.addr.v4.s_addr) + (iaddr == 0 || iaddr == pr.rule.dst.addr.v.a.addr.v4.s_addr) ) { pr.action = PF_CHANGE_GET_TICKET; @@ -809,12 +1145,19 @@ return 0; } } + syslog(LOG_NOTICE, "could not find filter rule to delete iport=%hu addr=%8x", iport, ntohl(iaddr)); error: return -1; #endif } int +delete_filter_rule(const char * ifname, unsigned short port, int proto) +{ + return priv_delete_filter_rule(ifname, port, proto, 0); +} + +int delete_redirect_and_filter_rules(const char * ifname, unsigned short eport, int proto) { @@ -824,6 +1167,11 @@ r = priv_delete_redirect_rule(ifname, eport, proto, &iport, &iaddr, NULL, 0); if(r == 0) { +#ifdef ENABLE_PORT_TRIGGERING + if (proto == IPPROTO_UDP) { + delete_nat_rule(ifname, iport, proto, iaddr); + } +#endif r = priv_delete_filter_rule(ifname, iport, proto, iaddr); } return r; @@ -916,22 +1264,36 @@ syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m"); goto error; } +#ifdef PFVAR_NEW_STYLE + inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4addr.s_addr, + iaddr, iaddrlen); +#else inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr, iaddr, iaddrlen); +#endif #else inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, iaddr, iaddrlen); #endif if(rhost && rhostlen > 0) { +#ifdef PFVAR_NEW_STYLE + if (pr.rule.src.addr.v.a.addr.v4addr.s_addr == 0) +#else if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0) +#endif { rhost[0] = '\0'; /* empty string */ } else { +#ifdef PFVAR_NEW_STYLE + inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4addr.s_addr, + rhost, rhostlen); +#else inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, rhost, rhostlen); +#endif } } if(timestamp) @@ -1017,7 +1379,7 @@ return array; } -/* update the port mapping internal port, decription and timestamp */ +/* update the port mapping internal port, description and timestamp */ int update_portmapping(const char * ifname, unsigned short eport, int proto, unsigned short iport, const char * desc, @@ -1044,7 +1406,7 @@ return 0; } -/* update the port mapping decription and timestamp */ +/* update the port mapping description and timestamp */ int update_portmapping_desc_timestamp(const char * ifname, unsigned short eport, int proto, diff -Nru miniupnpd-2.1/pf/obsdrdr.h miniupnpd-2.2.1/pf/obsdrdr.h --- miniupnpd-2.1/pf/obsdrdr.h 2014-03-06 12:24:33.000000000 +0000 +++ miniupnpd-2.2.1/pf/obsdrdr.h 2020-05-29 21:48:57.000000000 +0000 @@ -1,7 +1,8 @@ -/* $Id: obsdrdr.h,v 1.23 2014/03/06 12:24:33 nanard Exp $ */ -/* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2014 Thomas Bernard +/* $Id: obsdrdr.h,v 1.25 2020/05/29 21:48:57 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -58,11 +59,16 @@ delete_redirect_and_filter_rules(const char * ifname, unsigned short eport, int proto); +int +delete_filter_rule(const char * ifname, unsigned short port, int proto); + #ifdef TEST int clear_redirect_rules(void); int clear_filter_rules(void); +int +clear_nat_rules(void); #endif #endif diff -Nru miniupnpd-2.1/pf/pfpinhole.c miniupnpd-2.2.1/pf/pfpinhole.c --- miniupnpd-2.1/pf/pfpinhole.c 2018-04-06 09:10:56.000000000 +0000 +++ miniupnpd-2.2.1/pf/pfpinhole.c 2020-05-10 22:30:15.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: pfpinhole.c,v 1.27 2018/03/13 23:05:21 nanard Exp $ */ +/* $Id: pfpinhole.c,v 1.29 2020/05/10 22:22:50 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2012-2018 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2012-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -29,10 +29,11 @@ #include #include -#include "../config.h" +#include "config.h" #include "pfpinhole.h" #include "../upnpglobalvars.h" #include "../macros.h" +#include "../upnputils.h" /* the pass rules created by add_pinhole() are as follow : * diff -Nru miniupnpd-2.1/pf/testobsdrdr.c miniupnpd-2.2.1/pf/testobsdrdr.c --- miniupnpd-2.1/pf/testobsdrdr.c 2018-04-12 09:27:54.000000000 +0000 +++ miniupnpd-2.2.1/pf/testobsdrdr.c 2020-05-29 22:29:13.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: testobsdrdr.c,v 1.30 2018/04/12 09:27:54 nanard Exp $ */ +/* $Id: testobsdrdr.c,v 1.31 2020/05/29 22:29:13 nanard Exp $ */ /* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -97,7 +97,7 @@ add_redirect_rule("ep0", 12123, "192.168.1.23", 1234); add_redirect_rule2("ep0", 12155, "192.168.1.155", 1255, IPPROTO_TCP); #endif - if(add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234, + if(add_redirect_rule2("ep0", NULL/*"8.8.8.8"*/, 12123, "192.168.1.125", 1234, IPPROTO_UDP, "test description", 0) < 0) printf("add_redirect_rule2() #3 failed\n"); use_ext_ip_addr = NULL; @@ -124,8 +124,12 @@ packets, bytes); } +/* if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0) printf("delete_redirect_rule() failed\n"); +*/ + if(delete_redirect_and_filter_rules("ep0", 12123, IPPROTO_UDP) < 0) + printf("delete_redirect_rule() failed\n"); if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0) printf("delete_redirect_rule() failed\n"); @@ -138,6 +142,7 @@ if(clear) { clear_redirect_rules(); clear_filter_rules(); + clear_nat_rules(); } /*list_rules();*/ diff -Nru miniupnpd-2.1/pf/testpfpinhole.c miniupnpd-2.2.1/pf/testpfpinhole.c --- miniupnpd-2.1/pf/testpfpinhole.c 2017-11-02 17:38:04.000000000 +0000 +++ miniupnpd-2.2.1/pf/testpfpinhole.c 2020-05-21 00:11:41.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: testpfpinhole.c,v 1.14 2017/11/02 15:44:16 nanard Exp $ */ +/* $Id: testpfpinhole.c,v 1.15 2020/05/21 00:11:41 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2012-2017 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2012-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -22,6 +22,8 @@ const char * anchor_name = "miniupnpd"; const char * queue = NULL; +const char * use_ext_ip_addr = "42.42.42.42"; + #ifdef ENABLE_IPV6 static int print_pinhole(int uid) { diff -Nru miniupnpd-2.1/portinuse.c miniupnpd-2.2.1/portinuse.c --- miniupnpd-2.1/portinuse.c 2017-11-02 17:38:02.000000000 +0000 +++ miniupnpd-2.2.1/portinuse.c 2020-11-09 19:43:35.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: portinuse.c,v 1.7 2017/11/02 15:48:29 nanard Exp $ */ +/* $Id: portinuse.c,v 1.12 2020/11/04 21:29:50 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * (c) 2007-2017 Thomas Bernard - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2007-2020 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -163,7 +163,12 @@ kvm_close(kd); return -1; } - next = CIRCLEQ_FIRST(&table.inpt_queue); /*TAILQ_FIRST(&table.inpt_queue);*/ + /* inpt_queue was CIRCLEQ_HEAD, it is TAILQ_HEAD since OpenBSD 5.5 */ +#ifdef INPT_QUEUE_IS_CIRCLEQ + next = CIRCLEQ_FIRST(&table.inpt_queue); +#else + next = TAILQ_FIRST(&table.inpt_queue); +#endif while(next != NULL) { if(((u_long)next & 3) != 0) break; n = kvm_read(kd, (u_long)next, &inpcb, sizeof(inpcb)); @@ -171,7 +176,11 @@ syslog(LOG_ERR, "kvm_read(): %s", kvm_geterr(kd)); break; } - next = CIRCLEQ_NEXT(&inpcb, inp_queue); /*TAILQ_NEXT(&inpcb, inp_queue);*/ +#ifdef INPT_QUEUE_IS_CIRCLEQ + next = CIRCLEQ_NEXT(&inpcb, inp_queue); +#else + next = TAILQ_NEXT(&inpcb, inp_queue); +#endif /* skip IPv6 sockets */ if((inpcb.inp_flags & INP_IPV6) != 0) continue; @@ -259,7 +268,7 @@ /* no support for IPv6 */ if (INP_ISIPV6(inp) != 0) continue; - syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu", + syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %u %08lx:%u", (u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport), (u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport), eport, (u_long)ip_addr.s_addr, iport @@ -280,7 +289,7 @@ struct xinpgen *xig, *exig; struct xinpcb *xip; struct xtcpcb *xtp; - struct inpcb *inp; + struct in_conninfo *inc; void *buf = NULL; size_t len; @@ -339,7 +348,8 @@ free(buf); return -1; } - inp = &xtp->xt_inp; + xip = &xtp->xt_inp; + inc = &xip->inp_inc; break; case IPPROTO_UDP: xip = (struct xinpcb *)xig; @@ -349,21 +359,21 @@ free(buf); return -1; } - inp = &xip->xi_inp; + inc = &xip->inp_inc; break; default: abort(); } /* no support for IPv6 */ - if ((inp->inp_vflag & INP_IPV6) != 0) + if ((xip->inp_vflag & INP_IPV6) != 0) continue; - syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu", - (u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport), - (u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport), + syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %u %08lx:%u", + (u_long)inc->inc_laddr.s_addr, ntohs(inc->inc_lport), + (u_long)inc->inc_faddr.s_addr, ntohs(inc->inc_fport), eport, (u_long)ip_addr.s_addr, iport ); - if (eport == (unsigned)ntohs(inp->inp_lport)) { - if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) { + if (eport == (unsigned)ntohs(inc->inc_lport)) { + if (inc->inc_laddr.s_addr == INADDR_ANY || inc->inc_laddr.s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } diff -Nru miniupnpd-2.1/README miniupnpd-2.2.1/README --- miniupnpd-2.1/README 2017-05-26 11:02:42.000000000 +0000 +++ miniupnpd-2.2.1/README 2019-02-10 12:03:06.000000000 +0000 @@ -1,5 +1,5 @@ MiniUPnP project -(c) 2006-2017 Thomas Bernard +(c) 2006-2019 Thomas Bernard webpage: http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ github: https://github.com/miniupnp/miniupnp freecode: http://freecode.com/projects/miniupnp diff -Nru miniupnpd-2.1/testasyncsendto.c miniupnpd-2.2.1/testasyncsendto.c --- miniupnpd-2.1/testasyncsendto.c 2018-03-13 10:27:01.000000000 +0000 +++ miniupnpd-2.2.1/testasyncsendto.c 2019-09-24 11:51:15.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: testasyncsendto.c,v 1.5 2018/03/13 10:25:52 nanard Exp $ */ +/* $Id: testasyncsendto.c,v 1.6 2019/09/24 11:48:47 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2019 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -74,8 +74,8 @@ int max_fd; struct timeval timeout; struct timeval now; - syslog(LOG_DEBUG, "get_next_scheduled_send : %d next_send=%ld.%06ld", - i, (long)next_send.tv_sec, (long)next_send.tv_usec); + syslog(LOG_DEBUG, "get_next_scheduled_send : %d next_send=%lld.%06ld", + i, (long long)next_send.tv_sec, (long)next_send.tv_usec); FD_ZERO(&writefds); max_fd = 0; gettimeofday(&now, NULL); @@ -100,8 +100,8 @@ } } syslog(LOG_DEBUG, "get_sendto_fds() returned %d", i); - syslog(LOG_DEBUG, "select(%d, NULL, xx, NULL, %ld.%06ld)", - max_fd, (long)timeout.tv_sec, (long)timeout.tv_usec); + syslog(LOG_DEBUG, "select(%d, NULL, xx, NULL, %lld.%06ld)", + max_fd, (long long)timeout.tv_sec, (long)timeout.tv_usec); i = select(max_fd, NULL, &writefds, NULL, &timeout); if(i < 0) { syslog(LOG_ERR, "select: %m"); diff -Nru miniupnpd-2.1/testportinuse.c miniupnpd-2.2.1/testportinuse.c --- miniupnpd-2.1/testportinuse.c 2016-02-09 09:39:00.000000000 +0000 +++ miniupnpd-2.2.1/testportinuse.c 2020-09-28 21:55:14.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: testportinuse.c,v 1.4 2016/02/09 09:37:44 nanard Exp $ */ +/* $Id: testportinuse.c,v 1.5 2020/09/28 21:49:18 nanard Exp $ */ /* MiniUPnP project * (c) 2014 Thomas Bernard * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -14,12 +14,6 @@ #include "config.h" #include "portinuse.h" -#ifdef USE_NETFILTER -const char * miniupnpd_nat_chain = "MINIUPNPD"; -const char * miniupnpd_nat_postrouting_chain = "MINIUPNPD-POSTROUTING"; -const char * miniupnpd_forward_chain = "MINIUPNPD"; -#endif /* USE_NETFILTER */ - int main(int argc, char * * argv) { #ifndef CHECK_PORTINUSE diff -Nru miniupnpd-2.1/testupnpdescgen.c miniupnpd-2.2.1/testupnpdescgen.c --- miniupnpd-2.1/testupnpdescgen.c 2018-02-22 13:19:38.000000000 +0000 +++ miniupnpd-2.2.1/testupnpdescgen.c 2020-11-09 19:43:35.000000000 +0000 @@ -1,7 +1,8 @@ -/* $Id: testupnpdescgen.c,v 1.35 2018/02/22 13:18:58 nanard Exp $ */ -/* MiniUPnP project +/* $Id: testupnpdescgen.c,v 1.37 2020/11/04 21:02:29 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -36,7 +37,7 @@ char model_url[] = ROOTDEV_MODELURL; #endif /* ENABLE_MANUFACTURER_INFO_CONFIGURATION */ #ifdef RANDOMIZE_URLS -char random_url[] = "RANDOM"; +char random_url[RANDOM_URL_MAX_LEN] = "RANDOM"; #endif /* RANDOMIZE_URLS */ unsigned int upnp_configid = 666; @@ -54,6 +55,12 @@ return 0; } +int addr_is_reserved(struct in_addr * addr) +{ + UNUSED(addr); + return 0; +} + int upnp_get_portmapping_number_of_entries(void) { return 42; diff -Nru miniupnpd-2.1/upnpdescgen.c miniupnpd-2.2.1/upnpdescgen.c --- miniupnpd-2.1/upnpdescgen.c 2018-02-22 13:19:38.000000000 +0000 +++ miniupnpd-2.2.1/upnpdescgen.c 2020-06-06 18:02:59.000000000 +0000 @@ -1,14 +1,15 @@ -/* $Id: upnpdescgen.c,v 1.85 2018/02/22 13:18:58 nanard Exp $ */ +/* $Id: upnpdescgen.c,v 1.88 2020/06/06 17:50:49 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include #include #include +#include #include "config.h" #ifdef ENABLE_EVENTS @@ -816,7 +817,10 @@ newlen = *tmplen + s2len + 1; p = (char *)realloc(str, newlen); if(p == NULL) /* handle a failure of realloc() */ + { + syslog(LOG_ERR, "strcat_str: Failed to realloc %d bytes", newlen); return str; + } str = p; *tmplen = newlen; } @@ -840,6 +844,7 @@ p = (char *)realloc(str, *tmplen); if(p == NULL) /* handle a failure of realloc() */ { + syslog(LOG_ERR, "strcat_char: Failed to realloc %d bytes", *tmplen); *tmplen -= 256; return str; } @@ -1024,7 +1029,6 @@ const struct action * acts; const struct stateVar * vars; const struct argument * args; - const char * p; char * str; int tmplen; tmplen = 2048; @@ -1061,17 +1065,20 @@ j = 0; while(args[j].dir) { + const char * p; + size_t plen; str = strcat_str(str, len, &tmplen, ""); if((args[j].dir & 0x80) == 0) { str = strcat_str(str, len, &tmplen, "New"); } p = vars[args[j].relatedVar].name; + plen = strlen(p); if(args[j].dir & 0x7c) { /* use magic values ... */ str = strcat_str(str, len, &tmplen, magicargname[(args[j].dir & 0x7c) >> 2]); - } else if(0 == memcmp(p, "PortMapping", 11) - && 0 != memcmp(p + 11, "Description", 11)) { - if(0 == memcmp(p + 11, "NumberOfEntries", 15)) { + } else if(plen >= 11 && 0 == memcmp(p, "PortMapping", 11) + && (plen < 22 || 0 != memcmp(p + 11, "Description", 11))) { + if(plen >= (11+15) && 0 == memcmp(p + 11, "NumberOfEntries", 15)) { /* PortMappingNumberOfEntries */ #ifdef IGD_V2 if(0 == memcmp(acts[i].name, "GetListOfPortMappings", 22)) { @@ -1089,9 +1096,9 @@ str = strcat_str(str, len, &tmplen, p + 11); } #ifdef IGD_V2 - } else if(0 == memcmp(p, "A_ARG_TYPE_", 11)) { + } else if(plen >= 11 && 0 == memcmp(p, "A_ARG_TYPE_", 11)) { str = strcat_str(str, len, &tmplen, p + 11); - } else if(0 == memcmp(p, "ExternalPort", 13) + } else if(plen >= 13 && 0 == memcmp(p, "ExternalPort", 13) && args[j].dir == 2 && 0 == memcmp(acts[i].name, "AddAnyPortMapping", 18)) { str = strcat_str(str, len, &tmplen, "ReservedPort"); @@ -1281,8 +1288,9 @@ if(use_ext_ip_addr) str = strcat_str(str, len, &tmplen, use_ext_ip_addr); else { + struct in_addr addr; char ext_ip_addr[INET_ADDRSTRLEN]; - if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0) { + if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, &addr, NULL) < 0 || addr_is_reserved(&addr)) { str = strcat_str(str, len, &tmplen, "0.0.0.0"); } else { str = strcat_str(str, len, &tmplen, ext_ip_addr); diff -Nru miniupnpd-2.1/upnpevents.c miniupnpd-2.2.1/upnpevents.c --- miniupnpd-2.1/upnpevents.c 2018-05-03 08:29:27.000000000 +0000 +++ miniupnpd-2.2.1/upnpevents.c 2019-09-24 11:51:15.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: upnpevents.c,v 1.40 2018/05/03 08:26:32 nanard Exp $ */ +/* $Id: upnpevents.c,v 1.44 2019/09/24 11:47:06 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2008-2018 Thomas Bernard + * (c) 2008-2019 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -341,7 +342,7 @@ i = 1; p++; port = (unsigned short)atoi(p); - while(*p != '/') { + while(*p != '\0' && *p != '/') { if(i<7) obj->portstr[i++] = *p; p++; } @@ -443,19 +444,35 @@ l = 0; } obj->buffersize = 1024; - obj->buffer = malloc(obj->buffersize); - if(!obj->buffer) { - syslog(LOG_ERR, "%s: malloc returned NULL", "upnp_event_prepare"); - if(xml) { - free(xml); + for (;;) { + obj->buffer = malloc(obj->buffersize); + if(!obj->buffer) { + syslog(LOG_ERR, "%s: malloc returned NULL", "upnp_event_prepare"); + if(xml) { + free(xml); + } + obj->state = EError; + return; } - obj->state = EError; - return; + obj->tosend = snprintf(obj->buffer, obj->buffersize, notifymsg, + (obj->path[0] != '\0') ? obj->path : "/", + obj->addrstr, obj->portstr, l+2, + obj->sub->uuid, obj->sub->seq, + l, xml); + if (obj->tosend < 0) { + syslog(LOG_ERR, "%s: snprintf() failed", "upnp_event_prepare"); + if(xml) { + free(xml); + } + obj->state = EError; + return; + } else if (obj->tosend < obj->buffersize) { + break; /* the buffer was large enough */ + } + /* Try again with a buffer big enough */ + free(obj->buffer); + obj->buffersize = obj->tosend + 1; /* reserve space for the final 0 */ } - obj->tosend = snprintf(obj->buffer, obj->buffersize, notifymsg, - obj->path, obj->addrstr, obj->portstr, l+2, - obj->sub->uuid, obj->sub->seq, - l, xml); if(xml) { free(xml); xml = NULL; @@ -567,6 +584,9 @@ upnp_event_notify_connect(obj); if(obj->state != EConnecting) break; +#if defined(__GNUC__) && (__GNUC__ >= 7) + __attribute__ ((fallthrough)); +#endif case EConnecting: case ESending: FD_SET(obj->s, writeset); diff -Nru miniupnpd-2.1/upnpglobalvars.c miniupnpd-2.2.1/upnpglobalvars.c --- miniupnpd-2.1/upnpglobalvars.c 2017-12-12 11:51:58.000000000 +0000 +++ miniupnpd-2.2.1/upnpglobalvars.c 2020-09-28 21:55:14.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: upnpglobalvars.c,v 1.42 2017/12/12 11:45:22 nanard Exp $ */ +/* $Id: upnpglobalvars.c,v 1.46 2020/09/28 21:48:48 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2017 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -16,6 +16,15 @@ /* network interface for internet */ const char * ext_if_name = 0; +#ifdef ENABLE_IPV6 +/* network interface for internet - IPv6 */ +const char * ext_if_name6 = 0; +#endif + +/* stun host/port configuration */ +const char * ext_stun_host = 0; +uint16_t ext_stun_port = 0; + /* file to store leases */ #ifdef ENABLE_LEASEFILE const char* lease_file = 0; @@ -25,6 +34,10 @@ * when NULL, getifaddr() is used */ const char * use_ext_ip_addr = 0; +/* disallow all port forwarding requests when + * we are behind restrictive nat */ +int disable_port_forwarding = 0; + unsigned long downstream_bitrate = 0; unsigned long upstream_bitrate = 0; @@ -96,29 +109,6 @@ const char * tag = 0; #endif -#ifdef USE_NETFILTER -/* chain names to use in the nat and filter tables. */ - -/* iptables -t nat -N MINIUPNPD - * iptables -t nat -A PREROUTING -i -j MINIUPNPD */ -const char * miniupnpd_nat_chain = "MINIUPNPD"; - -/* iptables -t nat -N MINIUPNPD-POSTROUTING - * iptables -t nat -A POSTROUTING -o -j MINIUPNPD-POSTROUTING */ -const char * miniupnpd_nat_postrouting_chain = "MINIUPNPD-POSTROUTING"; - -/* iptables -t filter -N MINIUPNPD - * iptables -t filter -A FORWARD -i ! -o -j MINIUPNPD */ -const char * miniupnpd_forward_chain = "MINIUPNPD"; - -#ifdef ENABLE_UPNPPINHOLE -/* ip6tables -t filter -N MINIUPNPD - * ip6tables -t filter -A FORWARD -i ! -o -j MINIUPNPD */ -const char * miniupnpd_v6_filter_chain = "MINIUPNPD"; -#endif /* ENABLE_UPNPPINHOLE */ - -#endif /* USE_NETFILTER */ - #ifdef ENABLE_NFQUEUE int nfqueue = -1; int n_nfqix = 0; @@ -167,4 +157,3 @@ #ifdef RANDOMIZE_URLS char random_url[RANDOM_URL_MAX_LEN] = "random"; #endif /* RANDOMIZE_URLS */ - diff -Nru miniupnpd-2.1/upnpglobalvars.h miniupnpd-2.2.1/upnpglobalvars.h --- miniupnpd-2.1/upnpglobalvars.h 2018-02-22 13:19:38.000000000 +0000 +++ miniupnpd-2.2.1/upnpglobalvars.h 2020-09-28 21:55:14.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: upnpglobalvars.h,v 1.46 2018/02/22 13:18:58 nanard Exp $ */ +/* $Id: upnpglobalvars.h,v 1.50 2020/09/28 21:48:48 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -17,6 +17,15 @@ /* name of the network interface used to access internet */ extern const char * ext_if_name; +#ifdef ENABLE_IPV6 +/* name of the network interface used to access internet - for IPv6*/ +extern const char * ext_if_name6; +#endif + +/* stun host/port configuration */ +extern const char * ext_stun_host; +extern uint16_t ext_stun_port; + /* file to store all leases */ #ifdef ENABLE_LEASEFILE extern const char * lease_file; @@ -26,6 +35,10 @@ * when NULL, getifaddr() is used */ extern const char * use_ext_ip_addr; +/* disallow all port forwarding requests when + * we are behind restrictive nat */ +extern int disable_port_forwarding; + /* parameters to return to upnp client when asked */ extern unsigned long downstream_bitrate; extern unsigned long upstream_bitrate; @@ -69,6 +82,8 @@ #define FORCEIGDDESCV1MASK 0x0800 #endif +#define PERFORMSTUNMASK 0x1000 + #define SETFLAG(mask) runtime_flags |= mask #define GETFLAG(mask) (runtime_flags & mask) #define CLEARFLAG(mask) runtime_flags &= ~mask @@ -127,15 +142,6 @@ extern const char * tag; #endif -#ifdef USE_NETFILTER -extern const char * miniupnpd_nat_chain; -extern const char * miniupnpd_nat_postrouting_chain; -extern const char * miniupnpd_forward_chain; -#ifdef ENABLE_UPNPPINHOLE -extern const char * miniupnpd_v6_filter_chain; -#endif -#endif - #ifdef ENABLE_NFQUEUE extern int nfqueue; extern int n_nfqix; diff -Nru miniupnpd-2.1/upnphttp.c miniupnpd-2.2.1/upnphttp.c --- miniupnpd-2.1/upnphttp.c 2018-01-18 23:47:29.000000000 +0000 +++ miniupnpd-2.2.1/upnphttp.c 2020-11-27 18:25:03.000000000 +0000 @@ -1,9 +1,9 @@ -/* $Id: upnphttp.c,v 1.107 2018/01/16 00:50:49 nanard Exp $ */ +/* $Id: upnphttp.c,v 1.109 2020/11/11 12:20:59 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * Project : miniupnp - * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Website : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ * Author : Thomas Bernard - * Copyright (c) 2005-2018 Thomas Bernard + * Copyright (c) 2005-2020 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file included in this distribution. * */ @@ -67,9 +67,17 @@ const SSL_METHOD *method; SSL_library_init(); SSL_load_error_strings(); +#if OPENSSL_VERSION_NUMBER < 0x10100000L method = TLSv1_server_method(); +#else + method = TLS_server_method(); +#endif if(method == NULL) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L syslog(LOG_ERR, "TLSv1_server_method() failed"); +#else + syslog(LOG_ERR, "TLS_server_method() failed"); +#endif syslogsslerr(); return -1; } @@ -111,7 +119,11 @@ SSL_CTX_free(ssl_ctx); ssl_ctx = NULL; } +#if OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10100000L + ERR_remove_thread_state(NULL); +#elif OPENSSL_VERSION_NUMBER < 0x10000000L ERR_remove_state(0); +#endif ENGINE_cleanup(); CONF_modules_unload(1); ERR_free_strings(); @@ -937,7 +949,19 @@ } else if(n==0) { - syslog(LOG_WARNING, "HTTP Connection from %s closed unexpectedly", inet_ntoa(h->clientaddr)); +#ifdef ENABLE_IPV6 + if (h->ipv6) + { + char clientaddr_str[INET6_ADDRSTRLEN]; + if(inet_ntop(AF_INET6, &(h->clientaddr_v6), clientaddr_str, INET6_ADDRSTRLEN) == NULL) + strncpy(clientaddr_str, "*inet_ntop error*", sizeof(clientaddr_str)); + syslog(LOG_WARNING, "HTTP Connection from %s closed unexpectedly", clientaddr_str); + } + else +#endif + { + syslog(LOG_WARNING, "HTTP Connection from %s closed unexpectedly", inet_ntoa(h->clientaddr)); + } h->state = EToDelete; } else @@ -1007,7 +1031,19 @@ } else if(n==0) { - syslog(LOG_WARNING, "HTTP Connection from %s closed unexpectedly", inet_ntoa(h->clientaddr)); +#ifdef ENABLE_IPV6 + if (h->ipv6) + { + char clientaddr_str[INET6_ADDRSTRLEN]; + if(inet_ntop(AF_INET6, &(h->clientaddr_v6), clientaddr_str, INET6_ADDRSTRLEN) == NULL) + strncpy(clientaddr_str, "*inet_ntop error*", sizeof(clientaddr_str)); + syslog(LOG_WARNING, "HTTP Connection from %s closed unexpectedly", clientaddr_str); + } + else +#endif + { + syslog(LOG_WARNING, "HTTP Connection from %s closed unexpectedly", inet_ntoa(h->clientaddr)); + } h->state = EToDelete; } else diff -Nru miniupnpd-2.1/upnphttp.h miniupnpd-2.2.1/upnphttp.h --- miniupnpd-2.1/upnphttp.h 2015-12-16 10:21:49.000000000 +0000 +++ miniupnpd-2.2.1/upnphttp.h 2020-12-20 17:50:28.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: upnphttp.h,v 1.42 2015/12/16 10:21:49 nanard Exp $ */ -/* vim: tabstop=4 shiftwidth=4 noexpandtab */ -/* MiniUPnP project +/* $Id: upnphttp.h,v 1.43 2020/12/20 17:44:59 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2015 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ diff -Nru miniupnpd-2.1/upnppermissions.c miniupnpd-2.2.1/upnppermissions.c --- miniupnpd-2.1/upnppermissions.c 2014-03-13 10:38:41.000000000 +0000 +++ miniupnpd-2.2.1/upnppermissions.c 2020-10-30 21:38:06.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: upnppermissions.c,v 1.19 2014/03/13 10:11:24 nanard Exp $ */ +/* $Id: upnppermissions.c,v 1.20 2020/10/30 21:37:35 nanard Exp $ */ /* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2014 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -262,3 +262,44 @@ return 1; /* Default : accept */ } +void +get_permitted_ext_ports(uint32_t * allowed, + const struct upnpperm * permary, int n_perms, + in_addr_t addr, u_short iport) +{ + int i, j; + + /* build allowed external ports array */ + memset(allowed, 0xff, 65536 / 8); /* everything allowed by default */ + + for (i = n_perms - 1; i >= 0; i--) + { + if( (addr & permary[i].mask.s_addr) + != (permary[i].address.s_addr & permary[i].mask.s_addr) ) + continue; + if( (iport < permary[i].iport_min) || (permary[i].iport_max < iport)) + continue; + for (j = (int)permary[i].eport_min ; j <= (int)permary[i].eport_max; ) + { + if ((j % 32) == 0 && ((int)permary[i].eport_max >= (j + 31))) + { + /* 32bits at once */ + allowed[j / 32] = (permary[i].type == UPNPPERM_ALLOW) ? 0xffffffff : 0; + j += 32; + } + else + { + do + { + /* one bit at once */ + if (permary[i].type == UPNPPERM_ALLOW) + allowed[j / 32] |= (1 << (j % 32)); + else + allowed[j / 32] &= ~(1 << (j % 32)); + j++; + } + while ((j % 32) != 0 && (j <= (int)permary[i].eport_max)); + } + } + } +} diff -Nru miniupnpd-2.1/upnppermissions.h miniupnpd-2.2.1/upnppermissions.h --- miniupnpd-2.1/upnppermissions.h 2014-03-13 10:38:41.000000000 +0000 +++ miniupnpd-2.2.1/upnppermissions.h 2020-10-30 21:38:06.000000000 +0000 @@ -1,7 +1,7 @@ -/* $Id: upnppermissions.h,v 1.11 2014/03/13 10:11:25 nanard Exp $ */ +/* $Id: upnppermissions.h,v 1.12 2020/10/30 21:37:35 nanard Exp $ */ /* MiniUPnP project - * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2014 Thomas Bernard + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -45,6 +45,14 @@ u_short eport, struct in_addr address, u_short iport); +/** + * Build an array of all allowed external ports (for the address and internal port) + */ +void +get_permitted_ext_ports(uint32_t * allowed, + const struct upnpperm * permary, int n_perms, + in_addr_t addr, u_short iport); + #ifdef USE_MINIUPNPDCTL void write_permlist(int fd, const struct upnpperm * permary, diff -Nru miniupnpd-2.1/upnppinhole.c miniupnpd-2.2.1/upnppinhole.c --- miniupnpd-2.1/upnppinhole.c 2018-04-06 09:10:55.000000000 +0000 +++ miniupnpd-2.2.1/upnppinhole.c 2019-06-15 18:48:05.000000000 +0000 @@ -1,7 +1,8 @@ -/* $Id: upnppinhole.c,v 1.13 2018/03/13 10:49:13 nanard Exp $ */ -/* MiniUPnP project +/* $Id: upnppinhole.c,v 1.14 2019/05/21 08:39:45 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2019 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -142,7 +143,7 @@ return (r >= 0) ? 1 : r; } #if defined(USE_PF) || defined(USE_NETFILTER) - *uid = add_pinhole (ext_if_name, raddr, rport, + *uid = add_pinhole (ext_if_name6, raddr, rport, iaddr, iport, proto, desc, timestamp); return *uid >= 0 ? 1 : -1; #else diff -Nru miniupnpd-2.1/upnpredirect.c miniupnpd-2.2.1/upnpredirect.c --- miniupnpd-2.1/upnpredirect.c 2018-05-03 08:29:27.000000000 +0000 +++ miniupnpd-2.2.1/upnpredirect.c 2020-12-03 23:31:53.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: upnpredirect.c,v 1.94 2018/05/03 08:27:40 nanard Exp $ */ +/* $Id: upnpredirect.c,v 1.98 2020/12/03 23:29:53 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -356,6 +356,10 @@ "%hu->%s:%hu %s", eport, iaddr, iport, protocol); return -3; } + + if (desc == NULL) + desc = ""; /* assume empty description */ + /* IGDv1 (WANIPConnection:1 Service Template Version 1.01 / Nov 12, 2001) * - 2.2.20.PortMappingDescription : * Overwriting Previous / Existing Port Mappings: @@ -440,6 +444,8 @@ { /*syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s", eport, iaddr, iport, protocol, desc); */ + if(disable_port_forwarding) + return -1; if(add_redirect_rule2(ext_if_name, rhost, eport, iaddr, iport, proto, desc, timestamp) < 0) { return -1; @@ -573,14 +579,16 @@ return _upnp_delete_redir(eport, proto_atoi(protocol)); } -/* upnp_get_portmapping_number_of_entries() - * TODO: improve this code. */ +/* upnp_get_portmapping_number_of_entries() */ int upnp_get_portmapping_number_of_entries() { +#if defined(USE_PF) || defined(USE_NFTABLES) + return get_redirect_rule_count(ext_if_name); +#else int n = 0, r = 0; unsigned short eport, iport; - char protocol[4], iaddr[32], desc[64], rhost[32]; + char protocol[8], iaddr[32], desc[64], rhost[32]; unsigned int leaseduration; do { protocol[0] = '\0'; iaddr[0] = '\0'; desc[0] = '\0'; @@ -592,6 +600,7 @@ n++; } while(r==0); return (n-1); +#endif } /* functions used to remove unused rules @@ -779,4 +788,3 @@ } } #endif - diff -Nru miniupnpd-2.1/upnpreplyparse.c miniupnpd-2.2.1/upnpreplyparse.c --- miniupnpd-2.1/upnpreplyparse.c 2017-12-12 11:51:56.000000000 +0000 +++ miniupnpd-2.2.1/upnpreplyparse.c 2019-04-08 13:36:51.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: upnpreplyparse.c,v 1.20 2017/12/12 11:26:25 nanard Exp $ */ +/* $Id: upnpreplyparse.c,v 1.21 2019/04/08 13:30:51 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2017 Thomas Bernard + * (c) 2006-2019 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -78,6 +78,7 @@ if(strcmp(data->curelt, "NewPortListing") == 0) { /* specific case for NewPortListing which is a XML Document */ + free(data->portListing); data->portListing = malloc(l + 1); if(!data->portListing) { diff -Nru miniupnpd-2.1/upnpsoap.c miniupnpd-2.2.1/upnpsoap.c --- miniupnpd-2.1/upnpsoap.c 2018-03-13 10:32:53.000000000 +0000 +++ miniupnpd-2.2.1/upnpsoap.c 2020-10-30 21:38:06.000000000 +0000 @@ -1,8 +1,8 @@ -/* $Id: upnpsoap.c,v 1.151 2018/03/13 10:32:53 nanard Exp $ */ +/* $Id: upnpsoap.c,v 1.160 2020/10/30 21:37:33 nanard Exp $ */ /* vim: tabstop=4 shiftwidth=4 noexpandtab * MiniUPnP project * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ - * (c) 2006-2018 Thomas Bernard + * (c) 2006-2020 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -27,6 +27,7 @@ #include "upnpsoap.h" #include "upnpreplyparse.h" #include "upnpredirect.h" +#include "upnppermissions.h" #include "upnppinhole.h" #include "getifaddr.h" #include "getifstats.h" @@ -337,11 +338,18 @@ strncpy(ext_ip_addr, use_ext_ip_addr, INET_ADDRSTRLEN); ext_ip_addr[INET_ADDRSTRLEN - 1] = '\0'; } - else if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, NULL, NULL) < 0) + else { - syslog(LOG_ERR, "Failed to get ip address for interface %s", - ext_if_name); - strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); + struct in_addr addr; + if(getifaddr(ext_if_name, ext_ip_addr, INET_ADDRSTRLEN, &addr, NULL) < 0) + { + syslog(LOG_ERR, "Failed to get ip address for interface %s", + ext_if_name); + strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); + } else if (addr_is_reserved(&addr)) { + syslog(LOG_NOTICE, "private/reserved address %s is not suitable for external IP", ext_ip_addr); + strncpy(ext_ip_addr, "0.0.0.0", INET_ADDRSTRLEN); + } } #else struct lan_addr_s * lan_addr; @@ -356,6 +364,11 @@ } } #endif + if (strcmp(ext_ip_addr, "0.0.0.0") == 0) + { + SoapError(h, 501, "Action Failed"); + return; + } bodylen = snprintf(body, sizeof(body), resp, action, ns, /*SERVICE_TYPE_WANIPC,*/ ext_ip_addr, action); @@ -410,7 +423,7 @@ r_host = GetValueFromNameValueList(&data, "NewRemoteHost"); #ifndef SUPPORT_REMOTEHOST #ifdef UPNP_STRICT - if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) + if (r_host && (r_host[0] != '\0') && (0 != strcmp(r_host, "*"))) { ClearNameValueList(&data); SoapError(h, 726, "RemoteHostOnlySupportsWildcard"); @@ -513,6 +526,7 @@ /* possible error codes for AddPortMapping : * 402 - Invalid Args * 501 - Action Failed + * 606 - Action not authorized (added in IGD v2) * 715 - Wildcard not permited in SrcAddr * 716 - Wildcard not permited in ExtPort * 718 - ConflictInMappingEntry @@ -529,7 +543,8 @@ * 728 - NoPortMapsAvailable There are not enough free ports available to complete the mapping (added in IGD v2) - * 729 - ConflictWithOtherMechanisms (added in IGD v2) */ + * 729 - ConflictWithOtherMechanisms (added in IGD v2) + * 732 - WildCardNotPermittedInIntPort (added in IGD v2) */ switch(r) { case 0: /* success */ @@ -542,8 +557,12 @@ SoapError(h, 729, "ConflictWithOtherMechanisms"); break; #endif /* IGD_V2 */ - case -2: /* already redirected */ case -3: /* not permitted */ +#ifdef IGD_V2 + SoapError(h, 606, "Action not authorized"); + break; +#endif /* IGD_V2 */ + case -2: /* already redirected */ SoapError(h, 718, "ConflictInMappingEntry"); break; default: @@ -590,23 +609,26 @@ if(leaseduration == 0) leaseduration = 604800; - if (!int_ip || !ext_port || !int_port) + if (!int_ip || !ext_port || !int_port || !protocol) { ClearNameValueList(&data); SoapError(h, 402, "Invalid Args"); return; } - eport = (unsigned short)atoi(ext_port); + eport = (0 == strcmp(ext_port, "*")) ? 0 : (unsigned short)atoi(ext_port); + if (eport == 0) { + eport = 1024 + ((random() & 0x7ffffffL) % (65536-1024)); + } iport = (unsigned short)atoi(int_port); - if(iport == 0 || !is_numeric(ext_port)) { + if(iport == 0 || (!is_numeric(ext_port) && 0 != strcmp(ext_port, "*"))) { ClearNameValueList(&data); SoapError(h, 402, "Invalid Args"); return; } #ifndef SUPPORT_REMOTEHOST #ifdef UPNP_STRICT - if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) + if (r_host && (r_host[0] != '\0') && (0 != strcmp(r_host, "*"))) { ClearNameValueList(&data); SoapError(h, 726, "RemoteHostOnlySupportsWildcard"); @@ -651,14 +673,42 @@ } } - /* TODO : accept a different external port - * have some smart strategy to choose the port */ - for(;;) { - r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); - if(r==-2 && eport < 65535) { - eport++; - } else { - break; + /* first try the port asked in request, then + * try +1, -1, +2, -2, etc. */ + r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); + if (r != 0 && r != -1) { + unsigned short eport_below, eport_above; + struct in_addr address; + uint32_t allowed_eports[65536 / 32]; + + if(inet_aton(int_ip, &address) <= 0) { + syslog(LOG_ERR, "inet_aton(%s) FAILED", int_ip); + } + get_permitted_ext_ports(allowed_eports, upnppermlist, num_upnpperm, + address.s_addr, iport); + eport_above = eport_below = eport; + for(;;) { + /* loop invariant + * eport is equal to either eport_below or eport_above (or both) */ + if (eport_below <= 1 && eport_above == 65535) { + /* all possible ports tried */ + r = 1; + break; + } + if (eport_above == 65535 || (eport > eport_below && eport_below > 1)) { + eport = --eport_below; + } else { + eport = ++eport_above; + } + if (!(allowed_eports[eport / 32] & ((uint32_t)1U << (eport % 32)))) + continue; /* not allowed */ + r = upnp_redirect(r_host, eport, int_ip, iport, protocol, desc, leaseduration); + if (r == 0 || r == -1) { + /* OK or failure : Stop */ + break; + } + /* r : -2 / -4 already redirected or -3 permission check failed : + * continue */ } } @@ -666,6 +716,9 @@ switch(r) { + case 1: /* exhausted possible mappings */ + SoapError(h, 728, "NoPortMapsAvailable"); + break; case 0: /* success */ bodylen = snprintf(body, sizeof(body), resp, action, ns, /*SERVICE_TYPE_WANIPC,*/ @@ -724,7 +777,7 @@ } #ifndef SUPPORT_REMOTEHOST #ifdef UPNP_STRICT - if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) + if (r_host && (r_host[0] != '\0') && (0 != strcmp(r_host, "*"))) { ClearNameValueList(&data); SoapError(h, 726, "RemoteHostOnlySupportsWildcard"); @@ -757,10 +810,10 @@ } else { - syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s'", + syslog(LOG_INFO, "%s: rhost='%s' %s %s found => %s:%u desc='%s' duration=%u", action, r_host ? r_host : "NULL", ext_port, protocol, int_ip, - (unsigned int)iport, desc); + (unsigned int)iport, desc, leaseduration); bodylen = snprintf(body, sizeof(body), resp, action, ns/*SERVICE_TYPE_WANIPC*/, (unsigned int)iport, int_ip, desc, leaseduration, @@ -813,7 +866,7 @@ } #ifndef SUPPORT_REMOTEHOST #ifdef UPNP_STRICT - if (r_host && (strlen(r_host) > 0) && (0 != strcmp(r_host, "*"))) + if (r_host && (r_host[0] != '\0') && (0 != strcmp(r_host, "*"))) { ClearNameValueList(&data); SoapError(h, 726, "RemoteHostOnlySupportsWildcard"); @@ -1519,23 +1572,35 @@ if (inet_pton(AF_INET6, int_ip, &result_ip) <= 0) { n = getaddrinfo(int_ip, NULL, &hints, &ai); - if(!n && ai->ai_family == AF_INET6) + if (n == 0) { + int found = 0; for(p = ai; p; p = p->ai_next) { - inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); - result_ip = *((struct in6_addr *) p); - /* TODO : deal with more than one ip per hostname */ - break; + if(p->ai_family == AF_INET6) + { + inet_ntop(AF_INET6, (struct in6_addr *) p, int_ip, sizeof(struct in6_addr)); + result_ip = *((struct in6_addr *) p); + found = 1; + /* TODO : deal with more than one ip per hostname */ + break; + } + } + freeaddrinfo(ai); + if (!found) + { + syslog(LOG_NOTICE, "No IPv6 address for hostname '%s'", int_ip); + SoapError(h, 402, "Invalid Args"); + return -1; } } else { - syslog(LOG_ERR, "Failed to convert hostname '%s' to ip address", int_ip); + syslog(LOG_WARNING, "Failed to convert hostname '%s' to IP address : %s", + int_ip, gai_strerror(n)); SoapError(h, 402, "Invalid Args"); return -1; } - freeaddrinfo(p); } if(inet_ntop(AF_INET6, &(h->clientaddr_v6), senderAddr, INET6_ADDRSTRLEN) == NULL) @@ -1618,7 +1683,7 @@ * - InternalClient value equals to the control point's IP address. * It is REQUIRED that InternalClient cannot be one of IPv6 * addresses used by the gateway. */ - if(!int_ip || 0 == strlen(int_ip) || 0 == strcmp(int_ip, "*")) + if(!int_ip || int_ip[0] == '\0' || 0 == strcmp(int_ip, "*")) { SoapError(h, 708, "WildCardNotPermittedInSrcIP"); goto clear_and_exit; @@ -1842,6 +1907,13 @@ rem_port = GetValueFromNameValueList(&data, "RemotePort"); protocol = GetValueFromNameValueList(&data, "Protocol"); + if (!int_port || !rem_port || !protocol) + { + ClearNameValueList(&data); + SoapError(h, 402, "Invalid Args"); + return; + } + rport = (unsigned short)atoi(rem_port); iport = (unsigned short)atoi(int_port); /*proto = atoi(protocol);*/ diff -Nru miniupnpd-2.1/upnpstun.c miniupnpd-2.2.1/upnpstun.c --- miniupnpd-2.1/upnpstun.c 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/upnpstun.c 2020-11-09 19:43:35.000000000 +0000 @@ -0,0 +1,603 @@ +/* $Id: upnpstun.c,v 1.7 2020/11/04 21:01:44 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * MiniUPnP project + * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/ + * (c) 2020 Thomas Bernard + * (c) 2018 Pali Rohár + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef TEST_LINUX_DEBUG_APP +#include "config.h" +#endif + +#include "upnputils.h" +#include "upnpstun.h" + +#if defined(USE_NETFILTER) +#include "netfilter/iptcrdr.h" +#endif +#if defined(USE_PF) +#include "pf/obsdrdr.h" +#endif +#if defined(USE_IPF) +#include "ipf/ipfrdr.h" +#endif +#if defined(USE_IPFW) +#include "ipfw/ipfwrdr.h" +#endif + +#ifdef TEST_LINUX_DEBUG_APP +static int add_filter_rule2(const char *ifname, const char *rhost, const char *iaddr, unsigned short eport, unsigned short iport, int proto, const char *desc); +static int delete_filter_rule(const char * ifname, unsigned short port, int proto); +#define syslog(priority, format, ...) do { switch(priority) { case LOG_ERR: printf("Error: "); break; case LOG_WARNING: printf("Warning: "); } printf(format, ##__VA_ARGS__); putchar('\n'); } while (0) +#endif + +/* Generate random STUN Transaction Id */ +static void generate_transaction_id(unsigned char transaction_id[12]) +{ + size_t i; + + for (i = 0; i < 12; i++) + transaction_id[i] = random() & 255; +} + +/* Create and fill STUN Binding Request */ +static void fill_request(unsigned char buffer[28], int change_ip, int change_port) +{ + /* Type: Binding Request */ + buffer[0] = 0x00; + buffer[1] = 0x01; + + /* Length: One 8-byte attribute */ + buffer[2] = 0x00; + buffer[3] = 0x08; + + /* RFC5389 Magic Cookie: 0x2120A442 */ + buffer[4] = 0x21; + buffer[5] = 0x12; + buffer[6] = 0xA4; + buffer[7] = 0x42; + + /* Transaction Id */ + generate_transaction_id(buffer+8); + + /* Attribute Type: Change Request */ + buffer[20] = 0x00; + buffer[21] = 0x03; + + /* Attribute Length: 4 bytes */ + buffer[22] = 0x00; + buffer[23] = 0x04; + + buffer[24] = 0x00; + buffer[25] = 0x00; + buffer[26] = 0x00; + buffer[27] = 0x00; + + /* Change IP */ + buffer[27] |= change_ip ? 0x4 : 0x00; + + /* Change Port */ + buffer[27] |= change_port ? 0x2 : 0x00; +} + +/* Resolve STUN host+port and return sockaddr_in structure */ +/* When port is 0 then use default STUN port */ +static int resolve_stun_host(const char *stun_host, unsigned short stun_port, struct sockaddr_in *sock_addr) +{ + int have_sock; + struct addrinfo hints; + struct addrinfo *result, *rp; + char service[6]; + int r; + + if (stun_port == 0) + stun_port = (unsigned short)3478; + snprintf(service, sizeof(service), "%hu", stun_port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_NUMERICSERV; + + r = getaddrinfo(stun_host, service, &hints, &result); + if (r != 0) { + syslog(LOG_ERR, "%s: getaddrinfo(%s, %s, ...) failed : %s", + "resolve_stun_host", stun_host, service, gai_strerror(r)); + errno = EHOSTUNREACH; + return -1; + } + + have_sock = 0; + for (rp = result; rp != NULL; rp = rp->ai_next) { + if (rp->ai_addrlen > sizeof(*sock_addr) || rp->ai_addr->sa_family != AF_INET) + continue; + memcpy(sock_addr, rp->ai_addr, rp->ai_addrlen); + have_sock = 1; + break; + } + + freeaddrinfo(result); + + if (!have_sock) { + syslog(LOG_WARNING, "%s: failed to resolve IPv4 address for %s:%s", + "resolve_stun_host", stun_host, service); + errno = EHOSTUNREACH; + return -1; + } else { + char addr_str[48]; + if (sockaddr_to_string((struct sockaddr *)sock_addr, addr_str, sizeof(addr_str)) > 0) { + syslog(LOG_DEBUG, "%s: %s:%s => %s", + "resolve_stun_host", stun_host, service, addr_str); + } + } + + return 0; +} + +/* Create a new UDP socket for STUN connection and return file descriptor and local UDP port */ +static int stun_socket(unsigned short *local_port) +{ + int fd; + socklen_t addr_len; + struct sockaddr_in local_addr; + + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + syslog(LOG_ERR, "%s: socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP): %m", + "stun_socket"); + return -1; + } + + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sin_family = AF_INET; + local_addr.sin_addr.s_addr = htonl(INADDR_ANY); + local_addr.sin_port = 0; + + if (bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr)) != 0) { + syslog(LOG_ERR, "%s: bind(): %m", + "stun_socket"); + close(fd); + return -1; + } + + addr_len = sizeof(local_addr); + if (getsockname(fd, (struct sockaddr *)&local_addr, &addr_len) != 0) { + syslog(LOG_ERR, "%s: getsockname(): %m", + "stun_socket"); + close(fd); + return -1; + } + + *local_port = ntohs(local_addr.sin_port); + + return fd; +} + +/* Receive STUN response message for specified Transaction Id and returns message and peer address */ +static size_t receive_stun_response(int fd, unsigned char *buffer, unsigned char transaction_id[12], size_t buffer_len, struct sockaddr_in *peer_addr) +{ + ssize_t len; + socklen_t peer_addr_len = sizeof(*peer_addr); + + len = recvfrom(fd, buffer, buffer_len, 0, (struct sockaddr *)peer_addr, &peer_addr_len); + if (len < 0) { + syslog(LOG_ERR, "%s: recvfrom(): %m", "receive_stun_response"); + return 0; + } + if (peer_addr_len != sizeof(*peer_addr)) { + syslog(LOG_ERR, "%s: recvfrom(): peer_addr_len mismatch", + "receive_stun_response"); + return 0; + } + if (len < 20) { + syslog(LOG_WARNING, "%s: response too short : %ld", + "receive_stun_response", (long)len); + return 0; + } + + /* Check that buffer is STUN message with class Response + * and Binding method with transaction id */ + if ((buffer[0] & 0xFF) != 0x01 || (buffer[1] & 0xEF) != 0x01) { + syslog(LOG_WARNING, "%s: STUN message type is 0x%02x%02x", + "receive_stun_response", buffer[0], buffer[1]); + return 0; + } + if (memcmp(buffer+8, transaction_id, 12) != 0) { + syslog(LOG_WARNING, "%s: transaction id mismatch", + "receive_stun_response"); + return 0; + } + + return len; +} + +/* Wait for STUN response messages and try to receive them */ +static int wait_for_stun_responses(int fds[4], unsigned char *transaction_ids[4], unsigned char *buffers[4], size_t buffers_lens[4], struct sockaddr_in peer_addrs[4], size_t lens[4]) +{ + fd_set fdset; + struct timeval timeout; + int max_fd; + int ret; + int i; + + max_fd = fds[0]; + for (i = 1; i < 4; i++) { + if (fds[i] > max_fd) + max_fd = fds[i]; + } + + timeout.tv_sec = 3; + timeout.tv_usec = 0; + + while (timeout.tv_sec > 0 || timeout.tv_usec > 0) { + + FD_ZERO(&fdset); + for (i = 0; i < 4; i++) { + FD_SET(fds[i], &fdset); + } + + syslog(LOG_DEBUG, "%s: waiting %ld secs and %ld usecs", "wait_for_stun_responses", (long)timeout.tv_sec, (long)timeout.tv_usec); + ret = select(max_fd+1, &fdset, NULL, NULL, &timeout); + if (ret < 0) { + if (errno == EINTR) + continue; + syslog(LOG_ERR, "%s: select(): %m", "wait_for_stun_responses"); + return -1; + } + if (ret == 0) { + syslog(LOG_DEBUG, "%s: select(): no more responses", "wait_for_stun_responses"); + return 0; + } + + for (i = 0; i < 4; ++i) + if (FD_ISSET(fds[i], &fdset)) + lens[i] = receive_stun_response(fds[i], buffers[i], transaction_ids[i], buffers_lens[i], &peer_addrs[i]); + + syslog(LOG_DEBUG, "%s: received responses: %u", "wait_for_stun_responses", (unsigned)(!!lens[0] + !!lens[1] + !!lens[2] + !!lens[3])); + + if (lens[0] && lens[1] && lens[2] && lens[3]) + return 0; + } + + return 0; +} + +/* Parse Mapped Address (with port) from STUN response message */ +static int parse_stun_response(unsigned char *buffer, size_t len, struct sockaddr_in *mapped_addr) +{ + unsigned char *ptr, *end; + uint16_t attr_type; + uint16_t attr_len; + int have_address; + int have_xor_mapped_address; + + if (len < 20) + return -1; + + syslog(LOG_DEBUG, "%s: Type 0x%04x, Length %hu, Magic Cookie %02x%02x%02x%02x", + "parse_stun_response", ((uint16_t)buffer[0] << 8) + buffer[1], + (uint16_t)((buffer[2] << 8) + buffer[3]), + buffer[4], buffer[5], buffer[6], buffer[7]); + + /* Check that buffer is STUN message with class Response and Binding method */ + if (buffer[0] != 0x01 || (buffer[1] & 0xEF) != 0x01) + return -1; + + /* Check that STUN message is not longer as buffer length */ + if (((size_t)buffer[2] << 8) + buffer[3] + 20 > len) { + syslog(LOG_ERR, "%s: truncated STUN response", "parse_stun_response"); + return -1; + } + + ptr = buffer + 20; + end = buffer + len; + have_address = 0; + have_xor_mapped_address = 0; + + while (ptr + 4 <= end) { + + attr_type = ((uint16_t)ptr[0] << 8) + ptr[1]; + attr_len = ((uint16_t)ptr[2] << 8) + ptr[3]; + ptr += 4; + + if (ptr + attr_len > end) { + syslog(LOG_WARNING, "%s: truncated attribute", "parse_stun_response"); + break; + } + + switch (attr_type) { + case 0x0001: /* MAPPED-ADDRESS */ + case 0x0020: /* XOR-MAPPED-ADDRESS (RFC 5389) */ + case 0x8020: /* XOR-MAPPED-ADDRESS (2005 draft) */ + /* Mapped Address or XOR Mapped Address */ + if (attr_len == 8 && ptr[1] == 1) { + /* IPv4 address */ + if ((attr_type & 0x7fff) == 0x0020) { + /* Restore XOR Mapped Address */ + ptr[2] ^= buffer[4]; + ptr[3] ^= buffer[5]; + ptr[4] ^= buffer[4]; + ptr[5] ^= buffer[5]; + ptr[6] ^= buffer[6]; + ptr[7] ^= buffer[7]; + } + + syslog(LOG_DEBUG, "%s: %s %hhu.%hhu.%hhu.%hhu:%hu", + "parse_stun_response", + ((attr_type & 0x7fff) == 0x0020) ? "XOR-MAPPED-ADDRESS" : "MAPPED-ADDRESS", + ptr[4], ptr[5], ptr[6], ptr[7], + (uint16_t)((ptr[2] << 8) + ptr[3])); + + /* Prefer XOR Mapped Address, some NATs change IP addresses in UDP packets */ + if (!have_xor_mapped_address) { + mapped_addr->sin_family = AF_INET; + mapped_addr->sin_port = htons(((uint16_t)ptr[2] << 8) + ptr[3]); + mapped_addr->sin_addr.s_addr = htonl(((uint32_t)ptr[4] << 24) + (ptr[5] << 16) + (ptr[6] << 8) + ptr[7]); + } + + if ((attr_type & 0x7fff) == 0x0020) + have_xor_mapped_address = 1; + + have_address = 1; + } + break; + case 0x0009: /* ERROR-CODE */ + if (attr_len >= 4) { + syslog(LOG_WARNING, "%s: ERROR-CODE %u %.*s", + "parse_stun_response", (unsigned)ptr[2] * 100 + ptr[3], + attr_len - 4, ptr + 4); + } + break; + case 0x0004: /* SOURCE-ADDRESS (RFC 3489) */ + case 0x0005: /* CHANGED-ADDRESS (RFC 3489) */ + case 0x802b: /* RESPONSE-ORIGIN (RFC 5780) */ + case 0x802c: /* OTHER-ADDRESS (RFC 5780) */ + if (attr_len == 8 && ptr[1] == 1) { + syslog(LOG_DEBUG, "%s: %s %hhu.%hhu.%hhu.%hhu:%hu", + "parse_stun_response", + (attr_type == 0x0004) ? "SOURCE-ADDRESS" : + (attr_type == 0x0005) ? "CHANGED-ADDRESS" : + (attr_type == 0x802b) ? "RESPONSE-ORIGIN" : "OTHER-ADDRESS", + ptr[4], ptr[5], ptr[6], ptr[7], + (uint16_t)((ptr[2] << 8) + ptr[3])); + } + break; + case 0x8022: /* SOFTWARE (RFC 5780) */ + syslog(LOG_DEBUG, "%s: SOFTWARE %.*s", "parse_stun_response", attr_len, ptr); + break; + default: + syslog(LOG_WARNING, "%s: unknown attribute type 0x%04x (len=%hu)", + "parse_stun_response", attr_type, attr_len); + } + + ptr += attr_len; + } + + return have_address ? 0 : -1; +} + +/* Perform main STUN operation, return external IP address and check + * if host is behind restrictive NAT. + * Restrictive NAT means any NAT which do some filtering and + * which is not static 1:1, basically NAT which is not usable + * for port forwarding */ +int perform_stun(const char *if_name, const char *if_addr, const char *stun_host, unsigned short stun_port, struct in_addr *ext_addr, int *restrictive_nat) +{ + int fds[4]; + size_t responses_lens[4]; + unsigned char responses_bufs[4][1024]; + unsigned char *responses[4]; + size_t responses_sizes[4]; + unsigned char requests[4][28]; + unsigned char *transaction_ids[4]; + int have_mapped_addr, mapped_addrs_count; + struct sockaddr_in remote_addr, peer_addrs[4], mapped_addrs[4]; + unsigned short local_ports[4]; + int have_ext_addr; + int i, j; + + if (resolve_stun_host(stun_host, stun_port, &remote_addr) != 0) + return -1; + + /* Prepare four different STUN requests */ + for (i = 0; i < 4; ++i) { + + responses_lens[i] = 0; + responses[i] = responses_bufs[i]; + responses_sizes[i] = sizeof(responses_bufs[i]); + + fds[i] = stun_socket(&local_ports[i]); + if (fds[i] < 0) { + for (j = 0; j < i; ++j) + close(fds[j]); + return -1; + } + + fill_request(requests[i], i/2, i%2); + transaction_ids[i] = requests[i]+8; + } + + syslog(LOG_INFO, "%s: local ports %hu %hu %hu %hu", + "perform_stun", local_ports[0], local_ports[1], + local_ports[2], local_ports[3]); + + /* Unblock local ports */ + for (i = 0; i < 4; ++i) { + if (add_filter_rule2(if_name, NULL, if_addr, local_ports[i], local_ports[i], IPPROTO_UDP, "stun test") < 0) { + syslog(LOG_ERR, "%s: add_filter_rule2(..., %hu, ...) FAILED", + "perform_stun", local_ports[i]); + } + } + + /* Send STUN requests and wait for responses */ + for (j = 0; j < 3; ++j) { + + for (i = 0; i < 4; ++i) { + ssize_t n; + if (responses_lens[i]) + continue; + n = sendto(fds[i], requests[i], sizeof(requests[i]), 0, (struct sockaddr *)&remote_addr, sizeof(remote_addr)); + if (n != sizeof(requests[i])) { + syslog(LOG_ERR, "%s: #%d,%d sendto(): %m", "perform_stun", j, i); + break; + } + } + + if (wait_for_stun_responses(fds, transaction_ids, responses, responses_sizes, peer_addrs, responses_lens) != 0) + break; + + if (responses_lens[0] && responses_lens[1] && responses_lens[2] && responses_lens[3]) + break; + + } + + /* Remove unblock for local ports */ + for (i = 0; i < 4; ++i) { + delete_filter_rule(if_name, local_ports[i], IPPROTO_UDP); + close(fds[i]); + } + + /* Parse received STUN messages */ + have_ext_addr = 0; + have_mapped_addr = 0; + mapped_addrs_count = 0; + for (i = 0; i < 4; ++i) { + if (parse_stun_response(responses[i], responses_lens[i], &mapped_addrs[i]) == 0) { + mapped_addrs_count++; + have_mapped_addr |= (1 << i); + if (!have_ext_addr) { + memcpy(ext_addr, &mapped_addrs[i].sin_addr, sizeof(*ext_addr)); + have_ext_addr = 1; + } + } + } + + /* We have no external address */ + if (!have_ext_addr) { + errno = ENXIO; + return -1; + } + + *restrictive_nat = 0; + + if (mapped_addrs_count < 4) { + /* We have not received all four responses, + * therefore NAT or firewall is doing some filtering */ + syslog(LOG_NOTICE, "%s: %d response out of 4 received", + "perform_stun", mapped_addrs_count); + *restrictive_nat = 1; + } + + if (memcmp(&remote_addr, &peer_addrs[0], sizeof(peer_addrs[0])) != 0) { + /* We received STUN response from different address + * even we did not asked for it, so some strange NAT is active */ + syslog(LOG_NOTICE, "%s: address changed", + "perform_stun"); + *restrictive_nat = 1; + } + + for (i = 0; i < 4; ++i) { + if (!(have_mapped_addr & (1 << i))) + continue; + if (ntohs(mapped_addrs[i].sin_port) != local_ports[i] || memcmp(&mapped_addrs[i].sin_addr, ext_addr, sizeof(*ext_addr)) != 0) { + /* External IP address or port was changed, + * therefore symmetric NAT is active */ + syslog(LOG_NOTICE, "%s: #%d external address or port changed", + "perform_stun", i); + *restrictive_nat = 1; + } + } + + /* Otherwise we are either directly connected or behind unrestricted NAT 1:1 */ + /* There is no filtering, so port forwarding would work fine */ + return 0; +} + +#ifdef TEST_LINUX_DEBUG_APP + +/* This linux test application for debugging purposes can be compiled as: */ +/* gcc upnpstun.c upnputils.o -o upnpstun -g3 -W -Wall -O2 -DTEST_LINUX_DEBUG_APP */ + +#include +#include + +#include "upnpglobalvars.h" +struct lan_addr_list lan_addrs; +int runtime_flags = 0; +time_t startup_time = 0; + +static int add_filter_rule2(const char *ifname, const char *rhost, const char *iaddr, unsigned short eport, unsigned short iport, int proto, const char *desc) +{ + char buffer[100]; + ifname = ifname; + rhost = rhost; + iaddr = iaddr; + iport = iport; + desc = desc; + snprintf(buffer, sizeof(buffer), "/sbin/iptables -t filter -I INPUT -p %d --dport %hu -j ACCEPT", proto, eport); + printf("Executing: %s\n", buffer); + return system(buffer); +} + +static int delete_filter_rule(const char * ifname, unsigned short port, int proto) +{ + char buffer[100]; + ifname = ifname; + snprintf(buffer, sizeof(buffer), "/sbin/iptables -t filter -D INPUT -p %d --dport %hu -j ACCEPT", proto, port); + printf("Executing: %s\n", buffer); + return system(buffer); +} + +int main(int argc, char *argv[]) +{ + struct in_addr ext_addr; + int restrictive_nat; + int ret; + char str[INET_ADDRSTRLEN]; + + if (argc != 3 && argc != 2) { + printf("Usage: %s stun_host [stun_port]\n", argv[0]); + return 1; + } + + if (geteuid() != 0) { + printf("You need to run this application as root\n"); + return 1; + } + + if (argc == 2) + argv[2] = "0"; + + srandom(time(NULL) * getpid()); + + ret = perform_stun(NULL, NULL, argv[1], atoi(argv[2]), &ext_addr, &restrictive_nat); + if (ret != 0) { + printf("STUN Failed: %s\n", strerror(errno)); + return 1; + } + + if (!inet_ntop(AF_INET, &ext_addr, str, INET_ADDRSTRLEN)) + str[0] = 0; + + printf("External IP address: %s\n", str); + printf("Restrictive NAT: %s\n", restrictive_nat ? "active (port forwarding impossible)" : "not used (ready for port forwarding)"); + return 0; +} + +#endif diff -Nru miniupnpd-2.1/upnpstun.h miniupnpd-2.2.1/upnpstun.h --- miniupnpd-2.1/upnpstun.h 1970-01-01 00:00:00.000000000 +0000 +++ miniupnpd-2.2.1/upnpstun.h 2018-07-06 11:43:31.000000000 +0000 @@ -0,0 +1,12 @@ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2018 Pali Rohár + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef UPNPSTUN_H_INCLUDED +#define UPNPSTUN_H_INCLUDED + +int perform_stun(const char *if_name, const char *if_addr, const char *stun_host, unsigned short stun_port, struct in_addr *ext_addr, int *restrictive_nat); + +#endif diff -Nru miniupnpd-2.1/VERSION miniupnpd-2.2.1/VERSION --- miniupnpd-2.1/VERSION 2018-05-08 21:34:44.000000000 +0000 +++ miniupnpd-2.2.1/VERSION 2020-12-20 17:50:50.000000000 +0000 @@ -1 +1 @@ -2.1 +2.2.1