diff --git a/README b/README index d41910f..af0d1fe 100644 --- a/README +++ b/README @@ -7,7 +7,7 @@ Freecode : http://freecode.com/projects/miniupnp miniupnpc/ : MiniUPnP client - an UPnP IGD control point miniupnpd/ : MiniUPnP daemon - an implementation of a UPnP IGD - + NAT-PMP gateway + + NAT-PMP / PCP gateway minissdpd/ : SSDP managing daemon. Designed to work with miniupnpc, miniupnpd, minidlna, etc. @@ -43,4 +43,6 @@ Thanks to : * David Kerr * Jardel Weyrich * Leah X. Schmidt + * Peter Tatrai * Leo Moll + * Daniel Becker diff --git a/minissdpd/.gitignore b/minissdpd/.gitignore index 9c8b266..6e1b69d 100644 --- a/minissdpd/.gitignore +++ b/minissdpd/.gitignore @@ -2,4 +2,5 @@ minissdpd testcodelength testminissdpd +listifaces Makefile.bak diff --git a/minissdpd/Changelog.txt b/minissdpd/Changelog.txt index fa17abd..0cf152a 100644 --- a/minissdpd/Changelog.txt +++ b/minissdpd/Changelog.txt @@ -1,4 +1,8 @@ -$Id: Changelog.txt,v 1.32 2013/08/19 16:40:55 nanard Exp $ +$Id: Changelog.txt,v 1.33 2014/02/03 15:45:07 nanard Exp $ + +2014/02/03: + silently ignore EAGAIN, EWOULDBLOCK, EINTR of recv calls + Discover devices on the network at startup 2013/08/19: Translate README in english diff --git a/minissdpd/Makefile b/minissdpd/Makefile index e924acb..99c2691 100644 --- a/minissdpd/Makefile +++ b/minissdpd/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.17 2012/05/02 10:26:50 nanard Exp $ +# $Id: Makefile,v 1.18 2014/02/03 14:32:14 nanard Exp $ # MiniUPnP project # author: Thomas Bernard # website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -59,6 +59,8 @@ testminissdpd: $(TESTMINISSDPDOBJS) testcodelength: testcodelength.o +listifaces: listifaces.o upnputils.o + depend: makedepend -f$(MAKEFILE_LIST) -Y \ $(ALLOBJS:.o=.c) 2>/dev/null diff --git a/minissdpd/listifaces.c b/minissdpd/listifaces.c index 14124ef..f893d6e 100644 --- a/minissdpd/listifaces.c +++ b/minissdpd/listifaces.c @@ -1,4 +1,7 @@ -/* $Id: listifaces.c,v 1.4 2007/09/23 16:59:02 nanard Exp $ */ +/* $Id: listifaces.c,v 1.6 2014/02/03 14:32:14 nanard Exp $ */ +/* (c) 2006-2014 Thomas BERNARD + * http://miniupnp.free.fr/ http://miniupnp.tuxfamily.org/ + */ #include #include #include @@ -8,7 +11,9 @@ #include #include #include +#include "upnputils.h" +/* hexdump */ void printhex(const unsigned char * p, int n) { int i; @@ -27,20 +32,28 @@ void printhex(const unsigned char * p, int n) } } -void listifaces() +/* List network interfaces */ +void listifaces(void) { struct ifconf ifc; - char * buf = 0; - int buflen = sizeof(struct ifreq)*20; - /*[sizeof(struct ifreq)*8];*/ + char * buf = NULL; + int buflen; int s, i; int j; char saddr[256/*INET_ADDRSTRLEN*/]; +#ifdef __linux__ + buflen = sizeof(struct ifreq)*10; +#else + buflen = 0; +#endif /*s = socket(PF_INET, SOCK_DGRAM, 0);*/ s = socket(AF_INET, SOCK_DGRAM, 0); do { +#ifdef __linux__ buflen += buflen; - buf = realloc(buf, buflen); +#endif + if(buflen > 0) + buf = realloc(buf, buflen); ifc.ifc_len = buflen; ifc.ifc_buf = (caddr_t)buf; if(ioctl(s, SIOCGIFCONF, &ifc) < 0) @@ -50,22 +63,39 @@ void listifaces() free(buf); return; } - printf("%d - %d - %d\n", buflen, ifc.ifc_len, (int)sizeof(struct ifreq)); - printf(" %d\n", IFNAMSIZ); - printf(" %d %d\n", (int)sizeof(struct sockaddr), (int)sizeof(struct sockaddr_in) ); - } while(buflen == ifc.ifc_len); + printf("buffer length=%d - buffer used=%d - sizeof(struct ifreq)=%d\n", + buflen, ifc.ifc_len, (int)sizeof(struct ifreq)); + printf("IFNAMSIZ=%d ", IFNAMSIZ); + printf("sizeof(struct sockaddr)=%d sizeof(struct sockaddr_in)=%d\n", + (int)sizeof(struct sockaddr), (int)sizeof(struct sockaddr_in) ); +#ifndef __linux__ + if(buflen == 0) + buflen = ifc.ifc_len; + else + break; + } while(1); +#else + } while(buflen <= ifc.ifc_len); +#endif printhex((const unsigned char *)ifc.ifc_buf, ifc.ifc_len); - j = 0; - for(i=0; iifr_name) + 16;//ifrp->ifr_addr.sa_len; /*inet_ntop(AF_INET, &(((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr), saddr, sizeof(saddr));*/ saddr[0] = '\0'; - inet_ntop(ifrp->ifr_addr.sa_family, &(ifrp->ifr_addr.sa_data[2]), saddr, sizeof(saddr)); - printf("%2d %d %d %s %s\n", j, ifrp->ifr_addr.sa_family, -1/*ifrp->ifr_addr.sa_len*/, ifrp->ifr_name, saddr); - j++; + /* inet_ntop(ifrp->ifr_addr.sa_family, &(ifrp->ifr_addr.sa_data[2]), saddr, sizeof(saddr)); */ + sockaddr_to_string(&ifrp->ifr_addr, saddr, sizeof(saddr)); + printf("0x%03x %2d %2d %-16s %s\n", i, j, ifrp->ifr_addr.sa_family, ifrp->ifr_name, saddr); + /*ifrp->ifr_addr.sa_len is only available on BSD */ +#ifdef __linux__ + i += sizeof(struct ifreq); +#else + if(ifrp->ifr_addr.sa_len == 0) + break; + i += IFNAMSIZ + ifrp->ifr_addr.sa_len; +#endif } free(buf); close(s); @@ -73,6 +103,8 @@ void listifaces() int main(int argc, char * * argv) { + (void)argc; + (void)argv; listifaces(); return 0; } diff --git a/minissdpd/minissdpd.c b/minissdpd/minissdpd.c index 520a6c5..2421a42 100644 --- a/minissdpd/minissdpd.c +++ b/minissdpd/minissdpd.c @@ -1,6 +1,6 @@ -/* $Id: minissdpd.c,v 1.35 2012/05/21 17:13:11 nanard Exp $ */ +/* $Id: minissdpd.c,v 1.37 2014/02/28 18:39:11 nanard Exp $ */ /* MiniUPnP project - * (c) 2007-2012 Thomas Bernard + * (c) 2007-2014 Thomas Bernard * website : 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 */ @@ -224,6 +224,7 @@ SendSSDPMSEARCHResponse(int s, const struct sockaddr * sockname, n = sendto(s, buf, l, 0, sockname, sockname_len ); if(n < 0) { + /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ syslog(LOG_ERR, "sendto(udp): %m"); } } @@ -282,8 +283,10 @@ processMSEARCH(int s, const char * st, int st_len, } } else { /* find matching services */ + /* remove version at the end of the ST string */ if(st[st_len-2]==':' && isdigit(st[st_len-1])) st_len -= 2; + /* answer for each matching service */ for(serv = servicelisthead.lh_first; serv; serv = serv->entries.le_next) { @@ -338,6 +341,7 @@ ParseSSDPPacket(int s, const char * p, ssize_t n, unsigned int lifetime = 180; /* 3 minutes by default */ const char * st = NULL; int st_len = 0; + memset(headers, 0, sizeof(headers)); for(methodlen = 0; methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-'); @@ -346,6 +350,12 @@ ParseSSDPPacket(int s, const char * p, ssize_t n, method = METHOD_MSEARCH; else if(methodlen==6 && 0==memcmp(p, "NOTIFY", 6)) method = METHOD_NOTIFY; + else if(methodlen==4 && 0==memcmp(p, "HTTP", 4)) { + /* answer to a M-SEARCH => process it as a NOTIFY + * with NTS: ssdp:alive */ + method = METHOD_NOTIFY; + nts = NTS_SSDP_ALIVE; + } linestart = p; while(linestart < p + n - 2) { /* start parsing the line : detect line end */ @@ -435,6 +445,8 @@ ParseSSDPPacket(int s, const char * p, ssize_t n, } else if(l==2 && 0==strncasecmp(linestart, "st", 2)) { st = valuestart; st_len = m; + if(method == METHOD_NOTIFY) + i = HEADER_NT; /* it was a M-SEARCH response */ } if(i>=0) { headers[i].p = valuestart; @@ -559,16 +571,16 @@ void processRequest(struct reqelem * req) syslog(LOG_WARNING, "bad request (length encoding)"); goto error; } - if(l == 0) { + if(l == 0 && type != 3) { syslog(LOG_WARNING, "bad request (length=0)"); goto error; } syslog(LOG_INFO, "(s=%d) request type=%d str='%.*s'", req->socket, type, l, p); switch(type) { - case 1: - case 2: - case 3: + case 1: /* request by type */ + case 2: /* request by USN (unique id) */ + case 3: /* everything */ while(d && (nrep < 255)) { if(d->t < t) { syslog(LOG_INFO, "outdated device"); @@ -633,12 +645,14 @@ void processRequest(struct reqelem * req) } } rbuf[0] = nrep; + syslog(LOG_DEBUG, "(s=%d) response : %d device%s", + req->socket, nrep, (nrep > 1) ? "s" : ""); if(write(req->socket, rbuf, rp - rbuf) < 0) { syslog(LOG_ERR, "(s=%d) write: %m", req->socket); goto error; } break; - case 4: + case 4: /* submit service */ newserv = malloc(sizeof(struct service)); if(!newserv) { syslog(LOG_ERR, "cannot allocate memory"); @@ -779,6 +793,60 @@ sigterm(int sig) /*errno = save_errno;*/ } +#define PORT 1900 +#define XSTR(s) STR(s) +#define STR(s) #s +#define UPNP_MCAST_ADDR "239.255.255.250" +/* for IPv6 */ +#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */ +#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */ + +/* send the M-SEARCH request for all devices */ +void ssdpDiscoverAll(int s, int ipv6) +{ + static const char MSearchMsgFmt[] = + "M-SEARCH * HTTP/1.1\r\n" + "HOST: %s:" XSTR(PORT) "\r\n" + "ST: ssdp:all\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: %u\r\n" + "\r\n"; + char bufr[512]; + int n; + int mx = 3; + int linklocal = 1; + struct sockaddr_storage sockudp_w; + + { + n = snprintf(bufr, sizeof(bufr), + MSearchMsgFmt, + ipv6 ? + (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") + : UPNP_MCAST_ADDR, mx); + memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; + p->sin6_family = AF_INET6; + p->sin6_port = htons(PORT); + inet_pton(AF_INET6, + linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, + &(p->sin6_addr)); + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; + p->sin_family = AF_INET; + p->sin_port = htons(PORT); + p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); + } + + n = sendto(s, bufr, n, 0, (const struct sockaddr *)&sockudp_w, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if (n < 0) { + /* XXX : EINTR EWOULDBLOCK EAGAIN */ + syslog(LOG_ERR, "sendto: %m"); + } + } +} + /* main(): program entry point */ int main(int argc, char * * argv) { @@ -957,6 +1025,11 @@ int main(int argc, char * * argv) writepidfile(pidfilename, pid); + /* send M-SEARCH ssdp:all Requests */ + ssdpDiscoverAll(s_ssdp, 0); + if(s_ssdp6 >= 0) + ssdpDiscoverAll(s_ssdp6, 1); + /* Main loop */ while(!quitting) { @@ -997,7 +1070,10 @@ int main(int argc, char * * argv) (struct sockaddr *)&sendername6, &sendername6_len); if(n<0) { - syslog(LOG_ERR, "recvfrom: %m"); + /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time) + * other errors : log to LOG_ERR */ + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + syslog(LOG_ERR, "recvfrom: %m"); } else { @@ -1028,7 +1104,10 @@ int main(int argc, char * * argv) (struct sockaddr *)&sendername, &sendername_len); if(n<0) { - syslog(LOG_ERR, "recvfrom: %m"); + /* EAGAIN, EWOULDBLOCK, EINTR : silently ignore (try again next time) + * other errors : log to LOG_ERR */ + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + syslog(LOG_ERR, "recvfrom: %m"); } else { diff --git a/minissdpd/testminissdpd.c b/minissdpd/testminissdpd.c index c06cf50..30ee92d 100644 --- a/minissdpd/testminissdpd.c +++ b/minissdpd/testminissdpd.c @@ -1,12 +1,13 @@ -/* $Id: testminissdpd.c,v 1.7 2012/05/02 10:28:25 nanard Exp $ */ +/* $Id: testminissdpd.c,v 1.8 2014/02/28 18:38:21 nanard Exp $ */ /* Project : miniupnp * website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas BERNARD - * copyright (c) 2005-2007 Thomas Bernard + * copyright (c) 2005-2014 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include #include +#include #include #include #include @@ -21,6 +22,8 @@ void printresponse(const unsigned char * resp, int n) int i, l; unsigned int nresp; const unsigned char * p; + if(n == 0) + return; for(i=0; iai_addr, p->ai_addrlen); #ifdef MINIUPNPC_IGNORE_EINTR - while(n < 0 && errno == EINTR) + /* EINTR The system call was interrupted by a signal that was caught + * EINPROGRESS The socket is nonblocking and the connection cannot + * be completed immediately. */ + while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) { socklen_t len; fd_set wset; diff --git a/miniupnpc/java/JavaBridgeTest.java b/miniupnpc/java/JavaBridgeTest.java index d026dbe..a7fa56d 100644 --- a/miniupnpc/java/JavaBridgeTest.java +++ b/miniupnpc/java/JavaBridgeTest.java @@ -72,7 +72,7 @@ public class JavaBridgeTest { System.out.println("AddPortMapping() failed with code " + ret); ret = miniupnpc.UPNP_GetSpecificPortMappingEntry( urls.controlURL.getString(0), new String(data.first.servicetype), - args[0], args[1], intClient, intPort, + args[0], args[1], null, intClient, intPort, desc, enabled, leaseDuration); if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) System.out.println("GetSpecificPortMappingEntry() failed with code " + ret); diff --git a/miniupnpc/miniupnpc.c b/miniupnpc/miniupnpc.c index d9debde..4c1412b 100644 --- a/miniupnpc/miniupnpc.c +++ b/miniupnpc/miniupnpc.c @@ -1,8 +1,8 @@ -/* $Id: miniupnpc.c,v 1.113 2013/10/07 10:04:56 nanard Exp $ */ +/* $Id: miniupnpc.c,v 1.116 2014/01/31 14:09:03 nanard Exp $ */ /* Project : miniupnp * Web : http://miniupnp.free.fr/ * Author : Thomas BERNARD - * copyright (c) 2005-2013 Thomas Bernard + * copyright (c) 2005-2014 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENSE file. */ #define __EXTENSIONS__ 1 @@ -545,7 +545,8 @@ upnpDiscover(int delay, const char * multicastif, } } - /* Avant d'envoyer le paquet on bind pour recevoir la reponse */ + /* Before sending the packed, we first "bind" in order to be able + * to receive the response */ if (bind(sudp, (const struct sockaddr *)&sockudp_r, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) { @@ -560,6 +561,10 @@ upnpDiscover(int delay, const char * multicastif, *error = UPNPDISCOVER_SUCCESS; /* Calculating maximum response time in seconds */ mx = ((unsigned int)delay) / 1000u; + if(mx == 0) { + mx = 1; + delay = 1000; + } /* receiving SSDP response packet */ for(n = 0; deviceList[deviceIndex]; deviceIndex++) { diff --git a/miniupnpc/miniupnpc.def b/miniupnpc/miniupnpc.def index 10b9f58..3343356 100644 --- a/miniupnpc/miniupnpc.def +++ b/miniupnpc/miniupnpc.def @@ -1,5 +1,6 @@ LIBRARY ; miniupnpc library + miniupnpc EXPORTS ; miniupnpc diff --git a/miniupnpc/miniupnpc.h b/miniupnpc/miniupnpc.h index 6f9b63d..2c0e475 100644 --- a/miniupnpc/miniupnpc.h +++ b/miniupnpc/miniupnpc.h @@ -1,4 +1,4 @@ -/* $Id: miniupnpc.h,v 1.32 2013/02/06 14:44:42 nanard Exp $ */ +/* $Id: miniupnpc.h,v 1.34 2014/01/31 13:18:25 nanard Exp $ */ /* Project: miniupnp * http://miniupnp.free.fr/ * Author: Thomas Bernard @@ -18,8 +18,8 @@ #define UPNPDISCOVER_MEMORY_ERROR (-102) /* versions : */ -#define MINIUPNPC_VERSION "1.8" -#define MINIUPNPC_API_VERSION 9 +#define MINIUPNPC_VERSION "1.9" +#define MINIUPNPC_API_VERSION 10 #ifdef __cplusplus extern "C" { diff --git a/miniupnpc/miniupnpcmodule.c b/miniupnpc/miniupnpcmodule.c index f520e8f..4654c98 100644 --- a/miniupnpc/miniupnpcmodule.c +++ b/miniupnpc/miniupnpcmodule.c @@ -1,8 +1,8 @@ -/* $Id: miniupnpcmodule.c,v 1.19 2012/01/21 13:30:32 nanard Exp $*/ +/* $Id: miniupnpcmodule.c,v 1.22 2014/01/31 13:18:25 nanard Exp $*/ /* Project : miniupnp * Author : Thomas BERNARD * website : http://miniupnp.tuxfamily.org/ - * copyright (c) 2007-2012 Thomas Bernard + * copyright (c) 2007-2014 Thomas Bernard * This software is subjet to the conditions detailed in the * provided LICENCE file. */ #include @@ -310,7 +310,7 @@ Py_END_ALLOW_THREADS } } -/* GetSpecificPortMapping(ePort, proto) +/* GetSpecificPortMapping(ePort, proto, remoteHost='') * proto = 'UDP' or 'TCP' */ static PyObject * UPnP_getspecificportmapping(UPnPObject *self, PyObject *args) @@ -318,13 +318,14 @@ UPnP_getspecificportmapping(UPnPObject *self, PyObject *args) char extPort[6]; unsigned short ePort; const char * proto; + const char * remoteHost = ""; char intClient[40]; char intPort[6]; unsigned short iPort; char desc[80]; char enabled[4]; char leaseDuration[16]; - if(!PyArg_ParseTuple(args, "Hs", &ePort, &proto)) + if(!PyArg_ParseTuple(args, "Hs|z", &ePort, &proto, &remoteHost)) return NULL; extPort[0] = '\0'; intClient[0] = '\0'; intPort[0] = '\0'; desc[0] = '\0'; enabled[0] = '\0'; leaseDuration[0] = '\0'; @@ -332,7 +333,7 @@ Py_BEGIN_ALLOW_THREADS sprintf(extPort, "%hu", ePort); UPNP_GetSpecificPortMappingEntry(self->urls.controlURL, self->data.first.servicetype, - extPort, proto, + extPort, proto, remoteHost, intClient, intPort, desc, enabled, leaseDuration); Py_END_ALLOW_THREADS diff --git a/miniupnpc/miniwget.c b/miniupnpc/miniwget.c index a75f55b..813db93 100644 --- a/miniupnpc/miniwget.c +++ b/miniupnpc/miniwget.c @@ -1,8 +1,8 @@ -/* $Id: miniwget.c,v 1.60 2013/10/07 10:03:16 nanard Exp $ */ +/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */ /* Project : miniupnp * Website : http://miniupnp.free.fr/ * Author : Thomas Bernard - * Copyright (c) 2005-2013 Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -39,9 +39,6 @@ #include #include #define closesocket close -/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions - * during the connect() call */ -#define MINIUPNPC_IGNORE_EINTR #endif /* #else _WIN32 */ #if defined(__sun) || defined(sun) #define MIN(x,y) (((x)<(y))?(x):(y)) diff --git a/miniupnpc/minixml.c b/miniupnpc/minixml.c index d3f7d06..1f22273 100644 --- a/miniupnpc/minixml.c +++ b/miniupnpc/minixml.c @@ -1,10 +1,10 @@ -/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 nanard Exp $ */ +/* $Id: minixml.c,v 1.10 2012/03/05 19:42:47 nanard Exp $ */ /* minixml.c : the minimum size a xml parser can be ! */ /* Project : miniupnp * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard -Copyright (c) 2005-2011, Thomas BERNARD +Copyright (c) 2005-2014, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without @@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p) const char * elementname; while(p->xml < (p->xmlend - 1)) { - if((p->xml)[0]=='<' && (p->xml)[1]!='?') + if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); + p->xml += 3; + } + else if((p->xml)[0]=='<' && (p->xml)[1]!='?') { i = 0; elementname = ++p->xml; while( !IS_WHITE_SPACE(*p->xml) diff --git a/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue b/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue new file mode 100644 index 0000000..26b169c --- /dev/null +++ b/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.namevalue @@ -0,0 +1,3 @@ +NewProtocol=UDP +NewExternalPort=12345 +NewRemoteHost= diff --git a/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml b/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml new file mode 100644 index 0000000..bbb540e --- /dev/null +++ b/miniupnpc/testreplyparse/GetSpecificPortMappingEntryReq.xml @@ -0,0 +1,3 @@ + +12345UDP + diff --git a/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue b/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue new file mode 100644 index 0000000..2189789 --- /dev/null +++ b/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.namevalue @@ -0,0 +1,5 @@ +NewInternalPort=12345 +NewInternalClient=192.168.10.110 +NewEnabled=1 +NewPortMappingDescription=libminiupnpc +NewLeaseDuration=0 diff --git a/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml b/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml new file mode 100644 index 0000000..77e8d9c --- /dev/null +++ b/miniupnpc/testreplyparse/GetSpecificPortMappingEntryResp.xml @@ -0,0 +1,2 @@ +12345192.168.10.1101libminiupnpc0 + diff --git a/miniupnpc/testupnpreplyparse.c b/miniupnpc/testupnpreplyparse.c index d753a20..7ba7131 100644 --- a/miniupnpc/testupnpreplyparse.c +++ b/miniupnpc/testupnpreplyparse.c @@ -1,7 +1,7 @@ -/* $Id: testupnpreplyparse.c,v 1.3 2013/05/14 20:37:36 nanard Exp $ */ +/* $Id: testupnpreplyparse.c,v 1.4 2014/01/27 11:45:19 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include @@ -74,7 +74,7 @@ int main(int argc, char * * argv) fclose(f); f = NULL; buffer[l] = '\0'; - if(argc >= 2) + if(argc > 2) { f = fopen(argv[2], "r"); if(!f) diff --git a/miniupnpc/upnpc.c b/miniupnpc/upnpc.c index ff132aa..70c9a54 100644 --- a/miniupnpc/upnpc.c +++ b/miniupnpc/upnpc.c @@ -1,7 +1,7 @@ -/* $Id: upnpc.c,v 1.99 2013/02/06 12:56:41 nanard Exp $ */ +/* $Id: upnpc.c,v 1.102 2014/02/05 17:27:14 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard - * Copyright (c) 2005-2013 Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. */ @@ -266,7 +266,7 @@ static void SetRedirectAndTest(struct UPNPUrls * urls, r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, data->first.servicetype, - eport, proto, + eport, proto, NULL/*remoteHost*/, intClient, intPort, NULL/*desc*/, NULL/*enabled*/, duration); if(r!=UPNPCOMMAND_SUCCESS) @@ -500,7 +500,7 @@ int main(int argc, char ** argv) return -1; } #endif - printf("upnpc : miniupnpc library test client. (c) 2005-2013 Thomas Bernard\n"); + printf("upnpc : miniupnpc library test client. (c) 2005-2014 Thomas Bernard\n"); printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" "for more information.\n"); /* command line processing */ diff --git a/miniupnpc/upnpcommands.c b/miniupnpc/upnpcommands.c index 76d2d8a..ad69781 100644 --- a/miniupnpc/upnpcommands.c +++ b/miniupnpc/upnpcommands.c @@ -1,4 +1,4 @@ -/* $Id: upnpcommands.c,v 1.41 2013/12/09 08:18:23 nanard Exp $ */ +/* $Id: upnpcommands.c,v 1.42 2014/01/31 13:18:25 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2012 Thomas Bernard @@ -578,7 +578,8 @@ LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, - const char * proto, + const char * proto, + const char * remoteHost, char * intClient, char * intPort, char * desc, @@ -597,7 +598,7 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL, GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); GetPortMappingArgs[0].elt = "NewRemoteHost"; - /* TODO : add remote host ? */ + GetPortMappingArgs[0].val = remoteHost; GetPortMappingArgs[1].elt = "NewExternalPort"; GetPortMappingArgs[1].val = extPort; GetPortMappingArgs[2].elt = "NewProtocol"; diff --git a/miniupnpc/upnpcommands.h b/miniupnpc/upnpcommands.h index ee68dfd..93d9f3d 100644 --- a/miniupnpc/upnpcommands.h +++ b/miniupnpc/upnpcommands.h @@ -1,7 +1,7 @@ -/* $Id: upnpcommands.h,v 1.23 2011/04/11 09:14:00 nanard Exp $ */ +/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */ /* Miniupnp project : http://miniupnp.free.fr/ * Author : Thomas Bernard - * Copyright (c) 2005-2011 Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided within this distribution */ #ifndef UPNPCOMMANDS_H_INCLUDED @@ -100,6 +100,8 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL, * errorCode errorDescription (short) - Description (long) * 402 Invalid Args - See UPnP Device Architecture section on Control. * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be * wild-carded * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded @@ -112,7 +114,13 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL, * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard * and cannot be a specific IP address or DNS name * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and - * cannot be a specific port value */ + * cannot be a specific port value + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ LIBSPEC int UPNP_AddPortMapping(const char * controlURL, const char * servicetype, const char * extPort, @@ -132,6 +140,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype, * * List of possible UPnP errors for DeletePortMapping : * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. * 714 NoSuchEntryInArray - The specified value does not exist in the array */ LIBSPEC int UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, @@ -150,6 +160,7 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL, * params : * in extPort * in proto + * in remoteHost * out intClient (16 bytes) * out intPort (6 bytes) * out desc (80 bytes) @@ -158,12 +169,21 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL, * * return value : * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR - * or a UPnP Error Code. */ + * or a UPnP Error Code. + * + * List of possible UPnP errors for _GetSpecificPortMappingEntry : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array. + */ LIBSPEC int UPNP_GetSpecificPortMappingEntry(const char * controlURL, const char * servicetype, const char * extPort, const char * proto, + const char * remoteHost, char * intClient, char * intPort, char * desc, @@ -188,6 +208,8 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL, * * Possible UPNP Error codes : * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds */ LIBSPEC int diff --git a/miniupnpd/.gitignore b/miniupnpd/.gitignore index dc70043..d6c6eb9 100644 --- a/miniupnpd/.gitignore +++ b/miniupnpd/.gitignore @@ -9,3 +9,7 @@ testgetifstats testupnpdescgen testupnppermissions testgetroute +testasyncsendto +netfilter/testiptcrdr +netfilter/testiptcrdr_dscp +netfilter/testiptcrdr_peer diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 4e549ea..3b65368 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -1,7 +1,53 @@ -$Id: Changelog.txt,v 1.345 2013/06/13 13:21:28 nanard Exp $ +$Id: Changelog.txt,v 1.363 2014/03/13 10:53:40 nanard Exp $ + +2014/03/13: + fix getifaddr_in6() (used for PCP) + implement permissions with PCP Map + fix upnp_event_notify_connect() when ENABLE_IPV6 is set + +2014/03/10: + Enable PCP by default. + Work in IPv6 on system where PF_INET6 are restricted to IPv6 only + change ipv6_enabled/ipv6fc_inbound_pinhole_allowed/ipv6fc_firewall_enabled + global vars to flags in runtime_flags + +2014/03/09: + IPv6 support in testgetifaddr + +2014/03/07: + NAT-PMP search an allowed eport instead of returning an error + if the original eport is not allowed. + +2014/03/06: + Fix add_filter_rule2() for pf. + +2014/02/28: + log message when shutting down + natpmp : avoid hang when all external ports in use + +2014/02/25: + add implementation of scheduled sendto (asyncsendto) in order + to retry failed sendto() calls or schedule sending of packets + +2014/02/24: + Defaulting to SSDP_RESPOND_SAME_VERSION + +2014/02/11: + Fix PCP Map renewal + +2014/02/06: + possibility to disable ipv6 at runtime + +2014/02/03: + PCP : Add support for ANNOUNCE requests + minixml now handle XML comments + +2013/12/16: + Attempt to compile with OS X/pf 2013/12/13: Make all manufacturer info configurable thanks to Leo Moll + Merge PCP support (see https://github.com/miniupnp/miniupnp) 2013/06/13: Have 3 UUID for the 3 devices (IGD, WAN Device, WAN Connection Device) diff --git a/miniupnpd/INSTALL b/miniupnpd/INSTALL index e6a6fbc..f249e7d 100644 --- a/miniupnpd/INSTALL +++ b/miniupnpd/INSTALL @@ -1,5 +1,5 @@ MiniUPnP project. -(c) 2006-2013 Thomas Bernard +(c) 2006-2014 Thomas Bernard Homepage : http://miniupnp.free.fr/ Mirror: http://miniupnp.tuxfamily.org/ github: https://github.com/miniupnp/miniupnp @@ -17,7 +17,9 @@ To Build and Install : Alternatively to editing config.h, options can be passed to genconfig.sh For more details : > ./genconfig.sh -h -- add "rdr-anchor miniupnpd" and "anchor miniupnpd" lines to /etc/pf.conf +- 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). - some FreeBSD users reported that it is also necessary for them to explicitly allow udp traffic on 239.0.0.0/8 by adding the two following lines to /etc/pf.conf : @@ -26,7 +28,7 @@ To Build and Install : - dont forget to " pfctl -f /etc/pf.conf " - you can check your modifications are taken into accout with "pfctl -s nat" and "pfctl -s rule". Look for the "rdr-anchor miniupnpd" - and "anchor miniupnpd" lines. + (if applicable) and/or "anchor miniupnpd" lines. - install as root using : # make install or @@ -53,7 +55,17 @@ http://blogs.sun.com/avalon/category/IPFilter - To enable non standard compilation options, > ./genconfig.sh -h Or edit config.h after it has been generated by genconfig.sh -- use 'bsdmake' or 'make -f Makefile.macosx' to build +- use 'bsdmake' (if available) or 'make -f Makefile.macosx' to build + +============================== Mac OS X/pf ================================ + +Starting with Mac OS X 10.7 Lion, pf replaced ipfw as the OS X firewall. +also bsdmake is not available anymore. +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 ============================ Linux/netfilter ============================== To Build and install : @@ -108,11 +120,11 @@ also available through command line switches. 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 asked, permission rules are evaluated in top-down -order and the first permission rule matched gives the answer : redirection -allowed or denied. If no rule is matching, the redirection is allowed, so -it is a good practice to have a "catch all" deny permission rule at the end -of your mermission ruleset. +When a new redirection is requested, permission rules are evaluated in +top-down order and the first permission rule matched gives the response : +redirection allowed or denied. If no rule is matching, the redirection is +allowed, so it is a good practice to have a "catch all" deny permission +rule at the end of your permission ruleset. Sample permission ruleset : allow 4662-4672 192.168.1.34/32 4662-4672 deny 0-65535 192.168.1.34/32 0-65535 @@ -137,8 +149,8 @@ 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 should be done -automatically. +This target is needed by the "install" target, so it is done automatically +during install. To stop the daemon use : # kill `cat /var/run/miniupnpd.pid` diff --git a/miniupnpd/Makefile b/miniupnpd/Makefile index 3192942..0025377 100644 --- a/miniupnpd/Makefile +++ b/miniupnpd/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.73 2013/02/06 13:11:45 nanard Exp $ +# $Id: Makefile,v 1.76 2014/03/10 10:26:15 nanard Exp $ # MiniUPnP project # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # Author: Thomas Bernard @@ -78,9 +78,9 @@ CFLAGS += -m64 -mcmodel=medlow 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 \ + options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ upnpevents.o upnputils.o getconnstatus.o \ - upnppinhole.o + upnppinhole.o asyncsendto.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 @@ -116,10 +116,11 @@ 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 EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ testupnppermissions miniupnpdctl \ - testgetifaddr testgetroute + testgetifaddr testgetroute testasyncsendto .if $(OSNAME) == "Darwin" LIBS = .else @@ -142,13 +143,13 @@ clean: $(RM) $(STDOBJS) $(BSDOBJS) $(SUNOSOBJS) $(MACOBJS) $(EXECUTABLES) \ testupnpdescgen.o \ $(MISCOBJS) config.h testgetifstats.o testupnppermissions.o \ - miniupnpdctl.o testgetifaddr.o testgetroute.o \ + miniupnpdctl.o testgetifaddr.o testgetroute.o testasyncsendto.o \ $(PFOBJS) $(IPFOBJS) $(IPFWOBJS) install: miniupnpd genuuid $(STRIP) miniupnpd $(INSTALL) -d $(DESTDIR)$(INSTALLBINDIR) - $(INSTALL) -m 555 miniupnpd $(DESTDIR)$(INSTALLBINDIR) + $(INSTALL) -m 755 miniupnpd $(DESTDIR)$(INSTALLBINDIR) $(INSTALL) -d $(DESTDIR)$(INSTALLETCDIR) $(INSTALL) -b miniupnpd.conf $(DESTDIR)$(INSTALLETCDIR) # TODO : install man page correctly @@ -199,6 +200,9 @@ testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS) testgetroute: config.h $(TESTGETROUTEOBJS) $(CC) $(CFLAGS) -o $@ $(TESTGETROUTEOBJS) +testasyncsendto: config.h $(TESTASYNCSENDTOOBJS) + $(CC) $(CFLAGS) -o $@ $(TESTASYNCSENDTOOBJS) + # gmake : # $(CC) $(CFLAGS) -o $@ $^ # BSDmake : diff --git a/miniupnpd/Makefile.linux b/miniupnpd/Makefile.linux index 56fd9a6..27639b2 100644 --- a/miniupnpd/Makefile.linux +++ b/miniupnpd/Makefile.linux @@ -1,6 +1,6 @@ -# $Id: Makefile.linux,v 1.78 2013/05/03 09:30:33 nanard Exp $ +# $Id: Makefile.linux,v 1.81 2014/01/27 10:06:58 nanard Exp $ # MiniUPnP project -# (c) 2006-2013 Thomas Bernard +# (c) 2006-2014 Thomas Bernard # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # Author : Thomas Bernard # for use with GNU Make @@ -45,9 +45,9 @@ 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\ + options.o upnppermissions.o minissdp.o natpmp.o pcpserver.o \ upnpevents.o upnputils.o getconnstatus.o \ - upnppinhole.o pcplearndscp.o + upnppinhole.o pcplearndscp.o asyncsendto.o LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o NETFILTEROBJS = netfilter/iptcrdr.o netfilter/iptpinhole.o netfilter/nfct_get.o @@ -150,7 +150,7 @@ TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \ testupnppermissions miniupnpdctl testgetifaddr \ - testgetroute + testgetroute testasyncsendto .PHONY: all clean install depend genuuid @@ -161,7 +161,7 @@ clean: $(RM) $(EXECUTABLES) $(RM) testupnpdescgen.o testgetifstats.o $(RM) testupnppermissions.o testgetifaddr.o - $(RM) testgetroute.o + $(RM) testgetroute.o testasyncsendto.o $(RM) miniupnpdctl.o install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \ @@ -205,6 +205,9 @@ testgetifaddr: testgetifaddr.o getifaddr.o testgetroute: testgetroute.o linux/getroute.o upnputils.o -lnfnetlink +testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o \ + linux/getroute.o -lnfnetlink + miniupnpdctl: miniupnpdctl.o config.h: genconfig.sh VERSION @@ -214,15 +217,15 @@ depend: config.h makedepend -f$(MAKEFILE_LIST) -Y \ $(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \ testgetifstats.c testupnppermissions.c testgetifaddr.c \ - testgetroute.c miniupnpdctl.c 2>/dev/null + testgetroute.c testasyncsendto.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 natpmp.h commonrdr.h -miniupnpd.o: upnputils.h ifacewatcher.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 @@ -249,21 +252,25 @@ 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 codelength.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 -pcpserver.o: config.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 +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 @@ -275,12 +282,14 @@ 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: getifaddr.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 miniupnpdctl.o: macros.h diff --git a/miniupnpd/Makefile.macosx b/miniupnpd/Makefile.macosx index f8d2bf9..27280c6 100644 --- a/miniupnpd/Makefile.macosx +++ b/miniupnpd/Makefile.macosx @@ -3,6 +3,10 @@ # Author: Thomas Bernard # This Makefile should work for MacOSX # +# To compile with pf with OS X 10.7+, you need to specify +# path to XNU bsd sources : +# INCLUDES="-I.../xnu/bsd I.../xnu/libkern" make -f Makefile.macosx +# # To install use : # $ PREFIX=/dummyinstalldir make -f Makefile.macosx install # or : @@ -10,26 +14,38 @@ # CFLAGS = -Wall -O -g3 -DDEBUG #CFLAGS = -Wall -Os -CC = gcc +#CC = gcc #better use clang ! RM = rm -f MV = mv INSTALL = install STRIP = strip +CFLAGS += -DMACOSX + # OSNAME and FWNAME are used for building OS or FW dependent code. OSNAME = $(shell uname) ARCH = $(shell uname -p) -FWNAME = ipfw +# Firewall is ipfw up to OS X 10.6 Snow Leopard +# and pf since OS X 10.7 Lion (Darwin 11.0) +FWNAME = $(shell [ `uname -r | cut -d. -f1` -ge 11 ] && echo "pf" || echo "ipfw" ) STD_OBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \ upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.o \ options.o upnppermissions.o minissdp.o natpmp.o \ - upnpevents.o getconnstatus.o upnputils.o + upnpevents.o getconnstatus.o upnputils.o \ + asyncsendto.o MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o IPFW_OBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o +PF_OBJS = pf/obsdrdr.o pf/pfpinhole.o MISC_OBJS = upnpreplyparse.o minixml.o -ALL_OBJS = $(STD_OBJS) $(MISC_OBJS) $(MAC_OBJS) $(IPFW_OBJS) +ALL_OBJS = $(STD_OBJS) $(MISC_OBJS) $(MAC_OBJS) +ifeq ($(FWNAME), ipfw) + ALL_OBJS += $(IPFW_OBJS) +else + ALL_OBJS += $(PF_OBJS) + CFLAGS += -DPF +endif TEST_UPNPDESCGEN_OBJS = testupnpdescgen.o upnpdescgen.o TEST_GETIFSTATS_OBJS = testgetifstats.o mac/getifstats.o @@ -106,5 +122,5 @@ config.h: genconfig.sh .SUFFIXES: .o .c .c.o: - $(CC) $(CFLAGS) -c -o $@ $< + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< # $(CC) $(CFLAGS) -c -o $(.TARGET) $(.IMPSRC) diff --git a/miniupnpd/README b/miniupnpd/README index 0499bb0..09bd087 100644 --- a/miniupnpd/README +++ b/miniupnpd/README @@ -1,5 +1,5 @@ MiniUPnP project -(c) 2006-2012 Thomas Bernard +(c) 2006-2014 Thomas Bernard webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ github: https://github.com/miniupnp/miniupnp freecode: http://freecode.com/projects/miniupnp @@ -22,8 +22,11 @@ Support for the NAT Port Mapping Protocol (NAT-PMP) has been added. See information about NAT-PMP here : http://miniupnp.free.fr/nat-pmp.html +NAT-PMP is the precursor of Port Control Protocol (PCP). +In 2013, support for PCP has been added too. + Read the INSTALL files for instructions to compile, install and -configure miniupnpd. +configure miniupnpd on your system. Report bugs to miniupnp@free.fr on the web forum http://miniupnp.tuxfamily.org/forum/ diff --git a/miniupnpd/asyncsendto.c b/miniupnpd/asyncsendto.c new file mode 100644 index 0000000..8c83e25 --- /dev/null +++ b/miniupnpd/asyncsendto.c @@ -0,0 +1,273 @@ +/* $Id: $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2014 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 "asyncsendto.h" + +/* state diagram for a packet : + * + * | + * V + * -> ESCHEDULED -> ESENDNOW -> sent + * ^ | + * | V + * EWAITREADY -> sent + */ +struct scheduled_send { + LIST_ENTRY(scheduled_send) entries; + struct timeval ts; + enum {ESCHEDULED=1, EWAITREADY=2, ESENDNOW=3} state; + int sockfd; + const void * buf; + size_t len; + int flags; + const struct sockaddr *dest_addr; + socklen_t addrlen; + char data[]; +}; + +static LIST_HEAD(listhead, scheduled_send) send_list = { NULL }; + +/* + * ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, + * const struct sockaddr *dest_addr, socklen_t addrlen); + */ + +/* delay = milli seconds */ +ssize_t +sendto_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen, + unsigned int delay) +{ + enum {ESCHEDULED, EWAITREADY, ESENDNOW} state; + ssize_t n; + struct timeval tv; + struct scheduled_send * elt; + + if(delay == 0) { + /* first try to send at once */ + n = sendto(sockfd, buf, len, flags, dest_addr, addrlen); + if(n >= 0) + return n; + else if(errno == EAGAIN || errno == EWOULDBLOCK) { + /* use select() on this socket */ + state = EWAITREADY; + } else if(errno == EINTR) { + state = ESENDNOW; + } else { + /* uncatched error */ + return n; + } + } else { + state = ESCHEDULED; + } + + /* schedule */ + if(gettimeofday(&tv, 0) < 0) { + return -1; + } + /* allocate enough space for structure + buffers */ + elt = malloc(sizeof(struct scheduled_send) + len + addrlen); + if(elt == NULL) { + syslog(LOG_ERR, "malloc failed to allocate %u bytes", + (unsigned)(sizeof(struct scheduled_send) + len + addrlen)); + return -1; + } + elt->state = state; + /* time the packet should be sent */ + elt->ts.tv_sec = tv.tv_sec + (delay / 1000); + elt->ts.tv_usec = tv.tv_usec + (delay % 1000) * 1000; + if(elt->ts.tv_usec > 1000000) { + elt->ts.tv_sec++; + elt->ts.tv_usec -= 1000000; + } + elt->sockfd = sockfd; + elt->flags = flags; + memcpy(elt->data, dest_addr, addrlen); + elt->dest_addr = (struct sockaddr *)elt->data; + elt->addrlen = addrlen; + memcpy(elt->data + addrlen, buf, len); + elt->buf = (void *)(elt->data + addrlen); + elt->len = len; + /* insert */ + LIST_INSERT_HEAD( &send_list, elt, entries); + return 0; +} + + +/* try to send at once, and queue the packet if needed */ +ssize_t +sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen) +{ + return sendto_schedule(sockfd, buf, len, flags, dest_addr, addrlen, 0); +} + +/* get_next_scheduled_send() return number of scheduled send in list */ +int get_next_scheduled_send(struct timeval * next_send) +{ + int n = 0; + struct scheduled_send * elt; + if(next_send == NULL) + return -1; + for(elt = send_list.lh_first; elt != NULL; elt = elt->entries.le_next) { + if(n == 0 || (elt->ts.tv_sec < next_send->tv_sec) || + (elt->ts.tv_sec == next_send->tv_sec && elt->ts.tv_usec < next_send->tv_usec)) { + next_send->tv_sec = elt->ts.tv_sec; + next_send->tv_usec = elt->ts.tv_usec; + } + n++; + } + return n; +} + +/* update writefds for select() call + * return the number of packets to try to send at once */ +int get_sendto_fds(fd_set * writefds, int * max_fd, const struct timeval * now) +{ + int n = 0; + struct scheduled_send * elt; + for(elt = send_list.lh_first; elt != NULL; elt = elt->entries.le_next) { + if(elt->state == EWAITREADY) { + /* last sendto() call returned EAGAIN/EWOULDBLOCK */ + FD_SET(elt->sockfd, writefds); + if(elt->sockfd > *max_fd) + *max_fd = elt->sockfd; + n++; + } else if((elt->ts.tv_sec < now->tv_sec) || + (elt->ts.tv_sec == now->tv_sec && elt->ts.tv_usec <= now->tv_usec)) { + /* we waited long enough, now send ! */ + elt->state = ESENDNOW; + n++; + } + } + return n; +} + +/* executed sendto() when needed */ +int try_sendto(fd_set * writefds) +{ + ssize_t n; + struct scheduled_send * elt; + struct scheduled_send * next; + for(elt = send_list.lh_first; elt != NULL; elt = next) { + next = elt->entries.le_next; + if((elt->state == ESENDNOW) || + (elt->state == EWAITREADY && FD_ISSET(elt->sockfd, writefds))) { + syslog(LOG_DEBUG, "try_sendto(): %d bytes on socket %d", + (int)elt->len, elt->sockfd); + n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags, + elt->dest_addr, elt->addrlen); + if(n < 0) { + if(errno == EINTR) { + /* retry at once */ + elt->state = ESENDNOW; + continue; + } else if(errno == EAGAIN || errno == EWOULDBLOCK) { + /* retry once the socket is ready for writing */ + elt->state = EWAITREADY; + continue; + } + /* uncatched error */ + /* remove from the list */ + LIST_REMOVE(elt, entries); + free(elt); + return n; + } else { + /* remove from the list */ + LIST_REMOVE(elt, entries); + free(elt); + } + } + } + return 0; +} + +/* maximum execution time for finalize_sendto() in milliseconds */ +#define FINALIZE_SENDTO_DELAY (500) + +/* empty the list */ +void finalize_sendto(void) +{ + ssize_t n; + struct scheduled_send * elt; + struct scheduled_send * next; + fd_set writefds; + struct timeval deadline; + struct timeval now; + struct timeval timeout; + int max_fd; + + if(gettimeofday(&deadline, NULL) < 0) { + syslog(LOG_ERR, "gettimeofday: %m"); + return; + } + deadline.tv_usec += FINALIZE_SENDTO_DELAY*1000; + if(deadline.tv_usec > 1000000) { + deadline.tv_sec++; + deadline.tv_usec -= 1000000; + } + while(send_list.lh_first) { + FD_ZERO(&writefds); + max_fd = -1; + for(elt = send_list.lh_first; elt != NULL; elt = next) { + next = elt->entries.le_next; + syslog(LOG_DEBUG, "finalize_sendto(): %d bytes on socket %d", + (int)elt->len, elt->sockfd); + n = sendto(elt->sockfd, elt->buf, elt->len, elt->flags, + elt->dest_addr, elt->addrlen); + if(n < 0) { + if(errno==EAGAIN || errno==EWOULDBLOCK) { + FD_SET(elt->sockfd, &writefds); + if(elt->sockfd > max_fd) + max_fd = elt->sockfd; + continue; + } + syslog(LOG_WARNING, "finalize_sendto(): socket=%d sendto: %m", elt->sockfd); + } + /* remove from the list */ + LIST_REMOVE(elt, entries); + free(elt); + } + /* check deadline */ + if(gettimeofday(&now, NULL) < 0) { + syslog(LOG_ERR, "gettimeofday: %m"); + return; + } + if(now.tv_sec > deadline.tv_sec || + (now.tv_sec == deadline.tv_sec && now.tv_usec > deadline.tv_usec)) { + /* deadline ! */ + while((elt = send_list.lh_first) != NULL) { + LIST_REMOVE(elt, entries); + free(elt); + } + return; + } + /* compute timeout value */ + timeout.tv_sec = deadline.tv_sec - now.tv_sec; + timeout.tv_usec = deadline.tv_usec - now.tv_usec; + if(timeout.tv_usec < 0) { + timeout.tv_sec--; + timeout.tv_usec += 1000000; + } + if(max_fd >= 0) { + if(select(max_fd + 1, NULL, &writefds, NULL, &timeout) < 0) { + syslog(LOG_ERR, "select: %m"); + return; + } + } + } +} + diff --git a/miniupnpd/asyncsendto.h b/miniupnpd/asyncsendto.h new file mode 100644 index 0000000..60c04de --- /dev/null +++ b/miniupnpd/asyncsendto.h @@ -0,0 +1,38 @@ +/* $Id: $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2014 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef ASYNCSENDTO_H_INCLUDED +#define ASYNCSENDTO_H_INCLUDED + +/* sendto_schedule() : see sendto(2) + * schedule sendto() call after delay (milliseconds) */ +ssize_t +sendto_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen, + unsigned int delay); + +/* sendto_schedule() : see sendto(2) + * try sendto() at once and schedule if EINTR/EAGAIN/EWOULDBLOCK */ +ssize_t +sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); + +/* get_next_scheduled_send() + * return number of scheduled sendto + * set next_send to timestamp to send next packet */ +int get_next_scheduled_send(struct timeval * next_send); + +/* execute sendto() for needed packets */ +int try_sendto(fd_set * writefds); + +/* set writefds before select() */ +int get_sendto_fds(fd_set * writefds, int * max_fd, const struct timeval * now); + +/* empty the list */ +void finalize_sendto(void); + +#endif diff --git a/miniupnpd/commonrdr.h b/miniupnpd/commonrdr.h index dd5cf62..7c0bd7c 100644 --- a/miniupnpd/commonrdr.h +++ b/miniupnpd/commonrdr.h @@ -1,6 +1,6 @@ -/* $Id: commonrdr.h,v 1.7 2011/06/22 20:34:39 nanard Exp $ */ +/* $Id: commonrdr.h,v 1.9 2014/02/11 09:36:15 nanard Exp $ */ /* MiniUPnP project - * (c) 2006-2011 Thomas Bernard + * (c) 2006-2014 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 */ @@ -10,6 +10,9 @@ #include "config.h" /* init and shutdown functions */ +/* init_redirect() return values : + * 0 : OK + * -1 : error */ int init_redirect(void); @@ -17,7 +20,10 @@ void shutdown_redirect(void); /* get_redirect_rule() gets internal IP and port from - * interface, external port and protocl + * interface, external port and protocol + * return value : + * 0 success (rule found) + * -1 error or rule not found */ int get_redirect_rule(const char * ifname, unsigned short eport, int proto, @@ -27,6 +33,10 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto, unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes); +/* get_redirect_rule_by_index() + * return values : + * 0 success (rule found) + * -1 error or rule not found */ int get_redirect_rule_by_index(int index, char * ifname, unsigned short * eport, diff --git a/miniupnpd/genconfig.sh b/miniupnpd/genconfig.sh index efad1f5..13a54e6 100755 --- a/miniupnpd/genconfig.sh +++ b/miniupnpd/genconfig.sh @@ -1,8 +1,8 @@ #! /bin/sh -# $Id: genconfig.sh,v 1.63 2013/05/03 09:30:10 nanard Exp $ +# $Id: genconfig.sh,v 1.72 2014/03/10 10:17:17 nanard Exp $ # miniupnp daemon # http://miniupnp.free.fr or http://miniupnp.tuxfamily.org/ -# (c) 2006-2013 Thomas Bernard +# (c) 2006-2014 Thomas Bernard # This software is subject to the conditions detailed in the # LICENCE file provided within the distribution @@ -12,18 +12,15 @@ case "$argv" in --igd2) IGD2=1 ;; --strict) STRICT=1 ;; --leasefile) LEASEFILE=1 ;; - --pcp) PCP=1 ;; - --pcp-peer) - PCP=1 - PCP_PEER=1 - ;; + --vendorcfg) VENDORCFG=1 ;; + --pcp-peer) PCP_PEER=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 " --pcp enable PCP" + echo " --vendorcfg enable configuration of manufacturer info" echo " --pcp-peer enable PCP PEER operation" exit 1 ;; @@ -81,7 +78,7 @@ ${RM} ${CONFIGFILE} echo "/* MiniUPnP Project" >> ${CONFIGFILE} echo " * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/" >> ${CONFIGFILE} -echo " * (c) 2006-2013 Thomas Bernard" >> ${CONFIGFILE} +echo " * (c) 2006-2014 Thomas Bernard" >> ${CONFIGFILE} echo " * generated by $0 on `date`" >> ${CONFIGFILE} echo " * using command line options $* */" >> ${CONFIGFILE} echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE} @@ -118,6 +115,7 @@ case $OS_NAME in FW=pf echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} OS_URL=http://www.openbsd.org/ + V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only` ;; FreeBSD) VER=`grep '#define __FreeBSD_version' /usr/include/sys/param.h | awk '{print $3}'` @@ -148,12 +146,14 @@ case $OS_NAME in 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 @@ -273,8 +273,15 @@ case $OS_NAME in FW=netfilter ;; Darwin) + MAJORVER=`echo $OS_VERSION | cut -d. -f1` echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE} - FW=ipfw + # 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 ;; *) @@ -304,6 +311,11 @@ case $FW in ;; 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." @@ -332,15 +344,9 @@ echo "/* Comment the following line to disable NAT-PMP operations */" >> ${CONFI echo "#define ENABLE_NATPMP" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} -if [ -n "$PCP" ]; then echo "/* Comment the following line to disable PCP operations */" >> ${CONFIGFILE} echo "#define ENABLE_PCP" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} -else -echo "/* Uncomment the following line to enable PCP operations */" >> ${CONFIGFILE} -echo "/*#define ENABLE_PCP*/" >> ${CONFIGFILE} -echo "" >> ${CONFIGFILE} -fi echo "#ifdef ENABLE_PCP" >> ${CONFIGFILE} if [ -n "$PCP_PEER" ]; then @@ -352,9 +358,9 @@ echo "/*#define PCP_PEER*/" >> ${CONFIGFILE} fi echo "#ifdef PCP_PEER" >> ${CONFIGFILE} echo "/*#define PCP_FLOWP*/" >> ${CONFIGFILE} -echo "#endif //PCP_PEER" >> ${CONFIGFILE} +echo "#endif /*PCP_PEER*/" >> ${CONFIGFILE} echo "/*#define PCP_SADSCP*/" >> ${CONFIGFILE} -echo "#endif //ENABLE_PCP" >> ${CONFIGFILE} +echo "#endif /*ENABLE_PCP*/" >> ${CONFIGFILE} echo "" >> ${CONFIGFILE} echo "/* Uncomment the following line to enable generation of" >> ${CONFIGFILE} @@ -405,6 +411,15 @@ else 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} + 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} @@ -448,6 +463,12 @@ else 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} @@ -456,12 +477,24 @@ else 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 "/* Unable the ability to configure all manufacturer infos through miniupnpd.conf */" >> ${CONFIGFILE} -echo "/*#define ENABLE_MANUFACTURER_INFO_CONFIGURATION*/" >> ${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} echo "#endif" >> ${CONFIGFILE} diff --git a/miniupnpd/getifaddr.c b/miniupnpd/getifaddr.c index 2a84852..f3459a5 100644 --- a/miniupnpd/getifaddr.c +++ b/miniupnpd/getifaddr.c @@ -1,4 +1,4 @@ -/* $Id: getifaddr.c,v 1.17 2013/04/27 15:40:09 nanard Exp $ */ +/* $Id: getifaddr.c,v 1.19 2013/12/13 14:28:40 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2013 Thomas Bernard @@ -119,9 +119,16 @@ getifaddr(const char * ifname, char * buf, int len, } #ifdef ENABLE_PCP -int getifaddr_in6(const char * ifname, struct in6_addr * addr){ +/* XXX I don't know if this function should return + * IPv4 or IPv6 if both are enabled... */ +int getifaddr_in6(const char * ifname, struct in6_addr * addr) +{ struct ifaddrs * ifap; struct ifaddrs * ife; +#ifdef ENABLE_IPV6 + const struct sockaddr_in6 * tmpaddr; +#endif /* ENABLE_IPV6 */ + int found = 0; if(!ifname || ifname[0]=='\0') return -1; @@ -130,9 +137,8 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){ syslog(LOG_ERR, "getifaddrs: %m"); return -1; } - for(ife = ifap; ife; ife = ife->ifa_next) + for(ife = ifap; ife && !found; ife = ife->ifa_next) { - int found = 0; /* skip other interfaces if one was specified */ if(ifname && (0 != strcmp(ifname, ife->ifa_name))) continue; @@ -141,32 +147,35 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){ switch(ife->ifa_addr->sa_family) { case AF_INET: - addr->s6_addr32[0]=0; - addr->s6_addr32[1]=0; - addr->s6_addr32[2]=htonl(0xffff); - addr->s6_addr32[3]=((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr; - //inet_ntop(ife->ifa_addr->sa_family, - // &((struct sockaddr_in *)ife->ifa_addr)->sin_addr, - // buf, len); + /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */ + memset(addr->s6_addr, 0, 10); + addr->s6_addr[10] = 0xff; + addr->s6_addr[11] = 0xff; + memcpy(addr->s6_addr + 12, + &(((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr), + 4); found = 1; break; +#ifdef ENABLE_IPV6 case AF_INET6: - if(!IN6_IS_ADDR_LOOPBACK(&addr->s6_addr32) - && !IN6_IS_ADDR_LINKLOCAL(&addr->s6_addr32)) { - memcpy(addr->s6_addr32, &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr, sizeof(addr->s6_addr32)); + tmpaddr = (const struct sockaddr_in6 *)ife->ifa_addr; + if(!IN6_IS_ADDR_LOOPBACK(&tmpaddr->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&tmpaddr->sin6_addr)) + { + memcpy(addr->s6_addr, + &tmpaddr->sin6_addr, + 16); found = 1; } break; - } - if (found) { - break; +#endif /* ENABLE_IPV6 */ } } freeifaddrs(ifap); - return 0; + return (found ? 0 : -1); } -#endif +#endif /* ENABLE_PCP */ #ifdef ENABLE_IPV6 int diff --git a/miniupnpd/minissdp.c b/miniupnpd/minissdp.c index a67c94b..cdd6f08 100644 --- a/miniupnpd/minissdp.c +++ b/miniupnpd/minissdp.c @@ -1,7 +1,7 @@ -/* $Id: minissdp.c,v 1.54 2013/06/15 12:50:10 nanard Exp $ */ +/* $Id: minissdp.c,v 1.61 2014/03/10 11:04:51 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -24,6 +24,7 @@ #include "minissdp.h" #include "upnputils.h" #include "getroute.h" +#include "asyncsendto.h" #include "codelength.h" /* SSDP ip/port */ @@ -146,7 +147,11 @@ OpenAndConfSSDPReceiveSocket(int ipv6) #ifdef ENABLE_IPV6 if(ipv6) { - AddMulticastMembershipIPv6(s); + if(AddMulticastMembershipIPv6(s) < 0) + { + syslog(LOG_WARNING, + "Failed to add IPv6 multicast membership"); + } } else #endif @@ -276,9 +281,16 @@ OpenAndConfSSDPNotifySockets(int * sockets) goto error; i++; #ifdef ENABLE_IPV6 - sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index); - if(sockets[i] < 0) - goto error; + if(GETFLAG(IPV6DISABLEDMASK)) + { + sockets[i] = -1; + } + else + { + sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index); + if(sockets[i] < 0) + goto error; + } i++; #endif } @@ -319,11 +331,13 @@ EXT: * st, st_len : ST: header * suffix : suffix for USN: header * host, port : our HTTP host, port + * delay : in milli-seconds */ static void SendSSDPResponse(int s, const struct sockaddr * addr, const char * st, int st_len, const char * suffix, - const char * host, unsigned short port, const char * uuidvalue) + const char * host, unsigned short port, const char * uuidvalue, + unsigned int delay) { int l, n; char buf[512]; @@ -388,15 +402,14 @@ SendSSDPResponse(int s, const struct sockaddr * addr, } addrlen = (addr->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); - n = sendto(s, buf, l, 0, - addr, addrlen); + n = sendto_schedule(s, buf, l, 0, + addr, addrlen, delay); sockaddr_to_string(addr, addr_str, sizeof(addr_str)); syslog(LOG_INFO, "SSDP Announce %d bytes to %s ST: %.*s",n, addr_str, l, buf); if(n < 0) { - /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ syslog(LOG_ERR, "sendto(udp): %m"); } } @@ -477,7 +490,7 @@ SendSSDPNotify(int s, const struct sockaddr * dest, syslog(LOG_WARNING, "SendSSDPNotify(): truncated output"); l = sizeof(bufr) - 1; } - n = sendto(s, bufr, l, 0, dest, + n = sendto_or_schedule(s, bufr, l, 0, dest, #ifdef ENABLE_IPV6 ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in) #else @@ -486,7 +499,6 @@ SendSSDPNotify(int s, const struct sockaddr * dest, ); if(n < 0) { - /* XXX handle EINTR, EAGAIN, EWOULDBLOCK */ syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, host ? host : "NULL"); } @@ -494,6 +506,22 @@ SendSSDPNotify(int s, const struct sockaddr * dest, { syslog(LOG_NOTICE, "sendto() sent %d out of %d bytes", n, l); } + /* Due to the unreliable nature of UDP, devices SHOULD send the entire + * set of discovery messages more than once with some delay between + * sets e.g. a few hundred milliseconds. To avoid network congestion + * discovery messages SHOULD NOT be sent more than three times. */ + n = sendto_schedule(s, bufr, l, 0, dest, +#ifdef ENABLE_IPV6 + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in), +#else + sizeof(struct sockaddr_in), +#endif + 250); + if(n < 0) + { + syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s, + host ? host : "NULL"); + } } static void @@ -564,8 +592,11 @@ SendSSDPNotifies2(int * sockets, lifetime, 0); i++; #ifdef ENABLE_IPV6 - SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port, - lifetime, 1); + if(sockets[i] >= 0) + { + SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port, + lifetime, 1); + } i++; #endif } @@ -620,8 +651,20 @@ ProcessSSDPData(int s, const char *bufr, int n, #ifdef ENABLE_IPV6 char announced_host_buf[64]; #endif +#endif +#if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE) int mx_value = -1; #endif + unsigned int delay = 0; + /* UPnP Device Architecture v1.1. 1.3.3 Search response : + * Devices responding to a multicast M-SEARCH SHOULD wait a random period + * of time between 0 seconds and the number of seconds specified in the + * MX field value of the search request before responding, in order to + * avoid flooding the requesting control point with search responses + * from multiple devices. If the search request results in the need for + * a multiple part response from the device, those multiple part + * responses SHOULD be spread at random intervals through the time period + * from 0 to the number of seconds specified in the MX header field. */ /* get the string representation of the sender address */ sockaddr_to_string(sender, sender_str, sizeof(sender_str)); @@ -664,7 +707,7 @@ ProcessSSDPData(int s, const char *bufr, int n, /*while(bufr[i+j]!='\r') j++;*/ /*syslog(LOG_INFO, "%.*s", j, bufr+i);*/ } -#ifdef UPNP_STRICT +#if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE) else if((i < n - 3) && (strncasecmp(bufr+i, "mx:", 3) == 0)) { const char * mx; @@ -682,16 +725,32 @@ ProcessSSDPData(int s, const char *bufr, int n, #endif } #ifdef UPNP_STRICT + /* For multicast M-SEARCH requests, if the search request does + * not contain an MX header field, the device MUST silently + * discard and ignore the search request. */ if(mx_value < 0) { syslog(LOG_INFO, "ignoring SSDP packet missing MX: header"); return; + } else if(mx_value > 5) { + /* If the MX header field specifies a field value greater + * than 5, the device SHOULD assume that it contained the + * value 5 or less. */ + mx_value = 5; + } +#elif defined(DELAY_MSEARCH_RESPONSE) + if(mx_value < 0) { + mx_value = 1; + } else if(mx_value > 5) { + /* If the MX header field specifies a field value greater + * than 5, the device SHOULD assume that it contained the + * value 5 or less. */ + mx_value = 5; } #endif /*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s", sender_str );*/ if(st && (st_len > 0)) { - /* TODO : doesnt answer at once but wait for a random time */ syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s", sender_str, st_len, st); /* find in which sub network the client is */ @@ -753,11 +812,43 @@ ProcessSSDPData(int s, const char *bufr, int n, #endif ) { + /* SSDP_RESPOND_SAME_VERSION : + * response is urn:schemas-upnp-org:service:WANIPConnection:1 when + * M-SEARCH included urn:schemas-upnp-org:service:WANIPConnection:1 + * else the implemented versions is included in the response + * + * From UPnP Device Architecture v1.1 : + * 1.3.2 [...] Updated versions of device and service types + * are REQUIRED to be fully backward compatible with + * previous versions. Devices MUST respond to M-SEARCH + * requests for any supported version. For example, if a + * device implements “urn:schemas-upnporg:service:xyz:2”, + * it MUST respond to search requests for both that type + * and “urn:schemas-upnp-org:service:xyz:1”. The response + * MUST specify the same version as was contained in the + * search request. [...] */ +#ifndef SSDP_RESPOND_SAME_VERSION + if(i==0) + ver_str[0] = '\0'; + else + snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version); +#endif syslog(LOG_INFO, "Single search found"); +#ifdef DELAY_MSEARCH_RESPONSE + delay = random() / (1 + RAND_MAX / (1000 * mx_value)); +#ifdef DEBUG + syslog(LOG_DEBUG, "mx=%dsec delay=%ums", mx_value, delay); +#endif +#endif SendSSDPResponse(s, sender, +#ifdef SSDP_RESPOND_SAME_VERSION st, st_len, "", +#else + known_service_types[i].s, l, ver_str, +#endif announced_host, port, - known_service_types[i].uuid); + known_service_types[i].uuid, + delay); break; } } @@ -765,9 +856,15 @@ ProcessSSDPData(int s, const char *bufr, int n, /* strlen("ssdp:all") == 8 */ if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8))) { +#ifdef DELAY_MSEARCH_RESPONSE + unsigned int delay_increment = (mx_value * 1000) / 15; +#endif syslog(LOG_INFO, "ssdp:all found"); for(i=0; known_service_types[i].s; i++) { +#ifdef DELAY_MSEARCH_RESPONSE + delay += delay_increment; +#endif if(i==0) ver_str[0] = '\0'; else @@ -776,37 +873,53 @@ ProcessSSDPData(int s, const char *bufr, int n, SendSSDPResponse(s, sender, known_service_types[i].s, l, ver_str, announced_host, port, - known_service_types[i].uuid); + known_service_types[i].uuid, + delay); } /* also answer for uuid */ +#ifdef DELAY_MSEARCH_RESPONSE + delay += delay_increment; +#endif SendSSDPResponse(s, sender, uuidvalue_igd, strlen(uuidvalue_igd), "", - announced_host, port, uuidvalue_igd); + announced_host, port, uuidvalue_igd, delay); +#ifdef DELAY_MSEARCH_RESPONSE + delay += delay_increment; +#endif SendSSDPResponse(s, sender, uuidvalue_wan, strlen(uuidvalue_wan), "", - announced_host, port, uuidvalue_wan); + announced_host, port, uuidvalue_wan, delay); +#ifdef DELAY_MSEARCH_RESPONSE + delay += delay_increment; +#endif SendSSDPResponse(s, sender, uuidvalue_wcd, strlen(uuidvalue_wcd), "", - announced_host, port, uuidvalue_wcd); + announced_host, port, uuidvalue_wcd, delay); } /* responds to request by UUID value */ l = (int)strlen(uuidvalue_igd); if(l==st_len) { +#ifdef DELAY_MSEARCH_RESPONSE + delay = random() / (1 + RAND_MAX / (1000 * mx_value)); +#endif if(0 == memcmp(st, uuidvalue_igd, l)) { syslog(LOG_INFO, "ssdp:uuid (IGD) found"); SendSSDPResponse(s, sender, st, st_len, "", - announced_host, port, uuidvalue_igd); + announced_host, port, uuidvalue_igd, + delay); } else if(0 == memcmp(st, uuidvalue_wan, l)) { syslog(LOG_INFO, "ssdp:uuid (WAN) found"); SendSSDPResponse(s, sender, st, st_len, "", - announced_host, port, uuidvalue_wan); + announced_host, port, uuidvalue_wan, + delay); } else if(0 == memcmp(st, uuidvalue_wcd, l)) { syslog(LOG_INFO, "ssdp:uuid (WCD) found"); SendSSDPResponse(s, sender, st, st_len, "", - announced_host, port, uuidvalue_wcd); + announced_host, port, uuidvalue_wcd, + delay); } } } @@ -856,7 +969,7 @@ SendSSDPbyebye(int s, const struct sockaddr * dest, syslog(LOG_WARNING, "SendSSDPbyebye(): truncated output"); l = sizeof(bufr) - 1; } - n = sendto(s, bufr, l, 0, dest, + n = sendto_or_schedule(s, bufr, l, 0, dest, #ifdef ENABLE_IPV6 ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in) #else @@ -1013,6 +1126,8 @@ SubmitServicesToMiniSSDPD(const char * host, unsigned short port) { while(n > 0) { l = write(s, p, n); if (l < 0) { + if(errno == EINTR) + continue; syslog(LOG_ERR, "write(): %m"); close(s); return -1; diff --git a/miniupnpd/miniupnpd.c b/miniupnpd/miniupnpd.c index a30ce2a..3a8be99 100644 --- a/miniupnpd/miniupnpd.c +++ b/miniupnpd/miniupnpd.c @@ -1,7 +1,7 @@ -/* $Id: miniupnpd.c,v 1.176 2013/06/13 13:21:29 nanard Exp $ */ +/* $Id: miniupnpd.c,v 1.189 2014/03/10 11:04:52 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -63,6 +63,7 @@ #include "miniupnpdtypes.h" #include "daemonize.h" #include "upnpevents.h" +#include "asyncsendto.h" #ifdef ENABLE_NATPMP #include "natpmp.h" #ifdef ENABLE_PCP @@ -111,12 +112,17 @@ volatile sig_atomic_t should_send_public_address_change_notif = 0; /* OpenAndConfHTTPSocket() : * setup the socket used to handle incoming HTTP connections. */ static int +#ifdef ENABLE_IPV6 +OpenAndConfHTTPSocket(unsigned short port, int ipv6) +#else OpenAndConfHTTPSocket(unsigned short port) +#endif { int s; int i = 1; #ifdef ENABLE_IPV6 - struct sockaddr_in6 listenname; + struct sockaddr_in6 listenname6; + struct sockaddr_in listenname4; #else struct sockaddr_in listenname; #endif @@ -124,7 +130,7 @@ OpenAndConfHTTPSocket(unsigned short port) if( (s = socket( #ifdef ENABLE_IPV6 - PF_INET6, + ipv6 ? PF_INET6 : PF_INET, #else PF_INET, #endif @@ -153,19 +159,35 @@ OpenAndConfHTTPSocket(unsigned short port) } #ifdef ENABLE_IPV6 - memset(&listenname, 0, sizeof(struct sockaddr_in6)); - listenname.sin6_family = AF_INET6; - listenname.sin6_port = htons(port); - listenname.sin6_addr = in6addr_any; - listenname_len = sizeof(struct sockaddr_in6); + if(ipv6) + { + memset(&listenname6, 0, sizeof(struct sockaddr_in6)); + listenname6.sin6_family = AF_INET6; + listenname6.sin6_port = htons(port); + listenname6.sin6_addr = in6addr_any; + listenname_len = sizeof(struct sockaddr_in6); + } else { + memset(&listenname4, 0, sizeof(struct sockaddr_in)); + listenname4.sin_family = AF_INET; + listenname4.sin_port = htons(port); + listenname4.sin_addr.s_addr = htonl(INADDR_ANY); + listenname_len = sizeof(struct sockaddr_in); + } #else + memset(&listenname, 0, sizeof(struct sockaddr_in)); listenname.sin_family = AF_INET; listenname.sin_port = htons(port); listenname.sin_addr.s_addr = htonl(INADDR_ANY); listenname_len = sizeof(struct sockaddr_in); #endif +#ifdef ENABLE_IPV6 + if(bind(s, + ipv6 ? (struct sockaddr *)&listenname6 : (struct sockaddr *)&listenname4, + listenname_len) < 0) +#else if(bind(s, (struct sockaddr *)&listenname, listenname_len) < 0) +#endif { syslog(LOG_ERR, "bind(http): %m"); close(s); @@ -181,6 +203,85 @@ OpenAndConfHTTPSocket(unsigned short port) return s; } + +static struct upnphttp * +ProcessIncomingHTTP(int shttpl) +{ + int shttp; + socklen_t clientnamelen; +#ifdef ENABLE_IPV6 + struct sockaddr_storage clientname; + clientnamelen = sizeof(struct sockaddr_storage); +#else + struct sockaddr_in clientname; + clientnamelen = sizeof(struct sockaddr_in); +#endif + shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); + if(shttp<0) + { + /* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */ + if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) + syslog(LOG_ERR, "accept(http): %m"); + } + else + { + struct upnphttp * tmp = 0; + char addr_str[64]; + + sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str)); + syslog(LOG_INFO, "HTTP connection from %s", addr_str); + if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL) + { + /* The peer is not a LAN ! */ + syslog(LOG_WARNING, + "HTTP peer %s is not from a LAN, closing the connection", + addr_str); + close(shttp); + } + else + { + /* Create a new upnphttp object and add it to + * the active upnphttp object list */ + tmp = New_upnphttp(shttp); + if(tmp) + { +#ifdef ENABLE_IPV6 + if(clientname.ss_family == AF_INET) + { + tmp->clientaddr = ((struct sockaddr_in *)&clientname)->sin_addr; + } + else if(clientname.ss_family == AF_INET6) + { + struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&clientname; + if(IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) + { + memcpy(&tmp->clientaddr, + &addr->sin6_addr.s6_addr[12], + 4); + } + else + { + tmp->ipv6 = 1; + memcpy(&tmp->clientaddr_v6, + &addr->sin6_addr, + sizeof(struct in6_addr)); + } + } +#else + tmp->clientaddr = clientname.sin_addr; +#endif + return tmp; + } + else + { + syslog(LOG_ERR, "New_upnphttp() failed"); + close(shttp); + } + } + } + return NULL; +} + #ifdef ENABLE_NFQUEUE int identify_ip_protocol(char *payload) { @@ -586,6 +687,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str) p++; if(*p=='.') { + /* parse mask in /255.255.255.0 format */ while(*p && (*p=='.' || isdigit(*p))) p++; n = p - q; @@ -598,6 +700,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str) } else { + /* it is a /24 format */ int nbits = atoi(q); if(nbits > 32 || nbits < 0) goto parselan_error; @@ -685,7 +788,10 @@ void complete_uuidvalues(void) * 5) check and write pid file * 6) set startup time stamp * 7) compute presentation URL - * 8) set signal handlers */ + * 8) set signal handlers + * 9) init random generator (srandom()) + * 10) init redirection engine + * 11) reload mapping from leasefile */ static int init(int argc, char * * argv, struct runtime_vars * v) { @@ -906,12 +1012,14 @@ init(int argc, char * * argv, struct runtime_vars * v) optionsfile); } } - /* if lifetimes ae inverse*/ +#ifdef ENABLE_PCP + /* if lifetimes are inverse */ if (min_lifetime >= max_lifetime) { fprintf(stderr, "Minimum lifetime (%lu) is greater than or equal to maximum lifetime (%lu).\n", min_lifetime, max_lifetime); fprintf(stderr, "Check your configuration file.\n"); return 1; } +#endif } #endif /* DISABLE_CONFIG_FILE */ @@ -1241,6 +1349,10 @@ init(int argc, char * * argv, struct runtime_vars * v) syslog(LOG_NOTICE, "Failed to set %s handler", "SIGUSR1"); } + /* initialize random number generator */ + srandom((unsigned int)time(NULL)); + + /* initialize redirection engine (and pinholes) */ if(init_redirect() < 0) { syslog(LOG_ERR, "Failed to init redirection engine. EXITING"); @@ -1338,12 +1450,15 @@ main(int argc, char * * argv) { int i; int shttpl = -1; /* socket for HTTP */ +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + int shttpl_v4 = -1; /* socket for HTTP (ipv4 only) */ +#endif int sudp = -1; /* IP v4 socket for receiving SSDP */ #ifdef ENABLE_IPV6 int sudpv6 = -1; /* IP v6 socket for receiving SSDP */ #endif #ifdef ENABLE_NATPMP - int * snatpmp = NULL; + int * snatpmp = NULL; /* also used for PCP */ #endif #ifdef ENABLE_NFQUEUE int nfqh = -1; @@ -1429,7 +1544,11 @@ main(int argc, char * * argv) { /* open socket for HTTP connections. Listen on the 1st LAN address */ +#ifdef ENABLE_IPV6 + shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0, 1); +#else /* ENABLE_IPV6 */ shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0); +#endif /* ENABLE_IPV6 */ if(shttpl < 0) { syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING"); @@ -1445,13 +1564,22 @@ main(int argc, char * * argv) v.port = ntohs(sockinfo.sin_port); } syslog(LOG_NOTICE, "HTTP listening on port %d", v.port); +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + shttpl_v4 = OpenAndConfHTTPSocket(v.port, 0); + if(shttpl_v4 < 0) + { + syslog(LOG_ERR, "Failed to open socket for HTTP on port %hu (IPv4). EXITING", v.port); + return 1; + } +#endif /* V6SOCKETS_ARE_V6ONLY */ #ifdef ENABLE_IPV6 if(find_ipv6_addr(NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) { syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s", ipv6_addr_for_http_with_brackets); } else { memcpy(ipv6_addr_for_http_with_brackets, "[::1]", 6); - syslog(LOG_WARNING, "no HTTP IPv6 address"); + syslog(LOG_WARNING, "no HTTP IPv6 address, disabling IPv6"); + SETFLAG(IPV6DISABLEDMASK); } #endif @@ -1466,10 +1594,13 @@ main(int argc, char * * argv) } } #ifdef ENABLE_IPV6 - sudpv6 = OpenAndConfSSDPReceiveSocket(1); - if(sudpv6 < 0) + if(!GETFLAG(IPV6DISABLEDMASK)) { - syslog(LOG_WARNING, "Failed to open socket for receiving SSDP (IP v6)."); + sudpv6 = OpenAndConfSSDPReceiveSocket(1); + if(sudpv6 < 0) + { + syslog(LOG_WARNING, "Failed to open socket for receiving SSDP (IP v6)."); + } } #endif @@ -1513,9 +1644,6 @@ main(int argc, char * * argv) syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u", NATPMP_PORT); } -#endif -#if 0 - ScanNATPMPforExpiration(); #endif } #endif @@ -1548,7 +1676,7 @@ main(int argc, char * * argv) /* send public address change notifications if needed */ if(should_send_public_address_change_notif) { - syslog(LOG_DEBUG, "should send external iface address change notification(s)"); + syslog(LOG_INFO, "should send external iface address change notification(s)"); #ifdef ENABLE_NATPMP if(GETFLAG(ENABLENATPMPMASK)) SendNATPMPPublicAddressChangeNotification(snatpmp, addr_count); @@ -1629,28 +1757,6 @@ main(int argc, char * * argv) syslog(LOG_DEBUG, "setting timeout to %u sec", (unsigned)timeout.tv_sec); } -#ifdef ENABLE_NATPMP -#if 0 - /* Remove expired NAT-PMP mappings */ - while(nextnatpmptoclean_timestamp - && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time)) - { - /*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/ - if(CleanExpiredNATPMP() < 0) { - syslog(LOG_ERR, "CleanExpiredNATPMP() failed"); - break; - } - } - if(nextnatpmptoclean_timestamp - && timeout.tv_sec >= (nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec)) - { - /*syslog(LOG_DEBUG, "setting timeout to %d sec", - nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec);*/ - timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec; - timeout.tv_usec = 0; - } -#endif -#endif #ifdef ENABLE_6FC_SERVICE /* Clean up expired IPv6 PinHoles */ next_pinhole_ts = 0; @@ -1683,6 +1789,13 @@ main(int argc, char * * argv) FD_SET(shttpl, &readset); max_fd = MAX( max_fd, shttpl); } +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + if (shttpl_v4 >= 0) + { + FD_SET(shttpl_v4, &readset); + max_fd = MAX( max_fd, shttpl_v4); + } +#endif #ifdef ENABLE_IPV6 if (sudpv6 >= 0) { @@ -1748,6 +1861,38 @@ main(int argc, char * * argv) upnpevents_selectfds(&readset, &writeset, &max_fd); #endif + /* queued "sendto" */ + { + struct timeval next_send; + i = get_next_scheduled_send(&next_send); + if(i > 0) { +#ifdef DEBUG + syslog(LOG_DEBUG, "%d queued sendto", i); +#endif + i = get_sendto_fds(&writeset, &max_fd, &timeofday); + if(timeofday.tv_sec > next_send.tv_sec || + (timeofday.tv_sec == next_send.tv_sec && timeofday.tv_usec >= next_send.tv_usec)) { + if(i > 0) { + timeout.tv_sec = 0; + timeout.tv_usec = 0; + } + } else { + struct timeval tmp_timeout; + tmp_timeout.tv_sec = (next_send.tv_sec - timeofday.tv_sec); + tmp_timeout.tv_usec = (next_send.tv_usec - timeofday.tv_usec); + if(tmp_timeout.tv_usec < 0) { + tmp_timeout.tv_usec += 1000000; + tmp_timeout.tv_sec--; + } + if(timeout.tv_sec > tmp_timeout.tv_sec + || (timeout.tv_sec == tmp_timeout.tv_sec && timeout.tv_usec > tmp_timeout.tv_usec)) { + timeout.tv_sec = tmp_timeout.tv_sec; + timeout.tv_usec = tmp_timeout.tv_usec; + } + } + } + } + if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0) { if(quitting) goto shutdown; @@ -1756,6 +1901,9 @@ main(int argc, char * * argv) syslog(LOG_ERR, "Failed to select open sockets. EXITING"); return 1; /* very serious cause of error */ } + if(try_sendto(&writeset) < 0) { + syslog(LOG_ERR, "try_sendto: %m"); + } #ifdef USE_MINIUPNPDCTL for(ectl = ctllisthead.lh_first; ectl;) { @@ -1837,10 +1985,10 @@ main(int argc, char * * argv) if (len < 1) continue; #ifdef ENABLE_PCP - if (msg_buff[0]==0) { // version equals to 0 -> means NAT-PMP + if (msg_buff[0]==0) { /* version equals to 0 -> means NAT-PMP */ ProcessIncomingNATPMPPacket(snatpmp[i], msg_buff, len, &senderaddr); - } else { // everything else can be PCP + } else { /* everything else can be PCP */ ProcessIncomingPCPPacket(snatpmp[i], msg_buff, len, &senderaddr); } @@ -1886,79 +2034,24 @@ main(int argc, char * * argv) /* process incoming HTTP connections */ if(shttpl >= 0 && FD_ISSET(shttpl, &readset)) { - int shttp; - socklen_t clientnamelen; -#ifdef ENABLE_IPV6 - struct sockaddr_storage clientname; - clientnamelen = sizeof(struct sockaddr_storage); -#else - struct sockaddr_in clientname; - clientnamelen = sizeof(struct sockaddr_in); -#endif - shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); - if(shttp<0) + struct upnphttp * tmp; + tmp = ProcessIncomingHTTP(shttpl); + if(tmp) { - /* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */ - if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) - syslog(LOG_ERR, "accept(http): %m"); - } - else - { - struct upnphttp * tmp = 0; - char addr_str[64]; - - sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str)); - syslog(LOG_INFO, "HTTP connection from %s", addr_str); - if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL) - { - /* The peer is not a LAN ! */ - syslog(LOG_WARNING, - "HTTP peer %s is not from a LAN, closing the connection", - addr_str); - close(shttp); - } - else - { - /* Create a new upnphttp object and add it to - * the active upnphttp object list */ - tmp = New_upnphttp(shttp); - if(tmp) - { -#ifdef ENABLE_IPV6 - if(clientname.ss_family == AF_INET) - { - tmp->clientaddr = ((struct sockaddr_in *)&clientname)->sin_addr; - } - else if(clientname.ss_family == AF_INET6) - { - struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&clientname; - if(IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) - { - memcpy(&tmp->clientaddr, - &addr->sin6_addr.s6_addr[12], - 4); - } - else - { - tmp->ipv6 = 1; - memcpy(&tmp->clientaddr_v6, - &addr->sin6_addr, - sizeof(struct in6_addr)); - } - } -#else - tmp->clientaddr = clientname.sin_addr; -#endif - LIST_INSERT_HEAD(&upnphttphead, tmp, entries); - } - else - { - syslog(LOG_ERR, "New_upnphttp() failed"); - close(shttp); - } - } + LIST_INSERT_HEAD(&upnphttphead, tmp, entries); } } +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + if(shttpl_v4 >= 0 && FD_ISSET(shttpl_v4, &readset)) + { + struct upnphttp * tmp; + tmp = ProcessIncomingHTTP(shttpl_v4); + if(tmp) + { + LIST_INSERT_HEAD(&upnphttphead, tmp, entries); + } + } +#endif #ifdef ENABLE_NFQUEUE /* process NFQ packets */ if(nfqh >= 0 && FD_ISSET(nfqh, &readset)) @@ -1982,6 +2075,22 @@ main(int argc, char * * argv) } /* end of main loop */ shutdown: + syslog(LOG_NOTICE, "shutting down MiniUPnPd"); + /* send good-bye */ + if (GETFLAG(ENABLEUPNPMASK)) + { +#ifndef ENABLE_IPV6 + if(SendSSDPGoodbye(snotify, addr_count) < 0) +#else + if(SendSSDPGoodbye(snotify, addr_count * 2) < 0) +#endif + { + syslog(LOG_ERR, "Failed to broadcast good-bye notifications"); + } + } + /* try to send pending packets */ + finalize_sendto(); + /* close out open sockets */ while(upnphttphead.lh_first != NULL) { @@ -1992,6 +2101,9 @@ shutdown: if (sudp >= 0) close(sudp); if (shttpl >= 0) close(shttpl); +#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6) + if (shttpl_v4 >= 0) close(shttpl_v4); +#endif #ifdef ENABLE_IPV6 if (sudpv6 >= 0) close(sudpv6); #endif @@ -2021,14 +2133,6 @@ shutdown: if (GETFLAG(ENABLEUPNPMASK)) { -#ifndef ENABLE_IPV6 - if(SendSSDPGoodbye(snotify, addr_count) < 0) -#else - if(SendSSDPGoodbye(snotify, addr_count * 2) < 0) -#endif - { - syslog(LOG_ERR, "Failed to broadcast good-bye notifications"); - } #ifndef ENABLE_IPV6 for(i = 0; i < addr_count; i++) #else @@ -2037,6 +2141,7 @@ shutdown: close(snotify[i]); } + /* remove pidfile */ if(pidfilename && (unlink(pidfilename) < 0)) { syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename); diff --git a/miniupnpd/minixml.c b/miniupnpd/minixml.c index d3f7d06..1f22273 100644 --- a/miniupnpd/minixml.c +++ b/miniupnpd/minixml.c @@ -1,10 +1,10 @@ -/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 nanard Exp $ */ +/* $Id: minixml.c,v 1.10 2012/03/05 19:42:47 nanard Exp $ */ /* minixml.c : the minimum size a xml parser can be ! */ /* Project : miniupnp * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Author : Thomas Bernard -Copyright (c) 2005-2011, Thomas BERNARD +Copyright (c) 2005-2014, Thomas BERNARD All rights reserved. Redistribution and use in source and binary forms, with or without @@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p) const char * elementname; while(p->xml < (p->xmlend - 1)) { - if((p->xml)[0]=='<' && (p->xml)[1]!='?') + if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); + p->xml += 3; + } + else if((p->xml)[0]=='<' && (p->xml)[1]!='?') { i = 0; elementname = ++p->xml; while( !IS_WHITE_SPACE(*p->xml) diff --git a/miniupnpd/natpmp.c b/miniupnpd/natpmp.c index b086a21..b98a5c2 100644 --- a/miniupnpd/natpmp.c +++ b/miniupnpd/natpmp.c @@ -1,6 +1,6 @@ -/* $Id: natpmp.c,v 1.33 2013/03/23 10:46:55 nanard Exp $ */ +/* $Id: natpmp.c,v 1.39 2014/03/07 10:43:30 nanard Exp $ */ /* MiniUPnP project - * (c) 2007-2013 Thomas Bernard + * (c) 2007-2014 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 */ @@ -24,6 +24,7 @@ #include "commonrdr.h" #include "upnputils.h" #include "portinuse.h" +#include "asyncsendto.h" #ifdef ENABLE_NATPMP @@ -158,8 +159,6 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, unsigned char *req=msg_buff; /* request udp packet */ unsigned char resp[32]; /* response udp packet */ int resplen; - //struct sockaddr_in senderaddr; - //socklen_t senderaddrlen = sizeof(senderaddr); int n = len; char senderaddrstr[16]; @@ -266,38 +265,61 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } } eport = 0; /* to indicate correct removing of port mapping */ - } else if(iport==0 - || !check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { + } else if(iport==0) { resp[3] = 2; /* Not Authorized/Refused */ - } else do { - r = get_redirect_rule(ext_if_name, eport, proto, - iaddr_old, sizeof(iaddr_old), - &iport_old, 0, 0, 0, 0, - ×tamp, 0, 0); - if(r==0) { - if(strcmp(senderaddrstr, iaddr_old)==0 - && iport==iport_old) { - /* redirection allready existing */ - syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", - eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old); - /* remove and then add again */ - if(_upnp_delete_redir(eport, proto) < 0) { - syslog(LOG_ERR, "failed to remove port mapping"); - break; + } else { /* iport > 0 && lifetime > 0 */ + unsigned short eport_first = 0; + int any_eport_allowed = 0; + char desc[64]; + while(resp[3] == 0) { + if(eport_first == 0) { /* first time in loop */ + eport_first = eport; + } else if(eport == eport_first) { /* no eport available */ + if(any_eport_allowed == 0) { /* all eports rejected by permissions */ + syslog(LOG_ERR, "No allowed eport for NAT-PMP %hu %s->%s:%hu", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); + resp[3] = 2; /* Not Authorized/Refused */ + } else { /* at least one eport allowed (but none available) */ + syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport); + resp[3] = 4; /* Out of resources */ } - } else { + break; + } + if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) { eport++; + if(eport == 0) eport++; /* skip port zero */ continue; } - } - if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport)) { - syslog(LOG_INFO, "port %hu protocol %s already in use", eport, (proto==IPPROTO_TCP)?"tcp":"udp"); - eport++; - r = 0; - continue; - } - { /* do the redirection */ - char desc[64]; + any_eport_allowed = 1; /* at lease one eport is allowed */ + if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport)) { + syslog(LOG_INFO, "port %hu protocol %s already in use", eport, (proto==IPPROTO_TCP)?"tcp":"udp"); + eport++; + if(eport == 0) eport++; /* skip port zero */ + continue; + } + r = get_redirect_rule(ext_if_name, eport, proto, + iaddr_old, sizeof(iaddr_old), + &iport_old, 0, 0, 0, 0, + ×tamp, 0, 0); + if(r==0) { + if(strcmp(senderaddrstr, iaddr_old)==0 + && iport==iport_old) { + /* redirection allready existing */ + syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", + eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old); + /* remove and then add again */ + if(_upnp_delete_redir(eport, proto) < 0) { + syslog(LOG_ERR, "failed to remove port mapping"); + break; + } + } else { + eport++; + if(eport == 0) eport++; /* skip port zero */ + continue; + } + } + /* do the redirection */ #if 0 timestamp = (unsigned)(time(NULL) - startup_time) + lifetime; @@ -314,17 +336,10 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'", eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc); resp[3] = 3; /* Failure */ -#if 0 - } else if( !nextnatpmptoclean_eport - || timestamp < nextnatpmptoclean_timestamp) { - nextnatpmptoclean_timestamp = timestamp; - nextnatpmptoclean_eport = eport; - nextnatpmptoclean_proto = proto; -#endif } break; } - } while(r==0); + } *((uint16_t *)(resp+8)) = htons(iport); /* private port */ *((uint16_t *)(resp+10)) = htons(eport); /* public port */ *((uint32_t *)(resp+12)) = htonl(lifetime); /* Port Mapping lifetime */ @@ -334,7 +349,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, default: resp[3] = 5; /* Unsupported OPCODE */ } - n = sendto(s, resp, resplen, 0, + n = sendto_or_schedule(s, resp, resplen, 0, (struct sockaddr *)senderaddr, sizeof(*senderaddr)); if(n<0) { syslog(LOG_ERR, "sendto(natpmp): %m"); @@ -344,67 +359,6 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, } } -#if 0 -/* iterate through the redirection list to find those who came - * from NAT-PMP and select the first to expire */ -int ScanNATPMPforExpiration() -{ - char desc[64]; - unsigned short iport, eport; - int proto; - int r, i; - unsigned timestamp; - nextnatpmptoclean_eport = 0; - nextnatpmptoclean_timestamp = 0; - for(i = 0; ; i++) { - r = get_redirect_rule_by_index(i, 0, &eport, 0, 0, - &iport, &proto, desc, sizeof(desc), - ×tamp, 0, 0); - if(r<0) - break; - if(sscanf(desc, "NAT-PMP %u", ×tamp) == 1) { - if( !nextnatpmptoclean_eport - || timestamp < nextnatpmptoclean_timestamp) { - nextnatpmptoclean_eport = eport; - nextnatpmptoclean_proto = proto; - nextnatpmptoclean_timestamp = timestamp; - syslog(LOG_DEBUG, "set nextnatpmptoclean_timestamp to %u", timestamp); - } - } - } - return 0; -} - -/* remove the next redirection that is expired - */ -int CleanExpiredNATPMP() -{ - char desc[64]; - unsigned timestamp; - unsigned short iport; - if(get_redirect_rule(ext_if_name, nextnatpmptoclean_eport, - nextnatpmptoclean_proto, - 0, 0, - &iport, desc, sizeof(desc), ×tamp, 0, 0) < 0) - return ScanNATPMPforExpiration(); - /* check desc - this is important since we keep expiration time as part - * of the desc. - * If the rule is renewed, timestamp and nextnatpmptoclean_timestamp - * can be different. In that case, the rule must not be removed ! */ - if(sscanf(desc, "NAT-PMP %u", ×tamp) == 1) { - if(timestamp > nextnatpmptoclean_timestamp) - return ScanNATPMPforExpiration(); - } - /* remove redirection then search for next one:) */ - if(_upnp_delete_redir(nextnatpmptoclean_eport, nextnatpmptoclean_proto)<0) - return -1; - syslog(LOG_INFO, "Expired NAT-PMP mapping port %hu %s removed", - nextnatpmptoclean_eport, - nextnatpmptoclean_proto==IPPROTO_TCP?"TCP":"UDP"); - return ScanNATPMPforExpiration(); -} -#endif - /* SendNATPMPPublicAddressChangeNotification() * should be called when the public IP address changed */ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets) @@ -449,7 +403,7 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets) #endif /* Port to use in 2006 version of the NAT-PMP specification */ sockname.sin_port = htons(NATPMP_PORT); - n = sendto(sockets[j], notif, 12, 0, + n = sendto_or_schedule(sockets[j], notif, 12, 0, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)); if(n < 0) { @@ -459,7 +413,7 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets) } /* Port to use in 2008 version of the NAT-PMP specification */ sockname.sin_port = htons(NATPMP_NOTIF_PORT); - n = sendto(sockets[j], notif, 12, 0, + n = sendto_or_schedule(sockets[j], notif, 12, 0, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)); if(n < 0) { diff --git a/miniupnpd/natpmp.h b/miniupnpd/natpmp.h index b8a73bf..5f63517 100644 --- a/miniupnpd/natpmp.h +++ b/miniupnpd/natpmp.h @@ -1,4 +1,4 @@ -/* $Id: natpmp.h,v 1.8 2011/05/27 21:36:22 nanard Exp $ */ +/* $Id: natpmp.h,v 1.11 2014/02/01 17:17:35 nanard Exp $ */ /* MiniUPnP project * author : Thomas Bernard * website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ @@ -26,12 +26,6 @@ int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr_in* senderaddr, void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len, struct sockaddr_in *senderaddr); -#if 0 -int ScanNATPMPforExpiration(void); - -int CleanExpiredNATPMP(void); -#endif - void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets); #endif diff --git a/miniupnpd/options.c b/miniupnpd/options.c index ce368c9..8d0de20 100644 --- a/miniupnpd/options.c +++ b/miniupnpd/options.c @@ -1,4 +1,4 @@ -/* $Id: options.c,v 1.26 2012/06/29 19:26:09 nanard Exp $ */ +/* $Id: options.c,v 1.28 2013/12/13 14:07:08 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * author: Ryan Wagoner @@ -16,7 +16,7 @@ #include "upnppermissions.h" #ifdef PCP_SADSCP #include "pcplearndscp.h" -#endif // PCP_SADSPC +#endif /* PCP_SADSPC */ #include "upnpglobalvars.h" #ifndef DISABLE_CONFIG_FILE @@ -187,7 +187,7 @@ readoptionsfile(const char * fname) } continue; } -#endif //PCP_SADSCP +#endif /* PCP_SADSCP */ if(!(equals = strchr(name, '='))) { fprintf(stderr, "parsing error file %s line %d : %s\n", @@ -303,7 +303,7 @@ freeoptions(void) dscp_values_list = NULL; num_dscp_values = 0; } -#endif //PCP_SADSCP +#endif /* PCP_SADSCP */ } #endif /* DISABLE_CONFIG_FILE */ diff --git a/miniupnpd/pcp_msg_struct.h b/miniupnpd/pcp_msg_struct.h index 3c956ea..bb557bc 100644 --- a/miniupnpd/pcp_msg_struct.h +++ b/miniupnpd/pcp_msg_struct.h @@ -1,4 +1,4 @@ -/* $Id: pcp_msg_struct.h $ */ +/* $Id: pcp_msg_struct.h,v 1.3 2013/12/16 16:02:19 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -138,7 +138,7 @@ typedef enum pcp_options { #ifdef WIN32 #pragma warning (push) #pragma warning (disable:4200) -#endif // WIN32 +#endif /* WIN32 */ #pragma pack(push, 1) @@ -148,7 +148,7 @@ typedef struct pcp_request { uint8_t r_opcode; uint16_t reserved; uint32_t req_lifetime; - uint32_t ip[4]; /* ipv4 will be represented + struct in6_addr ip; /* ipv4 will be represented by the ipv4 mapped ipv6 */ uint8_t next_data[0]; } pcp_request_t; @@ -182,7 +182,7 @@ typedef struct pcp_map_v2 { uint8_t reserved[3]; uint16_t int_port; uint16_t ext_port; - uint32_t ext_ip[4]; /* ipv4 will be represented + struct in6_addr ext_ip; /* ipv4 will be represented by the ipv4 mapped ipv6 */ uint8_t next_data[0]; } pcp_map_v2_t; @@ -193,7 +193,7 @@ typedef struct pcp_map_v1 { uint8_t reserved[3]; uint16_t int_port; uint16_t ext_port; - uint32_t ext_ip[4]; /* ipv4 will be represented + struct in6_addr ext_ip; /* ipv4 will be represented by the ipv4 mapped ipv6 */ uint8_t next_data[0]; } pcp_map_v1_t; @@ -204,11 +204,11 @@ typedef struct pcp_peer_v1 { uint8_t reserved[3]; uint16_t int_port; uint16_t ext_port; - uint32_t ext_ip[4]; /* ipv4 will be represented + struct in6_addr ext_ip; /* ipv4 will be represented by the ipv4 mapped ipv6 */ uint16_t peer_port; uint16_t reserved1; - uint32_t peer_ip[4]; + struct in6_addr peer_ip; uint8_t next_data[0]; } pcp_peer_v1_t; @@ -219,11 +219,11 @@ typedef struct pcp_peer_v2 { uint8_t reserved[3]; uint16_t int_port; uint16_t ext_port; - uint32_t ext_ip[4]; /* ipv4 will be represented + struct in6_addr ext_ip; /* ipv4 will be represented by the ipv4 mapped ipv6 */ uint16_t peer_port; uint16_t reserved1; - uint32_t peer_ip[4]; + struct in6_addr peer_ip; uint8_t next_data[0]; } pcp_peer_v2_t; @@ -254,7 +254,7 @@ typedef struct pcp_3rd_party_option{ uint8_t option; uint8_t reserved; uint16_t len; - uint32_t ip[4]; + struct in6_addr ip; uint8_t next_data[0]; } pcp_3rd_party_option_t; @@ -280,11 +280,11 @@ typedef struct pcp_filter_option { uint8_t reserved2; uint8_t prefix_len; uint16_t peer_port; - uint32_t peer_ip[4]; + struct in6_addr peer_ip; }pcp_filter_option_t; #pragma pack(pop) #ifdef WIN32 #pragma warning (pop) -#endif // WIN32 +#endif /* WIN32 */ diff --git a/miniupnpd/pcplearndscp.h b/miniupnpd/pcplearndscp.h index ab720ff..93fee33 100644 --- a/miniupnpd/pcplearndscp.h +++ b/miniupnpd/pcplearndscp.h @@ -1,4 +1,4 @@ -/* $Id: pcplearndscp.h $ */ +/* $Id: pcplearndscp.h,v 1.2 2013/12/13 15:47:23 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Miroslav Bagljas @@ -44,8 +44,8 @@ struct dscp_values { -// #set_learn_dscp "Webex" 1 1 1 34 +/* #set_learn_dscp "Webex" 1 1 1 34 */ int read_learn_dscp_line(struct dscp_values *dscpvalues, char *p); -#endif // PCPLEARNDSCP_H_INCLUDED +#endif /* PCPLEARNDSCP_H_INCLUDED */ diff --git a/miniupnpd/pcpserver.c b/miniupnpd/pcpserver.c index 0253826..ed6416e 100644 --- a/miniupnpd/pcpserver.c +++ b/miniupnpd/pcpserver.c @@ -1,4 +1,4 @@ -/* $Id: pcpserver.c $ */ +/* $Id: pcpserver.c,v 1.12 2014/02/28 17:50:22 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include @@ -58,33 +59,21 @@ POSSIBILITY OF SUCH DAMAGE. #include "upnpredirect.h" #include "commonrdr.h" #include "getifaddr.h" +#include "asyncsendto.h" #include "pcp_msg_struct.h" #ifdef PCP_PEER -//TODO make this platform independent +/* TODO make this platform independent */ #include "netfilter/iptcrdr.h" #endif -#define IPV6_ADDR_COPY(dest, src) \ - do { \ - (dest)[0] = (src)[0]; \ - (dest)[1] = (src)[1]; \ - (dest)[2] = (src)[2]; \ - (dest)[3] = (src)[3]; \ - } while (0) - - typedef struct options_occur { - int third_party_occur; - int pfailure_occur; -} options_occur_t; - /* server specific information */ struct pcp_server_info { uint8_t server_version; }; /* default server settings, highest version supported is the default */ -struct pcp_server_info this_server_info = {2}; +static struct pcp_server_info this_server_info = {2}; /* structure holding information from PCP msg*/ /* all variables are in host byte order except IP addresses */ @@ -104,7 +93,7 @@ typedef struct pcp_info { #ifdef PCP_PEER uint16_t peer_port; const struct in6_addr *peer_ip; /* Destination IP in network order */ -#endif //PCP_PEER +#endif /* PCP_PEER */ #ifdef PCP_SADSCP /* SADSCP specific information */ @@ -129,7 +118,7 @@ typedef struct pcp_info { int pfailure_present; char senderaddrstr[INET_ADDRSTRLEN]; -}pcp_info_t; +} pcp_info_t; #ifdef PCP_SADSCP @@ -191,7 +180,7 @@ static int parseCommonRequestHeader(pcp_request_t *common_req, pcp_info_t *pcp_m pcp_msg_info->version = common_req->ver ; pcp_msg_info->opcode = common_req->r_opcode &0x7f ; pcp_msg_info->lifetime = ntohl(common_req->req_lifetime); - pcp_msg_info->int_ip = (struct in6_addr*)common_req->ip; + pcp_msg_info->int_ip = &common_req->ip; if ( (common_req->ver > this_server_info.server_version) ) { @@ -219,7 +208,7 @@ static void printMAPOpcodeVersion1(pcp_map_v1_t *map_buf) syslog(LOG_DEBUG, "MAP int port: \t\t %d\n", ntohs(map_buf->int_port) ); syslog(LOG_DEBUG, "MAP ext port: \t\t %d\n", ntohs(map_buf->ext_port) ); syslog(LOG_DEBUG, "MAP Ext IP: \t\t %s\n", inet_ntop(AF_INET6, - map_buf->ext_ip, map_addr, INET6_ADDRSTRLEN)); + &map_buf->ext_ip, map_addr, INET6_ADDRSTRLEN)); } static void printMAPOpcodeVersion2(pcp_map_v2_t *map_buf) @@ -230,11 +219,11 @@ static void printMAPOpcodeVersion2(pcp_map_v2_t *map_buf) syslog(LOG_DEBUG, "MAP int port: \t\t %d\n", ntohs(map_buf->int_port) ); syslog(LOG_DEBUG, "MAP ext port: \t\t %d\n", ntohs(map_buf->ext_port) ); syslog(LOG_DEBUG, "MAP Ext IP: \t\t %s\n", inet_ntop(AF_INET6, - map_buf->ext_ip, map_addr, INET6_ADDRSTRLEN)); + &map_buf->ext_ip, map_addr, INET6_ADDRSTRLEN)); } -#endif //DEBUG +#endif /* DEBUG */ -static int parsePCPMAP_version1(pcp_map_v1_t *map_v1, \ +static int parsePCPMAP_version1(pcp_map_v1_t *map_v1, pcp_info_t *pcp_msg_info) { pcp_msg_info->is_map_op = 1; @@ -242,7 +231,7 @@ static int parsePCPMAP_version1(pcp_map_v1_t *map_v1, \ pcp_msg_info->int_port = ntohs(map_v1->int_port); pcp_msg_info->ext_port = ntohs(map_v1->ext_port); - pcp_msg_info->ext_ip = (struct in6_addr*)map_v1->ext_ip; + pcp_msg_info->ext_ip = &(map_v1->ext_ip); if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ){ syslog(LOG_ERR, "PCP MAP: Protocol was ZERO, but internal port has non-ZERO value."); @@ -252,7 +241,7 @@ static int parsePCPMAP_version1(pcp_map_v1_t *map_v1, \ return 0; } -static int parsePCPMAP_version2(pcp_map_v2_t *map_v2, \ +static int parsePCPMAP_version2(pcp_map_v2_t *map_v2, pcp_info_t *pcp_msg_info) { pcp_msg_info->is_map_op = 1; @@ -260,7 +249,7 @@ static int parsePCPMAP_version2(pcp_map_v2_t *map_v2, \ pcp_msg_info->int_port = ntohs(map_v2->int_port); pcp_msg_info->ext_port = ntohs(map_v2->ext_port); - pcp_msg_info->ext_ip = (struct in6_addr*)map_v2->ext_ip; + pcp_msg_info->ext_ip = &(map_v2->ext_ip); if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ) { syslog(LOG_ERR, "PCP MAP: Protocol was ZERO, but internal port has non-ZERO value."); @@ -280,10 +269,10 @@ static void printPEEROpcodeVersion1(pcp_peer_v1_t *peer_buf) syslog(LOG_DEBUG, "PCP PEER: v1 Opcode specific information. \n"); syslog(LOG_DEBUG, "Protocol: \t\t %d\n",peer_buf->protocol ); syslog(LOG_DEBUG, "Internal port: \t\t %d\n", ntohs(peer_buf->int_port) ); - syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, peer_buf->ext_ip, + syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->ext_ip, ext_addr,INET6_ADDRSTRLEN)); syslog(LOG_DEBUG, "External port port: \t\t %d\n", ntohs(peer_buf->ext_port) ); - syslog(LOG_DEBUG, "PEER IP: \t\t %s\n", inet_ntop(AF_INET6, peer_buf->peer_ip, + syslog(LOG_DEBUG, "PEER IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->peer_ip, peer_addr,INET6_ADDRSTRLEN)); syslog(LOG_DEBUG, "PEER port port: \t\t %d\n", ntohs(peer_buf->peer_port) ); } @@ -296,14 +285,14 @@ static void printPEEROpcodeVersion2(pcp_peer_v2_t *peer_buf) syslog(LOG_DEBUG, "PCP PEER: v2 Opcode specific information. \n"); syslog(LOG_DEBUG, "Protocol: \t\t %d\n",peer_buf->protocol ); syslog(LOG_DEBUG, "Internal port: \t\t %d\n", ntohs(peer_buf->int_port) ); - syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, peer_buf->ext_ip, + syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->ext_ip, ext_addr,INET6_ADDRSTRLEN)); syslog(LOG_DEBUG, "External port port: \t\t %d\n", ntohs(peer_buf->ext_port) ); - syslog(LOG_DEBUG, "PEER IP: \t\t %s\n", inet_ntop(AF_INET6, peer_buf->peer_ip, + syslog(LOG_DEBUG, "PEER IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->peer_ip, peer_addr,INET6_ADDRSTRLEN)); syslog(LOG_DEBUG, "PEER port port: \t\t %d\n", ntohs(peer_buf->peer_port) ); } -#endif //DEBUG +#endif /* DEBUG */ /* * Function extracting information from peer_buf to pcp_msg_info @@ -318,8 +307,8 @@ static int parsePCPPEER_version1(pcp_peer_v1_t *peer_buf, \ pcp_msg_info->ext_port = ntohs(peer_buf->ext_port); pcp_msg_info->peer_port = ntohs(peer_buf->peer_port); - pcp_msg_info->ext_ip = (struct in6_addr*)peer_buf->ext_ip; - pcp_msg_info->peer_ip = (struct in6_addr*)peer_buf->peer_ip; + pcp_msg_info->ext_ip = &peer_buf->ext_ip; + pcp_msg_info->peer_ip = &peer_buf->peer_ip; if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ){ syslog(LOG_ERR, "PCP PEER: protocol was ZERO, but internal port has non-ZERO value."); @@ -342,8 +331,8 @@ static int parsePCPPEER_version2(pcp_peer_v2_t *peer_buf, \ pcp_msg_info->ext_port = ntohs(peer_buf->ext_port); pcp_msg_info->peer_port = ntohs(peer_buf->peer_port); - pcp_msg_info->ext_ip = (struct in6_addr*)peer_buf->ext_ip; - pcp_msg_info->peer_ip = (struct in6_addr*)peer_buf->peer_ip; + pcp_msg_info->ext_ip = &peer_buf->ext_ip; + pcp_msg_info->peer_ip = &peer_buf->peer_ip; if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ){ syslog(LOG_ERR, "PCP PEER: protocol was ZERO, but internal port has non-ZERO value."); @@ -352,7 +341,7 @@ static int parsePCPPEER_version2(pcp_peer_v2_t *peer_buf, \ } return 0; } -#endif //PCP_PEER +#endif /* PCP_PEER */ #ifdef PCP_SADSCP #ifdef DEBUG @@ -399,8 +388,8 @@ static int parseSADSCP(pcp_sadscp_req_t *sadscp, pcp_info_t *pcp_msg_info) { } #endif -static int parsePCPOptions(void* pcp_buf, int* remainingSize, int* processedSize, \ - pcp_info_t *pcp_msg_info) +static int parsePCPOptions(void* pcp_buf, int* remainingSize, + int* processedSize, pcp_info_t *pcp_msg_info) { int remain = *remainingSize; int processed = *processedSize; @@ -436,7 +425,7 @@ static int parsePCPOptions(void* pcp_buf, int* remainingSize, int* processedSize #ifdef DEBUG syslog(LOG_DEBUG, "PCP OPTION: \t Third party \n"); syslog(LOG_DEBUG, "Third PARTY IP: \t %s\n", inet_ntop(AF_INET6, - opt_3rd->ip, third_addr, INET6_ADDRSTRLEN)); + &(opt_3rd->ip), third_addr, INET6_ADDRSTRLEN)); #endif if (pcp_msg_info->thirdp_present != 0 ) { @@ -481,7 +470,7 @@ static int parsePCPOptions(void* pcp_buf, int* remainingSize, int* processedSize break; case PCP_OPTION_FILTER: - // TODO fully implement filter + /* TODO fully implement filter */ opt_filter = (pcp_filter_option_t*) (pcp_buf + processed); option_length = ntohs(opt_filter->len); @@ -538,7 +527,7 @@ static int parsePCPOptions(void* pcp_buf, int* remainingSize, int* processedSize break; } - // shift processed and remaining values to new values + /* shift processed and remaining values to new values */ *remainingSize = remain; *processedSize = processed; return pcp_msg_info->result_code; @@ -547,6 +536,7 @@ static int parsePCPOptions(void* pcp_buf, int* remainingSize, int* processedSize static int CheckExternalAddress(pcp_info_t* pcp_msg_info) { + /* can contain a IPv4-mapped IPv6 address */ static struct in6_addr external_addr; if(use_ext_ip_addr) { @@ -565,13 +555,14 @@ static int CheckExternalAddress(pcp_info_t* pcp_msg_info) pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE; return -1; } + /* how do we know which address we need ? IPv6 or IPv4 ? */ if(getifaddr_in6(ext_if_name, &external_addr) < 0) { pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE; return -1; } } - if (IN6_IS_ADDR_UNSPECIFIED(pcp_msg_info->ext_ip)) { + if (pcp_msg_info->ext_ip == NULL || IN6_IS_ADDR_UNSPECIFIED(pcp_msg_info->ext_ip)) { pcp_msg_info->ext_ip = &external_addr; @@ -616,8 +607,7 @@ static void FillSA(struct sockaddr *sa, const struct in6_addr *in6, } else { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; sa6->sin6_family = AF_INET6; - IPV6_ADDR_COPY((uint32_t*)sa6->sin6_addr.s6_addr, - (uint32_t*)in6->s6_addr); + sa6->sin6_addr = *in6; sa6->sin6_port = htons(port); } } @@ -675,7 +665,7 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info) return 0; } } - //Create Peer Mapping + /* Create Peer Mapping */ { char desc[64]; char peerip_s[INET_ADDRSTRLEN], extip_s[INET_ADDRSTRLEN]; @@ -724,7 +714,7 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info) } } #endif - //TODO: add upnp function for PI + /* TODO: add upnp function for PI */ if (add_peer_redirect_rule2(ext_if_name, peerip_s, pcp_msg_info->peer_port, @@ -810,20 +800,48 @@ static void DeletePCPPeer(pcp_info_t *pcp_msg_info) pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES; } } -#endif //PCP_PEER +#endif /* PCP_PEER */ static void CreatePCPMap(pcp_info_t *pcp_msg_info) { char desc[64]; char iaddr_old[INET_ADDRSTRLEN]; uint16_t iport_old; - unsigned int timestamp = time(NULL) + pcp_msg_info->lifetime; + uint16_t eport_first = 0; + int any_eport_allowed = 0; + unsigned int timestamp; int r=0; if (pcp_msg_info->ext_port == 0) { pcp_msg_info->ext_port = pcp_msg_info->int_port; } do { + if (eport_first == 0) { /* first time in loop */ + eport_first = pcp_msg_info->ext_port; + } else if (pcp_msg_info->ext_port == eport_first) { /* no eport available */ + if (any_eport_allowed == 0) { /* all eports rejected by permissions */ + pcp_msg_info->result_code = PCP_ERR_NOT_AUTHORIZED; + } else { /* at least one eport allowed (but none available) */ + pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES; + } + return; + } + if ((IN6_IS_ADDR_V4MAPPED(pcp_msg_info->int_ip) && + (!check_upnp_rule_against_permissions(upnppermlist, + num_upnpperm, pcp_msg_info->ext_port, + ((struct in_addr*)pcp_msg_info->int_ip->s6_addr)[3], + pcp_msg_info->int_port)))) { + if (pcp_msg_info->pfailure_present) { + pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; + return; + } + pcp_msg_info->ext_port++; + if (pcp_msg_info->ext_port == 0) { /* skip port zero */ + pcp_msg_info->ext_port++; + } + continue; + } + any_eport_allowed = 1; r = get_redirect_rule(ext_if_name, pcp_msg_info->ext_port, pcp_msg_info->protocol, @@ -841,24 +859,26 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) return; } } else { + syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", + pcp_msg_info->ext_port, (pcp_msg_info->protocol==IPPROTO_TCP)?"tcp":"udp", + iaddr_old, iport_old); + /* remove and then add again */ if (_upnp_delete_redir(pcp_msg_info->ext_port, pcp_msg_info->protocol)==0) { break; + } else if (pcp_msg_info->pfailure_present) { + pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; + return; } } pcp_msg_info->ext_port++; + if (pcp_msg_info->ext_port == 0) { /* skip port zero */ + pcp_msg_info->ext_port++; + } } } while (r==0); - if ((pcp_msg_info->ext_port == 0) || - (IN6_IS_ADDR_V4MAPPED(pcp_msg_info->int_ip) && - (!check_upnp_rule_against_permissions(upnppermlist, - num_upnpperm, pcp_msg_info->ext_port, - ((struct in_addr*)pcp_msg_info->int_ip->s6_addr)[3], - pcp_msg_info->int_port)))) { - pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL; - return; - } + timestamp = time(NULL) + pcp_msg_info->lifetime; snprintf(desc, sizeof(desc), "PCP %hu %s", pcp_msg_info->ext_port, @@ -879,6 +899,8 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info) pcp_msg_info->int_port, desc); + pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES; + } else { syslog(LOG_INFO, "PCP MAP: added mapping %s %hu->%s:%hu '%s'", (pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP", @@ -903,7 +925,7 @@ static void DeletePCPMap(pcp_info_t *pcp_msg_info) char desc[64]; unsigned int timestamp; - //iterate through all rules and delete the requested ones + /* iterate through all rules and delete the requested ones */ while(get_redirect_rule_by_index(index, 0, &eport2, iaddr2, sizeof(iaddr2), &iport2, &proto2, @@ -912,7 +934,7 @@ static void DeletePCPMap(pcp_info_t *pcp_msg_info) if(0 == strncmp(iaddr2, pcp_msg_info->senderaddrstr, sizeof(iaddr2)) && (proto2==proto) - && (0 == strncmp(desc, "PCP", 3)) //starts with PCP + && (0 == strncmp(desc, "PCP", 3)) /* starts with PCP */ && ((iport2==iport) || (iport==0))) { r = _upnp_delete_redir(eport2, proto2); @@ -984,26 +1006,31 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) #ifdef PCP_SADSCP pcp_sadscp_req_t* sadscp; #endif - // start with PCP_SUCCESS as result code, if everything is OK value will be unchanged + /* start with PCP_SUCCESS as result code, if everything is OK value will be unchanged */ pcp_msg_info->result_code = PCP_SUCCESS; remainingSize = req_size; processedSize = 0; - // discard request that exceeds maximal length, - // or that is shorter than 3 - // or that is not the multiple of 4 - if (req_size < PCP_MIN_LEN) - return 0; //ignore msg + /* discard request that exceeds maximal length, + or that is shorter than PCP_MIN_LEN (=24) + or that is not the multiple of 4 */ + if (req_size < 3) + return 0; /* ignore msg */ + + if (req_size < PCP_MIN_LEN) { + pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST; + return 1; /* send response */ + } if ( (req_size > PCP_MAX_LEN) || ( (req_size & 3) != 0)) { syslog(LOG_ERR, "PCP: Size of PCP packet(%d) is larger than %d bytes or " "the size is not multiple of 4.\n", req_size, PCP_MAX_LEN); pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST; - return 1; // send response + return 1; /* send response */ } - //first print out info from common request header + /* first print out info from common request header */ common_req = (pcp_request_t*)req; if (parseCommonRequestHeader(common_req, pcp_msg_info) ) { @@ -1014,7 +1041,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) processedSize += sizeof(pcp_request_t); if (common_req->ver == 1) { - + /* legacy PCP version 1 support */ switch ( common_req->r_opcode & 0x7F ) { case PCP_OPCODE_MAP: @@ -1027,7 +1054,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) map_v1 = (pcp_map_v1_t*)(req + processedSize); #ifdef DEBUG printMAPOpcodeVersion1(map_v1); -#endif //DEBUG +#endif /* DEBUG */ if ( parsePCPMAP_version1(map_v1, pcp_msg_info) ) { return pcp_msg_info->result_code; } @@ -1062,7 +1089,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) #ifdef DEBUG printPEEROpcodeVersion1(peer_v1); -#endif //DEBUG +#endif /* DEBUG */ if ( parsePCPPEER_version1(peer_v1, pcp_msg_info) ) { return pcp_msg_info->result_code; } @@ -1085,15 +1112,20 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) break; -#endif //PCP_PEER +#endif /* PCP_PEER */ default: pcp_msg_info->result_code = PCP_ERR_UNSUPP_OPCODE; break; } } else if (common_req->ver == 2) { - + /* RFC 6887 PCP support + * http://tools.ietf.org/html/rfc6887 */ switch ( common_req->r_opcode & 0x7F) { + case PCP_OPCODE_ANNOUNCE: + /* should check PCP Client's IP Address in request */ + /* see http://tools.ietf.org/html/rfc6887#section-14.1 */ + break; case PCP_OPCODE_MAP: remainingSize -= sizeof(pcp_map_v2_t); @@ -1106,7 +1138,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) #ifdef DEBUG printMAPOpcodeVersion2(map_v2); -#endif //DEBUG +#endif /* DEBUG */ if (parsePCPMAP_version2(map_v2, pcp_msg_info) ) { return pcp_msg_info->result_code; @@ -1142,7 +1174,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) #ifdef DEBUG printPEEROpcodeVersion2(peer_v2); -#endif //DEBUG +#endif /* DEBUG */ parsePCPPEER_version2(peer_v2, pcp_msg_info); processedSize += sizeof(pcp_peer_v2_t); @@ -1165,7 +1197,7 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info) } break; -#endif //PCP_PEER +#endif /* PCP_PEER */ #ifdef PCP_SADSCP case PCP_OPCODE_SADSCP: @@ -1225,7 +1257,7 @@ static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info) resp->result_code = pcp_msg_info->result_code; resp->epochtime = htonl(time(NULL) - startup_time); switch (pcp_msg_info->result_code) { - //long lifetime errors + /*long lifetime errors*/ case PCP_ERR_UNSUPP_VERSION: case PCP_ERR_NOT_AUTHORIZED: case PCP_ERR_MALFORMED_REQUEST: @@ -1254,15 +1286,13 @@ static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info) if (resp->r_opcode == 0x81) { /* MAP response */ if (resp->ver == 1 ) { pcp_map_v1_t *mapr = (pcp_map_v1_t *)resp->next_data; - IPV6_ADDR_COPY((uint32_t*)mapr->ext_ip, - (uint32_t*)pcp_msg_info->ext_ip); + mapr->ext_ip = *pcp_msg_info->ext_ip; mapr->ext_port = htons(pcp_msg_info->ext_port); mapr->int_port = htons(pcp_msg_info->int_port); } else if (resp->ver == 2 ) { pcp_map_v2_t *mapr = (pcp_map_v2_t *)resp->next_data; - IPV6_ADDR_COPY((uint32_t*)mapr->ext_ip, - (uint32_t*)pcp_msg_info->ext_ip); + mapr->ext_ip = *pcp_msg_info->ext_ip; mapr->ext_port = htons(pcp_msg_info->ext_port); mapr->int_port = htons(pcp_msg_info->int_port); } @@ -1274,19 +1304,17 @@ static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info) peer_resp->ext_port = htons(pcp_msg_info->ext_port); peer_resp->int_port = htons(pcp_msg_info->int_port); peer_resp->peer_port = htons(pcp_msg_info->peer_port); - IPV6_ADDR_COPY((uint32_t*)peer_resp->ext_ip, - (uint32_t*)pcp_msg_info->ext_ip); + peer_resp->ext_ip = *pcp_msg_info->ext_ip; } else if (resp->ver == 2 ){ pcp_peer_v2_t* peer_resp = (pcp_peer_v2_t*)resp->next_data; peer_resp->ext_port = htons(pcp_msg_info->ext_port); peer_resp->int_port = htons(pcp_msg_info->int_port); peer_resp->peer_port = htons(pcp_msg_info->peer_port); - IPV6_ADDR_COPY((uint32_t*)peer_resp->ext_ip, - (uint32_t*)pcp_msg_info->ext_ip); + peer_resp->ext_ip = *pcp_msg_info->ext_ip; } } -#endif //PCP_PEER +#endif /* PCP_PEER */ #ifdef PCP_SADSCP else if (resp->r_opcode == 0x83) { /*SADSCP response*/ @@ -1296,10 +1324,10 @@ static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info) sadscp_resp->a_r_dscp_value |= (pcp_msg_info->sadscp_dscp & PCP_SADSCP_MASK); memset(sadscp_resp->reserved, 0, sizeof(sadscp_resp->reserved)); } -#endif //PCP_SADSCP +#endif /* PCP_SADSCP */ } -int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, \ +int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, struct sockaddr_in *senderaddr) { pcp_info_t pcp_msg_info; @@ -1323,11 +1351,11 @@ int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len, \ createPCPResponse(buff, &pcp_msg_info); - if ((len&0x03)!=0) { - len = len+4-(len&0x03); //round up resp. length to multiple of 4 - } - - len = sendto(s, buff, len, 0, + if(len < PCP_MIN_LEN) + len = PCP_MIN_LEN; + else + len = (len + 3) & ~3; /* round up resp. length to multiple of 4 */ + len = sendto_or_schedule(s, buff, len, 0, (struct sockaddr *)senderaddr, sizeof(struct sockaddr_in)); if( len < 0 ) { syslog(LOG_ERR, "sendto(pcpserver): %m"); diff --git a/miniupnpd/pcpserver.h b/miniupnpd/pcpserver.h index ee46fee..cc295f3 100644 --- a/miniupnpd/pcpserver.h +++ b/miniupnpd/pcpserver.h @@ -1,4 +1,4 @@ -/* $Id: pcpserver.h $ */ +/* $Id: pcpserver.h,v 1.2 2013/12/13 15:48:39 nanard Exp $ */ /* MiniUPnP project * Website : http://miniupnp.free.fr/ * Author : Peter Tatrai @@ -36,10 +36,12 @@ POSSIBILITY OF SUCH DAMAGE. #define PCP_MIN_LEN 24 #define PCP_MAX_LEN 1100 +struct sockaddr_in; + /* * returns 0 upon success 1 otherwise */ -int ProcessIncomingPCPPacket(int s, unsigned char *msg_buff, int len, \ +int ProcessIncomingPCPPacket(int s, unsigned char *msg_buff, int len, struct sockaddr_in *senderaddr); #endif /* PCPSERVER_H_INCLUDED */ diff --git a/miniupnpd/pf/obsdrdr.c b/miniupnpd/pf/obsdrdr.c index d0287cb..349f68e 100644 --- a/miniupnpd/pf/obsdrdr.c +++ b/miniupnpd/pf/obsdrdr.c @@ -1,7 +1,7 @@ -/* $Id: obsdrdr.c,v 1.74 2012/05/01 09:20:43 nanard Exp $ */ +/* $Id: obsdrdr.c,v 1.80 2014/03/06 13:02:46 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -9,15 +9,19 @@ * pf rules created (with ext_if = xl1) * - OpenBSD up to version 4.6 : * rdr pass on xl1 inet proto udp from any to any port = 54321 \ - * label "test label" -> 192.168.0.141 port 12345 - * or a rdr rule + a pass rule + * keep state label "test label" -> 192.168.0.42 port 12345 + * or a rdr rule + a pass rule : + * rdr quick on xl1 inet proto udp from any to any port = 54321 \ + * keep state label "test label" -> 192.168.0.42 port 12345 + * pass in quick on xl1 inet proto udp from any to 192.168.0.42 port = 12345 \ + * flags S/SA keep state label "test label" * * - OpenBSD starting from version 4.7 * match in on xl1 inet proto udp from any to any port 54321 \ - * label "test label" rdr-to 192.168.0.141 port 12345 + * label "test label" rdr-to 192.168.0.42 port 12345 * or * pass in quick on xl1 inet proto udp from any to any port 54321 \ - * label "test label" rdr-to 192.168.0.141 port 12345 + * label "test label" rdr-to 192.168.0.42 port 12345 * * * @@ -45,6 +49,9 @@ #ifdef __DragonFly__ #include #else +#ifdef MACOSX +#define PRIVATE 1 +#endif #include #endif #include @@ -173,6 +180,45 @@ clear_redirect_rules(void) error: return -1; } + +int +clear_filter_rules(void) +{ +#ifndef PF_ENABLE_FILTER_RULES + return 0; +#else + 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_FILTER; +#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 +} #endif /* add_redirect_rule2() : @@ -219,9 +265,15 @@ add_redirect_rule2(const char * ifname, pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK; #endif +#ifdef MACOSX + pcr.rule.dst.xport.range.op = PF_OP_EQ; + pcr.rule.dst.xport.range.port[0] = htons(eport); + pcr.rule.dst.xport.range.port[1] = htons(eport); +#else pcr.rule.dst.port_op = PF_OP_EQ; pcr.rule.dst.port[0] = htons(eport); pcr.rule.dst.port[1] = htons(eport); +#endif #ifndef PF_NEWSTYLE pcr.rule.action = PF_RDR; #ifndef PF_ENABLE_FILTER_RULES @@ -338,8 +390,11 @@ add_filter_rule2(const char * ifname, struct pfioc_rule pcr; #ifndef PF_NEWSTYLE struct pfioc_pooladdr pp; - struct pf_pooladdr *a; #endif +#ifndef USE_IFNAME_IN_RULES + UNUSED(ifname); +#endif + UNUSED(eport); if(dev<0) { syslog(LOG_ERR, "pf device is not open"); return -1; @@ -363,9 +418,8 @@ add_filter_rule2(const char * ifname, if(1) { #endif - pcr.rule.dst.port_op = PF_OP_EQ; - pcr.rule.dst.port[0] = htons(eport); + pcr.rule.dst.port[0] = htons(iport); pcr.rule.direction = PF_IN; pcr.rule.action = PF_PASS; pcr.rule.af = AF_INET; @@ -398,33 +452,16 @@ add_filter_rule2(const char * ifname, inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr); pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); } -#ifndef PF_NEWSTYLE - pcr.rule.rpool.proxy_port[0] = eport; - a = calloc(1, sizeof(struct pf_pooladdr)); - inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr); - a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); - memcpy(&pp.addr, a, sizeof(struct pf_pooladdr)); - TAILQ_INIT(&pcr.rule.rpool.list); - inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr); - TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries); - - /* we have any - any port = # keep state label */ /* we want any - iaddr port = # keep state label */ - /* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */ - - memcpy(&pp.addr, a, sizeof(struct pf_pooladdr)); - strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE); - if(ioctl(dev, DIOCADDADDR, &pp) < 0) - { - syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m"); - r = -1; - } - else - { -#else + inet_pton(AF_INET, iaddr, &pcr.rule.dst.addr.v.a.addr.v4.s_addr); + pcr.rule.dst.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE); +#ifndef PF_NEWSTYLE + pcr.rule.rpool.proxy_port[0] = iport; + pcr.rule.rpool.proxy_port[1] = iport; + TAILQ_INIT(&pcr.rule.rpool.list); +#endif if(1) { -#endif pcr.action = PF_CHANGE_GET_TICKET; if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) { @@ -441,9 +478,6 @@ add_filter_rule2(const char * ifname, } } } -#ifndef PF_NEWSTYLE - free(a); -#endif } return r; #endif @@ -490,8 +524,13 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto, syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m"); goto error; } +#ifdef MACOSX + if( (eport == ntohs(pr.rule.dst.xport.range.port[0])) + && (eport == ntohs(pr.rule.dst.xport.range.port[1])) +#else if( (eport == ntohs(pr.rule.dst.port[0])) && (eport == ntohs(pr.rule.dst.port[1])) +#endif && (pr.rule.proto == proto) ) { #ifndef PF_NEWSTYLE @@ -561,8 +600,10 @@ error: return -1; } -int -delete_redirect_rule(const char * ifname, unsigned short eport, int proto) +static int +priv_delete_redirect_rule(const char * ifname, unsigned short eport, + int proto, unsigned short * iport, + in_addr_t * iaddr) { int i, n; struct pfioc_rule pr; @@ -591,10 +632,53 @@ delete_redirect_rule(const char * ifname, unsigned short eport, int proto) syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m"); goto error; } +#ifdef MACOSX + if( (eport == ntohs(pr.rule.dst.xport.range.port[0])) + && (eport == ntohs(pr.rule.dst.xport.range.port[1])) +#else if( (eport == ntohs(pr.rule.dst.port[0])) && (eport == ntohs(pr.rule.dst.port[1])) +#endif && (pr.rule.proto == proto) ) { + /* retrieve iport in order to remove filter rule */ +#ifndef PF_NEWSTYLE + if(iport) *iport = pr.rule.rpool.proxy_port[0]; + if(iaddr) + { + /* retrieve internal address */ + struct pfioc_pooladdr pp; + memset(&pp, 0, sizeof(pp)); + strlcpy(pp.anchor, anchor_name, MAXPATHLEN); + pp.r_action = PF_RDR; + pp.r_num = i; + pp.ticket = pr.ticket; + if(ioctl(dev, DIOCGETADDRS, &pp) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m"); + goto error; + } + if(pp.nr != 1) + { + syslog(LOG_NOTICE, "No address associated with pf rule"); + goto error; + } + pp.nr = 0; /* first */ + if(ioctl(dev, DIOCGETADDR, &pp) < 0) + { + syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m"); + goto error; + } + *iaddr = pp.addr.addr.v.a.addr.v4.s_addr; + } +#else + if(iport) *iport = pr.rule.rdr.proxy_port[0]; + if(iaddr) + { + /* retrieve internal address */ + *iaddr = pr.rule.rdr.addr.v.a.addr.v4.s_addr; + } +#endif pr.action = PF_CHANGE_GET_TICKET; if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) { @@ -617,14 +701,23 @@ error: } int -delete_filter_rule(const char * ifname, unsigned short eport, int proto) +delete_redirect_rule(const char * ifname, unsigned short eport, + int proto) +{ + return priv_delete_redirect_rule(ifname, eport, proto, NULL, NULL); +} + +static int +priv_delete_filter_rule(const char * ifname, unsigned short iport, + int proto, in_addr_t iaddr) { #ifndef PF_ENABLE_FILTER_RULES - UNUSED(ifname); UNUSED(eport); UNUSED(proto); + UNUSED(ifname); UNUSED(iport); UNUSED(proto); return 0; #else int i, n; struct pfioc_rule pr; + UNUSED(ifname); if(dev<0) { syslog(LOG_ERR, "pf device is not open"); return -1; @@ -646,8 +739,16 @@ delete_filter_rule(const char * ifname, unsigned short eport, int proto) syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m"); goto error; } - if( (eport == ntohs(pr.rule.dst.port[0])) - && (pr.rule.proto == proto) ) +#ifdef TEST +syslog(LOG_DEBUG, "%2d port=%hu proto=%d addr=%8x", + i, ntohs(pr.rule.dst.port[0]), pr.rule.proto, + pr.rule.dst.addr.v.a.addr.v4.s_addr); +/*pr.rule.dst.addr.v.a.mask.v4.s_addr*/ +#endif + if( (iport == ntohs(pr.rule.dst.port[0])) + && (pr.rule.proto == proto) && + (iaddr == pr.rule.dst.addr.v.a.addr.v4.s_addr) + ) { pr.action = PF_CHANGE_GET_TICKET; if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) @@ -670,6 +771,21 @@ error: #endif } +int +delete_redirect_and_filter_rules(const char * ifname, unsigned short eport, + int proto) +{ + int r; + unsigned short iport; + in_addr_t iaddr; + r = priv_delete_redirect_rule(ifname, eport, proto, &iport, &iaddr); + if(r == 0) + { + r = priv_delete_filter_rule(ifname, iport, proto, iaddr); + } + return r; +} + int get_redirect_rule_by_index(int index, char * ifname, unsigned short * eport, @@ -710,7 +826,11 @@ get_redirect_rule_by_index(int index, goto error; } *proto = pr.rule.proto; +#ifdef MACOSX + *eport = ntohs(pr.rule.dst.xport.range.port[0]); +#else *eport = ntohs(pr.rule.dst.port[0]); +#endif #ifndef PF_NEWSTYLE *iport = pr.rule.rpool.proxy_port[0]; #else @@ -822,8 +942,13 @@ get_portmappings_in_range(unsigned short startport, unsigned short endport, syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m"); continue; } +#ifdef MACOSX + eport = ntohs(pr.rule.dst.xport.range.port[0]); + if( (eport == ntohs(pr.rule.dst.xport.range.port[1])) +#else eport = ntohs(pr.rule.dst.port[0]); if( (eport == ntohs(pr.rule.dst.port[1])) +#endif && (pr.rule.proto == proto) && (startport <= eport) && (eport <= endport) ) { diff --git a/miniupnpd/pf/obsdrdr.h b/miniupnpd/pf/obsdrdr.h index 59225fd..3defa8e 100644 --- a/miniupnpd/pf/obsdrdr.h +++ b/miniupnpd/pf/obsdrdr.h @@ -1,7 +1,7 @@ -/* $Id: obsdrdr.h,v 1.20 2012/03/05 20:36:20 nanard Exp $ */ +/* $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 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -52,13 +52,18 @@ get_redirect_rule_by_index(int index, int delete_redirect_rule(const char * ifname, unsigned short eport, int proto); -/* delete_filter_rule() +/* delete_redirect_and_filter_rules() */ int -delete_filter_rule(const char * ifname, unsigned short eport, int proto); +delete_redirect_and_filter_rules(const char * ifname, unsigned short eport, + int proto); +#ifdef TEST int clear_redirect_rules(void); +int +clear_filter_rules(void); +#endif #endif diff --git a/miniupnpd/pf/testobsdrdr.c b/miniupnpd/pf/testobsdrdr.c index 7d288c6..13d9ee5 100644 --- a/miniupnpd/pf/testobsdrdr.c +++ b/miniupnpd/pf/testobsdrdr.c @@ -1,10 +1,11 @@ -/* $Id: testobsdrdr.c,v 1.24 2012/04/18 19:42:03 nanard Exp $ */ +/* $Id: testobsdrdr.c,v 1.28 2014/03/06 13:02:47 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ +#include #include #include #include @@ -17,6 +18,7 @@ int runtime_flags = 0; const char * tag = 0; const char * anchor_name = "miniupnpd"; +const char * queue = NULL; void list_rules(void); @@ -67,7 +69,7 @@ test_index(void) } int -main(int arc, char * * argv) +main(int argc, char * * argv) { char buf[32]; char desc[64]; @@ -77,6 +79,12 @@ main(int arc, char * * argv) unsigned int timestamp; u_int64_t packets = 0; u_int64_t bytes = 0; + int clear = 0; + + if(argc > 1) { + if(0 == strcmp(argv[1], "--clear") || 0 == strcmp(argv[1], "-c")) + clear = 1; + } openlog("testobsdrdr", LOG_PERROR, LOG_USER); if(init_redirect() < 0) @@ -88,12 +96,15 @@ main(int arc, char * * argv) add_redirect_rule("ep0", 12123, "192.168.1.23", 1234); add_redirect_rule2("ep0", 12155, "192.168.1.155", 1255, IPPROTO_TCP); #endif - add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234, - IPPROTO_UDP, "test description", 0); -#if 0 - add_redirect_rule2("em0", 12123, "127.1.2.3", 1234, - IPPROTO_TCP, "test description tcp"); -#endif + if(add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234, + IPPROTO_UDP, "test description", 0) < 0) + printf("add_redirect_rule2() #3 failed\n"); + if(add_redirect_rule2("em0", NULL, 12123, "127.1.2.3", 1234, + IPPROTO_TCP, "test description tcp", 0) < 0) + printf("add_redirect_rule2() #4 failed\n"); + if(add_filter_rule2("em0", NULL, "127.1.2.3", 12123, 1234, IPPROTO_TCP, + "test description tcp") < 0) + printf("add_filter_rule2() #1 failed\n"); list_rules(); list_eports_tcp(); @@ -113,20 +124,20 @@ main(int arc, char * * argv) if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0) printf("delete_redirect_rule() failed\n"); - else - printf("delete_redirect_rule() succeded\n"); if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0) printf("delete_redirect_rule() failed\n"); - else - printf("delete_redirect_rule() succeded\n"); -#if 0 + if(delete_redirect_and_filter_rules("em0", 12123, IPPROTO_TCP) < 0) + printf("delete_redirect_and_filter_rules() failed\n"); + test_index(); - clear_redirect_rules(); - list_rules(); -#endif + if(clear) { + clear_redirect_rules(); + clear_filter_rules(); + } + /*list_rules();*/ return 0; } diff --git a/miniupnpd/pf/testpfpinhole.c b/miniupnpd/pf/testpfpinhole.c index e09199c..ec754e2 100644 --- a/miniupnpd/pf/testpfpinhole.c +++ b/miniupnpd/pf/testpfpinhole.c @@ -1,7 +1,7 @@ -/* $Id: testpfpinhole.c,v 1.10 2012/04/22 23:12:51 nanard Exp $ */ +/* $Id: testpfpinhole.c,v 1.11 2014/02/28 16:49:15 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2012 Thomas Bernard + * (c) 2012-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -21,6 +21,7 @@ const char * tag = NULL; const char * anchor_name = "miniupnpd"; const char * queue = NULL; +#ifdef ENABLE_IPV6 static int print_pinhole(int uid) { int r; @@ -32,11 +33,11 @@ static int print_pinhole(int uid) unsigned int timestamp; u_int64_t packets, bytes; - r = get_pinhole((unsigned short)uid, - rem_host, sizeof(rem_host), &rem_port, - int_client, sizeof(int_client), &int_port, - &proto, ×tamp, - &packets, &bytes); + r = get_pinhole_info((unsigned short)uid, + rem_host, sizeof(rem_host), &rem_port, + int_client, sizeof(int_client), &int_port, + &proto, ×tamp, + &packets, &bytes); if(r < 0) { fprintf(stderr, "get_pinhole(%d) returned %d\n", uid, r); } else { @@ -47,6 +48,7 @@ static int print_pinhole(int uid) } return r; } +#endif int main(int argc, char * *argv) { diff --git a/miniupnpd/testasyncsendto.c b/miniupnpd/testasyncsendto.c new file mode 100644 index 0000000..e413bd7 --- /dev/null +++ b/miniupnpd/testasyncsendto.c @@ -0,0 +1,126 @@ +/* $Id: testasyncsendto.c,v 1.2 2014/02/25 11:00:14 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2014 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 "miniupnpdtypes.h" +#include "upnputils.h" +#include "asyncsendto.h" + +struct lan_addr_list lan_addrs; + +#define DEST_IP "239.255.255.250" +#define DEST_PORT 1900 +/* +ssize_t +sendto_schedule(int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen, + unsigned int delay) +*/ + +int test(void) +{ + int s; + ssize_t n; + int i; + struct sockaddr_in addr; + struct sockaddr_in dest_addr; + struct timeval next_send; + if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket(): %m"); + return 1; + } + set_non_blocking(s); + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + syslog(LOG_ERR, "bind(): %m"); + close(s); + return 1; + } + memset(&dest_addr, 0, sizeof(struct sockaddr_in)); + dest_addr.sin_family = AF_INET; + dest_addr.sin_addr.s_addr = inet_addr(DEST_IP); + dest_addr.sin_port = htons(DEST_PORT); + n = sendto_or_schedule(s, "1234", 4, 0, + (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + syslog(LOG_DEBUG, "sendto_or_schedule : %d", (int)n); + n = sendto_schedule(s, "1234", 4, 0, + (struct sockaddr *)&dest_addr, sizeof(dest_addr), + 4400); + syslog(LOG_DEBUG, "sendto_schedule : %d", (int)n); + n = sendto_schedule(s, "1234", 4, 0, + (struct sockaddr *)&dest_addr, sizeof(dest_addr), + 3000); + syslog(LOG_DEBUG, "sendto_schedule : %d", (int)n); + while ((i = get_next_scheduled_send(&next_send)) > 0) { + fd_set writefds; + int max_fd; + struct timeval timeout; + struct timeval now; + syslog(LOG_DEBUG, "get_next_scheduled_send : %d next_send=%ld.%06ld", + i, next_send.tv_sec, next_send.tv_usec); + FD_ZERO(&writefds); + max_fd = 0; + gettimeofday(&now, NULL); + i = get_sendto_fds(&writefds, &max_fd, &now); + if(now.tv_sec > next_send.tv_sec || + (now.tv_sec == next_send.tv_sec && now.tv_usec >= next_send.tv_usec)) { + if(i > 0) { + /* dont wait */ + timeout.tv_sec = 0; + } else { + /* wait 10sec :) */ + timeout.tv_sec = 10; + } + timeout.tv_usec = 0; + } else { + /* ... */ + timeout.tv_sec = (next_send.tv_sec - now.tv_sec); + timeout.tv_usec = (next_send.tv_usec - now.tv_usec); + if(timeout.tv_usec < 0) { + timeout.tv_usec += 1000000; + timeout.tv_sec--; + } + } + syslog(LOG_DEBUG, "get_sendto_fds() returned %d", i); + syslog(LOG_DEBUG, "select(%d, NULL, xx, NULL, %ld.%06ld)", + max_fd, timeout.tv_sec, timeout.tv_usec); + i = select(max_fd, NULL, &writefds, NULL, &timeout); + if(i < 0) { + syslog(LOG_ERR, "select: %m"); + if(errno != EINTR) + break; + } else if(try_sendto(&writefds) < 0) { + syslog(LOG_ERR, "try_sendto: %m"); + break; + } + } + close(s); + return 0; +} + +int main(int argc, char * * argv) +{ + int r; + (void)argc; + (void)argv; + openlog("testasyncsendto", LOG_CONS|LOG_PERROR, LOG_USER); + r = test(); + closelog(); + return r; +} + diff --git a/miniupnpd/testgetifaddr.c b/miniupnpd/testgetifaddr.c index 4c31907..8045b89 100644 --- a/miniupnpd/testgetifaddr.c +++ b/miniupnpd/testgetifaddr.c @@ -1,7 +1,7 @@ /* $Id: testgetifaddr.c,v 1.7 2013/04/27 15:38:57 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ #include @@ -10,6 +10,7 @@ #include #include #include +#include "config.h" #include "getifaddr.h" #if defined(__sun) @@ -21,6 +22,10 @@ int main(int argc, char * * argv) { char str_addr[64]; struct in_addr addr; struct in_addr mask; +#ifdef ENABLE_IPV6 + int r; + char str_addr6[64]; +#endif if(argc < 2) { fprintf(stderr, "Usage:\t%s interface_name\n", argv[0]); return 1; @@ -34,5 +39,16 @@ int main(int argc, char * * argv) { printf("Interface %s has IP address %s.\n", argv[1], str_addr); printf("addr=%s ", inet_ntoa(addr)); printf("mask=%s\n", inet_ntoa(mask)); +#ifdef ENABLE_IPV6 + r = find_ipv6_addr(argv[1], str_addr6, sizeof(str_addr6)); + if(r < 0) { + fprintf(stderr, "find_ipv6_addr() failed\n"); + return 1; + } else if(r == 0) { + printf("Interface %s has no IPv6 address.\n", argv[1]); + } else { + printf("Interface %s has IPv6 address %s.\n", argv[1], str_addr6); + } +#endif return 0; } diff --git a/miniupnpd/testupnpdescgen.c b/miniupnpd/testupnpdescgen.c index b838c62..ee30a8b 100644 --- a/miniupnpd/testupnpdescgen.c +++ b/miniupnpd/testupnpdescgen.c @@ -1,7 +1,7 @@ -/* $Id: testupnpdescgen.c,v 1.30 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: testupnpdescgen.c,v 1.32 2014/03/10 11:04:52 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -17,6 +17,7 @@ #include "config.h" #include "upnpdescgen.h" #include "upnpdescstrings.h" +#include "getifaddr.h" char uuidvalue_igd[] = "uuid:12345678-0000-0000-0000-000000abcd01"; char uuidvalue_wan[] = "uuid:12345678-0000-0000-0000-000000abcd02"; @@ -37,14 +38,13 @@ char model_url[] = ROOTDEV_MODELURL; char * use_ext_ip_addr = NULL; const char * ext_if_name = "eth0"; -#ifdef ENABLE_6FC_SERVICE -int ipv6fc_firewall_enabled = 1; -int ipv6fc_inbound_pinhole_allowed = 1; -#endif +int runtime_flags = 0; -int getifaddr(const char * ifname, char * buf, int len) +int getifaddr(const char * ifname, char * buf, int len, struct in_addr * addr, struct in_addr * mask) { UNUSED(ifname); + UNUSED(addr); + UNUSED(mask); strncpy(buf, "1.2.3.4", len); return 0; } diff --git a/miniupnpd/upnpdescgen.c b/miniupnpd/upnpdescgen.c index f88ea0b..5e5ebfb 100644 --- a/miniupnpd/upnpdescgen.c +++ b/miniupnpd/upnpdescgen.c @@ -1,7 +1,7 @@ -/* $Id: upnpdescgen.c,v 1.74 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: upnpdescgen.c,v 1.77 2014/03/10 11:04:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -1176,13 +1176,13 @@ genEventVars(int * len, const struct serviceDesc * s) case FIREWALLENABLED_MAGICALVALUE: /* see 2.4.2 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */ snprintf(tmp, sizeof(tmp), "%d", - ipv6fc_firewall_enabled); + GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1); str = strcat_str(str, len, &tmplen, tmp); break; case INBOUNDPINHOLEALLOWED_MAGICALVALUE: /* see 2.4.3 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */ snprintf(tmp, sizeof(tmp), "%d", - ipv6fc_inbound_pinhole_allowed); + GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1); str = strcat_str(str, len, &tmplen, tmp); break; #endif diff --git a/miniupnpd/upnpevents.c b/miniupnpd/upnpevents.c index 660ccc0..617da21 100644 --- a/miniupnpd/upnpevents.c +++ b/miniupnpd/upnpevents.c @@ -1,4 +1,4 @@ -/* $Id: upnpevents.c,v 1.27 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: upnpevents.c,v 1.28 2014/03/13 10:53:40 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2008-2013 Thomas Bernard @@ -233,8 +233,10 @@ upnp_event_notify_connect(struct upnp_event_notify * obj) unsigned short port; #ifdef ENABLE_IPV6 struct sockaddr_storage addr; + socklen_t addrlen; #else struct sockaddr_in addr; + socklen_t addrlen; #endif if(!obj) return; @@ -283,23 +285,28 @@ upnp_event_notify_connect(struct upnp_event_notify * obj) sa->sin6_family = AF_INET6; inet_pton(AF_INET6, obj->addrstr, &(sa->sin6_addr)); sa->sin6_port = htons(port); + addrlen = sizeof(struct sockaddr_in6); } else { struct sockaddr_in * sa = (struct sockaddr_in *)&addr; sa->sin_family = AF_INET; inet_pton(AF_INET, obj->addrstr, &(sa->sin_addr)); sa->sin_port = htons(port); + addrlen = sizeof(struct sockaddr_in); } #else addr.sin_family = AF_INET; inet_aton(obj->addrstr, &addr.sin_addr); addr.sin_port = htons(port); + addrlen = sizeof(struct sockaddr_in); #endif syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect", obj->addrstr, port, obj->path); obj->state = EConnecting; - if(connect(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + if(connect(obj->s, (struct sockaddr *)&addr, addrlen) < 0) { if(errno != EINPROGRESS && errno != EWOULDBLOCK) { - syslog(LOG_ERR, "%s: connect(): %m", "upnp_event_notify_connect"); + syslog(LOG_ERR, "%s: connect(%d, %s, %u): %m", + "upnp_event_notify_connect", obj->s, + obj->addrstr, addrlen); obj->state = EError; } } diff --git a/miniupnpd/upnpglobalvars.c b/miniupnpd/upnpglobalvars.c index 2181c43..9750f04 100644 --- a/miniupnpd/upnpglobalvars.c +++ b/miniupnpd/upnpglobalvars.c @@ -1,7 +1,7 @@ -/* $Id: upnpglobalvars.c,v 1.30 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: upnpglobalvars.c,v 1.35 2014/03/10 11:04:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -24,17 +24,17 @@ const char* lease_file = 0; * when NULL, getifaddr() is used */ const char * use_ext_ip_addr = 0; -/* LAN address */ -/*const char * listen_addr = 0;*/ - unsigned long downstream_bitrate = 0; unsigned long upstream_bitrate = 0; /* startup time */ time_t startup_time = 0; +#ifdef ENABLE_PCP +/* for PCP */ unsigned long int min_lifetime = 120; unsigned long int max_lifetime = 86400; +#endif int runtime_flags = 0; @@ -75,18 +75,10 @@ char model_url[MODEL_URL_MAX_LEN] = ROOTDEV_MODELURL; struct upnpperm * upnppermlist = 0; unsigned int num_upnpperm = 0; -#ifdef ENABLE_NATPMP -/* NAT-PMP */ -#if 0 -unsigned int nextnatpmptoclean_timestamp = 0; -unsigned short nextnatpmptoclean_eport = 0; -unsigned short nextnatpmptoclean_proto = 0; -#endif #ifdef PCP_SADSCP struct dscp_values* dscp_values_list = 0; unsigned int num_dscp_values = 0; -#endif //PCP_SADSCP -#endif +#endif /*PCP_SADSCP*/ /* For automatic removal of expired rules (with LeaseDuration) */ unsigned int nextruletoclean_timestamp = 0; @@ -127,8 +119,3 @@ const char * minissdpdsocketpath = "/var/run/minissdpd.sock"; unsigned int upnp_bootid = 1; unsigned int upnp_configid = 1337; -#ifdef ENABLE_6FC_SERVICE -int ipv6fc_firewall_enabled = 1; -int ipv6fc_inbound_pinhole_allowed = 1; -#endif - diff --git a/miniupnpd/upnpglobalvars.h b/miniupnpd/upnpglobalvars.h index 80ea147..bbfccef 100644 --- a/miniupnpd/upnpglobalvars.h +++ b/miniupnpd/upnpglobalvars.h @@ -1,7 +1,7 @@ -/* $Id: upnpglobalvars.h,v 1.35 2013/06/13 13:21:30 nanard Exp $ */ +/* $Id: upnpglobalvars.h,v 1.38 2014/03/10 11:04:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -51,6 +51,13 @@ extern int runtime_flags; #ifdef PF_ENABLE_FILTER_RULES #define PFNOQUICKRULESMASK 0x0040 #endif +#ifdef ENABLE_IPV6 +#define IPV6DISABLEDMASK 0x0080 +#endif +#ifdef ENABLE_6FC_SERVICE +#define IPV6FCFWDISABLEDMASK 0x0100 +#define IPV6FCINBOUNDDISALLOWEDMASK 0x0200 +#endif #define SETFLAG(mask) runtime_flags |= mask #define GETFLAG(mask) (runtime_flags & mask) @@ -95,18 +102,10 @@ extern char model_url[]; extern struct upnpperm * upnppermlist; extern unsigned int num_upnpperm; -#ifdef ENABLE_NATPMP -/* NAT-PMP */ -#if 0 -extern unsigned int nextnatpmptoclean_timestamp; -extern unsigned short nextnatpmptoclean_eport; -extern unsigned short nextnatpmptoclean_proto; -#endif #ifdef PCP_SADSCP extern struct dscp_values* dscp_values_list; extern unsigned int num_dscp_values; #endif -#endif /* For automatic removal of expired rules (with LeaseDuration) */ extern unsigned int nextruletoclean_timestamp; @@ -147,10 +146,5 @@ extern const char * minissdpdsocketpath; extern unsigned int upnp_bootid; extern unsigned int upnp_configid; -#ifdef ENABLE_6FC_SERVICE -extern int ipv6fc_firewall_enabled; -extern int ipv6fc_inbound_pinhole_allowed; -#endif - #endif diff --git a/miniupnpd/upnppermissions.c b/miniupnpd/upnppermissions.c index 0fd43f7..ad02d8c 100644 --- a/miniupnpd/upnppermissions.c +++ b/miniupnpd/upnppermissions.c @@ -1,7 +1,7 @@ -/* $Id: upnppermissions.c,v 1.17 2012/02/15 22:43:34 nanard Exp $ */ +/* $Id: upnppermissions.c,v 1.18 2014/03/07 10:43:29 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -223,6 +223,23 @@ match_permission(const struct upnpperm * perm, return 1; } +#if 0 +/* match_permission_internal() + * returns: 1 if address, iport matches the permission rule + * 0 if no match */ +static int +match_permission_internal(const struct upnpperm * perm, + struct in_addr address, u_short iport) +{ + if( (iport < perm->iport_min) || (perm->iport_max < iport)) + return 0; + if( (address.s_addr & perm->mask.s_addr) + != (perm->address.s_addr & perm->mask.s_addr) ) + return 0; + return 1; +} +#endif + int check_upnp_rule_against_permissions(const struct upnpperm * permary, int n_perms, diff --git a/miniupnpd/upnppermissions.h b/miniupnpd/upnppermissions.h index dea551e..933968e 100644 --- a/miniupnpd/upnppermissions.h +++ b/miniupnpd/upnppermissions.h @@ -1,7 +1,7 @@ -/* $Id: upnppermissions.h,v 1.7 2007/02/28 18:13:18 nanard Exp $ */ +/* $Id: upnppermissions.h,v 1.10 2014/03/07 10:43:29 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ diff --git a/miniupnpd/upnpredirect.c b/miniupnpd/upnpredirect.c index d3ecfeb..8306ce6 100644 --- a/miniupnpd/upnpredirect.c +++ b/miniupnpd/upnpredirect.c @@ -1,7 +1,7 @@ -/* $Id: upnpredirect.c,v 1.80 2012/05/01 20:08:22 nanard Exp $ */ +/* $Id: upnpredirect.c,v 1.82 2014/02/28 20:18:35 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2012 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -424,6 +424,8 @@ _upnp_delete_redir(unsigned short eport, int proto) int r; #if defined(__linux__) r = delete_redirect_and_filter_rules(eport, proto); +#elif defined(USE_PF) + r = delete_redirect_and_filter_rules(ext_if_name, eport, proto); #else r = delete_redirect_rule(ext_if_name, eport, proto); delete_filter_rule(ext_if_name, eport, proto); diff --git a/miniupnpd/upnpsoap.c b/miniupnpd/upnpsoap.c index a8023c0..21fc33b 100644 --- a/miniupnpd/upnpsoap.c +++ b/miniupnpd/upnpsoap.c @@ -1,7 +1,7 @@ -/* $Id: upnpsoap.c,v 1.119 2013/08/19 16:16:00 nanard Exp $ */ +/* $Id: upnpsoap.c,v 1.122 2014/03/10 11:04:53 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -1220,19 +1220,21 @@ GetFirewallStatus(struct upnphttp * h, const char * action) bodylen = snprintf(body, sizeof(body), resp, action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", - ipv6fc_firewall_enabled, ipv6fc_inbound_pinhole_allowed, action); + GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1, + GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1, + action); BuildSendAndCloseSoapResp(h, body, bodylen); } static int CheckStatus(struct upnphttp * h) { - if (!ipv6fc_firewall_enabled) + if (GETFLAG(IPV6FCFWDISABLEDMASK)) { SoapError(h, 702, "FirewallDisabled"); return 0; } - else if(!ipv6fc_inbound_pinhole_allowed) + else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK)) { SoapError(h, 703, "InboundPinholeNotAllowed"); return 0; @@ -1604,7 +1606,7 @@ GetOutboundPinholeTimeout(struct upnphttp * h, const char * action) int opt=0, proto=0; unsigned short iport, rport; - if (!ipv6fc_firewall_enabled) + if (GETFLAG(IPV6FCFWDISABLEDMASK)) { SoapError(h, 702, "FirewallDisabled"); return; @@ -1910,6 +1912,10 @@ ExecuteSoapAction(struct upnphttp * h, const char * action, int n) len = strlen(soapMethods[i].methodName); if(strncmp(p, soapMethods[i].methodName, len) == 0) { +#ifdef DEBUG + syslog(LOG_DEBUG, "Remote Call of SoapMethod '%s'\n", + soapMethods[i].methodName); +#endif soapMethods[i].methodImpl(h, soapMethods[i].methodName); return; } diff --git a/miniupnpd/upnputils.c b/miniupnpd/upnputils.c index 23ad242..33ebc66 100644 --- a/miniupnpd/upnputils.c +++ b/miniupnpd/upnputils.c @@ -1,7 +1,7 @@ -/* $Id: upnputils.c,v 1.7 2013/04/20 09:03:18 nanard Exp $ */ +/* $Id: upnputils.c,v 1.8 2014/02/05 17:00:26 nanard Exp $ */ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * (c) 2006-2013 Thomas Bernard + * (c) 2006-2014 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ @@ -93,6 +93,7 @@ struct lan_addr_s * get_lan_for_peer(const struct sockaddr * peer) { struct lan_addr_s * lan_addr = NULL; + char dbg_str[64]; #ifdef ENABLE_IPV6 if(peer->sa_family == AF_INET6) @@ -153,11 +154,15 @@ get_lan_for_peer(const struct sockaddr * peer) } #endif - if(lan_addr) - syslog(LOG_DEBUG, "%s: found in LAN %s %s", - "get_lan_for_peer()", lan_addr->ifname, lan_addr->str); - else - syslog(LOG_DEBUG, "%s: not found !", "get_lan_for_peer()"); + sockaddr_to_string(peer, dbg_str, sizeof(dbg_str)); + if(lan_addr) { + syslog(LOG_DEBUG, "%s: %s found in LAN %s %s", + "get_lan_for_peer()", dbg_str, + lan_addr->ifname, lan_addr->str); + } else { + syslog(LOG_DEBUG, "%s: %s not found !", "get_lan_for_peer()", + dbg_str); + } return lan_addr; }