@@ -444,6 +444,37 @@ function getLatestVersion($product='core', $major=null) {
444444 }
445445 }
446446
447+ /*
448+ * getTrustedProxies
449+ *
450+ * Get defined trusted proxies
451+ */
452+
453+ static function getTrustedProxies () {
454+ static $ proxies = null ;
455+ // Parse trusted proxies from config file
456+ if (!isset ($ proxies ) && defined ('TRUSTED_PROXIES ' ))
457+ $ proxies = array_filter (
458+ array_map ('trim ' , explode (', ' , TRUSTED_PROXIES )));
459+
460+ return $ proxies ?: array ();
461+ }
462+
463+ /*
464+ * getLocalNetworkAddresses
465+ *
466+ * Get defined local network addresses
467+ */
468+ static function getLocalNetworkAddresses () {
469+ static $ ips = null ;
470+ // Parse local addreses from config file
471+ if (!isset ($ ips ) && defined ('LOCAL_NETWORKS ' ))
472+ $ ips = array_filter (
473+ array_map ('trim ' , explode (', ' , LOCAL_NETWORKS )));
474+
475+ return $ ips ?: array ();
476+ }
477+
447478 static function get_root_path ($ dir ) {
448479
449480 /* If run from the commandline, DOCUMENT_ROOT will not be set. It is
@@ -488,14 +519,96 @@ static function get_root_path($dir) {
488519 return null ;
489520 }
490521
522+ /*
523+ * get_client_ip
524+ *
525+ * Get client IP address from "Http_X-Forwarded-For" header by following a
526+ * chain of trusted proxies.
527+ *
528+ * "Http_X-Forwarded-For" header value is a comma+space separated list of IP
529+ * addresses, the left-most being the original client, and each successive
530+ * proxy that passed the request all the way to the originating IP address.
531+ *
532+ */
533+ static function get_client_ip ($ header ='HTTP_X_FORWARDED_FOR ' ) {
534+
535+ // Request IP
536+ $ ip = $ _SERVER ['REMOTE_ADDR ' ];
537+ // Trusted proxies.
538+ $ proxies = self ::getTrustedProxies ();
539+ // Return current IP address if header is not set and
540+ // request is not from a trusted proxy.
541+ if (!isset ($ _SERVER [$ header ])
542+ || !$ proxies
543+ || !self ::is_trusted_proxy ($ ip , $ proxies ))
544+ return $ ip ;
545+
546+ // Get chain of proxied ip addresses
547+ $ ips = array_map ('trim ' , explode (', ' , $ _SERVER [$ header ]));
548+ // Add request IP to the chain
549+ $ ips [] = $ ip ;
550+ // Walk the chain in reverse - remove invalid IPs
551+ $ ips = array_reverse ($ ips );
552+ foreach ($ ips as $ k => $ ip ) {
553+ // Make sure the IP is valid and not a trusted proxy
554+ if ($ k && !Validator::is_ip ($ ip ))
555+ unset($ ips [$ k ]);
556+ elseif ($ k && !self ::is_trusted_proxy ($ ip , $ proxies ))
557+ return $ ip ;
558+ }
559+
560+ // We trust the 400 lb hacker... return left most valid IP
561+ return array_pop ($ ips );
562+ }
563+
564+ /*
565+ * Checks if the IP is that of a trusted proxy
566+ *
567+ */
568+ static function is_trusted_proxy ($ ip , $ proxies =array ()) {
569+ $ proxies = $ proxies ?: self ::getTrustedProxies ();
570+ // We don't have any proxies set.
571+ if (!$ proxies )
572+ return false ;
573+ // Wildcard set - trust all proxies
574+ else if ($ proxies == '* ' )
575+ return true ;
576+
577+ return ($ proxies && Validator::check_ip ($ ip , $ proxies ));
578+ }
579+
580+ /**
581+ * is_local_ip
582+ *
583+ * Check if a given IP is part of defined local address blocks
584+ *
585+ */
586+ static function is_local_ip ($ ip , $ ips =array ()) {
587+ $ ips = $ ips
588+ ?: self ::getLocalNetworkAddresses ()
589+ ?: array ();
590+
591+ foreach ($ ips as $ addr ) {
592+ if (Validator::check_ip ($ ip , $ addr ))
593+ return true ;
594+ }
595+
596+ return false ;
597+ }
598+
491599 /**
492600 * Returns TRUE if the request was made via HTTPS and false otherwise
493601 */
494602 function is_https () {
495- return (isset ($ _SERVER ['HTTPS ' ])
603+
604+ // Local server flags
605+ if (isset ($ _SERVER ['HTTPS ' ])
496606 && strtolower ($ _SERVER ['HTTPS ' ]) == 'on ' )
497- || (isset ($ _SERVER ['HTTP_X_FORWARDED_PROTO ' ])
498- && strtolower ($ _SERVER ['HTTP_X_FORWARDED_PROTO ' ]) == 'https ' );
607+ return true ;
608+
609+ // Check if SSL was terminated by a loadbalancer
610+ return (isset ($ _SERVER ['HTTP_X_FORWARDED_PROTO ' ])
611+ && !strcasecmp ($ _SERVER ['HTTP_X_FORWARDED_PROTO ' ], 'https ' ));
499612 }
500613
501614 /* returns true if script is being executed via commandline */
0 commit comments