uhttpd: add option to reject requests from RFC1918 IPs to public server IPs (DNS...
authorJo-Philipp Wich <jow@openwrt.org>
Wed, 11 Aug 2010 00:05:34 +0000 (00:05 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Wed, 11 Aug 2010 00:05:34 +0000 (00:05 +0000)
SVN-Revision: 22589

package/uhttpd/Makefile
package/uhttpd/files/uhttpd.config
package/uhttpd/files/uhttpd.init
package/uhttpd/src/uhttpd-utils.c
package/uhttpd/src/uhttpd-utils.h
package/uhttpd/src/uhttpd.c
package/uhttpd/src/uhttpd.h

index 2ad0816e3aa15fdbac400b23d3f6fb752c07082d..8a7b5295d9eedff3911676d705bba02fc5a8f860 100644 (file)
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=uhttpd
-PKG_RELEASE:=12
+PKG_RELEASE:=13
 
 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 PKG_BUILD_DEPENDS := libcyassl liblua
index acdd62ea4eb471aba1e9f5f9397ad1715ff008bb..534e8f8b29da31f1e33df1a2975250fbccd25742 100644 (file)
@@ -12,6 +12,11 @@ config uhttpd main
        # Server document root
        option home             /www
 
+       # Reject requests from RFC1918 IP addresses
+       # directed to the servers public IP(s).
+       # This is a DNS rebinding countermeasure.
+       option rfc1918_filter 1
+
        # Certificate and private key for HTTPS.
        # If no listen_https addresses are given,
        # the key options are ignored.
index d543dd84b9511975f22685309dc889bd2c084a2e..b00b2e281b97898c784ef986d9c4b71f5ba0f2fc 100755 (executable)
@@ -75,6 +75,7 @@ start_instance()
 
        append_bool "$cfg" no_symlinks "-S" 0
        append_bool "$cfg" no_dirlists "-D" 0
+       append_bool "$cfg" rfc1918_filter "-R" 0
 
        config_get http "$cfg" listen_http
        for listen in $http; do
index 60badf26df9c44f7d6cb41dc615bf2abe372297d..4a1423c715d0db9e9b6f7d1ff44f34250574b336 100644 (file)
@@ -59,6 +59,21 @@ int sa_port(void *sa)
        return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
 }
 
+int sa_rfc1918(void *sa)
+{
+       struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
+       unsigned long a = htonl(v4->sin_addr.s_addr);
+
+       if( v4->sin_family == AF_INET )
+       {
+               return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) ||
+                      ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) ||
+                      ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF));
+       }
+
+       return 0;
+}
+
 /* Simple strstr() like function that takes len arguments for both haystack and needle. */
 char *strfind(char *haystack, int hslen, const char *needle, int ndlen)
 {
index a6448b63bc1d1e9055ed67edd7c6b8ff8c71ed96..1b18265417910ad402e125dd5e924a4c54aac0ea 100644 (file)
@@ -49,6 +49,7 @@ struct path_info {
 const char * sa_straddr(void *sa);
 const char * sa_strport(void *sa);
 int sa_port(void *sa);
+int sa_rfc1918(void *sa);
 
 char *strfind(char *haystack, int hslen, const char *needle, int ndlen);
 
index 82729627e08ba0725e8bd3d179394d13deaceeee..be882470ad0b0988605a8e695c3e44488b3f1165 100644 (file)
@@ -524,7 +524,7 @@ int main (int argc, char **argv)
 #endif
 
        while( (opt = getopt(argc, argv,
-               "fSDC:K:E:I:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0
+               "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0
        ) {
                switch(opt)
                {
@@ -648,6 +648,10 @@ int main (int argc, char **argv)
                                conf.no_dirlists = 1;
                                break;
 
+                       case 'R':
+                               conf.rfc1918_filter = 1;
+                               break;
+
 #ifdef HAVE_CGI
                        /* cgi prefix */
                        case 'x':
@@ -728,6 +732,7 @@ int main (int argc, char **argv)
                                        "       -I string       Use given filename as index page for directories\n"
                                        "       -S              Do not follow symbolic links outside of the docroot\n"
                                        "       -D              Do not allow directory listings, send 403 instead\n"
+                                       "       -R              Enable RFC1918 filter\n"
 #ifdef HAVE_LUA
                                        "       -l string       URL prefix for Lua handler, default is '/lua'\n"
                                        "       -L file         Lua handler script, omit to disable Lua\n"
@@ -932,6 +937,14 @@ int main (int argc, char **argv)
                                        /* parse message header */
                                        if( (req = uh_http_header_recv(cl)) != NULL )
                                        {
+                                               /* RFC1918 filtering required? */
+                                               if( conf.rfc1918_filter && sa_rfc1918(&cl->peeraddr) &&
+                                                   !sa_rfc1918(&cl->servaddr) )
+                                               {
+                                                       uh_http_sendhf(cl, 403, "Forbidden",
+                                                               "Rejected request from RFC1918 IP to public server address");
+                                               }
+                                               else
 #ifdef HAVE_LUA
                                                /* Lua request? */
                                                if( L && uh_path_match(conf.lua_prefix, req->url) )
index c8fdaf4846450b5000f2c2e04dbd2e1f40526120..fd2176ebdd9c7a3fc5e4470698e8c6bb2c352b4f 100644 (file)
@@ -69,6 +69,7 @@ struct config {
        int no_symlinks;
        int no_dirlists;
        int network_timeout;
+       int rfc1918_filter;
 #ifdef HAVE_CGI
        char *cgi_prefix;
 #endif