10 ? $saved : self::CLOUDFLARE_RANGES; } /** * Daily: refresh Cloudflare's ranges. Keeps the previous list on any error. */ public static function refresh_ranges() { $res = wp_remote_get( 'https://api.cloudflare.com/client/v4/ips', [ 'timeout' => 10 ] ); if ( is_wp_error( $res ) || 200 !== wp_remote_retrieve_response_code( $res ) ) { return; } $data = json_decode( wp_remote_retrieve_body( $res ), true ); $ranges = []; foreach ( [ 'ipv4_cidrs', 'ipv6_cidrs' ] as $key ) { foreach ( (array) ( $data['result'][ $key ] ?? [] ) as $cidr ) { if ( is_string( $cidr ) && preg_match( '#^[0-9a-f:.]+/\d{1,3}$#i', $cidr ) ) { $ranges[] = $cidr; } } } if ( count( $ranges ) > 10 ) { update_option( self::RANGES_OPTION, $ranges, false ); } } public static function in_cidr( $ip, $cidr ) { list( $subnet, $bits ) = array_pad( explode( '/', $cidr, 2 ), 2, null ); $ip_bin = @inet_pton( $ip ); $net_bin = @inet_pton( $subnet ); if ( false === $ip_bin || false === $net_bin || strlen( $ip_bin ) !== strlen( $net_bin ) ) { return false; } $bits = null === $bits ? strlen( $ip_bin ) * 8 : (int) $bits; $bytes = intdiv( $bits, 8 ); if ( substr( $ip_bin, 0, $bytes ) !== substr( $net_bin, 0, $bytes ) ) { return false; } $rest = $bits % 8; if ( ! $rest ) { return true; } $mask = chr( ( 0xff << ( 8 - $rest ) ) & 0xff ); return ( $ip_bin[ $bytes ] & $mask ) === ( $net_bin[ $bytes ] & $mask ); } private static function is_private( $ip ) { return ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ); } private static function valid( $ip ) { $ip = trim( (string) $ip ); return filter_var( $ip, FILTER_VALIDATE_IP ) ? $ip : ''; } }