/** * sends a standard Net_DNS2_Packet_Request packet * * @param Net_DNS2_Packet $request a Net_DNS2_Packet_Request object * @param boolean $use_tcp true/false if the function should * use TCP for the request * * @return mixed returns a Net_DNS2_Packet_Response object, or false on error * @throws Net_DNS2_Exception * @access protected * */ protected function sendPacket(Net_DNS2_Packet $request, $use_tcp) { // // get the data from the packet // $data = $request->get(); if (strlen($data) < Net_DNS2_Lookups::DNS_HEADER_SIZE) { throw new Net_DNS2_Exception('invalid or empty packet for sending!', Net_DNS2_Lookups::E_PACKET_INVALID, null, $request); } reset($this->nameservers); // // randomize the name server list if it's asked for // if ($this->ns_random == true) { shuffle($this->nameservers); } // // loop so we can handle server errors // $response = null; $ns = ''; while (1) { // // grab the next DNS server // $ns = each($this->nameservers); if ($ns === false) { if (is_null($this->last_exception) == false) { throw $this->last_exception; } else { throw new Net_DNS2_Exception('every name server provided has failed', Net_DNS2_Lookups::E_NS_FAILED); } } $ns = $ns[1]; // // if the use TCP flag (force TCP) is set, or the packet is bigger than our // max allowed UDP size- which is either 512, or if this is DNSSEC request, // then whatever the configured dnssec_payload_size is. // $max_udp_size = Net_DNS2_Lookups::DNS_MAX_UDP_SIZE; if ($this->dnssec == true) { $max_udp_size = $this->dnssec_payload_size; } if ($use_tcp == true || strlen($data) > $max_udp_size) { try { $response = $this->sendTCPRequest($ns, $data, $request->question[0]->qtype == 'AXFR' ? true : false); } catch (Net_DNS2_Exception $e) { $this->last_exception = $e; $this->last_exception_list[$ns] = $e; continue; } // // otherwise, send it using UDP // } else { try { $response = $this->sendUDPRequest($ns, $data); // // check the packet header for a trucated bit; if it was truncated, // then re-send the request as TCP. // if ($response->header->tc == 1) { $response = $this->sendTCPRequest($ns, $data); } } catch (Net_DNS2_Exception $e) { $this->last_exception = $e; $this->last_exception_list[$ns] = $e; continue; } } // // make sure header id's match between the request and response // if ($request->header->id != $response->header->id) { $this->last_exception = new Net_DNS2_Exception('invalid header: the request and response id do not match.', Net_DNS2_Lookups::E_HEADER_INVALID, null, $request, $response); $this->last_exception_list[$ns] = $this->last_exception; continue; } // // make sure the response is actually a response // // 0 = query, 1 = response // if ($response->header->qr != Net_DNS2_Lookups::QR_RESPONSE) { $this->last_exception = new Net_DNS2_Exception('invalid header: the response provided is not a response packet.', Net_DNS2_Lookups::E_HEADER_INVALID, null, $request, $response); $this->last_exception_list[$ns] = $this->last_exception; continue; } // // make sure the response code in the header is ok // if ($response->header->rcode != Net_DNS2_Lookups::RCODE_NOERROR) { $this->last_exception = new Net_DNS2_Exception('DNS request failed: ' . Net_DNS2_Lookups::$result_code_messages[$response->header->rcode], $response->header->rcode, null, $request, $response); $this->last_exception_list[$ns] = $this->last_exception; continue; } break; } return $response; }
/** * sends a standard Net_DNS2_Packet_Request packet * * @param Net_DNS2_Packet $request a Net_DNS2_Packet_Request object * @param boolean $use_tcp true/false if the function should * use TCP for the request * * @return mixed returns a Net_DNS2_Packet_Response object, or false on error * @throws Net_DNS2_Exception * @access protected * */ protected function sendPacket(Net_DNS2_Packet $request, $use_tcp) { // // get the data from the packet // $data = $request->get(); if (strlen($data) < Net_DNS2_Lookups::DNS_HEADER_SIZE) { throw new Net_DNS2_Exception('invalid or empty packet for sending!', Net_DNS2_Lookups::E_PACKET_INVALID, null, $request); } reset($this->nameservers); // // randomize the name server list if it's asked for // if ($this->ns_random == true) { shuffle($this->nameservers); } // // loop so we can handle server errors // $response = null; $ns = ''; $socket_type = null; $tcp_fallback = false; while (1) { // // grab the next DNS server // if ($tcp_fallback == false) { $ns = each($this->nameservers); if ($ns === false) { throw new Net_DNS2_Exception('every name server provided has failed: ' . $this->_last_socket_error, Net_DNS2_Lookups::E_NS_FAILED); } $ns = $ns[1]; } // // if the use TCP flag (force TCP) is set, or the packet is bigger // than 512 bytes, use TCP for sending the packet // if ($use_tcp == true || strlen($data) > Net_DNS2_Lookups::DNS_MAX_UDP_SIZE || $tcp_fallback == true) { $tcp_fallback = false; $socket_type = Net_DNS2_Socket::SOCK_STREAM; // // create the socket object // if (!isset($this->sock['tcp'][$ns]) || !$this->sock['tcp'][$ns] instanceof Net_DNS2_Socket) { if ($this->sockets_enabled === true) { $this->sock['tcp'][$ns] = new Net_DNS2_Socket_Sockets(Net_DNS2_Socket::SOCK_STREAM, $ns, $this->dns_port, $this->timeout); } else { $this->sock['tcp'][$ns] = new Net_DNS2_Socket_Streams(Net_DNS2_Socket::SOCK_STREAM, $ns, $this->dns_port, $this->timeout); } } // // if a local IP address / port is set, then add it // if (strlen($this->local_host) > 0) { $this->sock['tcp'][$ns]->bindAddress($this->local_host, $this->local_port); } // // open it; if it fails, continue in the while loop // if ($this->sock['tcp'][$ns]->open() === false) { $this->_last_socket_error = $this->sock['tcp'][$ns]->last_error; continue; } // // write the data to the socket; if it fails, continue on // the while loop // if ($this->sock['tcp'][$ns]->write($data) === false) { $this->_last_socket_error = $this->sock['tcp'][$ns]->last_error; continue; } // // read the content, using select to wait for a response // $size = 0; $result = null; // // handle zone transfer requests differently than other requests. // if ($request->question[0]->qtype == 'AXFR') { $soa_count = 0; while (1) { // // read the data off the socket // $result = $this->sock['tcp'][$ns]->read($size); if ($result === false || $size < Net_DNS2_Lookups::DNS_HEADER_SIZE) { $this->_last_socket_error = $this->sock['tcp'][$ns]->last_error; break; } // // parse the first chunk as a packet // $chunk = new Net_DNS2_Packet_Response($result, $size); // // if this is the first packet, then clone it directly, then // go through it to see if there are two SOA records // (indicating that it's the only packet) // if (is_null($response) == true) { $response = clone $chunk; // // look for a failed response; if the zone transfer // failed, then we don't need to do anything else at this // point, and we should just break out. // if ($response->header->rcode != Net_DNS2_Lookups::RCODE_NOERROR) { break; } // // go through each answer // foreach ($response->answer as $index => $rr) { // // count the SOA records // if ($rr->type == 'SOA') { $soa_count++; } } // // if we have 2 or more SOA records, then we're done; // otherwise continue out so we read the rest of the // packets off the socket // if ($soa_count >= 2) { break; } else { continue; } } else { // // go through all these answers, and look for SOA records // foreach ($chunk->answer as $index => $rr) { // // count the number of SOA records we find // if ($rr->type == 'SOA') { $soa_count++; } // // add the records to a single response object // $response->answer[] = $rr; } // // if we've found the second SOA record, we're done // if ($soa_count >= 2) { break; } } } } else { $result = $this->sock['tcp'][$ns]->read($size); if ($result === false || $size < Net_DNS2_Lookups::DNS_HEADER_SIZE) { $this->_last_socket_error = $this->sock['tcp'][$ns]->last_error; continue; } // // create the packet object // $response = new Net_DNS2_Packet_Response($result, $size); } break; } else { $socket_type = Net_DNS2_Socket::SOCK_DGRAM; // // create the socket object // if (!isset($this->sock['udp'][$ns]) || !$this->sock['udp'][$ns] instanceof Net_DNS2_Socket) { if ($this->sockets_enabled === true) { $this->sock['udp'][$ns] = new Net_DNS2_Socket_Sockets(Net_DNS2_Socket::SOCK_DGRAM, $ns, $this->dns_port, $this->timeout); } else { $this->sock['udp'][$ns] = new Net_DNS2_Socket_Streams(Net_DNS2_Socket::SOCK_DGRAM, $ns, $this->dns_port, $this->timeout); } } // // if a local IP address / port is set, then add it // if (strlen($this->local_host) > 0) { $this->sock['udp'][$ns]->bindAddress($this->local_host, $this->local_port); } // // open it // if ($this->sock['udp'][$ns]->open() === false) { $this->_last_socket_error = $this->sock['udp'][$ns]->last_error; continue; } // // write the data to the socket // if ($this->sock['udp'][$ns]->write($data) === false) { $this->_last_socket_error = $this->sock['udp'][$ns]->last_error; continue; } // // read the content, using select to wait for a response // $size = 0; $result = $this->sock['udp'][$ns]->read($size); if ($result === false || $size < Net_DNS2_Lookups::DNS_HEADER_SIZE) { $this->_last_socket_error = $this->sock['udp'][$ns]->last_error; continue; } // // create the packet object // $response = new Net_DNS2_Packet_Response($result, $size); if (is_null($response)) { throw new Net_DNS2_Exception('empty response object', Net_DNS2_Lookups::E_NS_FAILED, null, $request); } // // check the packet header for a trucated bit; if it was truncated, // then re-send the request as TCP. // if ($response->header->tc == 1) { $tcp_fallback = true; continue; } break; } } // // if $response is null, then we didn't even try once; which shouldn't // actually ever happen // if (is_null($response)) { throw new Net_DNS2_Exception('empty response object', Net_DNS2_Lookups::E_NS_FAILED, null, $request); } // // add the name server that the response came from to the response object, // and the socket type that was used. // $response->answer_from = $ns; $response->answer_socket_type = $socket_type; // // make sure header id's match between the request and response // if ($request->header->id != $response->header->id) { throw new Net_DNS2_Exception('invalid header: the request and response id do not match.', Net_DNS2_Lookups::E_HEADER_INVALID, null, $request, $response); } // // make sure the response is actually a response // // 0 = query, 1 = response // if ($response->header->qr != Net_DNS2_Lookups::QR_RESPONSE) { throw new Net_DNS2_Exception('invalid header: the response provided is not a response packet.', Net_DNS2_Lookups::E_HEADER_INVALID, null, $request, $response); } // // make sure the response code in the header is ok // if ($response->header->rcode != Net_DNS2_Lookups::RCODE_NOERROR) { throw new Net_DNS2_Exception('DNS request failed: ' . Net_DNS2_Lookups::$result_code_messages[$response->header->rcode], $response->header->rcode, null, $request, $response); } return $response; }
/** * sends a standard Net_DNS2_Packet_Request packet * * @param Net_DNS2_Packet $request a Net_DNS2_Packet_Request object * @param boolean $use_tcp true/false if the function should * use TCP for the request * * @return mixed returns a Net_DNS2_Packet_Response object, or false on error * @throws Net_DNS2_Exception * @access protected * */ protected function sendPacket(Net_DNS2_Packet $request, $use_tcp) { // // get the data from the packet // $data = $request->get(); if (strlen($data) < Net_DNS2_Lookups::DNS_HEADER_SIZE) { throw new Net_DNS2_Exception('invalid or empty packet for sending!', Net_DNS2_Lookups::E_PACKET_INVALID); } reset($this->nameservers); // // randomize the name server list if it's asked for // if ($this->ns_random == true) { shuffle($this->nameservers); } // // loop so we can handle server errors // $response = null; $ns = ''; $tcp_fallback = false; while (1) { // // grab the next DNS server // if ($tcp_fallback == false) { $ns = each($this->nameservers); if ($ns === false) { throw new Net_DNS2_Exception('every name server provided has failed: ' . $this->_last_socket_error, Net_DNS2_Lookups::E_NS_FAILED); } $ns = $ns[1]; } // // if the use TCP flag (force TCP) is set, or the packet is bigger // than 512 bytes, use TCP for sending the packet // if ($use_tcp == true || strlen($data) > Net_DNS2_Lookups::DNS_MAX_UDP_SIZE || $tcp_fallback == true) { $tcp_fallback = false; // // create the socket object // if (!isset($this->sock['tcp'][$ns]) || !$this->sock['tcp'][$ns] instanceof Net_DNS2_Socket) { if ($this->sockets_enabled === true) { $this->sock['tcp'][$ns] = new Net_DNS2_Socket_Sockets(SOCK_STREAM, $ns, $this->dns_port, $this->timeout); } else { $this->sock['tcp'][$ns] = new Net_DNS2_Socket_Streams(SOCK_STREAM, $ns, $this->dns_port, $this->timeout); } } // // if a local IP address / port is set, then add it // if (strlen($this->local_host) > 0) { $this->sock['tcp'][$ns]->bindAddress($this->local_host, $this->local_port); } // // open it; if it fails, continue in the while loop // if ($this->sock['tcp'][$ns]->open() === false) { $this->_last_socket_error = $this->sock['tcp'][$ns]->last_error; continue; } // // write the data to the socket; if it fails, continue on // the while loop // if ($this->sock['tcp'][$ns]->write($data) === false) { $this->_last_socket_error = $this->sock['tcp'][$ns]->last_error; continue; } // // read the content, using select to wait for a response // $size = 0; $result = $this->sock['tcp'][$ns]->read($size); if ($result === false || $size < Net_DNS2_Lookups::DNS_HEADER_SIZE) { $this->_last_socket_error = $this->sock['tcp'][$ns]->last_error; continue; } // // create the packet object // $response = new Net_DNS2_Packet_Response($result, $size); break; } else { // // create the socket object // if (!isset($this->sock['udp'][$ns]) || !$this->sock['udp'][$ns] instanceof Net_DNS2_Socket) { if ($this->sockets_enabled === true) { $this->sock['udp'][$ns] = new Net_DNS2_Socket_Sockets(SOCK_DGRAM, $ns, $this->dns_port, $this->timeout); } else { $this->sock['udp'][$ns] = new Net_DNS2_Socket_Streams(SOCK_DGRAM, $ns, $this->dns_port, $this->timeout); } } // // if a local IP address / port is set, then add it // if (strlen($this->local_host) > 0) { $this->sock['udp'][$ns]->bindAddress($this->local_host, $this->local_port); } // // open it // if ($this->sock['udp'][$ns]->open() === false) { $this->_last_socket_error = $this->sock['udp'][$ns]->last_error; continue; } // // write the data to the socket // if ($this->sock['udp'][$ns]->write($data) === false) { $this->_last_socket_error = $this->sock['udp'][$ns]->last_error; continue; } // // read the content, using select to wait for a response // $size = 0; $result = $this->sock['udp'][$ns]->read($size); if ($result === false || $size < Net_DNS2_Lookups::DNS_HEADER_SIZE) { $this->_last_socket_error = $this->sock['udp'][$ns]->last_error; continue; } // // create the packet object // $response = new Net_DNS2_Packet_Response($result, $size); // // check the packet header for a trucated bit; if it was truncated, // then re-send the request as TCP. // if ($response->header->tc == 1) { $tcp_fallback = true; continue; } break; } } if (is_null($response)) { return false; } // // make sure header id's match between the request and response // if ($request->header->id != $response->header->id) { throw new Net_DNS2_Exception('invalid header: the request and response id do not match.', Net_DNS2_Lookups::E_HEADER_INVALID); } // // make sure the response is actually a response // // 0 = query, 1 = response // if ($response->header->qr != Net_DNS2_Lookups::QR_RESPONSE) { throw new Net_DNS2_Exception('invalid header: the response provided is not a response packet.', Net_DNS2_Lookups::E_HEADER_INVALID); } // // make sure the response code in the header is ok // if ($response->header->rcode != Net_DNS2_Lookups::RCODE_NOERROR) { throw new Net_DNS2_Exception('DNS request failed: ' . Net_DNS2_Lookups::$result_code_messages[$response->header->rcode], $response->header->rcode); } return $response; }