Merge branch 'master' into search_all
Conflicts: miniupnpc/miniupnpc.c
This commit is contained in:
commit
4e44ef642a
3
README
3
README
|
@ -40,7 +40,10 @@ Thanks to :
|
||||||
* Alexey Osipov
|
* Alexey Osipov
|
||||||
* Alexey Kuznetsov
|
* Alexey Kuznetsov
|
||||||
* Chiaki Ishikawa
|
* Chiaki Ishikawa
|
||||||
|
* David Kerr
|
||||||
* Jardel Weyrich
|
* Jardel Weyrich
|
||||||
* Leah X. Schmidt
|
* Leah X. Schmidt
|
||||||
* Peter Tatrai
|
* Peter Tatrai
|
||||||
* Leo Moll
|
* Leo Moll
|
||||||
|
* Daniel Becker
|
||||||
|
* Yonetani Tomokazu
|
||||||
|
|
|
@ -2,4 +2,5 @@
|
||||||
minissdpd
|
minissdpd
|
||||||
testcodelength
|
testcodelength
|
||||||
testminissdpd
|
testminissdpd
|
||||||
|
listifaces
|
||||||
Makefile.bak
|
Makefile.bak
|
||||||
|
|
|
@ -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:
|
2013/08/19:
|
||||||
Translate README in english
|
Translate README in english
|
||||||
|
|
|
@ -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
|
# MiniUPnP project
|
||||||
# author: Thomas Bernard
|
# author: Thomas Bernard
|
||||||
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
# website: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
@ -59,6 +59,8 @@ testminissdpd: $(TESTMINISSDPDOBJS)
|
||||||
|
|
||||||
testcodelength: testcodelength.o
|
testcodelength: testcodelength.o
|
||||||
|
|
||||||
|
listifaces: listifaces.o upnputils.o
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
makedepend -f$(MAKEFILE_LIST) -Y \
|
makedepend -f$(MAKEFILE_LIST) -Y \
|
||||||
$(ALLOBJS:.o=.c) 2>/dev/null
|
$(ALLOBJS:.o=.c) 2>/dev/null
|
||||||
|
|
|
@ -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 <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
@ -8,7 +11,9 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "upnputils.h"
|
||||||
|
|
||||||
|
/* hexdump */
|
||||||
void printhex(const unsigned char * p, int n)
|
void printhex(const unsigned char * p, int n)
|
||||||
{
|
{
|
||||||
int i;
|
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;
|
struct ifconf ifc;
|
||||||
char * buf = 0;
|
char * buf = NULL;
|
||||||
int buflen = sizeof(struct ifreq)*20;
|
int buflen;
|
||||||
/*[sizeof(struct ifreq)*8];*/
|
|
||||||
int s, i;
|
int s, i;
|
||||||
int j;
|
int j;
|
||||||
char saddr[256/*INET_ADDRSTRLEN*/];
|
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(PF_INET, SOCK_DGRAM, 0);*/
|
||||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
do {
|
do {
|
||||||
|
#ifdef __linux__
|
||||||
buflen += buflen;
|
buflen += buflen;
|
||||||
buf = realloc(buf, buflen);
|
#endif
|
||||||
|
if(buflen > 0)
|
||||||
|
buf = realloc(buf, buflen);
|
||||||
ifc.ifc_len = buflen;
|
ifc.ifc_len = buflen;
|
||||||
ifc.ifc_buf = (caddr_t)buf;
|
ifc.ifc_buf = (caddr_t)buf;
|
||||||
if(ioctl(s, SIOCGIFCONF, &ifc) < 0)
|
if(ioctl(s, SIOCGIFCONF, &ifc) < 0)
|
||||||
|
@ -50,22 +63,39 @@ void listifaces()
|
||||||
free(buf);
|
free(buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printf("%d - %d - %d\n", buflen, ifc.ifc_len, (int)sizeof(struct ifreq));
|
printf("buffer length=%d - buffer used=%d - sizeof(struct ifreq)=%d\n",
|
||||||
printf(" %d\n", IFNAMSIZ);
|
buflen, ifc.ifc_len, (int)sizeof(struct ifreq));
|
||||||
printf(" %d %d\n", (int)sizeof(struct sockaddr), (int)sizeof(struct sockaddr_in) );
|
printf("IFNAMSIZ=%d ", IFNAMSIZ);
|
||||||
} while(buflen == ifc.ifc_len);
|
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);
|
printhex((const unsigned char *)ifc.ifc_buf, ifc.ifc_len);
|
||||||
j = 0;
|
printf("off index fam name address\n");
|
||||||
for(i=0; i<ifc.ifc_len; /*i += sizeof(struct ifreq)*/)
|
for(i = 0, j = 0; i<ifc.ifc_len; j++)
|
||||||
{
|
{
|
||||||
//const struct ifreq * ifrp = &(ifc.ifc_req[j]);
|
/*const struct ifreq * ifrp = &(ifc.ifc_req[j]);*/
|
||||||
const struct ifreq * ifrp = (const struct ifreq *)(buf + i);
|
const struct ifreq * ifrp = (const struct ifreq *)(buf + i);
|
||||||
i += sizeof(ifrp->ifr_name) + 16;//ifrp->ifr_addr.sa_len;
|
|
||||||
/*inet_ntop(AF_INET, &(((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr), saddr, sizeof(saddr));*/
|
/*inet_ntop(AF_INET, &(((struct sockaddr_in *)&(ifrp->ifr_addr))->sin_addr), saddr, sizeof(saddr));*/
|
||||||
saddr[0] = '\0';
|
saddr[0] = '\0';
|
||||||
inet_ntop(ifrp->ifr_addr.sa_family, &(ifrp->ifr_addr.sa_data[2]), saddr, sizeof(saddr));
|
/* 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);
|
sockaddr_to_string(&ifrp->ifr_addr, saddr, sizeof(saddr));
|
||||||
j++;
|
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);
|
free(buf);
|
||||||
close(s);
|
close(s);
|
||||||
|
@ -73,6 +103,8 @@ void listifaces()
|
||||||
|
|
||||||
int main(int argc, char * * argv)
|
int main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
listifaces();
|
listifaces();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* (c) 2007-2012 Thomas Bernard
|
* (c) 2007-2014 Thomas Bernard
|
||||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* 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,
|
n = sendto(s, buf, l, 0,
|
||||||
sockname, sockname_len );
|
sockname, sockname_len );
|
||||||
if(n < 0) {
|
if(n < 0) {
|
||||||
|
/* XXX handle EINTR, EAGAIN, EWOULDBLOCK */
|
||||||
syslog(LOG_ERR, "sendto(udp): %m");
|
syslog(LOG_ERR, "sendto(udp): %m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,8 +283,10 @@ processMSEARCH(int s, const char * st, int st_len,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* find matching services */
|
/* find matching services */
|
||||||
|
/* remove version at the end of the ST string */
|
||||||
if(st[st_len-2]==':' && isdigit(st[st_len-1]))
|
if(st[st_len-2]==':' && isdigit(st[st_len-1]))
|
||||||
st_len -= 2;
|
st_len -= 2;
|
||||||
|
/* answer for each matching service */
|
||||||
for(serv = servicelisthead.lh_first;
|
for(serv = servicelisthead.lh_first;
|
||||||
serv;
|
serv;
|
||||||
serv = serv->entries.le_next) {
|
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 */
|
unsigned int lifetime = 180; /* 3 minutes by default */
|
||||||
const char * st = NULL;
|
const char * st = NULL;
|
||||||
int st_len = 0;
|
int st_len = 0;
|
||||||
|
|
||||||
memset(headers, 0, sizeof(headers));
|
memset(headers, 0, sizeof(headers));
|
||||||
for(methodlen = 0;
|
for(methodlen = 0;
|
||||||
methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-');
|
methodlen < n && (isalpha(p[methodlen]) || p[methodlen]=='-');
|
||||||
|
@ -346,6 +350,12 @@ ParseSSDPPacket(int s, const char * p, ssize_t n,
|
||||||
method = METHOD_MSEARCH;
|
method = METHOD_MSEARCH;
|
||||||
else if(methodlen==6 && 0==memcmp(p, "NOTIFY", 6))
|
else if(methodlen==6 && 0==memcmp(p, "NOTIFY", 6))
|
||||||
method = METHOD_NOTIFY;
|
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;
|
linestart = p;
|
||||||
while(linestart < p + n - 2) {
|
while(linestart < p + n - 2) {
|
||||||
/* start parsing the line : detect line end */
|
/* 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)) {
|
} else if(l==2 && 0==strncasecmp(linestart, "st", 2)) {
|
||||||
st = valuestart;
|
st = valuestart;
|
||||||
st_len = m;
|
st_len = m;
|
||||||
|
if(method == METHOD_NOTIFY)
|
||||||
|
i = HEADER_NT; /* it was a M-SEARCH response */
|
||||||
}
|
}
|
||||||
if(i>=0) {
|
if(i>=0) {
|
||||||
headers[i].p = valuestart;
|
headers[i].p = valuestart;
|
||||||
|
@ -559,16 +571,16 @@ void processRequest(struct reqelem * req)
|
||||||
syslog(LOG_WARNING, "bad request (length encoding)");
|
syslog(LOG_WARNING, "bad request (length encoding)");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if(l == 0) {
|
if(l == 0 && type != 3) {
|
||||||
syslog(LOG_WARNING, "bad request (length=0)");
|
syslog(LOG_WARNING, "bad request (length=0)");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
syslog(LOG_INFO, "(s=%d) request type=%d str='%.*s'",
|
syslog(LOG_INFO, "(s=%d) request type=%d str='%.*s'",
|
||||||
req->socket, type, l, p);
|
req->socket, type, l, p);
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case 1:
|
case 1: /* request by type */
|
||||||
case 2:
|
case 2: /* request by USN (unique id) */
|
||||||
case 3:
|
case 3: /* everything */
|
||||||
while(d && (nrep < 255)) {
|
while(d && (nrep < 255)) {
|
||||||
if(d->t < t) {
|
if(d->t < t) {
|
||||||
syslog(LOG_INFO, "outdated device");
|
syslog(LOG_INFO, "outdated device");
|
||||||
|
@ -633,17 +645,20 @@ void processRequest(struct reqelem * req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rbuf[0] = nrep;
|
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) {
|
if(write(req->socket, rbuf, rp - rbuf) < 0) {
|
||||||
syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
|
syslog(LOG_ERR, "(s=%d) write: %m", req->socket);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4: /* submit service */
|
||||||
newserv = malloc(sizeof(struct service));
|
newserv = malloc(sizeof(struct service));
|
||||||
if(!newserv) {
|
if(!newserv) {
|
||||||
syslog(LOG_ERR, "cannot allocate memory");
|
syslog(LOG_ERR, "cannot allocate memory");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
memset(newserv, 0, sizeof(struct service)); /* set pointers to NULL */
|
||||||
if(containsForbiddenChars(p, l)) {
|
if(containsForbiddenChars(p, l)) {
|
||||||
syslog(LOG_ERR, "bad request (st contains forbidden chars)");
|
syslog(LOG_ERR, "bad request (st contains forbidden chars)");
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -779,6 +794,60 @@ sigterm(int sig)
|
||||||
/*errno = save_errno;*/
|
/*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 */
|
/* main(): program entry point */
|
||||||
int main(int argc, char * * argv)
|
int main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
|
@ -957,6 +1026,11 @@ int main(int argc, char * * argv)
|
||||||
|
|
||||||
writepidfile(pidfilename, pid);
|
writepidfile(pidfilename, pid);
|
||||||
|
|
||||||
|
/* send M-SEARCH ssdp:all Requests */
|
||||||
|
ssdpDiscoverAll(s_ssdp, 0);
|
||||||
|
if(s_ssdp6 >= 0)
|
||||||
|
ssdpDiscoverAll(s_ssdp6, 1);
|
||||||
|
|
||||||
/* Main loop */
|
/* Main loop */
|
||||||
while(!quitting)
|
while(!quitting)
|
||||||
{
|
{
|
||||||
|
@ -997,7 +1071,10 @@ int main(int argc, char * * argv)
|
||||||
(struct sockaddr *)&sendername6, &sendername6_len);
|
(struct sockaddr *)&sendername6, &sendername6_len);
|
||||||
if(n<0)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -1028,7 +1105,10 @@ int main(int argc, char * * argv)
|
||||||
(struct sockaddr *)&sendername, &sendername_len);
|
(struct sockaddr *)&sendername, &sendername_len);
|
||||||
if(n<0)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
/* Project : miniupnp
|
||||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* Author : Thomas BERNARD
|
* 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
|
* This software is subjet to the conditions detailed in the
|
||||||
* provided LICENCE file. */
|
* provided LICENCE file. */
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -21,30 +22,64 @@ void printresponse(const unsigned char * resp, int n)
|
||||||
int i, l;
|
int i, l;
|
||||||
unsigned int nresp;
|
unsigned int nresp;
|
||||||
const unsigned char * p;
|
const unsigned char * p;
|
||||||
|
if(n == 0)
|
||||||
|
return;
|
||||||
for(i=0; i<n; i++)
|
for(i=0; i<n; i++)
|
||||||
printf("%02x ", resp[i]);
|
printf("%02x ", resp[i]);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
nresp = resp[0];
|
nresp = resp[0];
|
||||||
p = resp + 1;
|
p = resp + 1;
|
||||||
for(i = 0; i < (int)nresp; i++) {
|
for(i = 0; i < (int)nresp; i++) {
|
||||||
|
if(p >= resp + n)
|
||||||
|
goto error;
|
||||||
/*l = *(p++);*/
|
/*l = *(p++);*/
|
||||||
DECODELENGTH(l, p);
|
DECODELENGTH(l, p);
|
||||||
|
if(p + l > resp + n)
|
||||||
|
goto error;
|
||||||
printf("%d - %.*s\n", i, l, p);
|
printf("%d - %.*s\n", i, l, p);
|
||||||
p += l;
|
p += l;
|
||||||
|
if(p >= resp + n)
|
||||||
|
goto error;
|
||||||
/*l = *(p++);*/
|
/*l = *(p++);*/
|
||||||
DECODELENGTH(l, p);
|
DECODELENGTH(l, p);
|
||||||
|
if(p + l > resp + n)
|
||||||
|
goto error;
|
||||||
printf(" %.*s\n", l, p);
|
printf(" %.*s\n", l, p);
|
||||||
p += l;
|
p += l;
|
||||||
|
if(p >= resp + n)
|
||||||
|
goto error;
|
||||||
/*l = *(p++);*/
|
/*l = *(p++);*/
|
||||||
DECODELENGTH(l, p);
|
DECODELENGTH(l, p);
|
||||||
|
if(p + l > resp + n)
|
||||||
|
goto error;
|
||||||
printf(" %.*s\n", l, p);
|
printf(" %.*s\n", l, p);
|
||||||
p += l;
|
p += l;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
error:
|
||||||
|
printf("*** WARNING : TRUNCATED RESPONSE ***\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SENDCOMMAND(command, size) write(s, command, size); \
|
#define SENDCOMMAND(command, size) write(s, command, size); \
|
||||||
printf("Command written type=%u\n", (unsigned)command[0]);
|
printf("Command written type=%u\n", (unsigned)command[0]);
|
||||||
|
|
||||||
|
int connect_unix_socket(const char * sockpath)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
|
||||||
|
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
|
||||||
|
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
|
||||||
|
fprintf(stderr, "connecting to %s\n", addr.sun_path);
|
||||||
|
perror("connect");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("Connected.\n");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/* test program for minissdpd */
|
/* test program for minissdpd */
|
||||||
int
|
int
|
||||||
main(int argc, char * * argv)
|
main(int argc, char * * argv)
|
||||||
|
@ -52,10 +87,12 @@ main(int argc, char * * argv)
|
||||||
char command1[] = "\x01\x00urn:schemas-upnp-org:device:InternetGatewayDevice";
|
char command1[] = "\x01\x00urn:schemas-upnp-org:device:InternetGatewayDevice";
|
||||||
char command2[] = "\x02\x00uuid:fc4ec57e-b051-11db-88f8-0060085db3f6::upnp:rootdevice";
|
char command2[] = "\x02\x00uuid:fc4ec57e-b051-11db-88f8-0060085db3f6::upnp:rootdevice";
|
||||||
char command3[] = { 0x03, 0x00 };
|
char command3[] = { 0x03, 0x00 };
|
||||||
struct sockaddr_un addr;
|
char command4[] = "\x04\x00test:test:test";
|
||||||
|
char bad_command[] = { 0xff, 0xff };
|
||||||
|
char overflow[] = { 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||||
int s;
|
int s;
|
||||||
int i;
|
int i;
|
||||||
unsigned char buf[2048];
|
unsigned char buf[16*1024];
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
const char * sockpath = "/var/run/minissdpd.sock";
|
const char * sockpath = "/var/run/minissdpd.sock";
|
||||||
|
|
||||||
|
@ -65,30 +102,51 @@ main(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
command1[1] = sizeof(command1) - 3;
|
command1[1] = sizeof(command1) - 3;
|
||||||
command2[1] = sizeof(command2) - 3;
|
command2[1] = sizeof(command2) - 3;
|
||||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
command4[1] = sizeof(command4) - 3;
|
||||||
addr.sun_family = AF_UNIX;
|
s = connect_unix_socket(sockpath);
|
||||||
strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
|
|
||||||
if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
|
|
||||||
fprintf(stderr, "connecting to %s\n", addr.sun_path);
|
|
||||||
perror("connect");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("Connected.\n");
|
|
||||||
|
|
||||||
SENDCOMMAND(command1, sizeof(command1) - 1);
|
SENDCOMMAND(command1, sizeof(command1) - 1);
|
||||||
n = read(s, buf, sizeof(buf));
|
n = read(s, buf, sizeof(buf));
|
||||||
printf("Response received %d bytes\n", (int)n);
|
printf("Response received %d bytes\n", (int)n);
|
||||||
printresponse(buf, n);
|
printresponse(buf, n);
|
||||||
|
if(n == 0) {
|
||||||
|
close(s);
|
||||||
|
s = connect_unix_socket(sockpath);
|
||||||
|
}
|
||||||
|
|
||||||
SENDCOMMAND(command2, sizeof(command2) - 1);
|
SENDCOMMAND(command2, sizeof(command2) - 1);
|
||||||
n = read(s, buf, sizeof(buf));
|
n = read(s, buf, sizeof(buf));
|
||||||
printf("Response received %d bytes\n", (int)n);
|
printf("Response received %d bytes\n", (int)n);
|
||||||
printresponse(buf, n);
|
printresponse(buf, n);
|
||||||
|
if(n == 0) {
|
||||||
|
close(s);
|
||||||
|
s = connect_unix_socket(sockpath);
|
||||||
|
}
|
||||||
|
|
||||||
SENDCOMMAND(command3, sizeof(command3));
|
SENDCOMMAND(command3, sizeof(command3));
|
||||||
n = read(s, buf, sizeof(buf));
|
n = read(s, buf, sizeof(buf));
|
||||||
printf("Response received %d bytes\n", (int)n);
|
printf("Response received %d bytes\n", (int)n);
|
||||||
printresponse(buf, n);
|
printresponse(buf, n);
|
||||||
|
if(n == 0) {
|
||||||
|
close(s);
|
||||||
|
s = connect_unix_socket(sockpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
SENDCOMMAND(command4, sizeof(command4));
|
||||||
|
|
||||||
|
SENDCOMMAND(bad_command, sizeof(bad_command));
|
||||||
|
n = read(s, buf, sizeof(buf));
|
||||||
|
printf("Response received %d bytes\n", (int)n);
|
||||||
|
printresponse(buf, n);
|
||||||
|
if(n == 0) {
|
||||||
|
close(s);
|
||||||
|
s = connect_unix_socket(sockpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
SENDCOMMAND(overflow, sizeof(overflow));
|
||||||
|
n = read(s, buf, sizeof(buf));
|
||||||
|
printf("Response received %d bytes\n", (int)n);
|
||||||
|
printresponse(buf, n);
|
||||||
|
|
||||||
close(s);
|
close(s);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
$Id: Changelog.txt,v 1.191 2014/01/31 13:18:24 nanard Exp $
|
$Id: Changelog.txt,v 1.193 2014/02/05 17:26:45 nanard Exp $
|
||||||
miniUPnP client Changelog.
|
miniUPnP client Changelog.
|
||||||
|
|
||||||
|
2014/02/05:
|
||||||
|
handle EINPROGRESS after connect()
|
||||||
|
|
||||||
|
2014/02/03:
|
||||||
|
minixml now handle XML comments
|
||||||
|
|
||||||
VERSION 1.9 : released 2014/01/31
|
VERSION 1.9 : released 2014/01/31
|
||||||
|
|
||||||
2014/01/31:
|
2014/01/31:
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# http://miniupnp.free.fr/
|
# http://miniupnp.free.fr/
|
||||||
# http://miniupnp.tuxfamily.org/
|
# http://miniupnp.tuxfamily.org/
|
||||||
# https://github.com/miniupnp/miniupnp
|
# https://github.com/miniupnp/miniupnp
|
||||||
# (c) 2005-2013 Thomas Bernard
|
# (c) 2005-2014 Thomas Bernard
|
||||||
# to install use :
|
# to install use :
|
||||||
# $ make DESTDIR=/tmp/dummylocation install
|
# $ make DESTDIR=/tmp/dummylocation install
|
||||||
# or
|
# or
|
||||||
|
@ -176,7 +176,8 @@ validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh
|
||||||
clean:
|
clean:
|
||||||
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
|
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
|
||||||
# clean python stuff
|
# clean python stuff
|
||||||
$(RM) pythonmodule pythonmodule3 validateminixml validateminiwget
|
$(RM) pythonmodule pythonmodule3
|
||||||
|
$(RM) validateminixml validateminiwget validateupnpreplyparse
|
||||||
$(RM) -r build/ dist/
|
$(RM) -r build/ dist/
|
||||||
#python setup.py clean
|
#python setup.py clean
|
||||||
# clean jnaerator stuff
|
# clean jnaerator stuff
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: connecthostport.c,v 1.11 2013/08/01 21:21:25 nanard Exp $ */
|
/* $Id: connecthostport.c,v 1.12 2014/02/05 17:26:46 nanard Exp $ */
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* Author : Thomas Bernard
|
* Author : Thomas Bernard
|
||||||
* Copyright (c) 2010-2013 Thomas Bernard
|
* Copyright (c) 2010-2014 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed in the
|
* This software is subject to the conditions detailed in the
|
||||||
* LICENCE file provided in this distribution. */
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
@ -109,7 +109,10 @@ int connecthostport(const char * host, unsigned short port,
|
||||||
dest.sin_port = htons(port);
|
dest.sin_port = htons(port);
|
||||||
n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
|
n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
|
||||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
#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;
|
socklen_t len;
|
||||||
fd_set wset;
|
fd_set wset;
|
||||||
|
@ -203,7 +206,10 @@ int connecthostport(const char * host, unsigned short port,
|
||||||
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
|
||||||
n = connect(s, p->ai_addr, p->ai_addrlen);
|
n = connect(s, p->ai_addr, p->ai_addrlen);
|
||||||
#ifdef MINIUPNPC_IGNORE_EINTR
|
#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;
|
socklen_t len;
|
||||||
fd_set wset;
|
fd_set wset;
|
||||||
|
|
|
@ -2,13 +2,19 @@
|
||||||
#define DECLSPEC_H_INCLUDED
|
#define DECLSPEC_H_INCLUDED
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(STATICLIB)
|
#if defined(_WIN32) && !defined(STATICLIB)
|
||||||
|
/* for windows dll */
|
||||||
#ifdef MINIUPNP_EXPORTS
|
#ifdef MINIUPNP_EXPORTS
|
||||||
#define LIBSPEC __declspec(dllexport)
|
#define LIBSPEC __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define LIBSPEC __declspec(dllimport)
|
#define LIBSPEC __declspec(dllimport)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#define LIBSPEC
|
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */
|
||||||
|
#define LIBSPEC __attribute__ ((visibility ("default")))
|
||||||
|
#else
|
||||||
|
#define LIBSPEC
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: minihttptestserver.c,v 1.13 2012/05/29 13:03:07 nanard Exp $ */
|
/* $Id: minihttptestserver.c,v 1.16 2014/04/01 15:08:28 nanard Exp $ */
|
||||||
/* Project : miniUPnP
|
/* Project : miniUPnP
|
||||||
* Author : Thomas Bernard
|
* Author : Thomas Bernard
|
||||||
* Copyright (c) 2011-2012 Thomas Bernard
|
* Copyright (c) 2011-2014 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed in the
|
* This software is subject to the conditions detailed in the
|
||||||
* LICENCE file provided in this distribution.
|
* LICENCE file provided in this distribution.
|
||||||
* */
|
* */
|
||||||
|
@ -28,20 +28,20 @@ volatile sig_atomic_t child_to_wait_for = 0;
|
||||||
*/
|
*/
|
||||||
void handle_signal_chld(int sig)
|
void handle_signal_chld(int sig)
|
||||||
{
|
{
|
||||||
printf("handle_signal_chld(%d)\n", sig);
|
(void)sig;
|
||||||
|
/* printf("handle_signal_chld(%d)\n", sig); */
|
||||||
++child_to_wait_for;
|
++child_to_wait_for;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* signal handler for SIGINT (CRTL C)
|
* signal handler for SIGINT (CRTL C)
|
||||||
*/
|
*/
|
||||||
#if 0
|
|
||||||
void handle_signal_int(int sig)
|
void handle_signal_int(int sig)
|
||||||
{
|
{
|
||||||
printf("handle_signal_int(%d)\n", sig);
|
(void)sig;
|
||||||
|
/* printf("handle_signal_int(%d)\n", sig); */
|
||||||
quit = 1;
|
quit = 1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* build a text/plain content of the specified length
|
* build a text/plain content of the specified length
|
||||||
|
@ -94,7 +94,8 @@ void build_crap(char * p, int n)
|
||||||
* build chunked response.
|
* build chunked response.
|
||||||
* return a malloc'ed buffer
|
* return a malloc'ed buffer
|
||||||
*/
|
*/
|
||||||
char * build_chunked_response(int content_length, int * response_len) {
|
char * build_chunked_response(int content_length, int * response_len)
|
||||||
|
{
|
||||||
char * response_buffer;
|
char * response_buffer;
|
||||||
char * content_buffer;
|
char * content_buffer;
|
||||||
int buffer_length;
|
int buffer_length;
|
||||||
|
@ -141,7 +142,115 @@ char * build_chunked_response(int content_length, int * response_len) {
|
||||||
return response_buffer;
|
return response_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum modes { MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL };
|
/* favicon.ico generator */
|
||||||
|
#ifdef OLD_HEADER
|
||||||
|
#define FAVICON_LENGTH (6 + 16 + 12 + 8 + 32 * 4)
|
||||||
|
#else
|
||||||
|
#define FAVICON_LENGTH (6 + 16 + 40 + 8 + 32 * 4)
|
||||||
|
#endif
|
||||||
|
void build_favicon_content(char * p, int n)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if(n < FAVICON_LENGTH)
|
||||||
|
return;
|
||||||
|
/* header : 6 bytes */
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 1; /* type : ICO */
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 1; /* number of images in file */
|
||||||
|
*p++ = 0;
|
||||||
|
/* image directory (1 entry) : 16 bytes */
|
||||||
|
*p++ = 16; /* width */
|
||||||
|
*p++ = 16; /* height */
|
||||||
|
*p++ = 2; /* number of colors in the palette. 0 = no palette */
|
||||||
|
*p++ = 0; /* reserved */
|
||||||
|
*p++ = 1; /* color planes */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 1; /* bpp */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
#ifdef OLD_HEADER
|
||||||
|
*p++ = 12 + 8 + 32 * 4; /* bmp size */
|
||||||
|
#else
|
||||||
|
*p++ = 40 + 8 + 32 * 4; /* bmp size */
|
||||||
|
#endif
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 6 + 16; /* bmp offset */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
/* BMP */
|
||||||
|
#ifdef OLD_HEADER
|
||||||
|
/* BITMAPCOREHEADER */
|
||||||
|
*p++ = 12; /* size of this header */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 16; /* width */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 16 * 2; /* height x 2 ! */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 1; /* color planes */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 1; /* bpp */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
#else
|
||||||
|
/* BITMAPINFOHEADER */
|
||||||
|
*p++ = 40; /* size of this header */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 16; /* width */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 16 * 2; /* height x 2 ! */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 1; /* color planes */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
*p++ = 1; /* bpp */
|
||||||
|
*p++ = 0; /* " */
|
||||||
|
/* compression method, image size, ppm x, ppm y */
|
||||||
|
/* colors in the palette ? */
|
||||||
|
/* important colors */
|
||||||
|
for(i = 4 * 6; i > 0; --i)
|
||||||
|
*p++ = 0;
|
||||||
|
#endif
|
||||||
|
/* palette */
|
||||||
|
*p++ = 0; /* b */
|
||||||
|
*p++ = 0; /* g */
|
||||||
|
*p++ = 0; /* r */
|
||||||
|
*p++ = 0; /* reserved */
|
||||||
|
*p++ = 255; /* b */
|
||||||
|
*p++ = 255; /* g */
|
||||||
|
*p++ = 255; /* r */
|
||||||
|
*p++ = 0; /* reserved */
|
||||||
|
/* pixel data */
|
||||||
|
for(i = 16; i > 0; --i) {
|
||||||
|
if(i & 1) {
|
||||||
|
*p++ = 0125;
|
||||||
|
*p++ = 0125;
|
||||||
|
} else {
|
||||||
|
*p++ = 0252;
|
||||||
|
*p++ = 0252;
|
||||||
|
}
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 0;
|
||||||
|
}
|
||||||
|
/* Opacity MASK */
|
||||||
|
for(i = 16 * 4; i > 0; --i) {
|
||||||
|
*p++ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum modes {
|
||||||
|
MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL, MODE_FAVICON
|
||||||
|
};
|
||||||
|
|
||||||
const struct {
|
const struct {
|
||||||
const enum modes mode;
|
const enum modes mode;
|
||||||
const char * text;
|
const char * text;
|
||||||
|
@ -149,6 +258,7 @@ const struct {
|
||||||
{MODE_CHUNKED, "chunked"},
|
{MODE_CHUNKED, "chunked"},
|
||||||
{MODE_ADDCRAP, "addcrap"},
|
{MODE_ADDCRAP, "addcrap"},
|
||||||
{MODE_NORMAL, "normal"},
|
{MODE_NORMAL, "normal"},
|
||||||
|
{MODE_FAVICON, "favicon.ico"},
|
||||||
{MODE_INVALID, NULL}
|
{MODE_INVALID, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -201,6 +311,8 @@ void handle_http_connection(int c)
|
||||||
request_buffer + request_len,
|
request_buffer + request_len,
|
||||||
sizeof(request_buffer) - request_len);
|
sizeof(request_buffer) - request_len);
|
||||||
if(n < 0) {
|
if(n < 0) {
|
||||||
|
if(errno == EINTR)
|
||||||
|
continue;
|
||||||
perror("read");
|
perror("read");
|
||||||
return;
|
return;
|
||||||
} else if(n==0) {
|
} else if(n==0) {
|
||||||
|
@ -219,6 +331,7 @@ void handle_http_connection(int c)
|
||||||
}
|
}
|
||||||
if(!headers_found) {
|
if(!headers_found) {
|
||||||
/* error */
|
/* error */
|
||||||
|
printf("no HTTP header found in the request\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printf("headers :\n%.*s", request_len, request_buffer);
|
printf("headers :\n%.*s", request_len, request_buffer);
|
||||||
|
@ -292,6 +405,8 @@ void handle_http_connection(int c)
|
||||||
case MODE_ADDCRAP:
|
case MODE_ADDCRAP:
|
||||||
response_len = content_length+256;
|
response_len = content_length+256;
|
||||||
response_buffer = malloc(response_len);
|
response_buffer = malloc(response_len);
|
||||||
|
if(!response_buffer)
|
||||||
|
break;
|
||||||
n = snprintf(response_buffer, response_len,
|
n = snprintf(response_buffer, response_len,
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Server: minihttptestserver\r\n"
|
"Server: minihttptestserver\r\n"
|
||||||
|
@ -303,9 +418,27 @@ void handle_http_connection(int c)
|
||||||
build_content(response_buffer + n, content_length);
|
build_content(response_buffer + n, content_length);
|
||||||
build_crap(response_buffer + n + content_length, CRAP_LENGTH);
|
build_crap(response_buffer + n + content_length, CRAP_LENGTH);
|
||||||
break;
|
break;
|
||||||
|
case MODE_FAVICON:
|
||||||
|
content_length = FAVICON_LENGTH;
|
||||||
|
response_len = content_length + 256;
|
||||||
|
response_buffer = malloc(response_len);
|
||||||
|
if(!response_buffer)
|
||||||
|
break;
|
||||||
|
n = snprintf(response_buffer, response_len,
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Server: minihttptestserver\r\n"
|
||||||
|
"Content-Type: image/vnd.microsoft.icon\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"\r\n", content_length);
|
||||||
|
/* image/x-icon */
|
||||||
|
build_favicon_content(response_buffer + n, content_length);
|
||||||
|
response_len = content_length + n;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
response_len = content_length+256;
|
response_len = content_length+256;
|
||||||
response_buffer = malloc(response_len);
|
response_buffer = malloc(response_len);
|
||||||
|
if(!response_buffer)
|
||||||
|
break;
|
||||||
n = snprintf(response_buffer, response_len,
|
n = snprintf(response_buffer, response_len,
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Server: minihttptestserver\r\n"
|
"Server: minihttptestserver\r\n"
|
||||||
|
@ -338,6 +471,7 @@ int main(int argc, char * * argv) {
|
||||||
int child = 0;
|
int child = 0;
|
||||||
int status;
|
int status;
|
||||||
const char * expected_file_name = NULL;
|
const char * expected_file_name = NULL;
|
||||||
|
struct sigaction sa;
|
||||||
|
|
||||||
for(i = 1; i < argc; i++) {
|
for(i = 1; i < argc; i++) {
|
||||||
if(argv[i][0] == '-') {
|
if(argv[i][0] == '-') {
|
||||||
|
@ -364,10 +498,21 @@ int main(int argc, char * * argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
signal(SIGCHLD, handle_signal_chld);
|
|
||||||
#if 0
|
memset(&sa, 0, sizeof(struct sigaction));
|
||||||
signal(SIGINT, handle_signal_int);
|
|
||||||
#endif
|
/*signal(SIGCHLD, handle_signal_chld);*/
|
||||||
|
sa.sa_handler = handle_signal_chld;
|
||||||
|
if(sigaction(SIGCHLD, &sa, NULL) < 0) {
|
||||||
|
perror("sigaction");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*signal(SIGINT, handle_signal_int);*/
|
||||||
|
sa.sa_handler = handle_signal_int;
|
||||||
|
if(sigaction(SIGINT, &sa, NULL) < 0) {
|
||||||
|
perror("sigaction");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
|
s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
|
||||||
if(s < 0) {
|
if(s < 0) {
|
||||||
|
@ -442,12 +587,12 @@ int main(int argc, char * * argv) {
|
||||||
}
|
}
|
||||||
--child_to_wait_for;
|
--child_to_wait_for;
|
||||||
}
|
}
|
||||||
/* TODO : add a select() call in order to handle the case
|
|
||||||
* when a signal is caught */
|
|
||||||
client_addrlen = sizeof(struct sockaddr_storage);
|
client_addrlen = sizeof(struct sockaddr_storage);
|
||||||
c = accept(s, (struct sockaddr *)&client_addr,
|
c = accept(s, (struct sockaddr *)&client_addr,
|
||||||
&client_addrlen);
|
&client_addrlen);
|
||||||
if(c < 0) {
|
if(c < 0) {
|
||||||
|
if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
||||||
|
continue;
|
||||||
perror("accept");
|
perror("accept");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
|
||||||
{
|
{
|
||||||
struct UPNPDev * tmp;
|
struct UPNPDev * tmp;
|
||||||
struct UPNPDev * devlist = NULL;
|
struct UPNPDev * devlist = NULL;
|
||||||
unsigned char buffer[2048];
|
unsigned char buffer[4*1024]; /* is that enough ? */
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
unsigned char * p;
|
unsigned char * p;
|
||||||
unsigned char * url;
|
unsigned char * url;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $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
|
/* Project : miniupnp
|
||||||
* Web : http://miniupnp.free.fr/
|
* Web : http://miniupnp.free.fr/
|
||||||
* Author : Thomas BERNARD
|
* Author : Thomas BERNARD
|
||||||
|
@ -533,7 +533,8 @@ upnpDiscoverDevices(const char * const deviceTypes[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
if (bind(sudp, (const struct sockaddr *)&sockudp_r,
|
||||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
|
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
/* Project : miniupnp
|
||||||
* Website : http://miniupnp.free.fr/
|
* Website : http://miniupnp.free.fr/
|
||||||
* Author : Thomas Bernard
|
* 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
|
* This software is subject to the conditions detailed in the
|
||||||
* LICENCE file provided in this distribution. */
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
@ -39,9 +39,6 @@
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#define closesocket close
|
#define closesocket close
|
||||||
/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions
|
|
||||||
* during the connect() call */
|
|
||||||
#define MINIUPNPC_IGNORE_EINTR
|
|
||||||
#endif /* #else _WIN32 */
|
#endif /* #else _WIN32 */
|
||||||
#if defined(__sun) || defined(sun)
|
#if defined(__sun) || defined(sun)
|
||||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||||
|
|
|
@ -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 ! */
|
/* minixml.c : the minimum size a xml parser can be ! */
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* Author : Thomas Bernard
|
* Author : Thomas Bernard
|
||||||
|
|
||||||
Copyright (c) 2005-2011, Thomas BERNARD
|
Copyright (c) 2005-2014, Thomas BERNARD
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p)
|
||||||
const char * elementname;
|
const char * elementname;
|
||||||
while(p->xml < (p->xmlend - 1))
|
while(p->xml < (p->xmlend - 1))
|
||||||
{
|
{
|
||||||
if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
|
||||||
|
{
|
||||||
|
p->xml += 3;
|
||||||
|
/* ignore comments */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if ((p->xml + 3) >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while(memcmp(p->xml, "-->", 3) != 0);
|
||||||
|
p->xml += 3;
|
||||||
|
}
|
||||||
|
else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||||
{
|
{
|
||||||
i = 0; elementname = ++p->xml;
|
i = 0; elementname = ++p->xml;
|
||||||
while( !IS_WHITE_SPACE(*p->xml)
|
while( !IS_WHITE_SPACE(*p->xml)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: upnpc.c,v 1.101 2014/01/31 13:18:25 nanard Exp $ */
|
/* $Id: upnpc.c,v 1.102 2014/02/05 17:27:14 nanard Exp $ */
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* Author : Thomas Bernard
|
* 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
|
* This software is subject to the conditions detailed in the
|
||||||
* LICENCE file provided in this distribution. */
|
* LICENCE file provided in this distribution. */
|
||||||
|
|
||||||
|
@ -500,7 +500,7 @@ int main(int argc, char ** argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#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"
|
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
|
||||||
"for more information.\n");
|
"for more information.\n");
|
||||||
/* command line processing */
|
/* command line processing */
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: upnpcommands.h,v 1.26 2014/01/31 13:18:26 nanard Exp $ */
|
/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */
|
||||||
/* Miniupnp project : http://miniupnp.free.fr/
|
/* Miniupnp project : http://miniupnp.free.fr/
|
||||||
* Author : Thomas Bernard
|
* 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
|
* This software is subject to the conditions detailed in the
|
||||||
* LICENCE file provided within this distribution */
|
* LICENCE file provided within this distribution */
|
||||||
#ifndef UPNPCOMMANDS_H_INCLUDED
|
#ifndef UPNPCOMMANDS_H_INCLUDED
|
||||||
|
@ -100,6 +100,8 @@ UPNP_GetLinkLayerMaxBitRates(const char* controlURL,
|
||||||
* errorCode errorDescription (short) - Description (long)
|
* errorCode errorDescription (short) - Description (long)
|
||||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
||||||
* 501 Action Failed - 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
|
* 715 WildCardNotPermittedInSrcIP - The source IP address cannot be
|
||||||
* wild-carded
|
* wild-carded
|
||||||
* 716 WildCardNotPermittedInExtPort - The external port 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
|
* 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard
|
||||||
* and cannot be a specific IP address or DNS name
|
* and cannot be a specific IP address or DNS name
|
||||||
* 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and
|
* 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
|
LIBSPEC int
|
||||||
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||||
const char * extPort,
|
const char * extPort,
|
||||||
|
@ -132,6 +140,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
|
||||||
*
|
*
|
||||||
* List of possible UPnP errors for DeletePortMapping :
|
* List of possible UPnP errors for DeletePortMapping :
|
||||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
* 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 */
|
* 714 NoSuchEntryInArray - The specified value does not exist in the array */
|
||||||
LIBSPEC int
|
LIBSPEC int
|
||||||
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
|
||||||
|
@ -159,7 +169,15 @@ UPNP_GetPortMappingNumberOfEntries(const char* controlURL,
|
||||||
*
|
*
|
||||||
* return value :
|
* return value :
|
||||||
* UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR
|
* 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
|
LIBSPEC int
|
||||||
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||||
const char * servicetype,
|
const char * servicetype,
|
||||||
|
@ -190,6 +208,8 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
|
||||||
*
|
*
|
||||||
* Possible UPNP Error codes :
|
* Possible UPNP Error codes :
|
||||||
* 402 Invalid Args - See UPnP Device Architecture section on Control.
|
* 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
|
* 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds
|
||||||
*/
|
*/
|
||||||
LIBSPEC int
|
LIBSPEC int
|
||||||
|
|
|
@ -9,6 +9,8 @@ testgetifstats
|
||||||
testupnpdescgen
|
testupnpdescgen
|
||||||
testupnppermissions
|
testupnppermissions
|
||||||
testgetroute
|
testgetroute
|
||||||
|
testasyncsendto
|
||||||
|
testportinuse
|
||||||
netfilter/testiptcrdr
|
netfilter/testiptcrdr
|
||||||
netfilter/testiptcrdr_dscp
|
netfilter/testiptcrdr_dscp
|
||||||
netfilter/testiptcrdr_peer
|
netfilter/testiptcrdr_peer
|
||||||
|
|
|
@ -1,4 +1,53 @@
|
||||||
$Id: Changelog.txt,v 1.346 2013/12/13 13:41:52 nanard Exp $
|
$Id: Changelog.txt,v 1.366 2014/03/24 11:03:50 nanard Exp $
|
||||||
|
|
||||||
|
2014/03/24:
|
||||||
|
start work to enable IPv6 PCP operations
|
||||||
|
|
||||||
|
2014/03/14:
|
||||||
|
reject renewal of subscribtion that already timeouted
|
||||||
|
Support for multiple URL in Callback: header (SUBSCRIBE)
|
||||||
|
|
||||||
|
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:
|
2013/12/16:
|
||||||
Attempt to compile with OS X/pf
|
Attempt to compile with OS X/pf
|
||||||
|
@ -136,6 +185,9 @@ VERSION 1.8 : released on 2013/02/06
|
||||||
2012/07/14:
|
2012/07/14:
|
||||||
Add -z command line option to change friendly name (thanks to Shawn Fisher)
|
Add -z command line option to change friendly name (thanks to Shawn Fisher)
|
||||||
|
|
||||||
|
2012/07/10:
|
||||||
|
Detect port in use - patch by David Kerr
|
||||||
|
|
||||||
2012/06/29:
|
2012/06/29:
|
||||||
added DISABLE_CONFIG_FILE in options.h to disable miniupnpd.conf parsing
|
added DISABLE_CONFIG_FILE in options.h to disable miniupnpd.conf parsing
|
||||||
Add command line parsing for clean_ruleset_interval option
|
Add command line parsing for clean_ruleset_interval option
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $Id: Makefile,v 1.74 2013/12/13 15:28:34 nanard Exp $
|
# $Id: Makefile,v 1.80 2014/04/07 10:32:20 nanard Exp $
|
||||||
# MiniUPnP project
|
# MiniUPnP project
|
||||||
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
# Author: Thomas Bernard
|
# Author: Thomas Bernard
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
CFLAGS ?= -pipe -Os
|
CFLAGS ?= -pipe -Os
|
||||||
#CFLAGS = -pipe -O -g -DDEBUG
|
#CFLAGS = -pipe -O -g -DDEBUG
|
||||||
CFLAGS += -ansi
|
#CFLAGS += -ansi
|
||||||
CFLAGS += -Wall
|
CFLAGS += -Wall
|
||||||
CFLAGS += -W
|
CFLAGS += -W
|
||||||
CFLAGS += -Wstrict-prototypes
|
CFLAGS += -Wstrict-prototypes
|
||||||
|
@ -39,14 +39,14 @@ FWNAME = pf
|
||||||
.else
|
.else
|
||||||
FWNAME = ipf
|
FWNAME = ipf
|
||||||
.endif
|
.endif
|
||||||
.endif
|
|
||||||
|
|
||||||
# better way to find if we are using ipf or pf
|
# better way to find if we are using ipf or pf
|
||||||
.if defined(/etc/rc.subr) && defined(/etc/rc.conf)
|
.if exists(/etc/rc.subr) && exists(/etc/rc.conf)
|
||||||
.if $(OSNAME) == "FreeBSD"
|
.if $(OSNAME) == "FreeBSD"
|
||||||
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||||
if checkyesno ipfilter_enable; then \
|
if checkyesno ipfilter_enable; then \
|
||||||
echo "ipf"; else echo "pf"; fi
|
echo "ipf"; elif checkyesno pf_enable; then \
|
||||||
|
echo "pf"; else echo "ipfw"; fi
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.if $(OSNAME) == "NetBSD"
|
.if $(OSNAME) == "NetBSD"
|
||||||
|
@ -57,13 +57,18 @@ FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||||
|
|
||||||
.if $(OSNAME) == "DragonFly"
|
.if $(OSNAME) == "DragonFly"
|
||||||
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
FWNAME != . /etc/rc.subr; . /etc/rc.conf; \
|
||||||
if chechyesno ipfilter; then \
|
if checkyesno ipfilter; then \
|
||||||
echo "ipf"; else echo "pf"; fi
|
echo "ipf"; elif checkyesno pf_enable; then \
|
||||||
|
echo "pf"; else echo "ipfw"; fi
|
||||||
.endif
|
.endif
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.if $(OSNAME) == "Darwin"
|
.if $(OSNAME) == "Darwin"
|
||||||
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 != [ `uname -r | cut -d. -f1` -ge 11 ] && echo "pf" || echo "ipfw"
|
||||||
|
.endif
|
||||||
|
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# Solaris specific CFLAGS
|
# Solaris specific CFLAGS
|
||||||
|
@ -80,7 +85,7 @@ STDOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
||||||
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.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 \
|
upnpevents.o upnputils.o getconnstatus.o \
|
||||||
upnppinhole.o
|
upnppinhole.o asyncsendto.o portinuse.o
|
||||||
BSDOBJS = bsd/getifstats.o bsd/ifacewatcher.o bsd/getroute.o
|
BSDOBJS = bsd/getifstats.o bsd/ifacewatcher.o bsd/getroute.o
|
||||||
SUNOSOBJS = solaris/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
|
MACOBJS = mac/getifstats.o bsd/ifacewatcher.o bsd/getroute.o
|
||||||
|
@ -116,10 +121,14 @@ TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
||||||
TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o
|
TESTUPNPPERMISSIONSOBJS = testupnppermissions.o upnppermissions.o
|
||||||
TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o
|
TESTGETIFADDROBJS = testgetifaddr.o getifaddr.o
|
||||||
MINIUPNPDCTLOBJS = miniupnpdctl.o
|
MINIUPNPDCTLOBJS = miniupnpdctl.o
|
||||||
|
TESTASYNCSENDTOOBJS = testasyncsendto.o asyncsendto.o upnputils.o bsd/getroute.o
|
||||||
|
TESTPORTINUSEOBJS = testportinuse.o portinuse.o getifaddr.o
|
||||||
|
|
||||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||||
testupnppermissions miniupnpdctl \
|
testupnppermissions miniupnpdctl \
|
||||||
testgetifaddr testgetroute
|
testgetifaddr testgetroute testasyncsendto \
|
||||||
|
testportinuse
|
||||||
|
|
||||||
.if $(OSNAME) == "Darwin"
|
.if $(OSNAME) == "Darwin"
|
||||||
LIBS =
|
LIBS =
|
||||||
.else
|
.else
|
||||||
|
@ -142,13 +151,14 @@ clean:
|
||||||
$(RM) $(STDOBJS) $(BSDOBJS) $(SUNOSOBJS) $(MACOBJS) $(EXECUTABLES) \
|
$(RM) $(STDOBJS) $(BSDOBJS) $(SUNOSOBJS) $(MACOBJS) $(EXECUTABLES) \
|
||||||
testupnpdescgen.o \
|
testupnpdescgen.o \
|
||||||
$(MISCOBJS) config.h testgetifstats.o testupnppermissions.o \
|
$(MISCOBJS) config.h testgetifstats.o testupnppermissions.o \
|
||||||
miniupnpdctl.o testgetifaddr.o testgetroute.o \
|
miniupnpdctl.o testgetifaddr.o testgetroute.o testasyncsendto.o \
|
||||||
|
testportinuse.o \
|
||||||
$(PFOBJS) $(IPFOBJS) $(IPFWOBJS)
|
$(PFOBJS) $(IPFOBJS) $(IPFWOBJS)
|
||||||
|
|
||||||
install: miniupnpd genuuid
|
install: miniupnpd genuuid
|
||||||
$(STRIP) miniupnpd
|
$(STRIP) miniupnpd
|
||||||
$(INSTALL) -d $(DESTDIR)$(INSTALLBINDIR)
|
$(INSTALL) -d $(DESTDIR)$(INSTALLBINDIR)
|
||||||
$(INSTALL) -m 555 miniupnpd $(DESTDIR)$(INSTALLBINDIR)
|
$(INSTALL) -m 755 miniupnpd $(DESTDIR)$(INSTALLBINDIR)
|
||||||
$(INSTALL) -d $(DESTDIR)$(INSTALLETCDIR)
|
$(INSTALL) -d $(DESTDIR)$(INSTALLETCDIR)
|
||||||
$(INSTALL) -b miniupnpd.conf $(DESTDIR)$(INSTALLETCDIR)
|
$(INSTALL) -b miniupnpd.conf $(DESTDIR)$(INSTALLETCDIR)
|
||||||
# TODO : install man page correctly
|
# TODO : install man page correctly
|
||||||
|
@ -173,7 +183,7 @@ genuuid:
|
||||||
depend: config.h
|
depend: config.h
|
||||||
mkdep $(ALLOBJS:.o=.c) testupnpdescgen.c testgetifstats.c \
|
mkdep $(ALLOBJS:.o=.c) testupnpdescgen.c testgetifstats.c \
|
||||||
testupnppermissions.c miniupnpdctl.c testgetifaddr.c \
|
testupnppermissions.c miniupnpdctl.c testgetifaddr.c \
|
||||||
testgetroute.c
|
testgetroute.c testportinuse.c testasyncsendto.c
|
||||||
|
|
||||||
miniupnpd: config.h $(ALLOBJS)
|
miniupnpd: config.h $(ALLOBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $(ALLOBJS) $(LIBS)
|
$(CC) $(CFLAGS) -o $@ $(ALLOBJS) $(LIBS)
|
||||||
|
@ -185,19 +195,25 @@ miniupnpdctl: config.h $(MINIUPNPDCTLOBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $(MINIUPNPDCTLOBJS)
|
$(CC) $(CFLAGS) -o $@ $(MINIUPNPDCTLOBJS)
|
||||||
|
|
||||||
testupnpdescgen: config.h $(TESTUPNPDESCGENOBJS)
|
testupnpdescgen: config.h $(TESTUPNPDESCGENOBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $(TESTUPNPDESCGENOBJS)
|
$(CC) $(CFLAGS) -o $@ $(TESTUPNPDESCGENOBJS) $(LIBS)
|
||||||
|
|
||||||
testgetifstats: config.h $(TESTGETIFSTATSOBJS)
|
testgetifstats: config.h $(TESTGETIFSTATSOBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $(TESTGETIFSTATSOBJS) $(LIBS)
|
$(CC) $(CFLAGS) -o $@ $(TESTGETIFSTATSOBJS) $(LIBS)
|
||||||
|
|
||||||
testgetifaddr: config.h $(TESTGETIFADDROBJS)
|
testgetifaddr: config.h $(TESTGETIFADDROBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $(TESTGETIFADDROBJS)
|
$(CC) $(CFLAGS) -o $@ $(TESTGETIFADDROBJS) $(LIBS)
|
||||||
|
|
||||||
testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS)
|
testupnppermissions: config.h $(TESTUPNPPERMISSIONSOBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $(TESTUPNPPERMISSIONSOBJS)
|
$(CC) $(CFLAGS) -o $@ $(TESTUPNPPERMISSIONSOBJS) $(LIBS)
|
||||||
|
|
||||||
testgetroute: config.h $(TESTGETROUTEOBJS)
|
testgetroute: config.h $(TESTGETROUTEOBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $(TESTGETROUTEOBJS)
|
$(CC) $(CFLAGS) -o $@ $(TESTGETROUTEOBJS) $(LIBS)
|
||||||
|
|
||||||
|
testasyncsendto: config.h $(TESTASYNCSENDTOOBJS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $(TESTASYNCSENDTOOBJS)
|
||||||
|
|
||||||
|
testportinuse: config.h $(TESTPORTINUSEOBJS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $(TESTPORTINUSEOBJS) -lkvm
|
||||||
|
|
||||||
# gmake :
|
# gmake :
|
||||||
# $(CC) $(CFLAGS) -o $@ $^
|
# $(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $Id: Makefile.linux,v 1.81 2014/01/27 10:06:58 nanard Exp $
|
# $Id: Makefile.linux,v 1.84 2014/03/24 10:43:25 nanard Exp $
|
||||||
# MiniUPnP project
|
# MiniUPnP project
|
||||||
# (c) 2006-2014 Thomas Bernard
|
# (c) 2006-2014 Thomas Bernard
|
||||||
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
@ -43,11 +43,11 @@ ETCINSTALLDIR = $(PREFIX)/etc/miniupnpd
|
||||||
MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8
|
MANINSTALLDIR = $(INSTALLPREFIX)/share/man/man8
|
||||||
|
|
||||||
BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
BASEOBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
||||||
upnpreplyparse.o minixml.o \
|
upnpreplyparse.o minixml.o portinuse.o \
|
||||||
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.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 \
|
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
|
LNXOBJS = linux/getifstats.o linux/ifacewatcher.o linux/getroute.o
|
||||||
NETFILTEROBJS = netfilter/iptcrdr.o netfilter/iptpinhole.o netfilter/nfct_get.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 \
|
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||||
testupnppermissions miniupnpdctl testgetifaddr \
|
testupnppermissions miniupnpdctl testgetifaddr \
|
||||||
testgetroute
|
testgetroute testasyncsendto testportinuse
|
||||||
|
|
||||||
.PHONY: all clean install depend genuuid
|
.PHONY: all clean install depend genuuid
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ clean:
|
||||||
$(RM) $(EXECUTABLES)
|
$(RM) $(EXECUTABLES)
|
||||||
$(RM) testupnpdescgen.o testgetifstats.o
|
$(RM) testupnpdescgen.o testgetifstats.o
|
||||||
$(RM) testupnppermissions.o testgetifaddr.o
|
$(RM) testupnppermissions.o testgetifaddr.o
|
||||||
$(RM) testgetroute.o
|
$(RM) testgetroute.o testasyncsendto.o
|
||||||
$(RM) miniupnpdctl.o
|
$(RM) miniupnpdctl.o
|
||||||
|
|
||||||
install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \
|
install: miniupnpd miniupnpd.8 miniupnpd.conf genuuid \
|
||||||
|
@ -205,6 +205,12 @@ testgetifaddr: testgetifaddr.o getifaddr.o
|
||||||
|
|
||||||
testgetroute: testgetroute.o linux/getroute.o upnputils.o -lnfnetlink
|
testgetroute: testgetroute.o linux/getroute.o upnputils.o -lnfnetlink
|
||||||
|
|
||||||
|
testasyncsendto: testasyncsendto.o asyncsendto.o upnputils.o \
|
||||||
|
linux/getroute.o -lnfnetlink
|
||||||
|
|
||||||
|
testportinuse: testportinuse.o portinuse.o getifaddr.o \
|
||||||
|
netfilter/iptcrdr.o $(LIBS)
|
||||||
|
|
||||||
miniupnpdctl: miniupnpdctl.o
|
miniupnpdctl: miniupnpdctl.o
|
||||||
|
|
||||||
config.h: genconfig.sh VERSION
|
config.h: genconfig.sh VERSION
|
||||||
|
@ -214,15 +220,16 @@ depend: config.h
|
||||||
makedepend -f$(MAKEFILE_LIST) -Y \
|
makedepend -f$(MAKEFILE_LIST) -Y \
|
||||||
$(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \
|
$(ALLOBJS:.o=.c) $(TESTUPNPDESCGENOBJS:.o=.c) \
|
||||||
testgetifstats.c testupnppermissions.c testgetifaddr.c \
|
testgetifstats.c testupnppermissions.c testgetifaddr.c \
|
||||||
testgetroute.c miniupnpdctl.c 2>/dev/null
|
testgetroute.c testasyncsendto.c testportinuse.c \
|
||||||
|
miniupnpdctl.c 2>/dev/null
|
||||||
|
|
||||||
# DO NOT DELETE
|
# DO NOT DELETE
|
||||||
|
|
||||||
miniupnpd.o: config.h macros.h upnpglobalvars.h upnppermissions.h
|
miniupnpd.o: config.h macros.h upnpglobalvars.h upnppermissions.h
|
||||||
miniupnpd.o: miniupnpdtypes.h upnphttp.h upnpdescgen.h miniupnpdpath.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: getifaddr.h upnpsoap.h options.h minissdp.h upnpredirect.h
|
||||||
miniupnpd.o: upnppinhole.h daemonize.h upnpevents.h natpmp.h pcpserver.h
|
miniupnpd.o: upnppinhole.h daemonize.h upnpevents.h asyncsendto.h natpmp.h
|
||||||
miniupnpd.o: commonrdr.h upnputils.h ifacewatcher.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: config.h upnphttp.h upnpdescgen.h miniupnpdpath.h upnpsoap.h
|
||||||
upnphttp.o: upnpevents.h upnputils.h
|
upnphttp.o: upnpevents.h upnputils.h
|
||||||
upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h
|
upnpdescgen.o: config.h getifaddr.h upnpredirect.h upnpdescgen.h
|
||||||
|
@ -234,8 +241,11 @@ upnpsoap.o: upnpredirect.h upnppinhole.h getifaddr.h getifstats.h
|
||||||
upnpsoap.o: getconnstatus.h upnpurns.h
|
upnpsoap.o: getconnstatus.h upnpurns.h
|
||||||
upnpreplyparse.o: upnpreplyparse.h minixml.h
|
upnpreplyparse.o: upnpreplyparse.h minixml.h
|
||||||
minixml.o: minixml.h
|
minixml.o: minixml.h
|
||||||
|
portinuse.o: macros.h config.h upnpglobalvars.h upnppermissions.h
|
||||||
|
portinuse.o: miniupnpdtypes.h getifaddr.h portinuse.h netfilter/iptcrdr.h
|
||||||
|
portinuse.o: commonrdr.h
|
||||||
upnpredirect.o: macros.h config.h upnpredirect.h upnpglobalvars.h
|
upnpredirect.o: macros.h config.h upnpredirect.h upnpglobalvars.h
|
||||||
upnpredirect.o: upnppermissions.h miniupnpdtypes.h upnpevents.h
|
upnpredirect.o: upnppermissions.h miniupnpdtypes.h upnpevents.h portinuse.h
|
||||||
upnpredirect.o: netfilter/iptcrdr.h commonrdr.h
|
upnpredirect.o: netfilter/iptcrdr.h commonrdr.h
|
||||||
getifaddr.o: config.h getifaddr.h
|
getifaddr.o: config.h getifaddr.h
|
||||||
daemonize.o: daemonize.h config.h
|
daemonize.o: daemonize.h config.h
|
||||||
|
@ -246,12 +256,14 @@ options.o: miniupnpdtypes.h
|
||||||
upnppermissions.o: config.h upnppermissions.h
|
upnppermissions.o: config.h upnppermissions.h
|
||||||
minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h
|
minissdp.o: config.h upnpdescstrings.h miniupnpdpath.h upnphttp.h
|
||||||
minissdp.o: upnpglobalvars.h upnppermissions.h miniupnpdtypes.h minissdp.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: macros.h config.h natpmp.h upnpglobalvars.h upnppermissions.h
|
||||||
natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h
|
natpmp.o: miniupnpdtypes.h getifaddr.h upnpredirect.h commonrdr.h upnputils.h
|
||||||
|
natpmp.o: portinuse.h asyncsendto.h
|
||||||
pcpserver.o: config.h pcpserver.h macros.h upnpglobalvars.h upnppermissions.h
|
pcpserver.o: config.h pcpserver.h macros.h upnpglobalvars.h upnppermissions.h
|
||||||
pcpserver.o: miniupnpdtypes.h pcplearndscp.h upnpredirect.h commonrdr.h
|
pcpserver.o: miniupnpdtypes.h pcplearndscp.h upnpredirect.h commonrdr.h
|
||||||
pcpserver.o: getifaddr.h pcp_msg_struct.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: config.h upnpevents.h miniupnpdpath.h upnpglobalvars.h
|
||||||
upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h
|
upnpevents.o: upnppermissions.h miniupnpdtypes.h upnpdescgen.h upnputils.h
|
||||||
upnputils.o: config.h upnputils.h upnpglobalvars.h upnppermissions.h
|
upnputils.o: config.h upnputils.h upnpglobalvars.h upnppermissions.h
|
||||||
|
@ -262,6 +274,7 @@ upnppinhole.o: upnppermissions.h miniupnpdtypes.h upnpevents.h
|
||||||
upnppinhole.o: netfilter/iptpinhole.h
|
upnppinhole.o: netfilter/iptpinhole.h
|
||||||
pcplearndscp.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h
|
pcplearndscp.o: config.h upnpglobalvars.h upnppermissions.h miniupnpdtypes.h
|
||||||
pcplearndscp.o: pcplearndscp.h
|
pcplearndscp.o: pcplearndscp.h
|
||||||
|
asyncsendto.o: asyncsendto.h
|
||||||
linux/getifstats.o: config.h getifstats.h
|
linux/getifstats.o: config.h getifstats.h
|
||||||
linux/ifacewatcher.o: config.h ifacewatcher.h config.h minissdp.h
|
linux/ifacewatcher.o: config.h ifacewatcher.h config.h minissdp.h
|
||||||
linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h
|
linux/ifacewatcher.o: miniupnpdtypes.h getifaddr.h upnpglobalvars.h
|
||||||
|
@ -279,7 +292,9 @@ upnpdescgen.o: miniupnpdpath.h upnpglobalvars.h upnppermissions.h
|
||||||
upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h
|
upnpdescgen.o: miniupnpdtypes.h upnpdescstrings.h upnpurns.h getconnstatus.h
|
||||||
testgetifstats.o: getifstats.h
|
testgetifstats.o: getifstats.h
|
||||||
testupnppermissions.o: upnppermissions.h config.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: getroute.h upnputils.h upnpglobalvars.h upnppermissions.h
|
||||||
testgetroute.o: config.h miniupnpdtypes.h
|
testgetroute.o: config.h miniupnpdtypes.h
|
||||||
|
testasyncsendto.o: miniupnpdtypes.h config.h upnputils.h asyncsendto.h
|
||||||
|
testportinuse.o: macros.h config.h portinuse.h
|
||||||
miniupnpdctl.o: macros.h
|
miniupnpdctl.o: macros.h
|
||||||
|
|
|
@ -32,7 +32,8 @@ FWNAME = $(shell [ `uname -r | cut -d. -f1` -ge 11 ] && echo "pf" || echo "ipfw
|
||||||
STD_OBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
STD_OBJS = miniupnpd.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
||||||
upnpredirect.o getifaddr.o daemonize.o upnpglobalvars.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 \
|
||||||
upnpevents.o getconnstatus.o upnputils.o
|
upnpevents.o getconnstatus.o upnputils.o \
|
||||||
|
asyncsendto.o portinuse.o pcpserver.o
|
||||||
MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o
|
MAC_OBJS = mac/getifstats.o bsd/ifacewatcher.o
|
||||||
IPFW_OBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o
|
IPFW_OBJS = ipfw/ipfwrdr.o ipfw/ipfwaux.o
|
||||||
PF_OBJS = pf/obsdrdr.o pf/pfpinhole.o
|
PF_OBJS = pf/obsdrdr.o pf/pfpinhole.o
|
||||||
|
@ -50,11 +51,13 @@ TEST_UPNPDESCGEN_OBJS = testupnpdescgen.o upnpdescgen.o
|
||||||
TEST_GETIFSTATS_OBJS = testgetifstats.o mac/getifstats.o
|
TEST_GETIFSTATS_OBJS = testgetifstats.o mac/getifstats.o
|
||||||
TEST_UPNPPERMISSIONS_OBJS = testupnppermissions.o upnppermissions.o
|
TEST_UPNPPERMISSIONS_OBJS = testupnppermissions.o upnppermissions.o
|
||||||
TEST_GETIFADDR_OBJS = testgetifaddr.o getifaddr.o
|
TEST_GETIFADDR_OBJS = testgetifaddr.o getifaddr.o
|
||||||
|
TEST_PORTINUSE_OBJS = testportinuse.o portinuse.o getifaddr.o
|
||||||
|
TEST_ASYNCSENDTO_OBJS = testasyncsendto.o asyncsendto.o upnputils.o
|
||||||
MINIUPNPDCTL_OBJS = miniupnpdctl.o
|
MINIUPNPDCTL_OBJS = miniupnpdctl.o
|
||||||
|
|
||||||
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \
|
||||||
testupnppermissions miniupnpdctl \
|
testupnppermissions miniupnpdctl \
|
||||||
testgetifaddr
|
testgetifaddr testportinuse testasyncsendto
|
||||||
|
|
||||||
LIBS =
|
LIBS =
|
||||||
|
|
||||||
|
@ -115,6 +118,11 @@ testgetifaddr: config.h $(TEST_GETIFADDR_OBJS)
|
||||||
testupnppermissions: config.h $(TEST_UPNPPERMISSIONS_OBJS)
|
testupnppermissions: config.h $(TEST_UPNPPERMISSIONS_OBJS)
|
||||||
$(CC) $(CFLAGS) -o $@ $(TEST_UPNPPERMISSIONS_OBJS)
|
$(CC) $(CFLAGS) -o $@ $(TEST_UPNPPERMISSIONS_OBJS)
|
||||||
|
|
||||||
|
testasyncsendto: config.h $(TEST_ASYNCSENDTO_OBJS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $(TEST_ASYNCSENDTO_OBJS)
|
||||||
|
|
||||||
|
testportinuse: config.h $(TEST_PORTINUSE_OBJS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $(TEST_PORTINUSE_OBJS)
|
||||||
|
|
||||||
config.h: genconfig.sh
|
config.h: genconfig.sh
|
||||||
./genconfig.sh
|
./genconfig.sh
|
||||||
|
|
|
@ -33,3 +33,4 @@ use non blocking sockets everywhere :
|
||||||
- NAT-PMP => OK
|
- NAT-PMP => OK
|
||||||
- not needed for miniupnpdctl
|
- not needed for miniupnpdctl
|
||||||
|
|
||||||
|
implement port_in_use() for NetBSD and FreeBSD
|
||||||
|
|
|
@ -0,0 +1,281 @@
|
||||||
|
/* $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 <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "asyncsendto.h"
|
||||||
|
#include "upnputils.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)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
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, "%s: %d bytes on socket %d",
|
||||||
|
"try_sendto", (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;
|
||||||
|
} else {
|
||||||
|
char addr_str[64];
|
||||||
|
/* uncatched error */
|
||||||
|
if(sockaddr_to_string(elt->dest_addr, addr_str, sizeof(addr_str)) <= 0)
|
||||||
|
addr_str[0] = '\0';
|
||||||
|
syslog(LOG_ERR, "%s(sock=%d, len=%u, dest=%s): sendto: %m",
|
||||||
|
"try_sendto", elt->sockfd, (unsigned)elt->len,
|
||||||
|
addr_str);
|
||||||
|
ret--;
|
||||||
|
}
|
||||||
|
} else if((int)n != (int)elt->len) {
|
||||||
|
syslog(LOG_WARNING, "%s: %d bytes sent out of %d",
|
||||||
|
"try_sendto", (int)n, (int)elt->len);
|
||||||
|
}
|
||||||
|
/* remove from the list */
|
||||||
|
LIST_REMOVE(elt, entries);
|
||||||
|
free(elt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -12,6 +12,9 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
|
#ifdef __DragonFly__
|
||||||
|
#define _KERNEL_STRUCTURES
|
||||||
|
#endif
|
||||||
#include <net/if_var.h>
|
#include <net/if_var.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined(__DragonFly__)
|
#if defined(__DragonFly__)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: getroute.c,v 1.3 2013/02/06 13:11:45 nanard Exp $ */
|
/* $Id: getroute.c,v 1.4 2014/03/31 12:27:14 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2006-2013 Thomas Bernard
|
* (c) 2006-2013 Thomas Bernard
|
||||||
|
@ -83,7 +83,7 @@ get_src_for_route_to(const struct sockaddr * dst,
|
||||||
sa = (struct sockaddr *)p;
|
sa = (struct sockaddr *)p;
|
||||||
sockaddr_to_string(sa, tmp, sizeof(tmp));
|
sockaddr_to_string(sa, tmp, sizeof(tmp));
|
||||||
syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s",
|
syslog(LOG_DEBUG, "type=%d sa_len=%d sa_family=%d %s",
|
||||||
i, sa->sa_len, sa->sa_family, tmp);
|
i, SA_LEN(sa), sa->sa_family, tmp);
|
||||||
if((i == RTA_DST || i == RTA_GATEWAY) &&
|
if((i == RTA_DST || i == RTA_GATEWAY) &&
|
||||||
(src_len && src)) {
|
(src_len && src)) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -113,7 +113,7 @@ get_src_for_route_to(const struct sockaddr * dst,
|
||||||
*index = sdl->sdl_index;
|
*index = sdl->sdl_index;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
p += sa->sa_len;
|
p += SA_LEN(sa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: ifacewatcher.c,v 1.5 2012/05/21 08:55:10 nanard Exp $ */
|
/* $Id: ifacewatcher.c,v 1.6 2014/03/31 12:27:14 nanard Exp $ */
|
||||||
/* Project MiniUPnP
|
/* Project MiniUPnP
|
||||||
* web : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* web : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2011 Thomas BERNARD
|
* (c) 2011 Thomas BERNARD
|
||||||
|
@ -15,12 +15,8 @@
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#if !defined(SA_LEN)
|
|
||||||
#define SA_LEN(sa) (sa)->sa_len
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SALIGN (sizeof(long) - 1)
|
#define SALIGN (sizeof(long) - 1)
|
||||||
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
|
#define SA_RLEN(sa) (SA_LEN(sa) ? ((SA_LEN(sa) + SALIGN) & ~SALIGN) : (SALIGN + 1))
|
||||||
|
|
||||||
#include "../upnputils.h"
|
#include "../upnputils.h"
|
||||||
#include "../upnpglobalvars.h"
|
#include "../upnpglobalvars.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
|
/* MiniUPnP project
|
||||||
* (c) 2006-2011 Thomas Bernard
|
* (c) 2006-2014 Thomas Bernard
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
@ -10,6 +10,9 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
/* init and shutdown functions */
|
/* init and shutdown functions */
|
||||||
|
/* init_redirect() return values :
|
||||||
|
* 0 : OK
|
||||||
|
* -1 : error */
|
||||||
int
|
int
|
||||||
init_redirect(void);
|
init_redirect(void);
|
||||||
|
|
||||||
|
@ -17,7 +20,10 @@ void
|
||||||
shutdown_redirect(void);
|
shutdown_redirect(void);
|
||||||
|
|
||||||
/* get_redirect_rule() gets internal IP and port from
|
/* 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
|
int
|
||||||
get_redirect_rule(const char * ifname, unsigned short eport, int proto,
|
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,
|
unsigned int * timestamp,
|
||||||
u_int64_t * packets, u_int64_t * bytes);
|
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
|
int
|
||||||
get_redirect_rule_by_index(int index,
|
get_redirect_rule_by_index(int index,
|
||||||
char * ifname, unsigned short * eport,
|
char * ifname, unsigned short * eport,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# $Id: genconfig.sh,v 1.65 2013/12/13 14:07:08 nanard Exp $
|
# $Id: genconfig.sh,v 1.72 2014/03/10 10:17:17 nanard Exp $
|
||||||
# miniupnp daemon
|
# miniupnp daemon
|
||||||
# http://miniupnp.free.fr or http://miniupnp.tuxfamily.org/
|
# 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
|
# This software is subject to the conditions detailed in the
|
||||||
# LICENCE file provided within the distribution
|
# LICENCE file provided within the distribution
|
||||||
|
|
||||||
|
@ -13,11 +13,8 @@ case "$argv" in
|
||||||
--strict) STRICT=1 ;;
|
--strict) STRICT=1 ;;
|
||||||
--leasefile) LEASEFILE=1 ;;
|
--leasefile) LEASEFILE=1 ;;
|
||||||
--vendorcfg) VENDORCFG=1 ;;
|
--vendorcfg) VENDORCFG=1 ;;
|
||||||
--pcp) PCP=1 ;;
|
--pcp-peer) PCP_PEER=1 ;;
|
||||||
--pcp-peer)
|
--portinuse) PORTINUSE=1 ;;
|
||||||
PCP=1
|
|
||||||
PCP_PEER=1
|
|
||||||
;;
|
|
||||||
--help|-h)
|
--help|-h)
|
||||||
echo "Usage : $0 [options]"
|
echo "Usage : $0 [options]"
|
||||||
echo " --ipv6 enable IPv6"
|
echo " --ipv6 enable IPv6"
|
||||||
|
@ -25,8 +22,8 @@ case "$argv" in
|
||||||
echo " --strict be more strict regarding compliance with UPnP specifications"
|
echo " --strict be more strict regarding compliance with UPnP specifications"
|
||||||
echo " --leasefile enable lease file"
|
echo " --leasefile enable lease file"
|
||||||
echo " --vendorcfg enable configuration of manufacturer info"
|
echo " --vendorcfg enable configuration of manufacturer info"
|
||||||
echo " --pcp enable PCP"
|
|
||||||
echo " --pcp-peer enable PCP PEER operation"
|
echo " --pcp-peer enable PCP PEER operation"
|
||||||
|
echo " --portinuse enable port in use check"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
@ -83,7 +80,7 @@ ${RM} ${CONFIGFILE}
|
||||||
|
|
||||||
echo "/* MiniUPnP Project" >> ${CONFIGFILE}
|
echo "/* MiniUPnP Project" >> ${CONFIGFILE}
|
||||||
echo " * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/" >> ${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 " * generated by $0 on `date`" >> ${CONFIGFILE}
|
||||||
echo " * using command line options $* */" >> ${CONFIGFILE}
|
echo " * using command line options $* */" >> ${CONFIGFILE}
|
||||||
echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE}
|
echo "#ifndef $CONFIGMACRO" >> ${CONFIGFILE}
|
||||||
|
@ -120,6 +117,7 @@ case $OS_NAME in
|
||||||
FW=pf
|
FW=pf
|
||||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||||
OS_URL=http://www.openbsd.org/
|
OS_URL=http://www.openbsd.org/
|
||||||
|
V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only`
|
||||||
;;
|
;;
|
||||||
FreeBSD)
|
FreeBSD)
|
||||||
VER=`grep '#define __FreeBSD_version' /usr/include/sys/param.h | awk '{print $3}'`
|
VER=`grep '#define __FreeBSD_version' /usr/include/sys/param.h | awk '{print $3}'`
|
||||||
|
@ -150,12 +148,14 @@ case $OS_NAME in
|
||||||
fi
|
fi
|
||||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||||
OS_URL=http://www.freebsd.org/
|
OS_URL=http://www.freebsd.org/
|
||||||
|
V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only`
|
||||||
;;
|
;;
|
||||||
pfSense)
|
pfSense)
|
||||||
# we need to detect if PFRULE_INOUT_COUNTS macro is needed
|
# we need to detect if PFRULE_INOUT_COUNTS macro is needed
|
||||||
FW=pf
|
FW=pf
|
||||||
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
|
||||||
OS_URL=http://www.pfsense.com/
|
OS_URL=http://www.pfsense.com/
|
||||||
|
V6SOCKETS_ARE_V6ONLY=`sysctl -n net.inet6.ip6.v6only`
|
||||||
;;
|
;;
|
||||||
NetBSD)
|
NetBSD)
|
||||||
if [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then
|
if [ -f /etc/rc.subr ] && [ -f /etc/rc.conf ] ; then
|
||||||
|
@ -313,6 +313,11 @@ case $FW in
|
||||||
;;
|
;;
|
||||||
esac
|
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 "Configuring compilation for [$OS_NAME] [$OS_VERSION] with [$FW] firewall software."
|
||||||
echo "Please edit config.h for more compilation options."
|
echo "Please edit config.h for more compilation options."
|
||||||
|
|
||||||
|
@ -341,15 +346,9 @@ echo "/* Comment the following line to disable NAT-PMP operations */" >> ${CONFI
|
||||||
echo "#define ENABLE_NATPMP" >> ${CONFIGFILE}
|
echo "#define ENABLE_NATPMP" >> ${CONFIGFILE}
|
||||||
echo "" >> ${CONFIGFILE}
|
echo "" >> ${CONFIGFILE}
|
||||||
|
|
||||||
if [ -n "$PCP" ]; then
|
|
||||||
echo "/* Comment the following line to disable PCP operations */" >> ${CONFIGFILE}
|
echo "/* Comment the following line to disable PCP operations */" >> ${CONFIGFILE}
|
||||||
echo "#define ENABLE_PCP" >> ${CONFIGFILE}
|
echo "#define ENABLE_PCP" >> ${CONFIGFILE}
|
||||||
echo "" >> ${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}
|
echo "#ifdef ENABLE_PCP" >> ${CONFIGFILE}
|
||||||
if [ -n "$PCP_PEER" ]; then
|
if [ -n "$PCP_PEER" ]; then
|
||||||
|
@ -398,6 +397,14 @@ else
|
||||||
fi
|
fi
|
||||||
echo "" >> ${CONFIGFILE}
|
echo "" >> ${CONFIGFILE}
|
||||||
|
|
||||||
|
echo "/* Uncomment the following line to enable port in use check */" >> ${CONFIGFILE}
|
||||||
|
if [ -n "$PORTINUSE" ]; then
|
||||||
|
echo "#define CHECK_PORTINUSE" >> ${CONFIGFILE}
|
||||||
|
else
|
||||||
|
echo "/*#define CHECK_PORTINUSE*/" >> ${CONFIGFILE}
|
||||||
|
fi
|
||||||
|
echo "" >> ${CONFIGFILE}
|
||||||
|
|
||||||
echo "/* Define one or none of the two following macros in order to make some" >> ${CONFIGFILE}
|
echo "/* Define one or none of the two following macros in order to make some" >> ${CONFIGFILE}
|
||||||
echo " * clients happy. It will change the XML Root Description of the IGD." >> ${CONFIGFILE}
|
echo " * clients happy. It will change the XML Root Description of the IGD." >> ${CONFIGFILE}
|
||||||
echo " * Enabling the Layer3Forwarding Service seems to be the more compatible" >> ${CONFIGFILE}
|
echo " * Enabling the Layer3Forwarding Service seems to be the more compatible" >> ${CONFIGFILE}
|
||||||
|
@ -414,6 +421,15 @@ else
|
||||||
fi
|
fi
|
||||||
echo "" >> ${CONFIGFILE}
|
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 "/* Enable the support of IGD v2 specification." >> ${CONFIGFILE}
|
||||||
echo " * This is not fully tested yet and can cause incompatibilities with some" >> ${CONFIGFILE}
|
echo " * This is not fully tested yet and can cause incompatibilities with some" >> ${CONFIGFILE}
|
||||||
echo " * control points, so enable with care. */" >> ${CONFIGFILE}
|
echo " * control points, so enable with care. */" >> ${CONFIGFILE}
|
||||||
|
@ -457,6 +473,12 @@ else
|
||||||
fi
|
fi
|
||||||
echo "" >> ${CONFIGFILE}
|
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}
|
echo "/* Add the optional Date: header in all HTTP responses */" >> ${CONFIGFILE}
|
||||||
if [ -n "$STRICT" ] ; then
|
if [ -n "$STRICT" ] ; then
|
||||||
echo "#define ENABLE_HTTP_DATE" >> ${CONFIGFILE}
|
echo "#define ENABLE_HTTP_DATE" >> ${CONFIGFILE}
|
||||||
|
@ -465,6 +487,14 @@ else
|
||||||
fi
|
fi
|
||||||
echo "" >> ${CONFIGFILE}
|
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 "/* disable reading and parsing of config file (miniupnpd.conf) */" >> ${CONFIGFILE}
|
||||||
echo "/*#define DISABLE_CONFIG_FILE*/" >> ${CONFIGFILE}
|
echo "/*#define DISABLE_CONFIG_FILE*/" >> ${CONFIGFILE}
|
||||||
echo "" >> ${CONFIGFILE}
|
echo "" >> ${CONFIGFILE}
|
||||||
|
@ -477,7 +507,7 @@ else
|
||||||
fi
|
fi
|
||||||
echo "" >> ${CONFIGFILE}
|
echo "" >> ${CONFIGFILE}
|
||||||
|
|
||||||
echo "#endif" >> ${CONFIGFILE}
|
echo "#endif /* ${CONFIGMACRO} */" >> ${CONFIGFILE}
|
||||||
|
|
||||||
${MV} ${CONFIGFILE} ${CONFIGFILE_FINAL}
|
${MV} ${CONFIGFILE} ${CONFIGFILE_FINAL}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: getifaddr.c,v 1.19 2013/12/13 14:28:40 nanard Exp $ */
|
/* $Id: getifaddr.c,v 1.19 2013/12/13 14:28:40 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -47,6 +47,19 @@ getifaddr(const char * ifname, char * buf, int len,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||||
|
if(ioctl(s, SIOCGIFFLAGS, &ifr, &ifrlen) < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_DEBUG, "ioctl(s, SIOCGIFFLAGS, ...): %m");
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((ifr.ifr_flags & IFF_UP) == 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_DEBUG, "network interface %s is down", ifname);
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||||
if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
|
if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
|
syslog(LOG_ERR, "ioctl(s, SIOCGIFADDR, ...): %m");
|
||||||
|
@ -55,11 +68,14 @@ getifaddr(const char * ifname, char * buf, int len,
|
||||||
}
|
}
|
||||||
ifaddr = (struct sockaddr_in *)&ifr.ifr_addr;
|
ifaddr = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||||
if(addr) *addr = ifaddr->sin_addr;
|
if(addr) *addr = ifaddr->sin_addr;
|
||||||
if(!inet_ntop(AF_INET, &ifaddr->sin_addr, buf, len))
|
if(buf)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "inet_ntop(): %m");
|
if(!inet_ntop(AF_INET, &ifaddr->sin_addr, buf, len))
|
||||||
close(s);
|
{
|
||||||
return -1;
|
syslog(LOG_ERR, "inet_ntop(): %m");
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(mask)
|
if(mask)
|
||||||
{
|
{
|
||||||
|
@ -99,9 +115,12 @@ getifaddr(const char * ifname, char * buf, int len,
|
||||||
switch(ife->ifa_addr->sa_family)
|
switch(ife->ifa_addr->sa_family)
|
||||||
{
|
{
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
inet_ntop(ife->ifa_addr->sa_family,
|
if(buf)
|
||||||
&((struct sockaddr_in *)ife->ifa_addr)->sin_addr,
|
{
|
||||||
buf, len);
|
inet_ntop(ife->ifa_addr->sa_family,
|
||||||
|
&((struct sockaddr_in *)ife->ifa_addr)->sin_addr,
|
||||||
|
buf, len);
|
||||||
|
}
|
||||||
if(addr) *addr = ((struct sockaddr_in *)ife->ifa_addr)->sin_addr;
|
if(addr) *addr = ((struct sockaddr_in *)ife->ifa_addr)->sin_addr;
|
||||||
if(mask) *mask = ((struct sockaddr_in *)ife->ifa_netmask)->sin_addr;
|
if(mask) *mask = ((struct sockaddr_in *)ife->ifa_netmask)->sin_addr;
|
||||||
break;
|
break;
|
||||||
|
@ -119,9 +138,17 @@ getifaddr(const char * ifname, char * buf, int len,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_PCP
|
#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)
|
||||||
|
{
|
||||||
|
#if defined(ENABLE_IPV6) || defined(USE_GETIFADDRS)
|
||||||
struct ifaddrs * ifap;
|
struct ifaddrs * ifap;
|
||||||
struct ifaddrs * ife;
|
struct ifaddrs * ife;
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
const struct sockaddr_in6 * tmpaddr;
|
||||||
|
#endif /* ENABLE_IPV6 */
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
if(!ifname || ifname[0]=='\0')
|
if(!ifname || ifname[0]=='\0')
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -130,9 +157,8 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){
|
||||||
syslog(LOG_ERR, "getifaddrs: %m");
|
syslog(LOG_ERR, "getifaddrs: %m");
|
||||||
return -1;
|
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 */
|
/* skip other interfaces if one was specified */
|
||||||
if(ifname && (0 != strcmp(ifname, ife->ifa_name)))
|
if(ifname && (0 != strcmp(ifname, ife->ifa_name)))
|
||||||
continue;
|
continue;
|
||||||
|
@ -141,38 +167,47 @@ int getifaddr_in6(const char * ifname, struct in6_addr * addr){
|
||||||
switch(ife->ifa_addr->sa_family)
|
switch(ife->ifa_addr->sa_family)
|
||||||
{
|
{
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
#if 0
|
/* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */
|
||||||
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;
|
|
||||||
#endif
|
|
||||||
memset(addr->s6_addr, 0, 10);
|
memset(addr->s6_addr, 0, 10);
|
||||||
addr->s6_addr[10] = 0xff;
|
addr->s6_addr[10] = 0xff;
|
||||||
addr->s6_addr[11] = 0xff;
|
addr->s6_addr[11] = 0xff;
|
||||||
memcpy(addr->s6_addr + 12, &(((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr), 4);
|
memcpy(addr->s6_addr + 12,
|
||||||
/*inet_ntop(ife->ifa_addr->sa_family,
|
&(((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr),
|
||||||
&((struct sockaddr_in *)ife->ifa_addr)->sin_addr,
|
4);
|
||||||
buf, len);*/
|
|
||||||
found = 1;
|
found = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if(!IN6_IS_ADDR_LOOPBACK(addr)
|
tmpaddr = (const struct sockaddr_in6 *)ife->ifa_addr;
|
||||||
&& !IN6_IS_ADDR_LINKLOCAL(addr)) {
|
if(!IN6_IS_ADDR_LOOPBACK(&tmpaddr->sin6_addr)
|
||||||
memcpy(addr->s6_addr, &((struct sockaddr_in6 *)ife->ifa_addr)->sin6_addr, 16);
|
&& !IN6_IS_ADDR_LINKLOCAL(&tmpaddr->sin6_addr))
|
||||||
|
{
|
||||||
|
memcpy(addr->s6_addr,
|
||||||
|
&tmpaddr->sin6_addr,
|
||||||
|
16);
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
#endif /* ENABLE_IPV6 */
|
||||||
if (found) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeifaddrs(ifap);
|
freeifaddrs(ifap);
|
||||||
|
return (found ? 0 : -1);
|
||||||
|
#else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */
|
||||||
|
/* IPv4 only */
|
||||||
|
struct in_addr addr4;
|
||||||
|
if(getifaddr(ifname, NULL, 0, &addr4, NULL) < 0)
|
||||||
|
return -1;
|
||||||
|
/* 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, &addr4.s_addr, 4);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
#endif /* ENABLE_PCP */
|
||||||
|
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
int
|
int
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: minissdp.c,v 1.54 2013/06/15 12:50:10 nanard Exp $ */
|
/* $Id: minissdp.c,v 1.62 2014/03/24 09:31:23 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
||||||
#include "minissdp.h"
|
#include "minissdp.h"
|
||||||
#include "upnputils.h"
|
#include "upnputils.h"
|
||||||
#include "getroute.h"
|
#include "getroute.h"
|
||||||
|
#include "asyncsendto.h"
|
||||||
#include "codelength.h"
|
#include "codelength.h"
|
||||||
|
|
||||||
/* SSDP ip/port */
|
/* SSDP ip/port */
|
||||||
|
@ -146,7 +147,11 @@ OpenAndConfSSDPReceiveSocket(int ipv6)
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
if(ipv6)
|
if(ipv6)
|
||||||
{
|
{
|
||||||
AddMulticastMembershipIPv6(s);
|
if(AddMulticastMembershipIPv6(s) < 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"Failed to add IPv6 multicast membership");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -276,9 +281,16 @@ OpenAndConfSSDPNotifySockets(int * sockets)
|
||||||
goto error;
|
goto error;
|
||||||
i++;
|
i++;
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index);
|
if(GETFLAG(IPV6DISABLEDMASK))
|
||||||
if(sockets[i] < 0)
|
{
|
||||||
goto error;
|
sockets[i] = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sockets[i] = OpenAndConfSSDPNotifySocketIPv6(lan_addr->index);
|
||||||
|
if(sockets[i] < 0)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -319,11 +331,13 @@ EXT:
|
||||||
* st, st_len : ST: header
|
* st, st_len : ST: header
|
||||||
* suffix : suffix for USN: header
|
* suffix : suffix for USN: header
|
||||||
* host, port : our HTTP host, port
|
* host, port : our HTTP host, port
|
||||||
|
* delay : in milli-seconds
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
SendSSDPResponse(int s, const struct sockaddr * addr,
|
SendSSDPResponse(int s, const struct sockaddr * addr,
|
||||||
const char * st, int st_len, const char * suffix,
|
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;
|
int l, n;
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
@ -388,16 +402,16 @@ SendSSDPResponse(int s, const struct sockaddr * addr,
|
||||||
}
|
}
|
||||||
addrlen = (addr->sa_family == AF_INET6)
|
addrlen = (addr->sa_family == AF_INET6)
|
||||||
? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
|
? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
|
||||||
n = sendto(s, buf, l, 0,
|
n = sendto_schedule(s, buf, l, 0,
|
||||||
addr, addrlen);
|
addr, addrlen, delay);
|
||||||
sockaddr_to_string(addr, addr_str, sizeof(addr_str));
|
sockaddr_to_string(addr, addr_str, sizeof(addr_str));
|
||||||
syslog(LOG_INFO, "SSDP Announce %d bytes to %s ST: %.*s",n,
|
syslog(LOG_DEBUG, "%s: %d bytes to %s ST: %.*s",
|
||||||
addr_str,
|
"SendSSDPResponse()",
|
||||||
l, buf);
|
n, addr_str, l, buf);
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
{
|
{
|
||||||
/* XXX handle EINTR, EAGAIN, EWOULDBLOCK */
|
syslog(LOG_ERR, "%s: sendto(udp): %m",
|
||||||
syslog(LOG_ERR, "sendto(udp): %m");
|
"SendSSDPResponse()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +491,7 @@ SendSSDPNotify(int s, const struct sockaddr * dest,
|
||||||
syslog(LOG_WARNING, "SendSSDPNotify(): truncated output");
|
syslog(LOG_WARNING, "SendSSDPNotify(): truncated output");
|
||||||
l = sizeof(bufr) - 1;
|
l = sizeof(bufr) - 1;
|
||||||
}
|
}
|
||||||
n = sendto(s, bufr, l, 0, dest,
|
n = sendto_or_schedule(s, bufr, l, 0, dest,
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)
|
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)
|
||||||
#else
|
#else
|
||||||
|
@ -486,7 +500,6 @@ SendSSDPNotify(int s, const struct sockaddr * dest,
|
||||||
);
|
);
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
{
|
{
|
||||||
/* XXX handle EINTR, EAGAIN, EWOULDBLOCK */
|
|
||||||
syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s,
|
syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s,
|
||||||
host ? host : "NULL");
|
host ? host : "NULL");
|
||||||
}
|
}
|
||||||
|
@ -494,6 +507,22 @@ SendSSDPNotify(int s, const struct sockaddr * dest,
|
||||||
{
|
{
|
||||||
syslog(LOG_NOTICE, "sendto() sent %d out of %d bytes", n, l);
|
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
|
static void
|
||||||
|
@ -564,8 +593,11 @@ SendSSDPNotifies2(int * sockets,
|
||||||
lifetime, 0);
|
lifetime, 0);
|
||||||
i++;
|
i++;
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port,
|
if(sockets[i] >= 0)
|
||||||
lifetime, 1);
|
{
|
||||||
|
SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port,
|
||||||
|
lifetime, 1);
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -620,8 +652,20 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
char announced_host_buf[64];
|
char announced_host_buf[64];
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
#if defined(UPNP_STRICT) || defined(DELAY_MSEARCH_RESPONSE)
|
||||||
int mx_value = -1;
|
int mx_value = -1;
|
||||||
#endif
|
#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 */
|
/* get the string representation of the sender address */
|
||||||
sockaddr_to_string(sender, sender_str, sizeof(sender_str));
|
sockaddr_to_string(sender, sender_str, sizeof(sender_str));
|
||||||
|
@ -664,7 +708,7 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
/*while(bufr[i+j]!='\r') j++;*/
|
/*while(bufr[i+j]!='\r') j++;*/
|
||||||
/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
|
/*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))
|
else if((i < n - 3) && (strncasecmp(bufr+i, "mx:", 3) == 0))
|
||||||
{
|
{
|
||||||
const char * mx;
|
const char * mx;
|
||||||
|
@ -682,16 +726,32 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef UPNP_STRICT
|
#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) {
|
if(mx_value < 0) {
|
||||||
syslog(LOG_INFO, "ignoring SSDP packet missing MX: header");
|
syslog(LOG_INFO, "ignoring SSDP packet missing MX: header");
|
||||||
return;
|
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
|
#endif
|
||||||
/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
|
/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
|
||||||
sender_str );*/
|
sender_str );*/
|
||||||
if(st && (st_len > 0))
|
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",
|
syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
|
||||||
sender_str, st_len, st);
|
sender_str, st_len, st);
|
||||||
/* find in which sub network the client is */
|
/* find in which sub network the client is */
|
||||||
|
@ -753,11 +813,43 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
#endif
|
#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");
|
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,
|
SendSSDPResponse(s, sender,
|
||||||
|
#ifdef SSDP_RESPOND_SAME_VERSION
|
||||||
st, st_len, "",
|
st, st_len, "",
|
||||||
|
#else
|
||||||
|
known_service_types[i].s, l, ver_str,
|
||||||
|
#endif
|
||||||
announced_host, port,
|
announced_host, port,
|
||||||
known_service_types[i].uuid);
|
known_service_types[i].uuid,
|
||||||
|
delay);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -765,9 +857,15 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
/* strlen("ssdp:all") == 8 */
|
/* strlen("ssdp:all") == 8 */
|
||||||
if(st_len==8 && (0 == memcmp(st, "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");
|
syslog(LOG_INFO, "ssdp:all found");
|
||||||
for(i=0; known_service_types[i].s; i++)
|
for(i=0; known_service_types[i].s; i++)
|
||||||
{
|
{
|
||||||
|
#ifdef DELAY_MSEARCH_RESPONSE
|
||||||
|
delay += delay_increment;
|
||||||
|
#endif
|
||||||
if(i==0)
|
if(i==0)
|
||||||
ver_str[0] = '\0';
|
ver_str[0] = '\0';
|
||||||
else
|
else
|
||||||
|
@ -776,37 +874,53 @@ ProcessSSDPData(int s, const char *bufr, int n,
|
||||||
SendSSDPResponse(s, sender,
|
SendSSDPResponse(s, sender,
|
||||||
known_service_types[i].s, l, ver_str,
|
known_service_types[i].s, l, ver_str,
|
||||||
announced_host, port,
|
announced_host, port,
|
||||||
known_service_types[i].uuid);
|
known_service_types[i].uuid,
|
||||||
|
delay);
|
||||||
}
|
}
|
||||||
/* also answer for uuid */
|
/* also answer for uuid */
|
||||||
|
#ifdef DELAY_MSEARCH_RESPONSE
|
||||||
|
delay += delay_increment;
|
||||||
|
#endif
|
||||||
SendSSDPResponse(s, sender, uuidvalue_igd, strlen(uuidvalue_igd), "",
|
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), "",
|
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), "",
|
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 */
|
/* responds to request by UUID value */
|
||||||
l = (int)strlen(uuidvalue_igd);
|
l = (int)strlen(uuidvalue_igd);
|
||||||
if(l==st_len)
|
if(l==st_len)
|
||||||
{
|
{
|
||||||
|
#ifdef DELAY_MSEARCH_RESPONSE
|
||||||
|
delay = random() / (1 + RAND_MAX / (1000 * mx_value));
|
||||||
|
#endif
|
||||||
if(0 == memcmp(st, uuidvalue_igd, l))
|
if(0 == memcmp(st, uuidvalue_igd, l))
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "ssdp:uuid (IGD) found");
|
syslog(LOG_INFO, "ssdp:uuid (IGD) found");
|
||||||
SendSSDPResponse(s, sender, st, st_len, "",
|
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))
|
else if(0 == memcmp(st, uuidvalue_wan, l))
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "ssdp:uuid (WAN) found");
|
syslog(LOG_INFO, "ssdp:uuid (WAN) found");
|
||||||
SendSSDPResponse(s, sender, st, st_len, "",
|
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))
|
else if(0 == memcmp(st, uuidvalue_wcd, l))
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "ssdp:uuid (WCD) found");
|
syslog(LOG_INFO, "ssdp:uuid (WCD) found");
|
||||||
SendSSDPResponse(s, sender, st, st_len, "",
|
SendSSDPResponse(s, sender, st, st_len, "",
|
||||||
announced_host, port, uuidvalue_wcd);
|
announced_host, port, uuidvalue_wcd,
|
||||||
|
delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -856,7 +970,7 @@ SendSSDPbyebye(int s, const struct sockaddr * dest,
|
||||||
syslog(LOG_WARNING, "SendSSDPbyebye(): truncated output");
|
syslog(LOG_WARNING, "SendSSDPbyebye(): truncated output");
|
||||||
l = sizeof(bufr) - 1;
|
l = sizeof(bufr) - 1;
|
||||||
}
|
}
|
||||||
n = sendto(s, bufr, l, 0, dest,
|
n = sendto_or_schedule(s, bufr, l, 0, dest,
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)
|
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)
|
||||||
#else
|
#else
|
||||||
|
@ -1013,6 +1127,8 @@ SubmitServicesToMiniSSDPD(const char * host, unsigned short port) {
|
||||||
while(n > 0) {
|
while(n > 0) {
|
||||||
l = write(s, p, n);
|
l = write(s, p, n);
|
||||||
if (l < 0) {
|
if (l < 0) {
|
||||||
|
if(errno == EINTR)
|
||||||
|
continue;
|
||||||
syslog(LOG_ERR, "write(): %m");
|
syslog(LOG_ERR, "write(): %m");
|
||||||
close(s);
|
close(s);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: miniupnpd.c,v 1.178 2013/12/13 14:10:02 nanard Exp $ */
|
/* $Id: miniupnpd.c,v 1.190 2014/03/24 10:49:44 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@
|
||||||
#include "miniupnpdtypes.h"
|
#include "miniupnpdtypes.h"
|
||||||
#include "daemonize.h"
|
#include "daemonize.h"
|
||||||
#include "upnpevents.h"
|
#include "upnpevents.h"
|
||||||
|
#include "asyncsendto.h"
|
||||||
#ifdef ENABLE_NATPMP
|
#ifdef ENABLE_NATPMP
|
||||||
#include "natpmp.h"
|
#include "natpmp.h"
|
||||||
#ifdef ENABLE_PCP
|
#ifdef ENABLE_PCP
|
||||||
|
@ -111,12 +112,17 @@ volatile sig_atomic_t should_send_public_address_change_notif = 0;
|
||||||
/* OpenAndConfHTTPSocket() :
|
/* OpenAndConfHTTPSocket() :
|
||||||
* setup the socket used to handle incoming HTTP connections. */
|
* setup the socket used to handle incoming HTTP connections. */
|
||||||
static int
|
static int
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
OpenAndConfHTTPSocket(unsigned short port, int ipv6)
|
||||||
|
#else
|
||||||
OpenAndConfHTTPSocket(unsigned short port)
|
OpenAndConfHTTPSocket(unsigned short port)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
struct sockaddr_in6 listenname;
|
struct sockaddr_in6 listenname6;
|
||||||
|
struct sockaddr_in listenname4;
|
||||||
#else
|
#else
|
||||||
struct sockaddr_in listenname;
|
struct sockaddr_in listenname;
|
||||||
#endif
|
#endif
|
||||||
|
@ -124,7 +130,7 @@ OpenAndConfHTTPSocket(unsigned short port)
|
||||||
|
|
||||||
if( (s = socket(
|
if( (s = socket(
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
PF_INET6,
|
ipv6 ? PF_INET6 : PF_INET,
|
||||||
#else
|
#else
|
||||||
PF_INET,
|
PF_INET,
|
||||||
#endif
|
#endif
|
||||||
|
@ -153,19 +159,35 @@ OpenAndConfHTTPSocket(unsigned short port)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
memset(&listenname, 0, sizeof(struct sockaddr_in6));
|
if(ipv6)
|
||||||
listenname.sin6_family = AF_INET6;
|
{
|
||||||
listenname.sin6_port = htons(port);
|
memset(&listenname6, 0, sizeof(struct sockaddr_in6));
|
||||||
listenname.sin6_addr = in6addr_any;
|
listenname6.sin6_family = AF_INET6;
|
||||||
listenname_len = sizeof(struct sockaddr_in6);
|
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
|
#else
|
||||||
|
memset(&listenname, 0, sizeof(struct sockaddr_in));
|
||||||
listenname.sin_family = AF_INET;
|
listenname.sin_family = AF_INET;
|
||||||
listenname.sin_port = htons(port);
|
listenname.sin_port = htons(port);
|
||||||
listenname.sin_addr.s_addr = htonl(INADDR_ANY);
|
listenname.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
listenname_len = sizeof(struct sockaddr_in);
|
listenname_len = sizeof(struct sockaddr_in);
|
||||||
#endif
|
#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)
|
if(bind(s, (struct sockaddr *)&listenname, listenname_len) < 0)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "bind(http): %m");
|
syslog(LOG_ERR, "bind(http): %m");
|
||||||
close(s);
|
close(s);
|
||||||
|
@ -181,6 +203,85 @@ OpenAndConfHTTPSocket(unsigned short port)
|
||||||
|
|
||||||
return s;
|
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
|
#ifdef ENABLE_NFQUEUE
|
||||||
|
|
||||||
int identify_ip_protocol(char *payload) {
|
int identify_ip_protocol(char *payload) {
|
||||||
|
@ -586,6 +687,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
|
||||||
p++;
|
p++;
|
||||||
if(*p=='.')
|
if(*p=='.')
|
||||||
{
|
{
|
||||||
|
/* parse mask in /255.255.255.0 format */
|
||||||
while(*p && (*p=='.' || isdigit(*p)))
|
while(*p && (*p=='.' || isdigit(*p)))
|
||||||
p++;
|
p++;
|
||||||
n = p - q;
|
n = p - q;
|
||||||
|
@ -598,6 +700,7 @@ parselanaddr(struct lan_addr_s * lan_addr, const char * str)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* it is a /24 format */
|
||||||
int nbits = atoi(q);
|
int nbits = atoi(q);
|
||||||
if(nbits > 32 || nbits < 0)
|
if(nbits > 32 || nbits < 0)
|
||||||
goto parselan_error;
|
goto parselan_error;
|
||||||
|
@ -685,7 +788,10 @@ void complete_uuidvalues(void)
|
||||||
* 5) check and write pid file
|
* 5) check and write pid file
|
||||||
* 6) set startup time stamp
|
* 6) set startup time stamp
|
||||||
* 7) compute presentation URL
|
* 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
|
static int
|
||||||
init(int argc, char * * argv, struct runtime_vars * v)
|
init(int argc, char * * argv, struct runtime_vars * v)
|
||||||
{
|
{
|
||||||
|
@ -906,12 +1012,14 @@ init(int argc, char * * argv, struct runtime_vars * v)
|
||||||
optionsfile);
|
optionsfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* if lifetimes ae inverse*/
|
#ifdef ENABLE_PCP
|
||||||
|
/* if lifetimes are inverse */
|
||||||
if (min_lifetime >= max_lifetime) {
|
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, "Minimum lifetime (%lu) is greater than or equal to maximum lifetime (%lu).\n", min_lifetime, max_lifetime);
|
||||||
fprintf(stderr, "Check your configuration file.\n");
|
fprintf(stderr, "Check your configuration file.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* DISABLE_CONFIG_FILE */
|
#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");
|
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)
|
if(init_redirect() < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "Failed to init redirection engine. EXITING");
|
syslog(LOG_ERR, "Failed to init redirection engine. EXITING");
|
||||||
|
@ -1338,12 +1450,18 @@ main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int shttpl = -1; /* socket for HTTP */
|
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 */
|
int sudp = -1; /* IP v4 socket for receiving SSDP */
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
int sudpv6 = -1; /* IP v6 socket for receiving SSDP */
|
int sudpv6 = -1; /* IP v6 socket for receiving SSDP */
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_NATPMP
|
#ifdef ENABLE_NATPMP
|
||||||
int * snatpmp = NULL;
|
int * snatpmp = NULL; /* also used for PCP */
|
||||||
|
#endif
|
||||||
|
#if defined(ENABLE_IPV6) && defined(ENABLE_PCP)
|
||||||
|
int spcp_v6 = -1;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_NFQUEUE
|
#ifdef ENABLE_NFQUEUE
|
||||||
int nfqh = -1;
|
int nfqh = -1;
|
||||||
|
@ -1429,7 +1547,11 @@ main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* open socket for HTTP connections. Listen on the 1st LAN address */
|
/* 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);
|
shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0);
|
||||||
|
#endif /* ENABLE_IPV6 */
|
||||||
if(shttpl < 0)
|
if(shttpl < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
|
syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
|
||||||
|
@ -1445,13 +1567,22 @@ main(int argc, char * * argv)
|
||||||
v.port = ntohs(sockinfo.sin_port);
|
v.port = ntohs(sockinfo.sin_port);
|
||||||
}
|
}
|
||||||
syslog(LOG_NOTICE, "HTTP listening on port %d", v.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
|
#ifdef ENABLE_IPV6
|
||||||
if(find_ipv6_addr(NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) {
|
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",
|
syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s",
|
||||||
ipv6_addr_for_http_with_brackets);
|
ipv6_addr_for_http_with_brackets);
|
||||||
} else {
|
} else {
|
||||||
memcpy(ipv6_addr_for_http_with_brackets, "[::1]", 6);
|
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
|
#endif
|
||||||
|
|
||||||
|
@ -1466,10 +1597,13 @@ main(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
sudpv6 = OpenAndConfSSDPReceiveSocket(1);
|
if(!GETFLAG(IPV6DISABLEDMASK))
|
||||||
if(sudpv6 < 0)
|
|
||||||
{
|
{
|
||||||
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
|
#endif
|
||||||
|
|
||||||
|
@ -1513,13 +1647,14 @@ main(int argc, char * * argv)
|
||||||
syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
|
syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
|
||||||
NATPMP_PORT);
|
NATPMP_PORT);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if 0
|
|
||||||
ScanNATPMPforExpiration();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_IPV6) && defined(ENABLE_PCP)
|
||||||
|
spcp_v6 = OpenAndConfPCPv6Socket();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* for miniupnpdctl */
|
/* for miniupnpdctl */
|
||||||
#ifdef USE_MINIUPNPDCTL
|
#ifdef USE_MINIUPNPDCTL
|
||||||
sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");
|
sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");
|
||||||
|
@ -1548,7 +1683,7 @@ main(int argc, char * * argv)
|
||||||
/* send public address change notifications if needed */
|
/* send public address change notifications if needed */
|
||||||
if(should_send_public_address_change_notif)
|
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
|
#ifdef ENABLE_NATPMP
|
||||||
if(GETFLAG(ENABLENATPMPMASK))
|
if(GETFLAG(ENABLENATPMPMASK))
|
||||||
SendNATPMPPublicAddressChangeNotification(snatpmp, addr_count);
|
SendNATPMPPublicAddressChangeNotification(snatpmp, addr_count);
|
||||||
|
@ -1629,28 +1764,6 @@ main(int argc, char * * argv)
|
||||||
syslog(LOG_DEBUG, "setting timeout to %u sec",
|
syslog(LOG_DEBUG, "setting timeout to %u sec",
|
||||||
(unsigned)timeout.tv_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
|
#ifdef ENABLE_6FC_SERVICE
|
||||||
/* Clean up expired IPv6 PinHoles */
|
/* Clean up expired IPv6 PinHoles */
|
||||||
next_pinhole_ts = 0;
|
next_pinhole_ts = 0;
|
||||||
|
@ -1683,6 +1796,13 @@ main(int argc, char * * argv)
|
||||||
FD_SET(shttpl, &readset);
|
FD_SET(shttpl, &readset);
|
||||||
max_fd = MAX( max_fd, shttpl);
|
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
|
#ifdef ENABLE_IPV6
|
||||||
if (sudpv6 >= 0)
|
if (sudpv6 >= 0)
|
||||||
{
|
{
|
||||||
|
@ -1729,6 +1849,12 @@ main(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ENABLE_IPV6) && defined(ENABLE_PCP)
|
||||||
|
if(spcp_v6 >= 0) {
|
||||||
|
FD_SET(spcp_v6, &readset);
|
||||||
|
max_fd = MAX(max_fd, spcp_v6);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef USE_MINIUPNPDCTL
|
#ifdef USE_MINIUPNPDCTL
|
||||||
if(sctl >= 0) {
|
if(sctl >= 0) {
|
||||||
FD_SET(sctl, &readset);
|
FD_SET(sctl, &readset);
|
||||||
|
@ -1748,6 +1874,38 @@ main(int argc, char * * argv)
|
||||||
upnpevents_selectfds(&readset, &writeset, &max_fd);
|
upnpevents_selectfds(&readset, &writeset, &max_fd);
|
||||||
#endif
|
#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(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
|
||||||
{
|
{
|
||||||
if(quitting) goto shutdown;
|
if(quitting) goto shutdown;
|
||||||
|
@ -1756,6 +1914,10 @@ main(int argc, char * * argv)
|
||||||
syslog(LOG_ERR, "Failed to select open sockets. EXITING");
|
syslog(LOG_ERR, "Failed to select open sockets. EXITING");
|
||||||
return 1; /* very serious cause of error */
|
return 1; /* very serious cause of error */
|
||||||
}
|
}
|
||||||
|
i = try_sendto(&writeset);
|
||||||
|
if(i < 0) {
|
||||||
|
syslog(LOG_ERR, "try_sendto failed to send %d packets", -i);
|
||||||
|
}
|
||||||
#ifdef USE_MINIUPNPDCTL
|
#ifdef USE_MINIUPNPDCTL
|
||||||
for(ectl = ctllisthead.lh_first; ectl;)
|
for(ectl = ctllisthead.lh_first; ectl;)
|
||||||
{
|
{
|
||||||
|
@ -1830,19 +1992,23 @@ main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
unsigned char msg_buff[PCP_MAX_LEN];
|
unsigned char msg_buff[PCP_MAX_LEN];
|
||||||
struct sockaddr_in senderaddr;
|
struct sockaddr_in senderaddr;
|
||||||
|
socklen_t senderaddrlen;
|
||||||
int len;
|
int len;
|
||||||
memset(msg_buff, 0, PCP_MAX_LEN);
|
memset(msg_buff, 0, PCP_MAX_LEN);
|
||||||
len = ReceiveNATPMPOrPCPPacket(snatpmp[i], &senderaddr,
|
senderaddrlen = sizeof(senderaddr);
|
||||||
msg_buff, sizeof(msg_buff));
|
len = ReceiveNATPMPOrPCPPacket(snatpmp[i],
|
||||||
|
(struct sockaddr *)&senderaddr,
|
||||||
|
&senderaddrlen,
|
||||||
|
msg_buff, sizeof(msg_buff));
|
||||||
if (len < 1)
|
if (len < 1)
|
||||||
continue;
|
continue;
|
||||||
#ifdef ENABLE_PCP
|
#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,
|
ProcessIncomingNATPMPPacket(snatpmp[i], msg_buff, len,
|
||||||
&senderaddr);
|
&senderaddr);
|
||||||
} else { /* everything else can be PCP */
|
} else { /* everything else can be PCP */
|
||||||
ProcessIncomingPCPPacket(snatpmp[i], msg_buff, len,
|
ProcessIncomingPCPPacket(snatpmp[i], msg_buff, len,
|
||||||
&senderaddr);
|
(struct sockaddr *)&senderaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -1850,6 +2016,25 @@ main(int argc, char * * argv)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(ENABLE_IPV6) && defined(ENABLE_PCP)
|
||||||
|
/* in IPv6, only PCP is supported, not NAT-PMP */
|
||||||
|
if(spcp_v6 >= 0 && FD_ISSET(spcp_v6, &readset))
|
||||||
|
{
|
||||||
|
unsigned char msg_buff[PCP_MAX_LEN];
|
||||||
|
struct sockaddr_in6 senderaddr;
|
||||||
|
socklen_t senderaddrlen;
|
||||||
|
int len;
|
||||||
|
memset(msg_buff, 0, PCP_MAX_LEN);
|
||||||
|
senderaddrlen = sizeof(senderaddr);
|
||||||
|
len = ReceiveNATPMPOrPCPPacket(spcp_v6,
|
||||||
|
(struct sockaddr *)&senderaddr,
|
||||||
|
&senderaddrlen,
|
||||||
|
msg_buff, sizeof(msg_buff));
|
||||||
|
if(len >= 1)
|
||||||
|
ProcessIncomingPCPPacket(spcp_v6, msg_buff, len,
|
||||||
|
(struct sockaddr *)&senderaddr);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
/* process SSDP packets */
|
/* process SSDP packets */
|
||||||
if(sudp >= 0 && FD_ISSET(sudp, &readset))
|
if(sudp >= 0 && FD_ISSET(sudp, &readset))
|
||||||
|
@ -1886,79 +2071,24 @@ main(int argc, char * * argv)
|
||||||
/* process incoming HTTP connections */
|
/* process incoming HTTP connections */
|
||||||
if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
|
if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
|
||||||
{
|
{
|
||||||
int shttp;
|
struct upnphttp * tmp;
|
||||||
socklen_t clientnamelen;
|
tmp = ProcessIncomingHTTP(shttpl);
|
||||||
#ifdef ENABLE_IPV6
|
if(tmp)
|
||||||
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 */
|
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#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
|
#ifdef ENABLE_NFQUEUE
|
||||||
/* process NFQ packets */
|
/* process NFQ packets */
|
||||||
if(nfqh >= 0 && FD_ISSET(nfqh, &readset))
|
if(nfqh >= 0 && FD_ISSET(nfqh, &readset))
|
||||||
|
@ -1982,6 +2112,22 @@ main(int argc, char * * argv)
|
||||||
} /* end of main loop */
|
} /* end of main loop */
|
||||||
|
|
||||||
shutdown:
|
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 */
|
/* close out open sockets */
|
||||||
while(upnphttphead.lh_first != NULL)
|
while(upnphttphead.lh_first != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1992,6 +2138,9 @@ shutdown:
|
||||||
|
|
||||||
if (sudp >= 0) close(sudp);
|
if (sudp >= 0) close(sudp);
|
||||||
if (shttpl >= 0) close(shttpl);
|
if (shttpl >= 0) close(shttpl);
|
||||||
|
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
|
||||||
|
if (shttpl_v4 >= 0) close(shttpl_v4);
|
||||||
|
#endif
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
if (sudpv6 >= 0) close(sudpv6);
|
if (sudpv6 >= 0) close(sudpv6);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2007,6 +2156,13 @@ shutdown:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ENABLE_IPV6) && defined(ENABLE_PCP)
|
||||||
|
if(spcp_v6 >= 0)
|
||||||
|
{
|
||||||
|
close(spcp_v6);
|
||||||
|
spcp_v6 = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef USE_MINIUPNPDCTL
|
#ifdef USE_MINIUPNPDCTL
|
||||||
if(sctl>=0)
|
if(sctl>=0)
|
||||||
{
|
{
|
||||||
|
@ -2021,14 +2177,6 @@ shutdown:
|
||||||
|
|
||||||
if (GETFLAG(ENABLEUPNPMASK))
|
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
|
#ifndef ENABLE_IPV6
|
||||||
for(i = 0; i < addr_count; i++)
|
for(i = 0; i < addr_count; i++)
|
||||||
#else
|
#else
|
||||||
|
@ -2037,6 +2185,7 @@ shutdown:
|
||||||
close(snotify[i]);
|
close(snotify[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove pidfile */
|
||||||
if(pidfilename && (unlink(pidfilename) < 0))
|
if(pidfilename && (unlink(pidfilename) < 0))
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
|
syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
|
||||||
|
|
|
@ -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 ! */
|
/* minixml.c : the minimum size a xml parser can be ! */
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* Author : Thomas Bernard
|
* Author : Thomas Bernard
|
||||||
|
|
||||||
Copyright (c) 2005-2011, Thomas BERNARD
|
Copyright (c) 2005-2014, Thomas BERNARD
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -113,7 +113,20 @@ static void parseelt(struct xmlparser * p)
|
||||||
const char * elementname;
|
const char * elementname;
|
||||||
while(p->xml < (p->xmlend - 1))
|
while(p->xml < (p->xmlend - 1))
|
||||||
{
|
{
|
||||||
if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "<!--", 4)))
|
||||||
|
{
|
||||||
|
p->xml += 3;
|
||||||
|
/* ignore comments */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
p->xml++;
|
||||||
|
if ((p->xml + 3) >= p->xmlend)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while(memcmp(p->xml, "-->", 3) != 0);
|
||||||
|
p->xml += 3;
|
||||||
|
}
|
||||||
|
else if((p->xml)[0]=='<' && (p->xml)[1]!='?')
|
||||||
{
|
{
|
||||||
i = 0; elementname = ++p->xml;
|
i = 0; elementname = ++p->xml;
|
||||||
while( !IS_WHITE_SPACE(*p->xml)
|
while( !IS_WHITE_SPACE(*p->xml)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* $Id: natpmp.c,v 1.35 2013/12/13 14:07:08 nanard Exp $ */
|
/* $Id: natpmp.c,v 1.43 2014/03/24 10:49:45 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* (c) 2007-2013 Thomas Bernard
|
* (c) 2007-2014 Thomas Bernard
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
@ -23,9 +23,12 @@
|
||||||
#include "upnpredirect.h"
|
#include "upnpredirect.h"
|
||||||
#include "commonrdr.h"
|
#include "commonrdr.h"
|
||||||
#include "upnputils.h"
|
#include "upnputils.h"
|
||||||
|
#include "portinuse.h"
|
||||||
|
#include "asyncsendto.h"
|
||||||
|
|
||||||
#ifdef ENABLE_NATPMP
|
#ifdef ENABLE_NATPMP
|
||||||
|
|
||||||
|
|
||||||
int OpenAndConfNATPMPSocket(in_addr_t addr)
|
int OpenAndConfNATPMPSocket(in_addr_t addr)
|
||||||
{
|
{
|
||||||
int snatpmp;
|
int snatpmp;
|
||||||
|
@ -33,13 +36,13 @@ int OpenAndConfNATPMPSocket(in_addr_t addr)
|
||||||
snatpmp = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
|
snatpmp = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
|
||||||
if(snatpmp<0)
|
if(snatpmp<0)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "%s: socket(natpmp): %m",
|
syslog(LOG_ERR, "%s: socket(): %m",
|
||||||
"OpenAndConfNATPMPSocket");
|
"OpenAndConfNATPMPSocket");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(setsockopt(snatpmp, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
|
if(setsockopt(snatpmp, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_WARNING, "%s: setsockopt(natpmp, SO_REUSEADDR): %m",
|
syslog(LOG_WARNING, "%s: setsockopt(SO_REUSEADDR): %m",
|
||||||
"OpenAndConfNATPMPSocket");
|
"OpenAndConfNATPMPSocket");
|
||||||
}
|
}
|
||||||
if(!set_non_blocking(snatpmp))
|
if(!set_non_blocking(snatpmp))
|
||||||
|
@ -56,7 +59,8 @@ int OpenAndConfNATPMPSocket(in_addr_t addr)
|
||||||
natpmp_addr.sin_addr.s_addr = addr;
|
natpmp_addr.sin_addr.s_addr = addr;
|
||||||
if(bind(snatpmp, (struct sockaddr *)&natpmp_addr, sizeof(natpmp_addr)) < 0)
|
if(bind(snatpmp, (struct sockaddr *)&natpmp_addr, sizeof(natpmp_addr)) < 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "bind(natpmp): %m");
|
syslog(LOG_ERR, "%s: bind(): %m",
|
||||||
|
"OpenAndConfNATPMPSocket");
|
||||||
close(snatpmp);
|
close(snatpmp);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -66,22 +70,25 @@ int OpenAndConfNATPMPSocket(in_addr_t addr)
|
||||||
|
|
||||||
int OpenAndConfNATPMPSockets(int * sockets)
|
int OpenAndConfNATPMPSockets(int * sockets)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i;
|
||||||
struct lan_addr_s * lan_addr;
|
struct lan_addr_s * lan_addr;
|
||||||
for(i = 0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
|
for(i = 0, lan_addr = lan_addrs.lh_first;
|
||||||
|
lan_addr != NULL;
|
||||||
|
lan_addr = lan_addr->list.le_next)
|
||||||
{
|
{
|
||||||
sockets[i] = OpenAndConfNATPMPSocket(lan_addr->addr.s_addr);
|
sockets[i] = OpenAndConfNATPMPSocket(lan_addr->addr.s_addr);
|
||||||
if(sockets[i] < 0)
|
if(sockets[i] < 0)
|
||||||
{
|
goto error;
|
||||||
for(j=0; j<i; j++)
|
i++;
|
||||||
{
|
|
||||||
close(sockets[j]);
|
|
||||||
sockets[j] = -1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
error:
|
||||||
|
while(--i >= 0)
|
||||||
|
{
|
||||||
|
close(sockets[i]);
|
||||||
|
sockets[i] = -1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr)
|
static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr)
|
||||||
|
@ -123,15 +130,15 @@ static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr
|
||||||
* The sender information is stored in senderaddr.
|
* The sender information is stored in senderaddr.
|
||||||
* Returns number of bytes recevied, even if number is negative.
|
* Returns number of bytes recevied, even if number is negative.
|
||||||
*/
|
*/
|
||||||
int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr_in* senderaddr,
|
int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr * senderaddr,
|
||||||
unsigned char *msg_buff, size_t msg_buff_size)
|
socklen_t * senderaddrlen,
|
||||||
|
unsigned char * msg_buff, size_t msg_buff_size)
|
||||||
{
|
{
|
||||||
|
|
||||||
socklen_t senderaddrlen = sizeof(*senderaddr);
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
n = recvfrom(s, msg_buff, msg_buff_size, 0,
|
n = recvfrom(s, msg_buff, msg_buff_size, 0,
|
||||||
(struct sockaddr *)senderaddr, &senderaddrlen);
|
senderaddr, senderaddrlen);
|
||||||
|
|
||||||
if(n<0) {
|
if(n<0) {
|
||||||
/* EAGAIN, EWOULDBLOCK and EINTR : silently ignore (retry next time)
|
/* EAGAIN, EWOULDBLOCK and EINTR : silently ignore (retry next time)
|
||||||
|
@ -262,32 +269,64 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eport = 0; /* to indicate correct removing of port mapping */
|
eport = 0; /* to indicate correct removing of port mapping */
|
||||||
} else if(iport==0
|
} else if(iport==0) {
|
||||||
|| !check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) {
|
|
||||||
resp[3] = 2; /* Not Authorized/Refused */
|
resp[3] = 2; /* Not Authorized/Refused */
|
||||||
} else do {
|
} else { /* iport > 0 && lifetime > 0 */
|
||||||
r = get_redirect_rule(ext_if_name, eport, proto,
|
unsigned short eport_first = 0;
|
||||||
iaddr_old, sizeof(iaddr_old),
|
int any_eport_allowed = 0;
|
||||||
&iport_old, 0, 0, 0, 0,
|
char desc[64];
|
||||||
×tamp, 0, 0);
|
while(resp[3] == 0) {
|
||||||
if(r==0) {
|
if(eport_first == 0) { /* first time in loop */
|
||||||
if(strcmp(senderaddrstr, iaddr_old)==0
|
eport_first = eport;
|
||||||
&& iport==iport_old) {
|
} else if(eport == eport_first) { /* no eport available */
|
||||||
/* redirection allready existing */
|
if(any_eport_allowed == 0) { /* all eports rejected by permissions */
|
||||||
syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing",
|
syslog(LOG_ERR, "No allowed eport for NAT-PMP %hu %s->%s:%hu",
|
||||||
eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old);
|
eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport);
|
||||||
/* remove and then add again */
|
resp[3] = 2; /* Not Authorized/Refused */
|
||||||
if(_upnp_delete_redir(eport, proto) < 0) {
|
} else { /* at least one eport allowed (but none available) */
|
||||||
syslog(LOG_ERR, "failed to remove port mapping");
|
syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu",
|
||||||
break;
|
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++;
|
eport++;
|
||||||
|
if(eport == 0) eport++; /* skip port zero */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
any_eport_allowed = 1; /* at lease one eport is allowed */
|
||||||
{ /* do the redirection */
|
#ifdef CHECK_PORTINUSE
|
||||||
char desc[64];
|
if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport) > 0) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
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
|
#if 0
|
||||||
timestamp = (unsigned)(time(NULL) - startup_time)
|
timestamp = (unsigned)(time(NULL) - startup_time)
|
||||||
+ lifetime;
|
+ lifetime;
|
||||||
|
@ -304,17 +343,10 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
||||||
syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'",
|
syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'",
|
||||||
eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc);
|
eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc);
|
||||||
resp[3] = 3; /* Failure */
|
resp[3] = 3; /* Failure */
|
||||||
#if 0
|
|
||||||
} else if( !nextnatpmptoclean_eport
|
|
||||||
|| timestamp < nextnatpmptoclean_timestamp) {
|
|
||||||
nextnatpmptoclean_timestamp = timestamp;
|
|
||||||
nextnatpmptoclean_eport = eport;
|
|
||||||
nextnatpmptoclean_proto = proto;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while(r==0);
|
}
|
||||||
*((uint16_t *)(resp+8)) = htons(iport); /* private port */
|
*((uint16_t *)(resp+8)) = htons(iport); /* private port */
|
||||||
*((uint16_t *)(resp+10)) = htons(eport); /* public port */
|
*((uint16_t *)(resp+10)) = htons(eport); /* public port */
|
||||||
*((uint32_t *)(resp+12)) = htonl(lifetime); /* Port Mapping lifetime */
|
*((uint32_t *)(resp+12)) = htonl(lifetime); /* Port Mapping lifetime */
|
||||||
|
@ -324,7 +356,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
||||||
default:
|
default:
|
||||||
resp[3] = 5; /* Unsupported OPCODE */
|
resp[3] = 5; /* Unsupported OPCODE */
|
||||||
}
|
}
|
||||||
n = sendto(s, resp, resplen, 0,
|
n = sendto_or_schedule(s, resp, resplen, 0,
|
||||||
(struct sockaddr *)senderaddr, sizeof(*senderaddr));
|
(struct sockaddr *)senderaddr, sizeof(*senderaddr));
|
||||||
if(n<0) {
|
if(n<0) {
|
||||||
syslog(LOG_ERR, "sendto(natpmp): %m");
|
syslog(LOG_ERR, "sendto(natpmp): %m");
|
||||||
|
@ -334,67 +366,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()
|
/* SendNATPMPPublicAddressChangeNotification()
|
||||||
* should be called when the public IP address changed */
|
* should be called when the public IP address changed */
|
||||||
void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
|
void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
|
||||||
|
@ -439,7 +410,7 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
|
||||||
#endif
|
#endif
|
||||||
/* Port to use in 2006 version of the NAT-PMP specification */
|
/* Port to use in 2006 version of the NAT-PMP specification */
|
||||||
sockname.sin_port = htons(NATPMP_PORT);
|
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));
|
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in));
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
{
|
{
|
||||||
|
@ -449,7 +420,7 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
|
||||||
}
|
}
|
||||||
/* Port to use in 2008 version of the NAT-PMP specification */
|
/* Port to use in 2008 version of the NAT-PMP specification */
|
||||||
sockname.sin_port = htons(NATPMP_NOTIF_PORT);
|
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));
|
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in));
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: natpmp.h,v 1.8 2011/05/27 21:36:22 nanard Exp $ */
|
/* $Id: natpmp.h,v 1.12 2014/03/24 10:49:46 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* author : Thomas Bernard
|
* author : Thomas Bernard
|
||||||
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
|
@ -20,17 +20,12 @@
|
||||||
|
|
||||||
int OpenAndConfNATPMPSockets(int * sockets);
|
int OpenAndConfNATPMPSockets(int * sockets);
|
||||||
|
|
||||||
int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr_in* senderaddr,
|
int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr * senderaddr,
|
||||||
unsigned char *msg_buff, size_t msg_buff_size);
|
socklen_t * senderaddrlen,
|
||||||
|
unsigned char * msg_buff, size_t msg_buff_size);
|
||||||
|
|
||||||
void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
|
void ProcessIncomingNATPMPPacket(int s, unsigned char * msg_buff, int len,
|
||||||
struct sockaddr_in *senderaddr);
|
struct sockaddr_in * senderaddr);
|
||||||
|
|
||||||
#if 0
|
|
||||||
int ScanNATPMPforExpiration(void);
|
|
||||||
|
|
||||||
int CleanExpiredNATPMP(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets);
|
void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets);
|
||||||
|
|
||||||
|
|
|
@ -284,6 +284,22 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto,
|
||||||
char * rhost, int rhostlen,
|
char * rhost, int rhostlen,
|
||||||
unsigned int * timestamp,
|
unsigned int * timestamp,
|
||||||
u_int64_t * packets, u_int64_t * bytes)
|
u_int64_t * packets, u_int64_t * bytes)
|
||||||
|
{
|
||||||
|
return get_nat_redirect_rule(miniupnpd_nat_chain,
|
||||||
|
ifname, eport, proto,
|
||||||
|
iaddr, iaddrlen, iport,
|
||||||
|
desc, desclen,
|
||||||
|
rhost, rhostlen,
|
||||||
|
timestamp, packets, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, unsigned short eport, int proto,
|
||||||
|
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||||
|
char * desc, int desclen,
|
||||||
|
char * rhost, int rhostlen,
|
||||||
|
unsigned int * timestamp,
|
||||||
|
u_int64_t * packets, u_int64_t * bytes)
|
||||||
{
|
{
|
||||||
int r = -1;
|
int r = -1;
|
||||||
IPTC_HANDLE h;
|
IPTC_HANDLE h;
|
||||||
|
@ -301,18 +317,18 @@ get_redirect_rule(const char * ifname, unsigned short eport, int proto,
|
||||||
iptc_strerror(errno));
|
iptc_strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!iptc_is_chain(miniupnpd_nat_chain, h))
|
if(!iptc_is_chain(nat_chain_name, h))
|
||||||
{
|
{
|
||||||
syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
|
syslog(LOG_ERR, "chain %s not found", nat_chain_name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef IPTABLES_143
|
#ifdef IPTABLES_143
|
||||||
for(e = iptc_first_rule(miniupnpd_nat_chain, h);
|
for(e = iptc_first_rule(nat_chain_name, h);
|
||||||
e;
|
e;
|
||||||
e = iptc_next_rule(e, h))
|
e = iptc_next_rule(e, h))
|
||||||
#else
|
#else
|
||||||
for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
|
for(e = iptc_first_rule(nat_chain_name, &h);
|
||||||
e;
|
e;
|
||||||
e = iptc_next_rule(e, &h))
|
e = iptc_next_rule(e, &h))
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,6 +49,13 @@ get_peer_rule_by_index(int index,
|
||||||
char * rhost, int rhostlen, unsigned short * rport,
|
char * rhost, int rhostlen, unsigned short * rport,
|
||||||
unsigned int * timestamp,
|
unsigned int * timestamp,
|
||||||
u_int64_t * packets, u_int64_t * bytes);
|
u_int64_t * packets, u_int64_t * bytes);
|
||||||
|
int
|
||||||
|
get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, unsigned short eport, int proto,
|
||||||
|
char * iaddr, int iaddrlen, unsigned short * iport,
|
||||||
|
char * desc, int desclen,
|
||||||
|
char * rhost, int rhostlen,
|
||||||
|
unsigned int * timestamp,
|
||||||
|
u_int64_t * packets, u_int64_t * bytes);
|
||||||
|
|
||||||
/* for debug */
|
/* for debug */
|
||||||
int
|
int
|
||||||
|
|
|
@ -178,12 +178,12 @@ typedef struct pcp_options_hdr {
|
||||||
/* same for both request and response */
|
/* same for both request and response */
|
||||||
typedef struct pcp_map_v2 {
|
typedef struct pcp_map_v2 {
|
||||||
uint32_t nonce[3];
|
uint32_t nonce[3];
|
||||||
uint8_t protocol;
|
uint8_t protocol; /* 6 = TCP, 17 = UDP, 0 = 'all protocols' */
|
||||||
uint8_t reserved[3];
|
uint8_t reserved[3];
|
||||||
uint16_t int_port;
|
uint16_t int_port; /* 0 indicates 'all ports' */
|
||||||
uint16_t ext_port;
|
uint16_t ext_port; /* suggested external port */
|
||||||
struct in6_addr ext_ip; /* ipv4 will be represented
|
struct in6_addr ext_ip; /* suggested external IP address
|
||||||
by the ipv4 mapped ipv6 */
|
* ipv4 will be represented by the ipv4 mapped ipv6 */
|
||||||
uint8_t next_data[0];
|
uint8_t next_data[0];
|
||||||
} pcp_map_v2_t;
|
} pcp_map_v2_t;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: pcpserver.c,v 1.5 2014/01/27 10:06:08 nanard Exp $ */
|
/* $Id: pcpserver.c,v 1.26 2014/03/24 13:08:52 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* Website : http://miniupnp.free.fr/
|
* Website : http://miniupnp.free.fr/
|
||||||
* Author : Peter Tatrai
|
* Author : Peter Tatrai
|
||||||
|
@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -52,12 +53,15 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
#include "pcpserver.h"
|
#include "pcpserver.h"
|
||||||
|
#include "natpmp.h"
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
#include "upnpglobalvars.h"
|
#include "upnpglobalvars.h"
|
||||||
#include "pcplearndscp.h"
|
#include "pcplearndscp.h"
|
||||||
#include "upnpredirect.h"
|
#include "upnpredirect.h"
|
||||||
#include "commonrdr.h"
|
#include "commonrdr.h"
|
||||||
#include "getifaddr.h"
|
#include "getifaddr.h"
|
||||||
|
#include "asyncsendto.h"
|
||||||
|
#include "upnputils.h"
|
||||||
#include "pcp_msg_struct.h"
|
#include "pcp_msg_struct.h"
|
||||||
|
|
||||||
#ifdef PCP_PEER
|
#ifdef PCP_PEER
|
||||||
|
@ -82,6 +86,7 @@ typedef struct pcp_info {
|
||||||
uint32_t lifetime; /* lifetime of the mapping */
|
uint32_t lifetime; /* lifetime of the mapping */
|
||||||
uint32_t epochtime;
|
uint32_t epochtime;
|
||||||
/* both MAP and PEER opcode specific information */
|
/* both MAP and PEER opcode specific information */
|
||||||
|
uint32_t nonce[3]; /* random value generated by client */
|
||||||
uint8_t protocol;
|
uint8_t protocol;
|
||||||
uint16_t int_port;
|
uint16_t int_port;
|
||||||
const struct in6_addr *int_ip; /* in network order */
|
const struct in6_addr *int_ip; /* in network order */
|
||||||
|
@ -114,7 +119,7 @@ typedef struct pcp_info {
|
||||||
uint8_t is_peer_op;
|
uint8_t is_peer_op;
|
||||||
int thirdp_present; /* indicate presence of the options */
|
int thirdp_present; /* indicate presence of the options */
|
||||||
int pfailure_present;
|
int pfailure_present;
|
||||||
char senderaddrstr[INET_ADDRSTRLEN];
|
char senderaddrstr[INET_ADDRSTRLEN]; /* only if IPv4 sender */
|
||||||
|
|
||||||
} pcp_info_t;
|
} pcp_info_t;
|
||||||
|
|
||||||
|
@ -173,10 +178,10 @@ int get_dscp_value(pcp_info_t *pcp_msg_info) {
|
||||||
* result code is assigned to pcp_msg_info->result_code to indicate
|
* result code is assigned to pcp_msg_info->result_code to indicate
|
||||||
* what kind of error occurred
|
* what kind of error occurred
|
||||||
*/
|
*/
|
||||||
static int parseCommonRequestHeader(pcp_request_t *common_req, pcp_info_t *pcp_msg_info)
|
static int parseCommonRequestHeader(const pcp_request_t *common_req, pcp_info_t *pcp_msg_info)
|
||||||
{
|
{
|
||||||
pcp_msg_info->version = common_req->ver ;
|
pcp_msg_info->version = common_req->ver ;
|
||||||
pcp_msg_info->opcode = common_req->r_opcode &0x7f ;
|
pcp_msg_info->opcode = common_req->r_opcode & 0x7f;
|
||||||
pcp_msg_info->lifetime = ntohl(common_req->req_lifetime);
|
pcp_msg_info->lifetime = ntohl(common_req->req_lifetime);
|
||||||
pcp_msg_info->int_ip = &common_req->ip;
|
pcp_msg_info->int_ip = &common_req->ip;
|
||||||
|
|
||||||
|
@ -198,7 +203,7 @@ static int parseCommonRequestHeader(pcp_request_t *common_req, pcp_info_t *pcp_m
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static void printMAPOpcodeVersion1(pcp_map_v1_t *map_buf)
|
static void printMAPOpcodeVersion1(const pcp_map_v1_t *map_buf)
|
||||||
{
|
{
|
||||||
char map_addr[INET6_ADDRSTRLEN];
|
char map_addr[INET6_ADDRSTRLEN];
|
||||||
syslog(LOG_DEBUG, "PCP MAP: v1 Opcode specific information. \n");
|
syslog(LOG_DEBUG, "PCP MAP: v1 Opcode specific information. \n");
|
||||||
|
@ -209,19 +214,21 @@ static void printMAPOpcodeVersion1(pcp_map_v1_t *map_buf)
|
||||||
&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)
|
static void printMAPOpcodeVersion2(const pcp_map_v2_t *map_buf)
|
||||||
{
|
{
|
||||||
char map_addr[INET6_ADDRSTRLEN];
|
char map_addr[INET6_ADDRSTRLEN];
|
||||||
syslog(LOG_DEBUG, "PCP MAP: v2 Opcode specific information. \n");
|
syslog(LOG_DEBUG, "PCP MAP: v2 Opcode specific information.");
|
||||||
syslog(LOG_DEBUG, "MAP protocol: \t\t %d\n",map_buf->protocol );
|
syslog(LOG_DEBUG, "MAP nonce: \t%08x%08x%08x",
|
||||||
syslog(LOG_DEBUG, "MAP int port: \t\t %d\n", ntohs(map_buf->int_port) );
|
map_buf->nonce[0], map_buf->nonce[1], map_buf->nonce[2]);
|
||||||
syslog(LOG_DEBUG, "MAP ext port: \t\t %d\n", ntohs(map_buf->ext_port) );
|
syslog(LOG_DEBUG, "MAP protocol:\t%d", map_buf->protocol);
|
||||||
syslog(LOG_DEBUG, "MAP Ext IP: \t\t %s\n", inet_ntop(AF_INET6,
|
syslog(LOG_DEBUG, "MAP int port:\t%d", ntohs(map_buf->int_port));
|
||||||
|
syslog(LOG_DEBUG, "MAP ext port:\t%d", ntohs(map_buf->ext_port));
|
||||||
|
syslog(LOG_DEBUG, "MAP Ext IP: \t%s", 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(const pcp_map_v1_t *map_v1,
|
||||||
pcp_info_t *pcp_msg_info)
|
pcp_info_t *pcp_msg_info)
|
||||||
{
|
{
|
||||||
pcp_msg_info->is_map_op = 1;
|
pcp_msg_info->is_map_op = 1;
|
||||||
|
@ -239,10 +246,11 @@ static int parsePCPMAP_version1(pcp_map_v1_t *map_v1,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parsePCPMAP_version2(pcp_map_v2_t *map_v2,
|
static int parsePCPMAP_version2(const pcp_map_v2_t *map_v2,
|
||||||
pcp_info_t *pcp_msg_info)
|
pcp_info_t *pcp_msg_info)
|
||||||
{
|
{
|
||||||
pcp_msg_info->is_map_op = 1;
|
pcp_msg_info->is_map_op = 1;
|
||||||
|
memcpy(pcp_msg_info->nonce, map_v2->nonce, 12);
|
||||||
pcp_msg_info->protocol = map_v2->protocol;
|
pcp_msg_info->protocol = map_v2->protocol;
|
||||||
pcp_msg_info->int_port = ntohs(map_v2->int_port);
|
pcp_msg_info->int_port = ntohs(map_v2->int_port);
|
||||||
pcp_msg_info->ext_port = ntohs(map_v2->ext_port);
|
pcp_msg_info->ext_port = ntohs(map_v2->ext_port);
|
||||||
|
@ -280,15 +288,17 @@ static void printPEEROpcodeVersion2(pcp_peer_v2_t *peer_buf)
|
||||||
char ext_addr[INET6_ADDRSTRLEN];
|
char ext_addr[INET6_ADDRSTRLEN];
|
||||||
char peer_addr[INET6_ADDRSTRLEN];
|
char peer_addr[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
syslog(LOG_DEBUG, "PCP PEER: v2 Opcode specific information. \n");
|
syslog(LOG_DEBUG, "PCP PEER: v2 Opcode specific information.");
|
||||||
syslog(LOG_DEBUG, "Protocol: \t\t %d\n",peer_buf->protocol );
|
syslog(LOG_DEBUG, "nonce: \t%08x%08x%08x",
|
||||||
syslog(LOG_DEBUG, "Internal port: \t\t %d\n", ntohs(peer_buf->int_port) );
|
map_buf->nonce[0], map_buf->nonce[1], map_buf->nonce[2]);
|
||||||
syslog(LOG_DEBUG, "External IP: \t\t %s\n", inet_ntop(AF_INET6, &peer_buf->ext_ip,
|
syslog(LOG_DEBUG, "Protocol: \t%d",peer_buf->protocol );
|
||||||
|
syslog(LOG_DEBUG, "Internal port:\t%d", ntohs(peer_buf->int_port) );
|
||||||
|
syslog(LOG_DEBUG, "External IP: \t%s", inet_ntop(AF_INET6, &peer_buf->ext_ip,
|
||||||
ext_addr,INET6_ADDRSTRLEN));
|
ext_addr,INET6_ADDRSTRLEN));
|
||||||
syslog(LOG_DEBUG, "External port port: \t\t %d\n", ntohs(peer_buf->ext_port) );
|
syslog(LOG_DEBUG, "External port:\t%d", 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%s", inet_ntop(AF_INET6, &peer_buf->peer_ip,
|
||||||
peer_addr,INET6_ADDRSTRLEN));
|
peer_addr,INET6_ADDRSTRLEN));
|
||||||
syslog(LOG_DEBUG, "PEER port port: \t\t %d\n", ntohs(peer_buf->peer_port) );
|
syslog(LOG_DEBUG, "PEER port: \t%d", ntohs(peer_buf->peer_port) );
|
||||||
}
|
}
|
||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
@ -324,6 +334,7 @@ static int parsePCPPEER_version2(pcp_peer_v2_t *peer_buf, \
|
||||||
pcp_info_t *pcp_msg_info)
|
pcp_info_t *pcp_msg_info)
|
||||||
{
|
{
|
||||||
pcp_msg_info->is_peer_op = 1;
|
pcp_msg_info->is_peer_op = 1;
|
||||||
|
memcpy(pcp_msg_info->nonce, peer_buf->nonce, 12);
|
||||||
pcp_msg_info->protocol = peer_buf->protocol;
|
pcp_msg_info->protocol = peer_buf->protocol;
|
||||||
pcp_msg_info->int_port = ntohs(peer_buf->int_port);
|
pcp_msg_info->int_port = ntohs(peer_buf->int_port);
|
||||||
pcp_msg_info->ext_port = ntohs(peer_buf->ext_port);
|
pcp_msg_info->ext_port = ntohs(peer_buf->ext_port);
|
||||||
|
@ -534,6 +545,7 @@ static int parsePCPOptions(void* pcp_buf, int* remainingSize,
|
||||||
|
|
||||||
static int CheckExternalAddress(pcp_info_t* pcp_msg_info)
|
static int CheckExternalAddress(pcp_info_t* pcp_msg_info)
|
||||||
{
|
{
|
||||||
|
/* can contain a IPv4-mapped IPv6 address */
|
||||||
static struct in6_addr external_addr;
|
static struct in6_addr external_addr;
|
||||||
|
|
||||||
if(use_ext_ip_addr) {
|
if(use_ext_ip_addr) {
|
||||||
|
@ -552,13 +564,14 @@ static int CheckExternalAddress(pcp_info_t* pcp_msg_info)
|
||||||
pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE;
|
pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
/* how do we know which address we need ? IPv6 or IPv4 ? */
|
||||||
if(getifaddr_in6(ext_if_name, &external_addr) < 0) {
|
if(getifaddr_in6(ext_if_name, &external_addr) < 0) {
|
||||||
pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE;
|
pcp_msg_info->result_code = PCP_ERR_NETWORK_FAILURE;
|
||||||
return -1;
|
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;
|
pcp_msg_info->ext_ip = &external_addr;
|
||||||
|
|
||||||
|
@ -664,6 +677,7 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info)
|
||||||
/* Create Peer Mapping */
|
/* Create Peer Mapping */
|
||||||
{
|
{
|
||||||
char desc[64];
|
char desc[64];
|
||||||
|
char proto_str[8];
|
||||||
char peerip_s[INET_ADDRSTRLEN], extip_s[INET_ADDRSTRLEN];
|
char peerip_s[INET_ADDRSTRLEN], extip_s[INET_ADDRSTRLEN];
|
||||||
time_t timestamp = time(NULL) + pcp_msg_info->lifetime;
|
time_t timestamp = time(NULL) + pcp_msg_info->lifetime;
|
||||||
|
|
||||||
|
@ -671,8 +685,19 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info)
|
||||||
eport = pcp_msg_info->int_port;
|
eport = pcp_msg_info->int_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(desc, sizeof(desc), "PCP %hu %s",
|
switch(proto) {
|
||||||
eport, (proto==IPPROTO_TCP)?"tcp":"udp");
|
case IPPROTO_TCP:
|
||||||
|
snprintf(proto_str, sizeof(proto_str), "TCP");
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
snprintf(proto_str, sizeof(proto_str), "UDP");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(proto_str, sizeof(proto_str), "%d", proto);
|
||||||
|
}
|
||||||
|
snprintf(desc, sizeof(desc), "PCP %hu %s %08x%08x%08x",
|
||||||
|
eport, proto_str,
|
||||||
|
pcp_msg_info->nonce[0], pcp_msg_info->nonce[1], pcp_msg_info->nonce[2]);
|
||||||
|
|
||||||
inet_satop((struct sockaddr*)&peerip, peerip_s, sizeof(peerip_s));
|
inet_satop((struct sockaddr*)&peerip, peerip_s, sizeof(peerip_s));
|
||||||
inet_satop((struct sockaddr*)&extip, extip_s, sizeof(extip_s));
|
inet_satop((struct sockaddr*)&extip, extip_s, sizeof(extip_s));
|
||||||
|
@ -684,7 +709,7 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info)
|
||||||
pcp_msg_info->senderaddrstr, pcp_msg_info->int_port,
|
pcp_msg_info->senderaddrstr, pcp_msg_info->int_port,
|
||||||
proto, desc, timestamp) < 0 ) {
|
proto, desc, timestamp) < 0 ) {
|
||||||
syslog(LOG_ERR, "PCP: failed to add flowp upstream mapping %s %s:%hu->%s:%hu '%s'",
|
syslog(LOG_ERR, "PCP: failed to add flowp upstream mapping %s %s:%hu->%s:%hu '%s'",
|
||||||
(pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP",
|
proto_str,
|
||||||
pcp_msg_info->senderaddrstr,
|
pcp_msg_info->senderaddrstr,
|
||||||
pcp_msg_info->int_port,
|
pcp_msg_info->int_port,
|
||||||
peerip_s,
|
peerip_s,
|
||||||
|
@ -700,7 +725,7 @@ static int CreatePCPPeer(pcp_info_t *pcp_msg_info)
|
||||||
peerip_s, pcp_msg_info->peer_port, proto, desc, timestamp)
|
peerip_s, pcp_msg_info->peer_port, proto, desc, timestamp)
|
||||||
< 0 ) {
|
< 0 ) {
|
||||||
syslog(LOG_ERR, "PCP: failed to add flowp downstream mapping %s %s:%hu->%s:%hu '%s'",
|
syslog(LOG_ERR, "PCP: failed to add flowp downstream mapping %s %s:%hu->%s:%hu '%s'",
|
||||||
(pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP",
|
proto_str,
|
||||||
pcp_msg_info->senderaddrstr,
|
pcp_msg_info->senderaddrstr,
|
||||||
pcp_msg_info->int_port,
|
pcp_msg_info->int_port,
|
||||||
peerip_s,
|
peerip_s,
|
||||||
|
@ -798,18 +823,75 @@ static void DeletePCPPeer(pcp_info_t *pcp_msg_info)
|
||||||
}
|
}
|
||||||
#endif /* PCP_PEER */
|
#endif /* PCP_PEER */
|
||||||
|
|
||||||
|
/* internal external PCP remote peer actual remote peer
|
||||||
|
* -------- ------- --------------- ------------------
|
||||||
|
* IPv4 firewall IPv4 IPv4 IPv4 IPv4
|
||||||
|
* IPv6 firewall IPv6 IPv6 IPv6 IPv6
|
||||||
|
* NAT44 IPv4 IPv4 IPv4 IPv4
|
||||||
|
* NAT46 IPv4 IPv6 IPv4 IPv6
|
||||||
|
* NAT64 IPv6 IPv4 IPv6 IPv4
|
||||||
|
* NPTv6 IPv6 IPv6 IPv6 IPv6
|
||||||
|
*
|
||||||
|
* Address Families with MAP and PEER
|
||||||
|
*
|
||||||
|
* The 'internal' address is implicitly the same as the source IP
|
||||||
|
* address of the PCP request, except when the THIRD_PARTY option is
|
||||||
|
* used.
|
||||||
|
*
|
||||||
|
* The 'external' address is the Suggested External Address field of the
|
||||||
|
* MAP or PEER request, and its address family is usually the same as
|
||||||
|
* the 'internal' address family, except when technologies like NAT64
|
||||||
|
* are used.
|
||||||
|
*
|
||||||
|
* The 'remote peer' address is the remote peer IP address of the PEER
|
||||||
|
* request or the FILTER option of the MAP request, and is always the
|
||||||
|
* same address family as the 'internal' address, even when NAT64 is
|
||||||
|
* used. In NAT64, the IPv6 PCP client is not necessarily aware of the
|
||||||
|
* NAT64 or aware of the actual IPv4 address of the remote peer, so it
|
||||||
|
* expresses the IPv6 address from its perspective. */
|
||||||
|
|
||||||
|
/* TODO : support more scenarios than just NAT44 */
|
||||||
static void CreatePCPMap(pcp_info_t *pcp_msg_info)
|
static void CreatePCPMap(pcp_info_t *pcp_msg_info)
|
||||||
{
|
{
|
||||||
char desc[64];
|
char desc[64];
|
||||||
|
char proto_str[8];
|
||||||
char iaddr_old[INET_ADDRSTRLEN];
|
char iaddr_old[INET_ADDRSTRLEN];
|
||||||
uint16_t iport_old;
|
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;
|
int r=0;
|
||||||
|
|
||||||
if (pcp_msg_info->ext_port == 0) {
|
if (pcp_msg_info->ext_port == 0) {
|
||||||
pcp_msg_info->ext_port = pcp_msg_info->int_port;
|
pcp_msg_info->ext_port = pcp_msg_info->int_port;
|
||||||
}
|
}
|
||||||
do {
|
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,
|
r = get_redirect_rule(ext_if_name,
|
||||||
pcp_msg_info->ext_port,
|
pcp_msg_info->ext_port,
|
||||||
pcp_msg_info->protocol,
|
pcp_msg_info->protocol,
|
||||||
|
@ -827,28 +909,41 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
if (_upnp_delete_redir(pcp_msg_info->ext_port,
|
||||||
pcp_msg_info->protocol)==0) {
|
pcp_msg_info->protocol)==0) {
|
||||||
break;
|
break;
|
||||||
|
} else if (pcp_msg_info->pfailure_present) {
|
||||||
|
pcp_msg_info->result_code = PCP_ERR_CANNOT_PROVIDE_EXTERNAL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pcp_msg_info->ext_port++;
|
pcp_msg_info->ext_port++;
|
||||||
|
if (pcp_msg_info->ext_port == 0) { /* skip port zero */
|
||||||
|
pcp_msg_info->ext_port++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (r==0);
|
} while (r==0);
|
||||||
|
|
||||||
if ((pcp_msg_info->ext_port == 0) ||
|
timestamp = time(NULL) + pcp_msg_info->lifetime;
|
||||||
(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(desc, sizeof(desc), "PCP %hu %s",
|
switch(pcp_msg_info->protocol) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
snprintf(proto_str, sizeof(proto_str), "TCP");
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
snprintf(proto_str, sizeof(proto_str), "UDP");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(proto_str, sizeof(proto_str), "%d", pcp_msg_info->protocol);
|
||||||
|
}
|
||||||
|
snprintf(desc, sizeof(desc), "PCP %hu %s %08x%08x%08x",
|
||||||
pcp_msg_info->ext_port,
|
pcp_msg_info->ext_port,
|
||||||
(pcp_msg_info->protocol==IPPROTO_TCP)?"tcp":"udp");
|
proto_str,
|
||||||
|
pcp_msg_info->nonce[0], pcp_msg_info->nonce[1], pcp_msg_info->nonce[2]);
|
||||||
|
|
||||||
if(upnp_redirect_internal(NULL,
|
if(upnp_redirect_internal(NULL,
|
||||||
pcp_msg_info->ext_port,
|
pcp_msg_info->ext_port,
|
||||||
|
@ -859,15 +954,17 @@ static void CreatePCPMap(pcp_info_t *pcp_msg_info)
|
||||||
timestamp) < 0) {
|
timestamp) < 0) {
|
||||||
|
|
||||||
syslog(LOG_ERR, "PCP MAP: Failed to add mapping %s %hu->%s:%hu '%s'",
|
syslog(LOG_ERR, "PCP MAP: Failed to add mapping %s %hu->%s:%hu '%s'",
|
||||||
(pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP",
|
proto_str,
|
||||||
pcp_msg_info->ext_port,
|
pcp_msg_info->ext_port,
|
||||||
pcp_msg_info->senderaddrstr,
|
pcp_msg_info->senderaddrstr,
|
||||||
pcp_msg_info->int_port,
|
pcp_msg_info->int_port,
|
||||||
desc);
|
desc);
|
||||||
|
|
||||||
|
pcp_msg_info->result_code = PCP_ERR_NO_RESOURCES;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
syslog(LOG_INFO, "PCP MAP: added mapping %s %hu->%s:%hu '%s'",
|
syslog(LOG_INFO, "PCP MAP: added mapping %s %hu->%s:%hu '%s'",
|
||||||
(pcp_msg_info->protocol==IPPROTO_TCP)?"TCP":"UDP",
|
proto_str,
|
||||||
pcp_msg_info->ext_port,
|
pcp_msg_info->ext_port,
|
||||||
pcp_msg_info->senderaddrstr,
|
pcp_msg_info->senderaddrstr,
|
||||||
pcp_msg_info->int_port,
|
pcp_msg_info->int_port,
|
||||||
|
@ -926,7 +1023,8 @@ static int ValidatePCPMsg(pcp_info_t *pcp_msg_info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port !=0 ){
|
/* protocol zero means 'all protocols' : internal port MUST be zero */
|
||||||
|
if (pcp_msg_info->protocol == 0 && pcp_msg_info->int_port != 0) {
|
||||||
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
|
pcp_msg_info->result_code = PCP_ERR_MALFORMED_REQUEST;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -959,9 +1057,8 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
|
||||||
int remainingSize;
|
int remainingSize;
|
||||||
int processedSize;
|
int processedSize;
|
||||||
|
|
||||||
pcp_request_t* common_req;
|
const pcp_map_v1_t* map_v1;
|
||||||
pcp_map_v1_t* map_v1;
|
const pcp_map_v2_t* map_v2;
|
||||||
pcp_map_v2_t* map_v2;
|
|
||||||
#ifdef PCP_PEER
|
#ifdef PCP_PEER
|
||||||
pcp_peer_v1_t* peer_v1;
|
pcp_peer_v1_t* peer_v1;
|
||||||
pcp_peer_v2_t* peer_v2;
|
pcp_peer_v2_t* peer_v2;
|
||||||
|
@ -977,11 +1074,16 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
|
||||||
processedSize = 0;
|
processedSize = 0;
|
||||||
|
|
||||||
/* discard request that exceeds maximal length,
|
/* discard request that exceeds maximal length,
|
||||||
or that is shorter than 3
|
or that is shorter than PCP_MIN_LEN (=24)
|
||||||
or that is not the multiple of 4 */
|
or that is not the multiple of 4 */
|
||||||
if (req_size < PCP_MIN_LEN)
|
if (req_size < 3)
|
||||||
return 0; /* ignore msg */
|
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)) {
|
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 "
|
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);
|
"the size is not multiple of 4.\n", req_size, PCP_MAX_LEN);
|
||||||
|
@ -989,19 +1091,17 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
|
||||||
return 1; /* send response */
|
return 1; /* send response */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* first print out info from common request header */
|
/* first parse request header */
|
||||||
common_req = (pcp_request_t*)req;
|
if (parseCommonRequestHeader((pcp_request_t*)req, pcp_msg_info) ) {
|
||||||
|
|
||||||
if (parseCommonRequestHeader(common_req, pcp_msg_info) ) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingSize -= sizeof(pcp_request_t);
|
remainingSize -= sizeof(pcp_request_t);
|
||||||
processedSize += sizeof(pcp_request_t);
|
processedSize += sizeof(pcp_request_t);
|
||||||
|
|
||||||
if (common_req->ver == 1) {
|
if (pcp_msg_info->version == 1) {
|
||||||
|
/* legacy PCP version 1 support */
|
||||||
switch ( common_req->r_opcode & 0x7F ) {
|
switch (pcp_msg_info->opcode) {
|
||||||
case PCP_OPCODE_MAP:
|
case PCP_OPCODE_MAP:
|
||||||
|
|
||||||
remainingSize -= sizeof(pcp_map_v1_t);
|
remainingSize -= sizeof(pcp_map_v1_t);
|
||||||
|
@ -1077,9 +1177,14 @@ static int processPCPRequest(void * req, int req_size, pcp_info_t *pcp_msg_info)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (common_req->ver == 2) {
|
} else if (pcp_msg_info->version == 2) {
|
||||||
|
/* RFC 6887 PCP support
|
||||||
switch ( common_req->r_opcode & 0x7F) {
|
* http://tools.ietf.org/html/rfc6887 */
|
||||||
|
switch (pcp_msg_info->opcode) {
|
||||||
|
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:
|
case PCP_OPCODE_MAP:
|
||||||
|
|
||||||
remainingSize -= sizeof(pcp_map_v2_t);
|
remainingSize -= sizeof(pcp_map_v2_t);
|
||||||
|
@ -1282,32 +1387,51 @@ static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len,
|
int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len,
|
||||||
struct sockaddr_in *senderaddr)
|
const struct sockaddr * senderaddr)
|
||||||
{
|
{
|
||||||
pcp_info_t pcp_msg_info;
|
pcp_info_t pcp_msg_info;
|
||||||
|
struct lan_addr_s * lan_addr;
|
||||||
|
char addr_str[64];
|
||||||
|
|
||||||
memset(&pcp_msg_info, 0, sizeof(pcp_info_t));
|
memset(&pcp_msg_info, 0, sizeof(pcp_info_t));
|
||||||
|
|
||||||
if(!inet_ntop(AF_INET, &senderaddr->sin_addr,
|
if(senderaddr->sa_family == AF_INET) {
|
||||||
pcp_msg_info.senderaddrstr,
|
const struct sockaddr_in * senderaddr_v4;
|
||||||
sizeof(pcp_msg_info.senderaddrstr))) {
|
senderaddr_v4 = (const struct sockaddr_in *)senderaddr;
|
||||||
syslog(LOG_ERR, "inet_ntop(pcpserver): %m");
|
if(!inet_ntop(AF_INET, &senderaddr_v4->sin_addr,
|
||||||
|
pcp_msg_info.senderaddrstr,
|
||||||
|
sizeof(pcp_msg_info.senderaddrstr))) {
|
||||||
|
syslog(LOG_ERR, "inet_ntop(pcpserver): %m");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
syslog(LOG_DEBUG, "PCP request received from %s:%hu %dbytes",
|
if(sockaddr_to_string(senderaddr, addr_str, sizeof(addr_str)))
|
||||||
pcp_msg_info.senderaddrstr, ntohs(senderaddr->sin_port), len);
|
syslog(LOG_DEBUG, "PCP request received from %s %dbytes",
|
||||||
|
addr_str, len);
|
||||||
|
|
||||||
if(buff[1] & 128) {
|
if(buff[1] & 128) {
|
||||||
/* discarding PCP responses silently */
|
/* discarding PCP responses silently */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lan_addr = get_lan_for_peer(senderaddr);
|
||||||
|
if(lan_addr == NULL) {
|
||||||
|
syslog(LOG_WARNING, "SSDP packet sender %s not from a LAN, ignoring",
|
||||||
|
addr_str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (processPCPRequest(buff, len, &pcp_msg_info) ) {
|
if (processPCPRequest(buff, len, &pcp_msg_info) ) {
|
||||||
|
|
||||||
createPCPResponse(buff, &pcp_msg_info);
|
createPCPResponse(buff, &pcp_msg_info);
|
||||||
|
|
||||||
len = (len + 3) & ~3; /* round up resp. length to multiple of 4 */
|
if(len < PCP_MIN_LEN)
|
||||||
len = sendto(s, buff, len, 0,
|
len = PCP_MIN_LEN;
|
||||||
(struct sockaddr *)senderaddr, sizeof(struct sockaddr_in));
|
else
|
||||||
|
len = (len + 3) & ~3; /* round up resp. length to multiple of 4 */
|
||||||
|
len = sendto_or_schedule(s, buff, len, 0, senderaddr,
|
||||||
|
(senderaddr->sa_family == AF_INET) ?
|
||||||
|
sizeof(struct sockaddr_in) :
|
||||||
|
sizeof(struct sockaddr_in6) );
|
||||||
if( len < 0 ) {
|
if( len < 0 ) {
|
||||||
syslog(LOG_ERR, "sendto(pcpserver): %m");
|
syslog(LOG_ERR, "sendto(pcpserver): %m");
|
||||||
}
|
}
|
||||||
|
@ -1315,4 +1439,44 @@ int ProcessIncomingPCPPacket(int s, unsigned char *buff, int len,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
int OpenAndConfPCPv6Socket(void)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
int i = 1;
|
||||||
|
struct sockaddr_in6 addr;
|
||||||
|
s = socket(PF_INET6, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
|
||||||
|
if(s < 0) {
|
||||||
|
syslog(LOG_ERR, "%s: socket(): %m", "OpenAndConfPCPv6Socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) {
|
||||||
|
syslog(LOG_WARNING, "%s: setsockopt(SO_REUSEADDR): %m",
|
||||||
|
"OpenAndConfPCPv6Socket");
|
||||||
|
}
|
||||||
|
#ifdef IPV6_V6ONLY
|
||||||
|
/* force IPV6 only for IPV6 socket.
|
||||||
|
* see http://www.ietf.org/rfc/rfc3493.txt section 5.3 */
|
||||||
|
if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i)) < 0) {
|
||||||
|
syslog(LOG_WARNING, "%s: setsockopt(IPV6_V6ONLY): %m",
|
||||||
|
"OpenAndConfPCPv6Socket");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(!set_non_blocking(s)) {
|
||||||
|
syslog(LOG_WARNING, "%s: set_non_blocking(): %m",
|
||||||
|
"OpenAndConfPCPv6Socket");
|
||||||
|
}
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin6_family = AF_INET6;
|
||||||
|
addr.sin6_port = htons(NATPMP_PORT);
|
||||||
|
addr.sin6_addr = in6addr_any;
|
||||||
|
if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
|
syslog(LOG_ERR, "%s: bind(): %m", "OpenAndConfPCPv6Socket");
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
#endif /*ENABLE_IPV6*/
|
||||||
#endif /*ENABLE_PCP*/
|
#endif /*ENABLE_PCP*/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: pcpserver.h,v 1.2 2013/12/13 15:48:39 nanard Exp $ */
|
/* $Id: pcpserver.h,v 1.3 2014/03/24 10:49:46 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* Website : http://miniupnp.free.fr/
|
* Website : http://miniupnp.free.fr/
|
||||||
* Author : Peter Tatrai
|
* Author : Peter Tatrai
|
||||||
|
@ -36,12 +36,17 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define PCP_MIN_LEN 24
|
#define PCP_MIN_LEN 24
|
||||||
#define PCP_MAX_LEN 1100
|
#define PCP_MAX_LEN 1100
|
||||||
|
|
||||||
struct sockaddr_in;
|
struct sockaddr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns 0 upon success 1 otherwise
|
* 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);
|
const struct sockaddr *senderaddr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns the socket
|
||||||
|
*/
|
||||||
|
int OpenAndConfPCPv6Socket(void);
|
||||||
|
|
||||||
#endif /* PCPSERVER_H_INCLUDED */
|
#endif /* PCPSERVER_H_INCLUDED */
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -9,15 +9,19 @@
|
||||||
* pf rules created (with ext_if = xl1)
|
* pf rules created (with ext_if = xl1)
|
||||||
* - OpenBSD up to version 4.6 :
|
* - OpenBSD up to version 4.6 :
|
||||||
* rdr pass on xl1 inet proto udp from any to any port = 54321 \
|
* rdr pass on xl1 inet proto udp from any to any port = 54321 \
|
||||||
* label "test label" -> 192.168.0.141 port 12345
|
* keep state label "test label" -> 192.168.0.42 port 12345
|
||||||
* or a rdr rule + a pass rule
|
* 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
|
* - OpenBSD starting from version 4.7
|
||||||
* match in on xl1 inet proto udp from any to any port 54321 \
|
* 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
|
* or
|
||||||
* pass in quick on xl1 inet proto udp from any to any port 54321 \
|
* 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
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -176,6 +180,45 @@ clear_redirect_rules(void)
|
||||||
error:
|
error:
|
||||||
return -1;
|
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
|
#endif
|
||||||
|
|
||||||
/* add_redirect_rule2() :
|
/* add_redirect_rule2() :
|
||||||
|
@ -347,8 +390,11 @@ add_filter_rule2(const char * ifname,
|
||||||
struct pfioc_rule pcr;
|
struct pfioc_rule pcr;
|
||||||
#ifndef PF_NEWSTYLE
|
#ifndef PF_NEWSTYLE
|
||||||
struct pfioc_pooladdr pp;
|
struct pfioc_pooladdr pp;
|
||||||
struct pf_pooladdr *a;
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef USE_IFNAME_IN_RULES
|
||||||
|
UNUSED(ifname);
|
||||||
|
#endif
|
||||||
|
UNUSED(eport);
|
||||||
if(dev<0) {
|
if(dev<0) {
|
||||||
syslog(LOG_ERR, "pf device is not open");
|
syslog(LOG_ERR, "pf device is not open");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -372,9 +418,8 @@ add_filter_rule2(const char * ifname,
|
||||||
if(1)
|
if(1)
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pcr.rule.dst.port_op = PF_OP_EQ;
|
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.direction = PF_IN;
|
||||||
pcr.rule.action = PF_PASS;
|
pcr.rule.action = PF_PASS;
|
||||||
pcr.rule.af = AF_INET;
|
pcr.rule.af = AF_INET;
|
||||||
|
@ -407,33 +452,16 @@ add_filter_rule2(const char * ifname,
|
||||||
inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
|
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);
|
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 */
|
/* we want any - iaddr port = # keep state label */
|
||||||
/* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */
|
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);
|
||||||
memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
|
#ifndef PF_NEWSTYLE
|
||||||
strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
|
pcr.rule.rpool.proxy_port[0] = iport;
|
||||||
if(ioctl(dev, DIOCADDADDR, &pp) < 0)
|
pcr.rule.rpool.proxy_port[1] = iport;
|
||||||
{
|
TAILQ_INIT(&pcr.rule.rpool.list);
|
||||||
syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
|
#endif
|
||||||
r = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#else
|
|
||||||
if(1)
|
if(1)
|
||||||
{
|
{
|
||||||
#endif
|
|
||||||
pcr.action = PF_CHANGE_GET_TICKET;
|
pcr.action = PF_CHANGE_GET_TICKET;
|
||||||
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
|
if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
|
||||||
{
|
{
|
||||||
|
@ -450,9 +478,6 @@ add_filter_rule2(const char * ifname,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifndef PF_NEWSTYLE
|
|
||||||
free(a);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
#endif
|
#endif
|
||||||
|
@ -575,8 +600,10 @@ error:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
|
priv_delete_redirect_rule(const char * ifname, unsigned short eport,
|
||||||
|
int proto, unsigned short * iport,
|
||||||
|
in_addr_t * iaddr)
|
||||||
{
|
{
|
||||||
int i, n;
|
int i, n;
|
||||||
struct pfioc_rule pr;
|
struct pfioc_rule pr;
|
||||||
|
@ -614,6 +641,44 @@ delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
|
||||||
#endif
|
#endif
|
||||||
&& (pr.rule.proto == proto) )
|
&& (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;
|
pr.action = PF_CHANGE_GET_TICKET;
|
||||||
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
||||||
{
|
{
|
||||||
|
@ -636,14 +701,23 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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
|
#ifndef PF_ENABLE_FILTER_RULES
|
||||||
UNUSED(ifname); UNUSED(eport); UNUSED(proto);
|
UNUSED(ifname); UNUSED(iport); UNUSED(proto);
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
int i, n;
|
int i, n;
|
||||||
struct pfioc_rule pr;
|
struct pfioc_rule pr;
|
||||||
|
UNUSED(ifname);
|
||||||
if(dev<0) {
|
if(dev<0) {
|
||||||
syslog(LOG_ERR, "pf device is not open");
|
syslog(LOG_ERR, "pf device is not open");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -665,8 +739,16 @@ delete_filter_rule(const char * ifname, unsigned short eport, int proto)
|
||||||
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
|
syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if( (eport == ntohs(pr.rule.dst.port[0]))
|
#ifdef TEST
|
||||||
&& (pr.rule.proto == proto) )
|
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;
|
pr.action = PF_CHANGE_GET_TICKET;
|
||||||
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
|
||||||
|
@ -689,6 +771,21 @@ error:
|
||||||
#endif
|
#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
|
int
|
||||||
get_redirect_rule_by_index(int index,
|
get_redirect_rule_by_index(int index,
|
||||||
char * ifname, unsigned short * eport,
|
char * ifname, unsigned short * eport,
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -52,13 +52,18 @@ get_redirect_rule_by_index(int index,
|
||||||
int
|
int
|
||||||
delete_redirect_rule(const char * ifname, unsigned short eport, int proto);
|
delete_redirect_rule(const char * ifname, unsigned short eport, int proto);
|
||||||
|
|
||||||
/* delete_filter_rule()
|
/* delete_redirect_and_filter_rules()
|
||||||
*/
|
*/
|
||||||
int
|
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
|
int
|
||||||
clear_redirect_rules(void);
|
clear_redirect_rules(void);
|
||||||
|
int
|
||||||
|
clear_filter_rules(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
int runtime_flags = 0;
|
int runtime_flags = 0;
|
||||||
const char * tag = 0;
|
const char * tag = 0;
|
||||||
const char * anchor_name = "miniupnpd";
|
const char * anchor_name = "miniupnpd";
|
||||||
|
const char * queue = NULL;
|
||||||
|
|
||||||
void
|
void
|
||||||
list_rules(void);
|
list_rules(void);
|
||||||
|
@ -67,7 +69,7 @@ test_index(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int arc, char * * argv)
|
main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
char desc[64];
|
char desc[64];
|
||||||
|
@ -77,6 +79,12 @@ main(int arc, char * * argv)
|
||||||
unsigned int timestamp;
|
unsigned int timestamp;
|
||||||
u_int64_t packets = 0;
|
u_int64_t packets = 0;
|
||||||
u_int64_t bytes = 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);
|
openlog("testobsdrdr", LOG_PERROR, LOG_USER);
|
||||||
if(init_redirect() < 0)
|
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_rule("ep0", 12123, "192.168.1.23", 1234);
|
||||||
add_redirect_rule2("ep0", 12155, "192.168.1.155", 1255, IPPROTO_TCP);
|
add_redirect_rule2("ep0", 12155, "192.168.1.155", 1255, IPPROTO_TCP);
|
||||||
#endif
|
#endif
|
||||||
add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234,
|
if(add_redirect_rule2("ep0", "8.8.8.8", 12123, "192.168.1.125", 1234,
|
||||||
IPPROTO_UDP, "test description", 0);
|
IPPROTO_UDP, "test description", 0) < 0)
|
||||||
#if 0
|
printf("add_redirect_rule2() #3 failed\n");
|
||||||
add_redirect_rule2("em0", 12123, "127.1.2.3", 1234,
|
if(add_redirect_rule2("em0", NULL, 12123, "127.1.2.3", 1234,
|
||||||
IPPROTO_TCP, "test description tcp");
|
IPPROTO_TCP, "test description tcp", 0) < 0)
|
||||||
#endif
|
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_rules();
|
||||||
list_eports_tcp();
|
list_eports_tcp();
|
||||||
|
@ -113,20 +124,20 @@ main(int arc, char * * argv)
|
||||||
|
|
||||||
if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0)
|
if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0)
|
||||||
printf("delete_redirect_rule() failed\n");
|
printf("delete_redirect_rule() failed\n");
|
||||||
else
|
|
||||||
printf("delete_redirect_rule() succeded\n");
|
|
||||||
|
|
||||||
if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0)
|
if(delete_redirect_rule("ep0", 12123, IPPROTO_UDP) < 0)
|
||||||
printf("delete_redirect_rule() failed\n");
|
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();
|
test_index();
|
||||||
|
|
||||||
clear_redirect_rules();
|
if(clear) {
|
||||||
list_rules();
|
clear_redirect_rules();
|
||||||
#endif
|
clear_filter_rules();
|
||||||
|
}
|
||||||
|
/*list_rules();*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ const char * tag = NULL;
|
||||||
const char * anchor_name = "miniupnpd";
|
const char * anchor_name = "miniupnpd";
|
||||||
const char * queue = NULL;
|
const char * queue = NULL;
|
||||||
|
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
static int print_pinhole(int uid)
|
static int print_pinhole(int uid)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
@ -32,11 +33,11 @@ static int print_pinhole(int uid)
|
||||||
unsigned int timestamp;
|
unsigned int timestamp;
|
||||||
u_int64_t packets, bytes;
|
u_int64_t packets, bytes;
|
||||||
|
|
||||||
r = get_pinhole((unsigned short)uid,
|
r = get_pinhole_info((unsigned short)uid,
|
||||||
rem_host, sizeof(rem_host), &rem_port,
|
rem_host, sizeof(rem_host), &rem_port,
|
||||||
int_client, sizeof(int_client), &int_port,
|
int_client, sizeof(int_client), &int_port,
|
||||||
&proto, ×tamp,
|
&proto, ×tamp,
|
||||||
&packets, &bytes);
|
&packets, &bytes);
|
||||||
if(r < 0) {
|
if(r < 0) {
|
||||||
fprintf(stderr, "get_pinhole(%d) returned %d\n", uid, r);
|
fprintf(stderr, "get_pinhole(%d) returned %d\n", uid, r);
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,6 +48,7 @@ static int print_pinhole(int uid)
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char * *argv)
|
int main(int argc, char * *argv)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,401 @@
|
||||||
|
/* $Id: $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* (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 */
|
||||||
|
|
||||||
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#if defined(__OpenBSD__)
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <kvm.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <nlist.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <net/route.h>
|
||||||
|
#include <netinet/in_systm.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/in_pcb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
/* sys/socketvar.h must be included above the following headers */
|
||||||
|
#include <netinet/in_pcb.h>
|
||||||
|
#include <netinet/tcp_var.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "upnpglobalvars.h"
|
||||||
|
#include "getifaddr.h"
|
||||||
|
#include "portinuse.h"
|
||||||
|
|
||||||
|
#if defined(USE_NETFILTER)
|
||||||
|
#include "netfilter/iptcrdr.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CHECK_PORTINUSE
|
||||||
|
|
||||||
|
#if defined(USE_NETFILTER)
|
||||||
|
/* Hardcoded for now. Ideally would come from .conf file */
|
||||||
|
char *chains_to_check[] = { "PREROUTING" , 0 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
port_in_use(const char *if_name,
|
||||||
|
unsigned eport, int proto,
|
||||||
|
const char *iaddr, unsigned iport)
|
||||||
|
{
|
||||||
|
int found = 0;
|
||||||
|
char ip_addr_str[INET_ADDRSTRLEN];
|
||||||
|
struct in_addr ip_addr;
|
||||||
|
#ifdef __linux__
|
||||||
|
/* linux code */
|
||||||
|
char line[256];
|
||||||
|
FILE *f;
|
||||||
|
const char * tcpfile = "/proc/net/tcp";
|
||||||
|
const char * udpfile = "/proc/net/udp";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(getifaddr(if_name, ip_addr_str, INET_ADDRSTRLEN, &ip_addr, NULL) < 0)
|
||||||
|
ip_addr.s_addr = 0;
|
||||||
|
|
||||||
|
syslog(LOG_DEBUG, "Check protocol %s for port %d on ext_if %s %s, %08X",
|
||||||
|
(proto==IPPROTO_TCP)?"tcp":"udp", eport, if_name,
|
||||||
|
ip_addr_str, (unsigned)ip_addr.s_addr);
|
||||||
|
|
||||||
|
/* Phase 1 : check for local sockets (would be listed by netstat) */
|
||||||
|
#if defined(__linux__)
|
||||||
|
f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r");
|
||||||
|
if (!f) {
|
||||||
|
syslog(LOG_ERR, "cannot open %s", (proto==IPPROTO_TCP)?tcpfile:udpfile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(line, 255, f)) {
|
||||||
|
char eaddr[68];
|
||||||
|
unsigned tmp_port;
|
||||||
|
if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x "
|
||||||
|
"%*x:%*x %*x %*d %*d %*llu",
|
||||||
|
eaddr, &tmp_port) == 2
|
||||||
|
) {
|
||||||
|
/* TODO add IPV6 support if enabled
|
||||||
|
* Presently assumes IPV4 */
|
||||||
|
#ifdef DEBUG
|
||||||
|
syslog(LOG_DEBUG, "port_in_use check port %d and address %s", tmp_port, eaddr);
|
||||||
|
#endif
|
||||||
|
if (tmp_port == eport) {
|
||||||
|
char tmp_addr[4];
|
||||||
|
struct in_addr *tmp_ip_addr = (struct in_addr *)tmp_addr;
|
||||||
|
if (sscanf(eaddr,"%2hhx%2hhx%2hhx%2hhx",
|
||||||
|
&tmp_addr[3],&tmp_addr[2],&tmp_addr[1],&tmp_addr[0]) == 4)
|
||||||
|
{
|
||||||
|
if (tmp_ip_addr->s_addr == 0 || tmp_ip_addr->s_addr == ip_addr.s_addr)
|
||||||
|
{
|
||||||
|
found++;
|
||||||
|
break; /* don't care how many, just that we found at least one */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
static struct nlist list[] = {
|
||||||
|
#if 0
|
||||||
|
{"_tcpstat", 0, 0, 0, 0},
|
||||||
|
{"_udpstat", 0, 0, 0, 0},
|
||||||
|
{"_tcbinfo", 0, 0, 0, 0},
|
||||||
|
{"_udbinfo", 0, 0, 0, 0},
|
||||||
|
#endif
|
||||||
|
{"_tcbtable", 0, 0, 0, 0},
|
||||||
|
{"_udbtable", 0, 0, 0, 0},
|
||||||
|
{NULL,0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
char errstr[_POSIX2_LINE_MAX];
|
||||||
|
kvm_t *kd;
|
||||||
|
ssize_t n;
|
||||||
|
struct inpcbtable table;
|
||||||
|
struct inpcb *next;
|
||||||
|
struct inpcb inpcb;
|
||||||
|
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr);
|
||||||
|
if(!kd) {
|
||||||
|
syslog(LOG_ERR, "%s: kvm_openfiles(): %s",
|
||||||
|
"portinuse()", errstr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(kvm_nlist(kd, list) < 0) {
|
||||||
|
syslog(LOG_ERR, "%s: kvm_nlist(): %s",
|
||||||
|
"portinuse()", kvm_geterr(kd));
|
||||||
|
kvm_close(kd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = kvm_read(kd, list[(proto==IPPROTO_TCP)?0:1].n_value, &table, sizeof(table));
|
||||||
|
if(n < 0) {
|
||||||
|
syslog(LOG_ERR, "%s: kvm_read(): %s",
|
||||||
|
"portinuse()", kvm_geterr(kd));
|
||||||
|
kvm_close(kd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
next = CIRCLEQ_FIRST(&table.inpt_queue); /*TAILQ_FIRST(&table.inpt_queue);*/
|
||||||
|
while(next != NULL) {
|
||||||
|
if(((u_long)next & 3) != 0) break;
|
||||||
|
n = kvm_read(kd, (u_long)next, &inpcb, sizeof(inpcb));
|
||||||
|
if(n < 0) {
|
||||||
|
syslog(LOG_ERR, "kvm_read(): %s", kvm_geterr(kd));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next = CIRCLEQ_NEXT(&inpcb, inp_queue); /*TAILQ_NEXT(&inpcb, inp_queue);*/
|
||||||
|
/* skip IPv6 sockets */
|
||||||
|
if((inpcb.inp_flags & INP_IPV6) != 0)
|
||||||
|
continue;
|
||||||
|
#ifdef DEBUG
|
||||||
|
syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu",
|
||||||
|
(u_long)inpcb.inp_laddr.s_addr, ntohs(inpcb.inp_lport),
|
||||||
|
(u_long)inpcb.inp_faddr.s_addr, ntohs(inpcb.inp_fport));
|
||||||
|
#endif
|
||||||
|
if(eport == (unsigned)ntohs(inpcb.inp_lport)) {
|
||||||
|
if(inpcb.inp_laddr.s_addr == INADDR_ANY || inpcb.inp_laddr.s_addr == ip_addr.s_addr) {
|
||||||
|
found++;
|
||||||
|
break; /* don't care how many, just that we found at least one */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kvm_close(kd);
|
||||||
|
|
||||||
|
#elif defined(__DragonFly__)
|
||||||
|
const char *varname;
|
||||||
|
struct xinpcb *xip;
|
||||||
|
struct xtcpcb *xtp;
|
||||||
|
struct inpcb *inp;
|
||||||
|
void *buf = NULL;
|
||||||
|
void *so_begin, *so_end;
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
switch (proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
varname = "net.inet.tcp.pcblist";
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
varname = "net.inet.udp.pcblist";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sysctlbyname(varname, NULL, &len, NULL, 0) < 0) {
|
||||||
|
syslog(LOG_ERR, "sysctlbyname(%s, NULL, ...): %m", varname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf = malloc(len);
|
||||||
|
if (buf == NULL) {
|
||||||
|
syslog(LOG_ERR, "malloc(%u) failed", (unsigned)len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sysctlbyname(varname, buf, &len, NULL, 0) < 0) {
|
||||||
|
syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
so_begin = buf;
|
||||||
|
so_end = (uint8_t *)buf + len;
|
||||||
|
for (so_begin = buf, so_end = (uint8_t *)so_begin + len;
|
||||||
|
(uint8_t *)so_begin + sizeof(size_t) < (uint8_t *)so_end &&
|
||||||
|
(uint8_t *)so_begin + *(size_t *)so_begin <= (uint8_t *)so_end;
|
||||||
|
so_begin = (uint8_t *)so_begin + *(size_t *)so_begin) {
|
||||||
|
switch (proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
xtp = (struct xtcpcb *)so_begin;
|
||||||
|
if (xtp->xt_len != sizeof *xtp) {
|
||||||
|
syslog(LOG_WARNING, "struct xtcpcb size mismatch; %ld vs %ld",
|
||||||
|
(long)xtp->xt_len, sizeof *xtp);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
inp = &xtp->xt_inp;
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
xip = (struct xinpcb *)so_begin;
|
||||||
|
if (xip->xi_len != sizeof *xip) {
|
||||||
|
syslog(LOG_WARNING, "struct xinpcb size mismatch : %ld vs %ld",
|
||||||
|
(long)xip->xi_len, sizeof *xip);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
inp = &xip->xi_inp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
/* no support for IPv6 */
|
||||||
|
if ((inp->inp_vflag & INP_IPV6) != 0)
|
||||||
|
continue;
|
||||||
|
syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu",
|
||||||
|
(u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport),
|
||||||
|
(u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport),
|
||||||
|
eport, (u_long)ip_addr.s_addr, iport
|
||||||
|
);
|
||||||
|
if (eport == (unsigned)ntohs(inp->inp_lport)) {
|
||||||
|
if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) {
|
||||||
|
found++;
|
||||||
|
break; /* don't care how many, just that we found at least one */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf) {
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
const char *varname;
|
||||||
|
struct xinpgen *xig, *exig;
|
||||||
|
struct xinpcb *xip;
|
||||||
|
struct xtcpcb *xtp;
|
||||||
|
struct inpcb *inp;
|
||||||
|
void *buf = NULL;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
switch (proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
varname = "net.inet.tcp.pcblist";
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
varname = "net.inet.udp.pcblist";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sysctlbyname(varname, NULL, &len, NULL, 0) < 0) {
|
||||||
|
syslog(LOG_ERR, "sysctlbyname(%s, NULL, ...): %m", varname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buf = malloc(len);
|
||||||
|
if (buf == NULL) {
|
||||||
|
syslog(LOG_ERR, "malloc(%u) failed", (unsigned)len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (sysctlbyname(varname, buf, &len, NULL, 0) < 0) {
|
||||||
|
syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xig = (struct xinpgen *)buf;
|
||||||
|
exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig);
|
||||||
|
if (xig->xig_len != sizeof *xig) {
|
||||||
|
syslog(LOG_WARNING, "struct xinpgen size mismatch; %ld vs %ld",
|
||||||
|
(long)xig->xig_len, sizeof *xig);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (exig->xig_len != sizeof *exig) {
|
||||||
|
syslog(LOG_WARNING, "struct xinpgen size mismatch; %ld vs %ld",
|
||||||
|
(long)exig->xig_len, sizeof *exig);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
|
||||||
|
if (xig >= exig)
|
||||||
|
break;
|
||||||
|
switch (proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
xtp = (struct xtcpcb *)xig;
|
||||||
|
if (xtp->xt_len != sizeof *xtp) {
|
||||||
|
syslog(LOG_WARNING, "struct xtcpcb size mismatch; %ld vs %ld",
|
||||||
|
(long)xtp->xt_len, sizeof *xtp);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
inp = &xtp->xt_inp;
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
xip = (struct xinpcb *)xig;
|
||||||
|
if (xip->xi_len != sizeof *xip) {
|
||||||
|
syslog(LOG_WARNING, "struct xinpcb size mismatch : %ld vs %ld",
|
||||||
|
(long)xip->xi_len, sizeof *xip);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
inp = &xip->xi_inp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
/* no support for IPv6 */
|
||||||
|
if ((inp->inp_vflag & INP_IPV6) != 0)
|
||||||
|
continue;
|
||||||
|
syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu",
|
||||||
|
(u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport),
|
||||||
|
(u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport),
|
||||||
|
eport, (u_long)ip_addr.s_addr, iport
|
||||||
|
);
|
||||||
|
if (eport == (unsigned)ntohs(inp->inp_lport)) {
|
||||||
|
if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) {
|
||||||
|
found++;
|
||||||
|
break; /* don't care how many, just that we found at least one */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf) {
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
/* #elif __NetBSD__ */
|
||||||
|
#else
|
||||||
|
/* TODO : NetBSD / Darwin (OS X) / Solaris code */
|
||||||
|
#error "No port_in_use() implementation available for this OS"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Phase 2 : check existing mappings
|
||||||
|
* TODO : implement for pf/ipfw/etc. */
|
||||||
|
#if defined(USE_NETFILTER)
|
||||||
|
if (!found) {
|
||||||
|
char iaddr_old[16];
|
||||||
|
unsigned short iport_old;
|
||||||
|
int i;
|
||||||
|
for (i = 0; chains_to_check[i]; i++) {
|
||||||
|
if (get_nat_redirect_rule(chains_to_check[i], if_name, eport, proto,
|
||||||
|
iaddr_old, sizeof(iaddr_old), &iport_old,
|
||||||
|
0, 0, 0, 0, 0, 0, 0) == 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_DEBUG, "port_in_use check port %d on nat chain %s redirected to %s port %d", eport,
|
||||||
|
chains_to_check[i], iaddr_old, iport_old);
|
||||||
|
if (!(strcmp(iaddr, iaddr_old)==0 && iport==iport_old)) {
|
||||||
|
/* only "in use" if redirected to somewhere else */
|
||||||
|
found++;
|
||||||
|
break; /* don't care how many, just that we found at least one */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else /* USE_NETFILTER */
|
||||||
|
UNUSED(iport); UNUSED(iaddr);
|
||||||
|
#endif /* USE_NETFILTER */
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
#endif /* CHECK_PORTINUSE */
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* $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 __PORTINUSE_H__
|
||||||
|
#define __PORTINUSE_H__
|
||||||
|
|
||||||
|
#ifdef CHECK_PORTINUSE
|
||||||
|
/* portinuse()
|
||||||
|
* determine wether a port is already in use
|
||||||
|
* on a given interface.
|
||||||
|
* returns: 0 not in use, > 0 in use
|
||||||
|
* -1 in case of error */
|
||||||
|
int
|
||||||
|
port_in_use(const char *if_name,
|
||||||
|
unsigned port, int proto,
|
||||||
|
const char *iaddr, unsigned iport);
|
||||||
|
#endif /* CHECK_PORTINUSE */
|
||||||
|
|
||||||
|
#endif
|
|
@ -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 <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#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, (long)next_send.tv_sec, (long)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, (long)timeout.tv_sec, (long)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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: testgetifaddr.c,v 1.7 2013/04/27 15:38:57 nanard Exp $ */
|
/* $Id: testgetifaddr.c,v 1.7 2013/04/27 15:38:57 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include "config.h"
|
||||||
#include "getifaddr.h"
|
#include "getifaddr.h"
|
||||||
|
|
||||||
#if defined(__sun)
|
#if defined(__sun)
|
||||||
|
@ -21,6 +22,10 @@ int main(int argc, char * * argv) {
|
||||||
char str_addr[64];
|
char str_addr[64];
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
struct in_addr mask;
|
struct in_addr mask;
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
int r;
|
||||||
|
char str_addr6[64];
|
||||||
|
#endif
|
||||||
if(argc < 2) {
|
if(argc < 2) {
|
||||||
fprintf(stderr, "Usage:\t%s interface_name\n", argv[0]);
|
fprintf(stderr, "Usage:\t%s interface_name\n", argv[0]);
|
||||||
return 1;
|
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("Interface %s has IP address %s.\n", argv[1], str_addr);
|
||||||
printf("addr=%s ", inet_ntoa(addr));
|
printf("addr=%s ", inet_ntoa(addr));
|
||||||
printf("mask=%s\n", inet_ntoa(mask));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/* $Id: testportinuse.c,v 1.3 2014/03/28 12:13:17 nanard Exp $ */
|
||||||
|
/* MiniUPnP project
|
||||||
|
* (c) 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 */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "portinuse.h"
|
||||||
|
|
||||||
|
#ifdef USE_NETFILTER
|
||||||
|
const char * miniupnpd_nat_chain = "MINIUPNPD";
|
||||||
|
const char * miniupnpd_peer_chain = "MINIUPNPD-PCP-PEER";
|
||||||
|
const char * miniupnpd_forward_chain = "MINIUPNPD";
|
||||||
|
#endif /* USE_NETFILTER */
|
||||||
|
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
#ifndef CHECK_PORTINUSE
|
||||||
|
UNUSED(argc); UNUSED(argv);
|
||||||
|
printf("CHECK_PORTINUSE is not defined.\n");
|
||||||
|
#else /* CHECK_PORTINUSE */
|
||||||
|
int r;
|
||||||
|
const char * if_name;
|
||||||
|
unsigned eport;
|
||||||
|
int proto;
|
||||||
|
const char * iaddr;
|
||||||
|
unsigned iport;
|
||||||
|
|
||||||
|
if(argc <= 5) {
|
||||||
|
fprintf(stderr, "usage: %s if_name eport (tcp|udp) iaddr iport\n",
|
||||||
|
argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
openlog("testportinuse", LOG_CONS|LOG_PERROR, LOG_USER);
|
||||||
|
if_name = argv[1];
|
||||||
|
eport = (unsigned)atoi(argv[2]);
|
||||||
|
proto = (0==strcmp(argv[3], "tcp"))?IPPROTO_TCP:IPPROTO_UDP;
|
||||||
|
iaddr = argv[4];
|
||||||
|
iport = (unsigned)atoi(argv[5]);
|
||||||
|
|
||||||
|
r = port_in_use(if_name, eport, proto, iaddr, iport);
|
||||||
|
printf("port_in_use(%s, %u, %d, %s, %u) returned %d\n",
|
||||||
|
if_name, eport, proto, iaddr, iport, r);
|
||||||
|
closelog();
|
||||||
|
#endif /* CHECK_PORTINUSE */
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -38,10 +38,7 @@ char model_url[] = ROOTDEV_MODELURL;
|
||||||
char * use_ext_ip_addr = NULL;
|
char * use_ext_ip_addr = NULL;
|
||||||
const char * ext_if_name = "eth0";
|
const char * ext_if_name = "eth0";
|
||||||
|
|
||||||
#ifdef ENABLE_6FC_SERVICE
|
int runtime_flags = 0;
|
||||||
int ipv6fc_firewall_enabled = 1;
|
|
||||||
int ipv6fc_inbound_pinhole_allowed = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int getifaddr(const char * ifname, char * buf, int len, struct in_addr * addr, struct in_addr * mask)
|
int getifaddr(const char * ifname, char * buf, int len, struct in_addr * addr, struct in_addr * mask)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -1176,13 +1176,13 @@ genEventVars(int * len, const struct serviceDesc * s)
|
||||||
case FIREWALLENABLED_MAGICALVALUE:
|
case FIREWALLENABLED_MAGICALVALUE:
|
||||||
/* see 2.4.2 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
|
/* see 2.4.2 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
|
||||||
snprintf(tmp, sizeof(tmp), "%d",
|
snprintf(tmp, sizeof(tmp), "%d",
|
||||||
ipv6fc_firewall_enabled);
|
GETFLAG(IPV6FCFWDISABLEDMASK) ? 0 : 1);
|
||||||
str = strcat_str(str, len, &tmplen, tmp);
|
str = strcat_str(str, len, &tmplen, tmp);
|
||||||
break;
|
break;
|
||||||
case INBOUNDPINHOLEALLOWED_MAGICALVALUE:
|
case INBOUNDPINHOLEALLOWED_MAGICALVALUE:
|
||||||
/* see 2.4.3 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
|
/* see 2.4.3 of UPnP-gw-WANIPv6FirewallControl-v1-Service.pdf */
|
||||||
snprintf(tmp, sizeof(tmp), "%d",
|
snprintf(tmp, sizeof(tmp), "%d",
|
||||||
ipv6fc_inbound_pinhole_allowed);
|
GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK) ? 0 : 1);
|
||||||
str = strcat_str(str, len, &tmplen, tmp);
|
str = strcat_str(str, len, &tmplen, tmp);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: upnpevents.c,v 1.27 2013/06/13 13:21:30 nanard Exp $ */
|
/* $Id: upnpevents.c,v 1.30 2014/03/14 22:26:07 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2008-2013 Thomas Bernard
|
* (c) 2008-2014 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -149,6 +149,11 @@ renewSubscription(const char * sid, int sidlen, int timeout)
|
||||||
struct subscriber * sub;
|
struct subscriber * sub;
|
||||||
for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
|
for(sub = subscriberlist.lh_first; sub != NULL; sub = sub->entries.le_next) {
|
||||||
if((sidlen == 41) && (memcmp(sid, sub->uuid, 41) == 0)) {
|
if((sidlen == 41) && (memcmp(sid, sub->uuid, 41) == 0)) {
|
||||||
|
#ifdef UPNP_STRICT
|
||||||
|
/* check if the subscription already timeouted */
|
||||||
|
if(sub->timeout && time(NULL) > sub->timeout)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
sub->timeout = (timeout ? time(NULL) + timeout : 0);
|
sub->timeout = (timeout ? time(NULL) + timeout : 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -192,6 +197,7 @@ static void
|
||||||
upnp_event_create_notify(struct subscriber * sub)
|
upnp_event_create_notify(struct subscriber * sub)
|
||||||
{
|
{
|
||||||
struct upnp_event_notify * obj;
|
struct upnp_event_notify * obj;
|
||||||
|
/*struct timeval sock_timeout;*/
|
||||||
|
|
||||||
obj = calloc(1, sizeof(struct upnp_event_notify));
|
obj = calloc(1, sizeof(struct upnp_event_notify));
|
||||||
if(!obj) {
|
if(!obj) {
|
||||||
|
@ -210,6 +216,22 @@ upnp_event_create_notify(struct subscriber * sub)
|
||||||
syslog(LOG_ERR, "%s: socket(): %m", "upnp_event_create_notify");
|
syslog(LOG_ERR, "%s: socket(): %m", "upnp_event_create_notify");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
#if 0 /* does not work for non blocking connect() */
|
||||||
|
/* set timeout to 3 seconds */
|
||||||
|
sock_timeout.tv_sec = 3;
|
||||||
|
sock_timeout.tv_usec = 0;
|
||||||
|
if(setsockopt(obj->s, SOL_SOCKET, SO_RCVTIMEO, &sock_timeout, sizeof(struct timeval)) < 0) {
|
||||||
|
syslog(LOG_WARNING, "%s: setsockopt(SO_RCVTIMEO): %m",
|
||||||
|
"upnp_event_create_notify");
|
||||||
|
}
|
||||||
|
sock_timeout.tv_sec = 3;
|
||||||
|
sock_timeout.tv_usec = 0;
|
||||||
|
if(setsockopt(obj->s, SOL_SOCKET, SO_SNDTIMEO, &sock_timeout, sizeof(struct timeval)) < 0) {
|
||||||
|
syslog(LOG_WARNING, "%s: setsockopt(SO_SNDTIMEO): %m",
|
||||||
|
"upnp_event_create_notify");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* set socket non blocking */
|
||||||
if(!set_non_blocking(obj->s)) {
|
if(!set_non_blocking(obj->s)) {
|
||||||
syslog(LOG_ERR, "%s: set_non_blocking(): %m",
|
syslog(LOG_ERR, "%s: set_non_blocking(): %m",
|
||||||
"upnp_event_create_notify");
|
"upnp_event_create_notify");
|
||||||
|
@ -233,9 +255,12 @@ upnp_event_notify_connect(struct upnp_event_notify * obj)
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
|
socklen_t addrlen;
|
||||||
#else
|
#else
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
|
socklen_t addrlen;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!obj)
|
if(!obj)
|
||||||
return;
|
return;
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
@ -283,23 +308,28 @@ upnp_event_notify_connect(struct upnp_event_notify * obj)
|
||||||
sa->sin6_family = AF_INET6;
|
sa->sin6_family = AF_INET6;
|
||||||
inet_pton(AF_INET6, obj->addrstr, &(sa->sin6_addr));
|
inet_pton(AF_INET6, obj->addrstr, &(sa->sin6_addr));
|
||||||
sa->sin6_port = htons(port);
|
sa->sin6_port = htons(port);
|
||||||
|
addrlen = sizeof(struct sockaddr_in6);
|
||||||
} else {
|
} else {
|
||||||
struct sockaddr_in * sa = (struct sockaddr_in *)&addr;
|
struct sockaddr_in * sa = (struct sockaddr_in *)&addr;
|
||||||
sa->sin_family = AF_INET;
|
sa->sin_family = AF_INET;
|
||||||
inet_pton(AF_INET, obj->addrstr, &(sa->sin_addr));
|
inet_pton(AF_INET, obj->addrstr, &(sa->sin_addr));
|
||||||
sa->sin_port = htons(port);
|
sa->sin_port = htons(port);
|
||||||
|
addrlen = sizeof(struct sockaddr_in);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
inet_aton(obj->addrstr, &addr.sin_addr);
|
inet_aton(obj->addrstr, &addr.sin_addr);
|
||||||
addr.sin_port = htons(port);
|
addr.sin_port = htons(port);
|
||||||
|
addrlen = sizeof(struct sockaddr_in);
|
||||||
#endif
|
#endif
|
||||||
syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect",
|
syslog(LOG_DEBUG, "%s: '%s' %hu '%s'", "upnp_event_notify_connect",
|
||||||
obj->addrstr, port, obj->path);
|
obj->addrstr, port, obj->path);
|
||||||
obj->state = EConnecting;
|
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) {
|
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;
|
obj->state = EError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,7 +407,7 @@ static void upnp_event_send(struct upnp_event_notify * obj)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
syslog(LOG_DEBUG, "%s: sending event notify message to %s:%s",
|
syslog(LOG_DEBUG, "%s: sending event notify message to %s%s",
|
||||||
"upnp_event_send", obj->addrstr, obj->portstr);
|
"upnp_event_send", obj->addrstr, obj->portstr);
|
||||||
syslog(LOG_DEBUG, "%s: msg: %s",
|
syslog(LOG_DEBUG, "%s: msg: %s",
|
||||||
"upnp_event_send", obj->buffer + obj->sent);
|
"upnp_event_send", obj->buffer + obj->sent);
|
||||||
|
@ -439,7 +469,9 @@ upnp_event_process_notify(struct upnp_event_notify * obj)
|
||||||
}
|
}
|
||||||
if(err != 0) {
|
if(err != 0) {
|
||||||
errno = err;
|
errno = err;
|
||||||
syslog(LOG_WARNING, "%s: connect failed: %m", "upnp_event_process_notify");
|
syslog(LOG_WARNING, "%s: connect(%s%s): %m",
|
||||||
|
"upnp_event_process_notify",
|
||||||
|
obj->addrstr, obj->portstr);
|
||||||
obj->state = EError;
|
obj->state = EError;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -535,6 +567,8 @@ void upnpevents_processfds(fd_set *readset, fd_set *writeset)
|
||||||
for(sub = subscriberlist.lh_first; sub != NULL; ) {
|
for(sub = subscriberlist.lh_first; sub != NULL; ) {
|
||||||
subnext = sub->entries.le_next;
|
subnext = sub->entries.le_next;
|
||||||
if(sub->timeout && curtime > sub->timeout && sub->notify == NULL) {
|
if(sub->timeout && curtime > sub->timeout && sub->notify == NULL) {
|
||||||
|
syslog(LOG_INFO, "subscriber timeouted : %u > %u SID=%s",
|
||||||
|
(unsigned)curtime, (unsigned)sub->timeout, sub->uuid);
|
||||||
LIST_REMOVE(sub, entries);
|
LIST_REMOVE(sub, entries);
|
||||||
free(sub);
|
free(sub);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* $Id: upnpglobalvars.c,v 1.32 2013/12/13 14:07:09 nanard Exp $ */
|
/* $Id: upnpglobalvars.c,v 1.35 2014/03/10 11:04:53 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -24,17 +24,17 @@ const char* lease_file = 0;
|
||||||
* when NULL, getifaddr() is used */
|
* when NULL, getifaddr() is used */
|
||||||
const char * use_ext_ip_addr = 0;
|
const char * use_ext_ip_addr = 0;
|
||||||
|
|
||||||
/* LAN address */
|
|
||||||
/*const char * listen_addr = 0;*/
|
|
||||||
|
|
||||||
unsigned long downstream_bitrate = 0;
|
unsigned long downstream_bitrate = 0;
|
||||||
unsigned long upstream_bitrate = 0;
|
unsigned long upstream_bitrate = 0;
|
||||||
|
|
||||||
/* startup time */
|
/* startup time */
|
||||||
time_t startup_time = 0;
|
time_t startup_time = 0;
|
||||||
|
|
||||||
|
#ifdef ENABLE_PCP
|
||||||
|
/* for PCP */
|
||||||
unsigned long int min_lifetime = 120;
|
unsigned long int min_lifetime = 120;
|
||||||
unsigned long int max_lifetime = 86400;
|
unsigned long int max_lifetime = 86400;
|
||||||
|
#endif
|
||||||
|
|
||||||
int runtime_flags = 0;
|
int runtime_flags = 0;
|
||||||
|
|
||||||
|
@ -75,18 +75,10 @@ char model_url[MODEL_URL_MAX_LEN] = ROOTDEV_MODELURL;
|
||||||
struct upnpperm * upnppermlist = 0;
|
struct upnpperm * upnppermlist = 0;
|
||||||
unsigned int num_upnpperm = 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
|
#ifdef PCP_SADSCP
|
||||||
struct dscp_values* dscp_values_list = 0;
|
struct dscp_values* dscp_values_list = 0;
|
||||||
unsigned int num_dscp_values = 0;
|
unsigned int num_dscp_values = 0;
|
||||||
#endif /*PCP_SADSCP*/
|
#endif /*PCP_SADSCP*/
|
||||||
#endif
|
|
||||||
|
|
||||||
/* For automatic removal of expired rules (with LeaseDuration) */
|
/* For automatic removal of expired rules (with LeaseDuration) */
|
||||||
unsigned int nextruletoclean_timestamp = 0;
|
unsigned int nextruletoclean_timestamp = 0;
|
||||||
|
@ -127,8 +119,3 @@ const char * minissdpdsocketpath = "/var/run/minissdpd.sock";
|
||||||
unsigned int upnp_bootid = 1;
|
unsigned int upnp_bootid = 1;
|
||||||
unsigned int upnp_configid = 1337;
|
unsigned int upnp_configid = 1337;
|
||||||
|
|
||||||
#ifdef ENABLE_6FC_SERVICE
|
|
||||||
int ipv6fc_firewall_enabled = 1;
|
|
||||||
int ipv6fc_inbound_pinhole_allowed = 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -51,6 +51,13 @@ extern int runtime_flags;
|
||||||
#ifdef PF_ENABLE_FILTER_RULES
|
#ifdef PF_ENABLE_FILTER_RULES
|
||||||
#define PFNOQUICKRULESMASK 0x0040
|
#define PFNOQUICKRULESMASK 0x0040
|
||||||
#endif
|
#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 SETFLAG(mask) runtime_flags |= mask
|
||||||
#define GETFLAG(mask) (runtime_flags & mask)
|
#define GETFLAG(mask) (runtime_flags & mask)
|
||||||
|
@ -95,18 +102,10 @@ extern char model_url[];
|
||||||
extern struct upnpperm * upnppermlist;
|
extern struct upnpperm * upnppermlist;
|
||||||
extern unsigned int num_upnpperm;
|
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
|
#ifdef PCP_SADSCP
|
||||||
extern struct dscp_values* dscp_values_list;
|
extern struct dscp_values* dscp_values_list;
|
||||||
extern unsigned int num_dscp_values;
|
extern unsigned int num_dscp_values;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
/* For automatic removal of expired rules (with LeaseDuration) */
|
/* For automatic removal of expired rules (with LeaseDuration) */
|
||||||
extern unsigned int nextruletoclean_timestamp;
|
extern unsigned int nextruletoclean_timestamp;
|
||||||
|
@ -147,10 +146,5 @@ extern const char * minissdpdsocketpath;
|
||||||
extern unsigned int upnp_bootid;
|
extern unsigned int upnp_bootid;
|
||||||
extern unsigned int upnp_configid;
|
extern unsigned int upnp_configid;
|
||||||
|
|
||||||
#ifdef ENABLE_6FC_SERVICE
|
|
||||||
extern int ipv6fc_firewall_enabled;
|
|
||||||
extern int ipv6fc_inbound_pinhole_allowed;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/* $Id: upnphttp.c,v 1.86 2013/02/07 10:26:07 nanard Exp $ */
|
/* $Id: upnphttp.c,v 1.87 2014/03/14 21:26:01 nanard Exp $ */
|
||||||
/* Project : miniupnp
|
/* Project : miniupnp
|
||||||
* Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* Author : Thomas Bernard
|
* Author : Thomas Bernard
|
||||||
* Copyright (c) 2005-2012 Thomas Bernard
|
* Copyright (c) 2005-2014 Thomas Bernard
|
||||||
* This software is subject to the conditions detailed in the
|
* This software is subject to the conditions detailed in the
|
||||||
* LICENCE file included in this distribution.
|
* LICENCE file included in this distribution.
|
||||||
* */
|
* */
|
||||||
|
@ -162,14 +162,22 @@ ParseHttpHeaders(struct upnphttp * h)
|
||||||
#ifdef ENABLE_EVENTS
|
#ifdef ENABLE_EVENTS
|
||||||
else if(strncasecmp(line, "Callback", 8)==0)
|
else if(strncasecmp(line, "Callback", 8)==0)
|
||||||
{
|
{
|
||||||
|
/* The Callback can contain several urls :
|
||||||
|
* If there is more than one URL, when the service sends
|
||||||
|
* events, it will try these URLs in order until one
|
||||||
|
* succeeds. One or more URLs each enclosed by angle
|
||||||
|
* brackets ("<" and ">") */
|
||||||
p = colon;
|
p = colon;
|
||||||
while(*p != '<' && *p != '\r' )
|
while(*p != '<' && *p != '\r' )
|
||||||
p++;
|
p++;
|
||||||
n = 0;
|
n = 0;
|
||||||
while(p[n] != '>' && p[n] != '\r' )
|
while(p[n] != '\r')
|
||||||
n++;
|
n++;
|
||||||
h->req_CallbackOff = p + 1 - h->req_buf;
|
while(n > 0 && p[n] != '>')
|
||||||
h->req_CallbackLen = MAX(0, n - 1);
|
n--;
|
||||||
|
/* found last > character */
|
||||||
|
h->req_CallbackOff = p - h->req_buf;
|
||||||
|
h->req_CallbackLen = MAX(0, n + 1);
|
||||||
}
|
}
|
||||||
else if(strncasecmp(line, "SID", 3)==0)
|
else if(strncasecmp(line, "SID", 3)==0)
|
||||||
{
|
{
|
||||||
|
@ -374,6 +382,9 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h)
|
||||||
|
|
||||||
#ifdef ENABLE_EVENTS
|
#ifdef ENABLE_EVENTS
|
||||||
/**
|
/**
|
||||||
|
* checkCallbackURL()
|
||||||
|
* check that url is on originating IP
|
||||||
|
* extract first correct URL
|
||||||
* returns 0 if the callback header value is not valid
|
* returns 0 if the callback header value is not valid
|
||||||
* 1 if it is valid.
|
* 1 if it is valid.
|
||||||
*/
|
*/
|
||||||
|
@ -385,56 +396,76 @@ checkCallbackURL(struct upnphttp * h)
|
||||||
const char * p;
|
const char * p;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if(h->req_CallbackOff <= 0 || h->req_CallbackLen < 8)
|
start_again:
|
||||||
|
if(h->req_CallbackOff <= 0 || h->req_CallbackLen < 10)
|
||||||
return 0;
|
return 0;
|
||||||
if(memcmp(h->req_buf + h->req_CallbackOff, "http://", 7) != 0)
|
if(memcmp(h->req_buf + h->req_CallbackOff, "<http://", 8) != 0) {
|
||||||
return 0;
|
p = h->req_buf + h->req_CallbackOff + 1;
|
||||||
ipv6 = 0;
|
goto invalid;
|
||||||
|
}
|
||||||
|
/* extract host from url to addrstr[] */
|
||||||
i = 0;
|
i = 0;
|
||||||
p = h->req_buf + h->req_CallbackOff + 7;
|
p = h->req_buf + h->req_CallbackOff + 8;
|
||||||
if(*p == '[') {
|
if(*p == '[') {
|
||||||
p++;
|
p++;
|
||||||
ipv6 = 1;
|
ipv6 = 1;
|
||||||
while(*p != ']' && i < (sizeof(addrstr)-1)
|
while(*p != ']' && *p != '>' && i < (sizeof(addrstr)-1)
|
||||||
&& p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen))
|
&& p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen))
|
||||||
addrstr[i++] = *(p++);
|
addrstr[i++] = *(p++);
|
||||||
} else {
|
} else {
|
||||||
while(*p != '/' && *p != ':' && i < (sizeof(addrstr)-1)
|
ipv6 = 0;
|
||||||
|
while(*p != '/' && *p != ':' && *p != '>' && i < (sizeof(addrstr)-1)
|
||||||
&& p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen))
|
&& p < (h->req_buf + h->req_CallbackOff + h->req_CallbackLen))
|
||||||
addrstr[i++] = *(p++);
|
addrstr[i++] = *(p++);
|
||||||
}
|
}
|
||||||
addrstr[i] = '\0';
|
addrstr[i] = '\0';
|
||||||
|
/* check addrstr */
|
||||||
if(ipv6) {
|
if(ipv6) {
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
struct in6_addr addr;
|
struct in6_addr addr;
|
||||||
if(inet_pton(AF_INET6, addrstr, &addr) <= 0)
|
if(inet_pton(AF_INET6, addrstr, &addr) <= 0)
|
||||||
return 0;
|
goto invalid;
|
||||||
#ifdef ENABLE_IPV6
|
|
||||||
if(!h->ipv6
|
if(!h->ipv6
|
||||||
|| (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr))))
|
|| (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr))))
|
||||||
return 0;
|
goto invalid;
|
||||||
#else
|
#else
|
||||||
return 0;
|
goto invalid;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
if(inet_pton(AF_INET, addrstr, &addr) <= 0)
|
if(inet_pton(AF_INET, addrstr, &addr) <= 0)
|
||||||
return 0;
|
goto invalid;
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
if(h->ipv6) {
|
if(h->ipv6) {
|
||||||
if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6)))
|
if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6)))
|
||||||
return 0;
|
goto invalid;
|
||||||
if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4))
|
if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4))
|
||||||
return 0;
|
goto invalid;
|
||||||
} else {
|
} else {
|
||||||
if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
|
if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
|
||||||
return 0;
|
goto invalid;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
|
if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
|
||||||
return 0;
|
goto invalid;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
/* select only the good callback url */
|
||||||
|
while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '>')
|
||||||
|
p++;
|
||||||
|
h->req_CallbackOff++; /* skip initial '<' */
|
||||||
|
h->req_CallbackLen = (int)(p - h->req_buf - h->req_CallbackOff);
|
||||||
return 1;
|
return 1;
|
||||||
|
invalid:
|
||||||
|
while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '>')
|
||||||
|
p++;
|
||||||
|
if(*p != '>') return 0;
|
||||||
|
while(p < h->req_buf + h->req_CallbackOff + h->req_CallbackLen && *p != '<')
|
||||||
|
p++;
|
||||||
|
if(*p != '<') return 0;
|
||||||
|
h->req_CallbackLen -= (int)(p - h->req_buf - h->req_CallbackOff);
|
||||||
|
h->req_CallbackOff = (int)(p - h->req_buf);
|
||||||
|
goto start_again;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -223,6 +223,23 @@ match_permission(const struct upnpperm * perm,
|
||||||
return 1;
|
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
|
int
|
||||||
check_upnp_rule_against_permissions(const struct upnpperm * permary,
|
check_upnp_rule_against_permissions(const struct upnpperm * permary,
|
||||||
int n_perms,
|
int n_perms,
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
||||||
#include "upnpredirect.h"
|
#include "upnpredirect.h"
|
||||||
#include "upnpglobalvars.h"
|
#include "upnpglobalvars.h"
|
||||||
#include "upnpevents.h"
|
#include "upnpevents.h"
|
||||||
|
#include "portinuse.h"
|
||||||
#if defined(USE_NETFILTER)
|
#if defined(USE_NETFILTER)
|
||||||
#include "netfilter/iptcrdr.h"
|
#include "netfilter/iptcrdr.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -294,6 +295,12 @@ upnp_redirect(const char * rhost, unsigned short eport,
|
||||||
eport, protocol, iaddr_old, iport_old);
|
eport, protocol, iaddr_old, iport_old);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
#ifdef CHECK_PORTINUSE
|
||||||
|
} else if (port_in_use(ext_if_name, eport, proto, iaddr, iport) > 0) {
|
||||||
|
syslog(LOG_INFO, "port %hu protocol %s already in use",
|
||||||
|
eport, protocol);
|
||||||
|
return -2;
|
||||||
|
#endif /* CHECK_PORTINUSE */
|
||||||
} else {
|
} else {
|
||||||
timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
|
timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
|
||||||
syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
|
syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
|
||||||
|
@ -419,6 +426,8 @@ _upnp_delete_redir(unsigned short eport, int proto)
|
||||||
int r;
|
int r;
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
r = delete_redirect_and_filter_rules(eport, proto);
|
r = delete_redirect_and_filter_rules(eport, proto);
|
||||||
|
#elif defined(USE_PF)
|
||||||
|
r = delete_redirect_and_filter_rules(ext_if_name, eport, proto);
|
||||||
#else
|
#else
|
||||||
r = delete_redirect_rule(ext_if_name, eport, proto);
|
r = delete_redirect_rule(ext_if_name, eport, proto);
|
||||||
delete_filter_rule(ext_if_name, eport, proto);
|
delete_filter_rule(ext_if_name, eport, proto);
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* 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,
|
bodylen = snprintf(body, sizeof(body), resp,
|
||||||
action, "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1",
|
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);
|
BuildSendAndCloseSoapResp(h, body, bodylen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
CheckStatus(struct upnphttp * h)
|
CheckStatus(struct upnphttp * h)
|
||||||
{
|
{
|
||||||
if (!ipv6fc_firewall_enabled)
|
if (GETFLAG(IPV6FCFWDISABLEDMASK))
|
||||||
{
|
{
|
||||||
SoapError(h, 702, "FirewallDisabled");
|
SoapError(h, 702, "FirewallDisabled");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if(!ipv6fc_inbound_pinhole_allowed)
|
else if(GETFLAG(IPV6FCINBOUNDDISALLOWEDMASK))
|
||||||
{
|
{
|
||||||
SoapError(h, 703, "InboundPinholeNotAllowed");
|
SoapError(h, 703, "InboundPinholeNotAllowed");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1604,7 +1606,7 @@ GetOutboundPinholeTimeout(struct upnphttp * h, const char * action)
|
||||||
int opt=0, proto=0;
|
int opt=0, proto=0;
|
||||||
unsigned short iport, rport;
|
unsigned short iport, rport;
|
||||||
|
|
||||||
if (!ipv6fc_firewall_enabled)
|
if (GETFLAG(IPV6FCFWDISABLEDMASK))
|
||||||
{
|
{
|
||||||
SoapError(h, 702, "FirewallDisabled");
|
SoapError(h, 702, "FirewallDisabled");
|
||||||
return;
|
return;
|
||||||
|
@ -1910,6 +1912,10 @@ ExecuteSoapAction(struct upnphttp * h, const char * action, int n)
|
||||||
len = strlen(soapMethods[i].methodName);
|
len = strlen(soapMethods[i].methodName);
|
||||||
if(strncmp(p, soapMethods[i].methodName, len) == 0)
|
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);
|
soapMethods[i].methodImpl(h, soapMethods[i].methodName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* 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
|
* This software is subject to the conditions detailed
|
||||||
* in the LICENCE file provided within the distribution */
|
* in the LICENCE file provided within the distribution */
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ struct lan_addr_s *
|
||||||
get_lan_for_peer(const struct sockaddr * peer)
|
get_lan_for_peer(const struct sockaddr * peer)
|
||||||
{
|
{
|
||||||
struct lan_addr_s * lan_addr = NULL;
|
struct lan_addr_s * lan_addr = NULL;
|
||||||
|
char dbg_str[64];
|
||||||
|
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
if(peer->sa_family == AF_INET6)
|
if(peer->sa_family == AF_INET6)
|
||||||
|
@ -153,11 +154,15 @@ get_lan_for_peer(const struct sockaddr * peer)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(lan_addr)
|
sockaddr_to_string(peer, dbg_str, sizeof(dbg_str));
|
||||||
syslog(LOG_DEBUG, "%s: found in LAN %s %s",
|
if(lan_addr) {
|
||||||
"get_lan_for_peer()", lan_addr->ifname, lan_addr->str);
|
syslog(LOG_DEBUG, "%s: %s found in LAN %s %s",
|
||||||
else
|
"get_lan_for_peer()", dbg_str,
|
||||||
syslog(LOG_DEBUG, "%s: not found !", "get_lan_for_peer()");
|
lan_addr->ifname, lan_addr->str);
|
||||||
|
} else {
|
||||||
|
syslog(LOG_DEBUG, "%s: %s not found !", "get_lan_for_peer()",
|
||||||
|
dbg_str);
|
||||||
|
}
|
||||||
return lan_addr;
|
return lan_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: upnputils.h,v 1.4 2013/02/06 10:50:04 nanard Exp $ */
|
/* $Id: upnputils.h,v 1.6 2014/03/31 12:32:57 nanard Exp $ */
|
||||||
/* MiniUPnP project
|
/* MiniUPnP project
|
||||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||||
* (c) 2011-2013 Thomas Bernard
|
* (c) 2011-2013 Thomas Bernard
|
||||||
|
@ -29,5 +29,30 @@ set_non_blocking(int fd);
|
||||||
struct lan_addr_s *
|
struct lan_addr_s *
|
||||||
get_lan_for_peer(const struct sockaddr * peer);
|
get_lan_for_peer(const struct sockaddr * peer);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* define portability macros
|
||||||
|
*/
|
||||||
|
#if defined(__sun)
|
||||||
|
static size_t _sa_len(const struct sockaddr *addr)
|
||||||
|
{
|
||||||
|
if (addr->sa_family == AF_INET)
|
||||||
|
return (sizeof(struct sockaddr_in));
|
||||||
|
else if (addr->sa_family == AF_INET6)
|
||||||
|
return (sizeof(struct sockaddr_in6));
|
||||||
|
else
|
||||||
|
return (sizeof(struct sockaddr));
|
||||||
|
}
|
||||||
|
# define SA_LEN(sa) (_sa_len(sa))
|
||||||
|
#else
|
||||||
|
#if !defined(SA_LEN)
|
||||||
|
# define SA_LEN(sa) ((sa)->sa_len)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
# define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue