| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | namespace RemotelyLiving\PHPDNS\Resolvers; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | use GuzzleHttp\Client; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | use GuzzleHttp\ClientInterface; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | use GuzzleHttp\Exception\RequestException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | use GuzzleHttp\Promise\EachPromise; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | use GuzzleHttp\Psr7\Response; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | use RemotelyLiving\PHPDNS\Entities\DNSRecordCollection; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | use RemotelyLiving\PHPDNS\Entities\DNSRecordType; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | use RemotelyLiving\PHPDNS\Entities\Hostname; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | use RemotelyLiving\PHPDNS\Mappers\CloudFlare as CloudFlareMapper; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | use RemotelyLiving\PHPDNS\Resolvers\Exceptions\QueryFailure; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  | class CloudFlare extends ResolverAbstract | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  | { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     protected const BASE_URI = 'https://cloudflare-dns.com'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |     protected const DEFAULT_TIMEOUT = 5.0; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     protected const DEFAULT_OPTIONS = [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |         'base_uri' => self::BASE_URI, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         'connect_timeout' => self::DEFAULT_TIMEOUT, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |         'strict' => true, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |         'allow_redirects' => false, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |         'protocols' => ['https'], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |         'headers' => [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |             'Accept' => 'application/dns-json', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |         ], | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |     ]; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |      * @var \GuzzleHttp\Client|\GuzzleHttp\ClientInterface | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |     private $http; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |      * @var \RemotelyLiving\PHPDNS\Mappers\CloudFlare | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     private $mapper; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 39 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 40 |  |  |     public function __construct(ClientInterface $http = null, CloudFlareMapper $mapper = null) | 
            
                                                                        
                            
            
                                    
            
            
                | 41 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 42 |  |  |         $this->http = $http ?? new Client(self::DEFAULT_OPTIONS); | 
            
                                                                        
                            
            
                                    
            
            
                | 43 |  |  |         $this->mapper = $mapper ?? new CloudFlareMapper(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |     protected function doQuery(Hostname $hostname, DNSRecordType $type): DNSRecordCollection | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |         try { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |             return (!$type->isA(DNSRecordType::TYPE_ANY)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |                 ? $this->doApiQuery($hostname, $type) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |                 : $this->doAnyApiQuery($hostname); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |         } catch (RequestException $e) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |             throw new QueryFailure("Unable to query CloudFlare API", 0, $e); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |      * Cloudflare does not support ANY queries, so we must ask for all record types individually | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     private function doAnyApiQuery(Hostname $hostname): DNSRecordCollection | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         $results = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         $eachPromise = new EachPromise($this->generateEachTypeQuery($hostname), [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |             'concurrency' => 4, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |             'fulfilled' => function (Response $response) use (&$results) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |                 $results = array_merge( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |                     $results, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |                     $this->parseResult((array) json_decode((string)$response->getBody(), true)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |                 ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |             }, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |             'rejected' => function (RequestException $e) : void { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |                 throw $e; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |             }, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |         ]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |         $eachPromise->promise()->wait(true); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |         return $this->mapResults($this->mapper, $results); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |     private function generateEachTypeQuery(Hostname $hostname): \Generator | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |         foreach (DNSRecordType::VALID_TYPES as $type) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |             if ($type === DNSRecordType::TYPE_ANY) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |                 continue 1; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |             yield $this->http->requestAsync( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |                 'GET', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |                 '/dns-query?' . http_build_query(['name' => (string)$hostname, 'type' => $type]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |             ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |     private function doApiQuery(Hostname $hostname, DNSRecordType $type): DNSRecordCollection | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |         $url = '/dns-query?' . http_build_query(['name' => (string)$hostname, 'type' => (string)$type]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |         $decoded = (array)json_decode( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |             (string)$this->http->requestAsync('GET', $url)->wait(true)->getBody(), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |             true | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |         ); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |         return $this->mapResults($this->mapper, $this->parseResult($decoded)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |     private function parseResult(array $result): array | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |         if (isset($result['Answer'])) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |             return $result['Answer']; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |         if (isset($result['Authority'])) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |             return $result['Authority']; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |         return []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 118 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 119 |  |  |  |