[vlc-devel] [PATCH 2/2] httpd: mitigate DNS rebinding attack by allowing to specify a domain white list.
Pierre Lamot
pierre at videolabs.io
Wed Jan 31 18:38:02 CET 2018
---
src/libvlc-module.c | 5 +++
src/network/httpd.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 108 insertions(+), 6 deletions(-)
diff --git a/src/libvlc-module.c b/src/libvlc-module.c
index cc816873f7..5ca902d67a 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -848,6 +848,10 @@ static const char *const ppsz_prefres[] = {
#define KEY_LONGTEXT N_( \
"This private key file (PEM format) is used for server-side TLS.")
+#define HTTP_DOMAIN_WHITELIST_TEXT N_("HTTP server list of allowed domain")
+#define HTTP_DOMAIN_WHITELIST_LONGTEXT N_( "By default, the HTTP server will accept requests " \
+ "from any domain. Specify a comma-separated list of domains to restrict them." )
+
#define SOCKS_SERVER_TEXT N_("SOCKS server")
#define SOCKS_SERVER_LONGTEXT N_( \
"SOCKS proxy server to use. This must be of the form " \
@@ -1800,6 +1804,7 @@ vlc_module_begin ()
add_loadfile( "http-cert", NULL, HTTP_CERT_TEXT, CERT_LONGTEXT, true )
add_obsolete_string( "sout-http-cert" ) /* since 2.0.0 */
add_loadfile( "http-key", NULL, HTTP_KEY_TEXT, KEY_LONGTEXT, true )
+ add_string( "http-domain-whitelist", NULL, HTTP_DOMAIN_WHITELIST_TEXT, HTTP_DOMAIN_WHITELIST_LONGTEXT, true )
add_obsolete_string( "sout-http-key" ) /* since 2.0.0 */
add_obsolete_string( "http-ca" ) /* since 3.0.0 */
add_obsolete_string( "sout-http-ca" ) /* since 2.0.0 */
diff --git a/src/network/httpd.c b/src/network/httpd.c
index cfd947ad94..542cb20968 100644
--- a/src/network/httpd.c
+++ b/src/network/httpd.c
@@ -52,6 +52,9 @@
#ifdef HAVE_POLL
# include <poll.h>
#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
#if defined(_WIN32)
# include <winsock2.h>
@@ -81,7 +84,9 @@ struct httpd_host_t
int *fds;
unsigned nfd;
unsigned port;
+
char *psz_origin;
+ vlc_array_t *domainwhitelist;
vlc_thread_t thread;
vlc_mutex_t lock;
@@ -860,12 +865,12 @@ void httpd_StreamDelete(httpd_stream_t *stream)
*****************************************************************************/
static void* httpd_HostThread(void *);
static httpd_host_t *httpd_HostCreate(vlc_object_t *, const char *,
- const char *, vlc_tls_creds_t *);
+ const char *, const char *, vlc_tls_creds_t *);
/* create a new host */
httpd_host_t *vlc_http_HostNew(vlc_object_t *p_this)
{
- return httpd_HostCreate(p_this, "http-host", "http-port", NULL);
+ return httpd_HostCreate(p_this, "http-host", "http-port", "http-domain-whitelist", NULL);
}
httpd_host_t *vlc_https_HostNew(vlc_object_t *obj)
@@ -889,12 +894,12 @@ httpd_host_t *vlc_https_HostNew(vlc_object_t *obj)
free(key);
free(cert);
- return httpd_HostCreate(obj, "http-host", "https-port", tls);
+ return httpd_HostCreate(obj, "http-host", "https-port", "http-domain-whitelist", tls);
}
httpd_host_t *vlc_rtsp_HostNew(vlc_object_t *p_this)
{
- return httpd_HostCreate(p_this, "rtsp-host", "rtsp-port", NULL);
+ return httpd_HostCreate(p_this, "rtsp-host", "rtsp-port", NULL, NULL);
}
static struct httpd
@@ -905,9 +910,48 @@ static struct httpd
int i_host;
} httpd = { VLC_STATIC_MUTEX, NULL, 0 };
+static vlc_array_t *httpd_DomainListFromString(vlc_object_t *p_this, const char* variable)
+{
+ char *buf = var_InheritString (p_this, variable);
+ if ( buf == NULL )
+ return NULL;
+
+ vlc_array_t* domainwhitelist = (vlc_array_t*) malloc( sizeof( vlc_array_t ) );
+ if ( !domainwhitelist )
+ return NULL;
+ vlc_array_init(domainwhitelist);
+
+ char *p = buf;
+ if ( *p == '{' )
+ p++;
+
+ char *end = strchr( p, '}' );
+ if ( end != NULL )
+ *end = '\0';
+
+ while( p != NULL && *p )
+ {
+ const char *host;
+
+ p += strspn( p, ", " );
+ host = p;
+ end = strchr( p, ',' );
+ if ( end != NULL )
+ *( end++ ) = '\0';
+ p = end;
+
+ if ( *host == '\0' )
+ break;
+
+ vlc_array_append_or_abort( domainwhitelist, (void*) strdup( host ) );
+ }
+ free( buf );
+ return domainwhitelist;
+}
+
static httpd_host_t *httpd_HostCreate(vlc_object_t *p_this,
const char *hostvar,
- const char *portvar,
+ const char *portvar, const char *domainwhitelistvar,
vlc_tls_creds_t *p_tls)
{
httpd_host_t *host;
@@ -972,7 +1016,9 @@ static httpd_host_t *httpd_HostCreate(vlc_object_t *p_this,
host->i_client = 0;
host->client = NULL;
host->p_tls = p_tls;
+
host->psz_origin = url.psz_host ? strdup( url.psz_host ) : NULL;
+ host->domainwhitelist = httpd_DomainListFromString( p_this, domainwhitelistvar );
/* create the thread */
if (vlc_clone(&host->thread, httpd_HostThread, host,
@@ -1044,6 +1090,15 @@ void httpd_HostDelete(httpd_host_t *host)
vlc_mutex_destroy(&host->lock);
if ( host->psz_origin )
free( host->psz_origin );
+ if ( host->domainwhitelist )
+ {
+ int index = vlc_array_count(host->domainwhitelist);
+ while ( index-- )
+ free( vlc_array_item_at_index( host->domainwhitelist, index ) );
+ vlc_array_clear( host->domainwhitelist );
+ free( host->domainwhitelist );
+ }
+
vlc_object_release(host);
vlc_mutex_unlock(&httpd.mutex);
}
@@ -1725,6 +1780,47 @@ static bool httpdOriginOk( const httpd_host_t *p_host, const httpd_message_t *p_
return ret;
}
+static bool httpIsDomainAllowed( const httpd_host_t *p_host, const httpd_message_t *p_query )
+{
+ if ( p_host->domainwhitelist == NULL )
+ return true;
+
+ const char* psz_host = httpd_MsgGet( p_query, "Host" );
+ if ( psz_host == NULL )
+ return true;
+ char* psz_hostname = strndup( psz_host, strcspn( psz_host, ":" ) );
+
+
+#ifdef AF_INET6
+ char tmp[sizeof(struct in6_addr)];
+#else
+ char tmp[sizeof(struct in_addr)];
+#endif
+
+ if ( (strcmp( psz_hostname, "localhost" ) == 0)
+ || (strcmp( psz_hostname , "localhost." ) == 0)
+ || (inet_pton( AF_INET, psz_hostname, &tmp ) == 1)
+#ifdef AF_INET6
+ || (inet_pton( AF_INET6, psz_hostname, &tmp ) == 1)
+#endif
+ )
+ {
+ free( psz_hostname );
+ return true;
+ }
+
+ int count = vlc_array_count( p_host->domainwhitelist );
+ while (count--) {
+ const char* psz_allowedhost = vlc_array_item_at_index( p_host->domainwhitelist, count );
+ if ( strcmp( psz_allowedhost, psz_hostname ) == 0 ) {
+ free( psz_hostname );
+ return true;
+ }
+ }
+
+ free( psz_hostname );
+ return false;
+}
static void httpdLoop(httpd_host_t *host)
{
@@ -1881,7 +1977,8 @@ static void httpdLoop(httpd_host_t *host)
if ( query->i_proto == HTTPD_PROTO_HTTP )
{
- b_crsf_failed = !httpdOriginOk( host, query );
+ b_crsf_failed = !httpdOriginOk( host, query )
+ || !httpIsDomainAllowed( host, query );
if ( b_crsf_failed )
break;
--
2.14.1
More information about the vlc-devel
mailing list