miniupnpd: adding HTTPS support

This commit is contained in:
Thomas Bernard 2014-04-09 15:35:06 +02:00
parent 29e951c1e5
commit bbe96a15b6
9 changed files with 464 additions and 30 deletions

View File

@ -1,4 +1,7 @@
$Id: Changelog.txt,v 1.366 2014/03/24 11:03:50 nanard Exp $
$Id: Changelog.txt,v 1.368 2014/04/09 12:39:53 nanard Exp $
2014/04/09:
Add HTTPS support and skeleton of DeviceProtection implementation
2014/03/24:
start work to enable IPv6 PCP operations

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.80 2014/04/07 10:32:20 nanard Exp $
# $Id: Makefile,v 1.81 2014/04/09 10:30:08 nanard Exp $
# MiniUPnP project
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
# Author: Thomas Bernard
@ -138,6 +138,8 @@ LIBS = -lkvm
LIBS += -lsocket -lnsl -lkstat -lresolv
.endif
LIBS += -lssl -lcrypto
# set PREFIX variable to install in the wanted place
INSTALLBINDIR = $(PREFIX)/sbin

View File

@ -1,4 +1,4 @@
# $Id: Makefile.linux,v 1.84 2014/03/24 10:43:25 nanard Exp $
# $Id: Makefile.linux,v 1.86 2014/04/09 07:22:28 nanard Exp $
# MiniUPnP project
# (c) 2006-2014 Thomas Bernard
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -146,6 +146,8 @@ LIBS += $(shell pkg-config --static --libs-only-l libmnl)
LIBS += $(shell pkg-config --static --libs-only-l libnetfilter_conntrack)
endif # ($(TEST),1)
LIBS += $(shell pkg-config --static --libs-only-l libssl)
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
EXECUTABLES = miniupnpd testupnpdescgen testgetifstats \

View File

@ -1,5 +1,5 @@
#! /bin/sh
# $Id: genconfig.sh,v 1.72 2014/03/10 10:17:17 nanard Exp $
# $Id: genconfig.sh,v 1.74 2014/04/09 07:21:00 nanard Exp $
# miniupnp daemon
# http://miniupnp.free.fr or http://miniupnp.tuxfamily.org/
# (c) 2006-2014 Thomas Bernard
@ -443,6 +443,7 @@ echo "" >> ${CONFIGFILE}
echo "#ifdef IGD_V2" >> ${CONFIGFILE}
echo "/* Enable DeviceProtection service (IGDv2) */" >> ${CONFIGFILE}
echo "#define ENABLE_DP_SERVICE" >> ${CONFIGFILE}
echo "/*#define ENABLE_HTTPS*/" >> ${CONFIGFILE}
echo "" >> ${CONFIGFILE}
echo "/* Enable WANIPv6FirewallControl service (IGDv2). needs IPv6 */" >> ${CONFIGFILE}
echo "#ifdef ENABLE_IPV6" >> ${CONFIGFILE}

View File

@ -1,4 +1,4 @@
/* $Id: minissdp.c,v 1.62 2014/03/24 09:31:23 nanard Exp $ */
/* $Id: minissdp.c,v 1.64 2014/04/09 11:14:16 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
@ -336,8 +336,11 @@ EXT:
static void
SendSSDPResponse(int s, const struct sockaddr * addr,
const char * st, int st_len, const char * suffix,
const char * host, unsigned short port, const char * uuidvalue,
unsigned int delay)
const char * host, unsigned short port,
#ifdef ENABLE_HTTPS
unsigned short https_port,
#endif
const char * uuidvalue, unsigned int delay)
{
int l, n;
char buf[512];
@ -375,6 +378,9 @@ SendSSDPResponse(int s, const struct sockaddr * addr,
"EXT:\r\n"
"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
#ifdef ENABLE_HTTPS
"SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH "\r\n"
#endif
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
@ -387,6 +393,9 @@ SendSSDPResponse(int s, const struct sockaddr * addr,
uuidvalue, st_is_uuid ? "" : "::",
st_is_uuid ? 0 : st_len, st, suffix,
host, (unsigned int)port,
#ifdef ENABLE_HTTPS
host, (unsigned int)https_port,
#endif
upnp_bootid, upnp_bootid, upnp_configid);
if(l<0)
{
@ -453,6 +462,9 @@ static struct {
static void
SendSSDPNotify(int s, const struct sockaddr * dest,
const char * host, unsigned short port,
#ifdef ENABLE_HTTPS
unsigned short https_port,
#endif
const char * nt, const char * suffix,
const char * usn1, const char * usn2, const char * usn3,
unsigned int lifetime, int ipv6)
@ -464,7 +476,10 @@ SendSSDPNotify(int s, const struct sockaddr * dest,
"NOTIFY * HTTP/1.1\r\n"
"HOST: %s:%d\r\n"
"CACHE-CONTROL: max-age=%u\r\n"
"LOCATION: http://%s:%d" ROOTDESC_PATH"\r\n"
"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
#ifdef ENABLE_HTTPS
"SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH "\r\n"
#endif
"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
"NT: %s%s\r\n"
"USN: %s%s%s%s\r\n"
@ -477,13 +492,16 @@ SendSSDPNotify(int s, const struct sockaddr * dest,
ipv6 ? "[" LL_SSDP_MCAST_ADDR "]" : SSDP_MCAST_ADDR,
SSDP_PORT,
lifetime,
host, port,
host, (unsigned int)port,
#ifdef ENABLE_HTTPS
host, (unsigned int)https_port,
#endif
nt, suffix, /* NT: */
usn1, usn2, usn3, suffix, /* USN: */
upnp_bootid, upnp_bootid, upnp_configid );
if(l<0)
{
syslog(LOG_ERR, "SendSSDPNotify() snprintf error");
syslog(LOG_ERR, "%s: snprintf error", "SendSSDPNotify()");
return;
}
else if((unsigned int)l >= sizeof(bufr))
@ -527,6 +545,9 @@ SendSSDPNotify(int s, const struct sockaddr * dest,
static void
SendSSDPNotifies(int s, const char * host, unsigned short port,
#ifdef ENABLE_HTTPS
unsigned short https_port,
#endif
unsigned int lifetime, int ipv6)
{
#ifdef ENABLE_IPV6
@ -562,6 +583,9 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
else
snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
SendSSDPNotify(s, (struct sockaddr *)&sockname, host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
known_service_types[i].s, ver_str, /* NT: */
known_service_types[i].uuid, "::",
known_service_types[i].s, /* ver_str, USN: */
@ -570,6 +594,9 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
"urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1))
{
SendSSDPNotify(s, (struct sockaddr *)&sockname, host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
known_service_types[i].uuid, "", /* NT: */
known_service_types[i].uuid, "", "", /* ver_str, USN: */
lifetime, ipv6);
@ -581,6 +608,9 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
void
SendSSDPNotifies2(int * sockets,
unsigned short port,
#ifdef ENABLE_HTTPS
unsigned short https_port,
#endif
unsigned int lifetime)
{
int i;
@ -590,12 +620,18 @@ SendSSDPNotifies2(int * sockets,
lan_addr = lan_addr->list.le_next)
{
SendSSDPNotifies(sockets[i], lan_addr->str, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
lifetime, 0);
i++;
#ifdef ENABLE_IPV6
if(sockets[i] >= 0)
{
SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
lifetime, 1);
}
i++;
@ -606,7 +642,11 @@ SendSSDPNotifies2(int * sockets,
/* ProcessSSDPRequest()
* process SSDP M-SEARCH requests and responds to them */
void
#ifdef ENABLE_HTTPS
ProcessSSDPRequest(int s, unsigned short port, unsigned short https_port)
#else
ProcessSSDPRequest(int s, unsigned short port)
#endif
{
int n;
char bufr[1500];
@ -633,13 +673,24 @@ ProcessSSDPRequest(int s, unsigned short port)
}
return;
}
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername, port);
ProcessSSDPData(s, bufr, n, (struct sockaddr *)&sendername,
#ifdef ENABLE_HTTPS
port, https_port);
#else
port);
#endif
}
void
ProcessSSDPData(int s, const char *bufr, int n,
const struct sockaddr * sender, unsigned short port) {
const struct sockaddr * sender,
#ifdef ENABLE_HTTPS
unsigned short port, unsigned short https_port)
#else
unsigned short port)
#endif
{
int i, l;
struct lan_addr_s * lan_addr = NULL;
const char * st = NULL;
@ -848,6 +899,9 @@ ProcessSSDPData(int s, const char *bufr, int n,
known_service_types[i].s, l, ver_str,
#endif
announced_host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
known_service_types[i].uuid,
delay);
break;
@ -874,6 +928,9 @@ ProcessSSDPData(int s, const char *bufr, int n,
SendSSDPResponse(s, sender,
known_service_types[i].s, l, ver_str,
announced_host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
known_service_types[i].uuid,
delay);
}
@ -882,17 +939,29 @@ ProcessSSDPData(int s, const char *bufr, int n,
delay += delay_increment;
#endif
SendSSDPResponse(s, sender, uuidvalue_igd, strlen(uuidvalue_igd), "",
announced_host, port, uuidvalue_igd, delay);
announced_host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
uuidvalue_igd, delay);
#ifdef DELAY_MSEARCH_RESPONSE
delay += delay_increment;
#endif
SendSSDPResponse(s, sender, uuidvalue_wan, strlen(uuidvalue_wan), "",
announced_host, port, uuidvalue_wan, delay);
announced_host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
uuidvalue_wan, delay);
#ifdef DELAY_MSEARCH_RESPONSE
delay += delay_increment;
#endif
SendSSDPResponse(s, sender, uuidvalue_wcd, strlen(uuidvalue_wcd), "",
announced_host, port, uuidvalue_wcd, delay);
announced_host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
uuidvalue_wcd, delay);
}
/* responds to request by UUID value */
l = (int)strlen(uuidvalue_igd);
@ -905,22 +974,31 @@ ProcessSSDPData(int s, const char *bufr, int n,
{
syslog(LOG_INFO, "ssdp:uuid (IGD) found");
SendSSDPResponse(s, sender, st, st_len, "",
announced_host, port, uuidvalue_igd,
delay);
announced_host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
uuidvalue_igd, delay);
}
else if(0 == memcmp(st, uuidvalue_wan, l))
{
syslog(LOG_INFO, "ssdp:uuid (WAN) found");
SendSSDPResponse(s, sender, st, st_len, "",
announced_host, port, uuidvalue_wan,
delay);
announced_host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
uuidvalue_wan, delay);
}
else if(0 == memcmp(st, uuidvalue_wcd, l))
{
syslog(LOG_INFO, "ssdp:uuid (WCD) found");
SendSSDPResponse(s, sender, st, st_len, "",
announced_host, port, uuidvalue_wcd,
delay);
announced_host, port,
#ifdef ENABLE_HTTPS
https_port,
#endif
uuidvalue_wcd, delay);
}
}
}

View File

@ -1,4 +1,4 @@
/* $Id: minissdp.h,v 1.10 2011/05/23 12:39:41 nanard Exp $ */
/* $Id: minissdp.h,v 1.12 2014/04/09 07:20:59 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2007 Thomas Bernard
@ -23,19 +23,31 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
void
SendSSDPNotifies2(int * sockets,
unsigned short port,
#ifdef ENABLE_HTTPS
unsigned short https_port,
#endif
unsigned int lifetime);
/*SendSSDPNotifies2(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr,
unsigned short port,
unsigned int lifetime);*/
void
#ifdef ENABLE_HTTPS
ProcessSSDPRequest(int s, unsigned short port, unsigned short https_port);
#else
ProcessSSDPRequest(int s, unsigned short port);
#endif
/*ProcessSSDPRequest(int s, struct lan_addr_s * lan_addr, int n_lan_addr,
unsigned short port);*/
void
ProcessSSDPData(int s, const char *bufr, int n,
const struct sockaddr * sendername, unsigned short port);
const struct sockaddr * sendername,
#ifdef ENABLE_HTTPS
unsigned short port, unsigned short https_port);
#else
unsigned short port);
#endif
int
SendSSDPGoodbye(int * sockets, int n);

View File

@ -1,4 +1,4 @@
/* $Id: miniupnpd.c,v 1.190 2014/03/24 10:49:44 nanard Exp $ */
/* $Id: miniupnpd.c,v 1.192 2014/04/09 11:07:36 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
@ -632,6 +632,9 @@ struct runtime_vars {
/* LAN IP addresses for SSDP traffic and HTTP */
/* moved to global vars */
int port; /* HTTP Port */
#ifdef ENABLE_HTTPS
int https_port; /* HTTPS Port */
#endif
int notify_interval; /* seconds between SSDP announces */
/* unused rules cleaning related variables : */
int clean_ruleset_threshold; /* threshold for removing unused rules */
@ -833,6 +836,9 @@ init(int argc, char * * argv, struct runtime_vars * v)
LIST_INIT(&lan_addrs);
v->port = -1;
#ifdef ENABLE_HTTPS
v->https_port = -1;
#endif
v->notify_interval = 30; /* seconds between SSDP announces */
v->clean_ruleset_threshold = 20;
v->clean_ruleset_interval = 0; /* interval between ruleset check. 0=disabled */
@ -1126,6 +1132,16 @@ init(int argc, char * * argv, struct runtime_vars * v)
if(i+1 < argc)
v->port = atoi(argv[++i]);
else
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
break;
#ifdef ENABLE_HTTPS
case 'H':
if(i+1 < argc)
v->https_port = atoi(argv[++i]);
else
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
break;
#endif
#ifdef ENABLE_NFQUEUE
case 'Q':
if(i+1<argc)
@ -1148,8 +1164,6 @@ init(int argc, char * * argv, struct runtime_vars * v)
}
break;
#endif
fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
break;
case 'P':
if(i+1 < argc)
pidfilename = argv[++i];
@ -1385,6 +1399,9 @@ print_usage:
"\t\t[-a listening_ip]"
#else
"\t\t[-a listening_ip ext_ip]"
#endif
#ifdef ENABLE_HTTPS
" [-H https_port]"
#endif
" [-p port] [-d]"
#if defined(USE_PF) || defined(USE_IPF)
@ -1453,6 +1470,12 @@ main(int argc, char * * argv)
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
int shttpl_v4 = -1; /* socket for HTTP (ipv4 only) */
#endif
#ifdef ENABLE_HTTPS
int shttpsl = -1; /* socket for HTTPS */
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
int shttpsl_v4 = -1; /* socket for HTTPS (ipv4 only) */
#endif
#endif /* ENABLE_HTTPS */
int sudp = -1; /* IP v4 socket for receiving SSDP */
#ifdef ENABLE_IPV6
int sudpv6 = -1; /* IP v6 socket for receiving SSDP */
@ -1496,6 +1519,10 @@ main(int argc, char * * argv)
if(init(argc, argv, &v) != 0)
return 1;
#ifdef ENABLE_HTTPS
if(init_ssl() < 0)
return 1;
#endif /* ENABLE_HTTPS */
/* count lan addrs */
addr_count = 0;
for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
@ -1558,6 +1585,15 @@ main(int argc, char * * argv)
return 1;
}
if(v.port <= 0) {
#ifdef ENABLE_IPV6
struct sockaddr_in6 sockinfo;
socklen_t len = sizeof(struct sockaddr_in6);
if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
return 1;
}
v.port = ntohs(sockinfo.sin6_port);
#else /* ENABLE_IPV6 */
struct sockaddr_in sockinfo;
socklen_t len = sizeof(struct sockaddr_in);
if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
@ -1565,6 +1601,7 @@ main(int argc, char * * argv)
return 1;
}
v.port = ntohs(sockinfo.sin_port);
#endif /* ENABLE_IPV6 */
}
syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
@ -1575,6 +1612,47 @@ main(int argc, char * * argv)
return 1;
}
#endif /* V6SOCKETS_ARE_V6ONLY */
#ifdef ENABLE_HTTPS
/* https */
#ifdef ENABLE_IPV6
shttpsl = OpenAndConfHTTPSocket((v.https_port > 0) ? v.https_port : 0, 1);
#else /* ENABLE_IPV6 */
shttpsl = OpenAndConfHTTPSocket((v.https_port > 0) ? v.https_port : 0);
#endif /* ENABLE_IPV6 */
if(shttpl < 0)
{
syslog(LOG_ERR, "Failed to open socket for HTTPS. EXITING");
return 1;
}
if(v.https_port <= 0) {
#ifdef ENABLE_IPV6
struct sockaddr_in6 sockinfo;
socklen_t len = sizeof(struct sockaddr_in6);
if (getsockname(shttpsl, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
return 1;
}
v.https_port = ntohs(sockinfo.sin6_port);
#else /* ENABLE_IPV6 */
struct sockaddr_in sockinfo;
socklen_t len = sizeof(struct sockaddr_in);
if (getsockname(shttpsl, (struct sockaddr *)&sockinfo, &len) < 0) {
syslog(LOG_ERR, "getsockname(): %m");
return 1;
}
v.https_port = ntohs(sockinfo.sin_port);
#endif /* ENABLE_IPV6 */
}
syslog(LOG_NOTICE, "HTTPS listening on port %d", v.https_port);
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
shttpsl_v4 = OpenAndConfHTTPSocket(v.https_port, 0);
if(shttpsl_v4 < 0)
{
syslog(LOG_ERR, "Failed to open socket for HTTPS on port %hu (IPv4). EXITING", v.https_port);
return 1;
}
#endif /* V6SOCKETS_ARE_V6ONLY */
#endif /* ENABLE_HTTPS */
#ifdef ENABLE_IPV6
if(find_ipv6_addr(NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) {
syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s",
@ -1712,6 +1790,9 @@ main(int argc, char * * argv)
if (GETFLAG(ENABLEUPNPMASK))
SendSSDPNotifies2(snotify,
(unsigned short)v.port,
#ifdef ENABLE_HTTPS
(unsigned short)v.https_port,
#endif
v.notify_interval << 1);
memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
timeout.tv_sec = v.notify_interval;
@ -1803,6 +1884,20 @@ main(int argc, char * * argv)
max_fd = MAX( max_fd, shttpl_v4);
}
#endif
#ifdef ENABLE_HTTPS
if (shttpsl >= 0)
{
FD_SET(shttpsl, &readset);
max_fd = MAX( max_fd, shttpsl);
}
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
if (shttpsl_v4 >= 0)
{
FD_SET(shttpsl_v4, &readset);
max_fd = MAX( max_fd, shttpsl_v4);
}
#endif
#endif /* ENABLE_HTTPS */
#ifdef ENABLE_IPV6
if (sudpv6 >= 0)
{
@ -2039,13 +2134,21 @@ main(int argc, char * * argv)
if(sudp >= 0 && FD_ISSET(sudp, &readset))
{
/*syslog(LOG_INFO, "Received UDP Packet");*/
#ifdef ENABLE_HTTPS
ProcessSSDPRequest(sudp, (unsigned short)v.port, (unsigned short)v.https_port);
#else
ProcessSSDPRequest(sudp, (unsigned short)v.port);
#endif
}
#ifdef ENABLE_IPV6
if(sudpv6 >= 0 && FD_ISSET(sudpv6, &readset))
{
syslog(LOG_INFO, "Received UDP Packet (IPv6)");
#ifdef ENABLE_HTTPS
ProcessSSDPRequest(sudpv6, (unsigned short)v.port, (unsigned short)v.https_port);
#else
ProcessSSDPRequest(sudpv6, (unsigned short)v.port);
#endif
}
#endif
#ifdef USE_IFACEWATCHER
@ -2088,6 +2191,30 @@ main(int argc, char * * argv)
}
}
#endif
#ifdef ENABLE_HTTPS
if(shttpsl >= 0 && FD_ISSET(shttpsl, &readset))
{
struct upnphttp * tmp;
tmp = ProcessIncomingHTTP(shttpsl);
if(tmp)
{
InitSSL_upnphttp(tmp);
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
}
}
#if defined(V6SOCKETS_ARE_V6ONLY) && defined(ENABLE_IPV6)
if(shttpsl_v4 >= 0 && FD_ISSET(shttpsl_v4, &readset))
{
struct upnphttp * tmp;
tmp = ProcessIncomingHTTP(shttpsl_v4);
if(tmp)
{
InitSSL_upnphttp(tmp);
LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
}
}
#endif
#endif /* ENABLE_HTTPS */
#ifdef ENABLE_NFQUEUE
/* process NFQ packets */
if(nfqh >= 0 && FD_ISSET(nfqh, &readset))

View File

@ -1,4 +1,4 @@
/* $Id: upnphttp.c,v 1.87 2014/03/14 21:26:01 nanard Exp $ */
/* $Id: upnphttp.c,v 1.90 2014/04/09 13:15:43 nanard Exp $ */
/* Project : miniupnp
* Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author : Thomas Bernard
@ -29,6 +29,66 @@
#include "upnpevents.h"
#include "upnputils.h"
#ifdef ENABLE_HTTPS
#include <openssl/err.h>
static SSL_CTX *ssl_ctx = NULL;
#ifndef HTTPS_CERTFILE
#define HTTPS_CERTFILE "/etc/ssl/certs/ssl-cert-snakeoil.pem"
#endif
#ifndef HTTPS_KEYFILE
#define HTTPS_KEYFILE "/etc/ssl/private/ssl-cert-snakeoil.key"
#endif
static void
syslogsslerr(void)
{
unsigned long err;
char buffer[256];
while((err = ERR_get_error()) != 0) {
syslog(LOG_ERR, "%s", ERR_error_string(err, buffer));
}
}
int init_ssl(void)
{
SSL_METHOD *method;
SSL_library_init();
SSL_load_error_strings();
method = TLSv1_server_method();
if(method == NULL) {
syslog(LOG_ERR, "TLSv1_server_method() failed");
syslogsslerr();
return -1;
}
ssl_ctx = SSL_CTX_new(method);
if(ssl_ctx == NULL) {
syslog(LOG_ERR, "SSL_CTX_new() failed");
syslogsslerr();
return -1;
}
/* set the local certificate */
if(!SSL_CTX_use_certificate_file(ssl_ctx, HTTPS_CERTFILE, SSL_FILETYPE_PEM)) {
syslog(LOG_ERR, "SSL_CTX_use_certificate_file(%s) failed", HTTPS_CERTFILE);
syslogsslerr();
return -1;
}
/* set the private key */
if(!SSL_CTX_use_PrivateKey_file(ssl_ctx, HTTPS_KEYFILE, SSL_FILETYPE_PEM)) {
syslog(LOG_ERR, "SSL_CTX_use_PrivateKey_file(%s) failed", HTTPS_KEYFILE);
syslogsslerr();
return -1;
}
/* verify private key */
if(!SSL_CTX_check_private_key(ssl_ctx)) {
syslog(LOG_ERR, "SSL_CTX_check_private_key() failed");
syslogsslerr();
return -1;
}
return 0;
}
#endif /* ENABLE_HTTPS */
struct upnphttp *
New_upnphttp(int s)
{
@ -45,9 +105,40 @@ New_upnphttp(int s)
return ret;
}
#ifdef ENABLE_HTTPS
void
InitSSL_upnphttp(struct upnphttp * h)
{
int r;
h->ssl = SSL_new(ssl_ctx);
if(h->ssl == NULL) {
syslog(LOG_ERR, "SSL_new() failed");
syslogsslerr();
abort();
}
if(!SSL_set_fd(h->ssl, h->socket)) {
syslog(LOG_ERR, "SSL_set_fd() failed");
syslogsslerr();
abort();
}
r = SSL_accept(h->ssl); /* start the handshaking */
if(r < 0) {
int err;
err = SSL_get_error(h->ssl, r);
syslog(LOG_DEBUG, "SSL_accept() returned %d, SSL_get_error() %d", r, err);
if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
syslog(LOG_ERR, "SSL_accept() failed");
syslogsslerr();
abort();
}
}
}
#endif /* ENABLE_HTTPS */
void
CloseSocket_upnphttp(struct upnphttp * h)
{
/* SSL_shutdown() ? */
if(close(h->socket) < 0)
{
syslog(LOG_ERR, "CloseSocket_upnphttp: close(%d): %m", h->socket);
@ -61,6 +152,10 @@ Delete_upnphttp(struct upnphttp * h)
{
if(h)
{
#ifdef ENABLE_HTTPS
if(h->ssl)
SSL_free(h->ssl);
#endif
if(h->socket >= 0)
CloseSocket_upnphttp(h);
if(h->req_buf)
@ -702,9 +797,29 @@ Process_upnphttp(struct upnphttp * h)
switch(h->state)
{
case EWaitingForHttpRequest:
#ifdef ENABLE_HTTPS
if(h->ssl) {
n = SSL_read(h->ssl, buf, sizeof(buf));
} else {
n = recv(h->socket, buf, sizeof(buf), 0);
}
#else
n = recv(h->socket, buf, sizeof(buf), 0);
#endif
if(n<0)
{
#ifdef ENABLE_HTTPS
if(h->ssl) {
int err;
err = SSL_get_error(h->ssl, n);
if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE)
{
syslog(LOG_ERR, "SSL_read() failed");
syslogsslerr();
h->state = EToDelete;
}
} else {
#endif
if(errno != EAGAIN &&
errno != EWOULDBLOCK &&
errno != EINTR)
@ -713,6 +828,9 @@ Process_upnphttp(struct upnphttp * h)
h->state = EToDelete;
}
/* if errno is EAGAIN, EWOULDBLOCK or EINTR, try again later */
#ifdef ENABLE_HTTPS
}
#endif
}
else if(n==0)
{
@ -749,9 +867,29 @@ Process_upnphttp(struct upnphttp * h)
}
break;
case EWaitingForHttpContent:
#ifdef ENABLE_HTTPS
if(h->ssl) {
n = SSL_read(h->ssl, buf, sizeof(buf));
} else {
n = recv(h->socket, buf, sizeof(buf), 0);
}
#else
n = recv(h->socket, buf, sizeof(buf), 0);
#endif
if(n<0)
{
#ifdef ENABLE_HTTPS
if(h->ssl) {
int err;
err = SSL_get_error(h->ssl, n);
if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE)
{
syslog(LOG_ERR, "SSL_read() failed");
syslogsslerr();
h->state = EToDelete;
}
} else {
#endif
if(errno != EAGAIN &&
errno != EWOULDBLOCK &&
errno != EINTR)
@ -760,6 +898,9 @@ Process_upnphttp(struct upnphttp * h)
h->state = EToDelete;
}
/* if errno is EAGAIN, EWOULDBLOCK or EINTR, try again later */
#ifdef ENABLE_HTTPS
}
#endif
}
else if(n==0)
{
@ -941,10 +1082,33 @@ SendResp_upnphttp(struct upnphttp * h)
while (h->res_sent < h->res_buflen)
{
#ifdef ENABLE_HTTPS
if(h->ssl) {
n = SSL_write(h->ssl, h->res_buf + h->res_sent,
h->res_buflen - h->res_sent);
} else {
n = send(h->socket, h->res_buf + h->res_sent,
h->res_buflen - h->res_sent, 0);
}
#else
n = send(h->socket, h->res_buf + h->res_sent,
h->res_buflen - h->res_sent, 0);
#endif
if(n<0)
{
#ifdef ENABLE_HTTPS
if(h->ssl) {
int err;
err = SSL_get_error(h->ssl, n);
if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
/* try again later */
return 0;
}
syslog(LOG_ERR, "SSL_write() failed");
syslogsslerr();
break;
} else {
#endif
if(errno == EINTR)
continue; /* try again immediatly */
if(errno == EAGAIN || errno == EWOULDBLOCK)
@ -954,6 +1118,9 @@ SendResp_upnphttp(struct upnphttp * h)
}
syslog(LOG_ERR, "send(res_buf): %m");
break; /* avoid infinite loop */
#ifdef ENABLE_HTTPS
}
#endif
}
else if(n == 0)
{
@ -976,10 +1143,34 @@ SendRespAndClose_upnphttp(struct upnphttp * h)
while (h->res_sent < h->res_buflen)
{
#ifdef ENABLE_HTTPS
if(h->ssl) {
n = SSL_write(h->ssl, h->res_buf + h->res_sent,
h->res_buflen - h->res_sent);
} else {
n = send(h->socket, h->res_buf + h->res_sent,
h->res_buflen - h->res_sent, 0);
}
#else
n = send(h->socket, h->res_buf + h->res_sent,
h->res_buflen - h->res_sent, 0);
#endif
if(n<0)
{
#ifdef ENABLE_HTTPS
if(h->ssl) {
int err;
err = SSL_get_error(h->ssl, n);
if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
/* try again later */
h->state = ESendingAndClosing;
return;
}
syslog(LOG_ERR, "SSL_write() failed");
syslogsslerr();
break; /* avoid infinite loop */
} else {
#endif
if(errno == EINTR)
continue; /* try again immediatly */
if(errno == EAGAIN || errno == EWOULDBLOCK)
@ -990,6 +1181,9 @@ SendRespAndClose_upnphttp(struct upnphttp * h)
}
syslog(LOG_ERR, "send(res_buf): %m");
break; /* avoid infinite loop */
#ifdef ENABLE_HTTPS
}
#endif
}
else if(n == 0)
{

View File

@ -1,7 +1,7 @@
/* $Id: upnphttp.h,v 1.35 2012/10/03 21:03:50 nanard Exp $ */
/* $Id: upnphttp.h,v 1.37 2014/04/09 13:15:45 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2012 Thomas Bernard
* (c) 2006-2014 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -13,6 +13,10 @@
#include "config.h"
#ifdef ENABLE_HTTPS
#include <openssl/ssl.h>
#endif /* ENABLE_HTTPS */
#if 0
/* according to "UPnP Device Architecture 1.0" */
#define UPNP_VERSION_STRING "UPnP/1.0"
@ -53,7 +57,10 @@ struct upnphttp {
#ifdef ENABLE_IPV6
int ipv6;
struct in6_addr clientaddr_v6;
#endif
#endif /* ENABLE_IPV6 */
#ifdef ENABLE_HTTPS
SSL * ssl;
#endif /* ENABLE_HTTPS */
enum httpStates state;
char HttpVer[16];
/* request */
@ -101,11 +108,19 @@ struct upnphttp {
#define FLAG_ALLOW_POST 0x100
#define FLAG_ALLOW_SUB_UNSUB 0x200
#ifdef ENABLE_HTTPS
int init_ssl(void);
#endif /* ENABLE_HTTPS */
/* New_upnphttp() */
struct upnphttp *
New_upnphttp(int);
#ifdef ENABLE_HTTPS
void
InitSSL_upnphttp(struct upnphttp *);
#endif /* ENABLE_HTTPS */
/* CloseSocket_upnphttp() */
void
CloseSocket_upnphttp(struct upnphttp *);