/** * Sends a DNS query to the given server, and waits for a response. * Possibly times out with a SocketException if the response takes * too long. */ public static DNSPacket SendQuery(EndPoint server, DNSQuestion question, bool recursive) { var rng = new Random(); var packet_id = (UInt16)rng.Next(0, (1 << 16) - 1); var to_send = new DNSPacket( packet_id, true, QueryType.STANDARD_QUERY, false, false, recursive, false, ResponseType.NO_ERROR, new DNSQuestion[] { question }, new DNSRecord[0], new DNSRecord[0], new DNSRecord[0]); var send_bytes = to_send.ToBytes(); using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { socket.ReceiveTimeout = 5 * 1000; socket.Bind(new IPEndPoint(IPAddress.Any, 0)); logger.Trace("Sending packet {0} to {1}", packet_id, server); socket.SendTo(send_bytes, server); DNSPacket recv_packet = null; while (recv_packet == null) { logger.Trace("Preparing to receive"); var recv_bytes = new byte[512]; EndPoint remote_endpoint = new IPEndPoint(IPAddress.Any, 0); socket.ReceiveFrom(recv_bytes, ref remote_endpoint); recv_packet = DNSPacket.FromBytes(recv_bytes); if (recv_packet.Id != packet_id) { logger.Trace("Trashing bad packet"); recv_packet = null; } } logger.Trace("Got response {0}", recv_packet); return(recv_packet); } }
private void RespondToClient(byte[] buffer, EndPoint peer) { UInt16 outbound_id; var outbound_is_authority = false; QueryType outbound_qtype; bool outbound_recursive_request; bool outbound_recursive_response = false; ResponseType outbound_rtype; var outbound_questions = new List <DNSQuestion>(); var outbound_answers = new List <DNSRecord>(); var outbound_authoritative = new List <DNSRecord>(); var outbound_additional = new List <DNSRecord>(); try { var inbound = DNSPacket.FromBytes(buffer); outbound_id = inbound.Id; outbound_qtype = inbound.QueryType; outbound_recursive_request = inbound.RecursiveRequest; logger.Trace("{0}: Parsed inbound request {1}", peer, inbound); outbound_questions.AddRange(inbound.Questions); if (inbound.QueryType == QueryType.UNSUPPORTED) { logger.Trace("{0}: Unsupported query type", peer); outbound_rtype = ResponseType.NOT_IMPLEMENTED; } else if (inbound.Questions.Length != 1) { // BIND does this, so apparently we're in good company if we turn down multi-question packets logger.Trace("{0}: Multi-question packet", peer); outbound_rtype = ResponseType.NOT_IMPLEMENTED; } else { outbound_recursive_response = outbound_recursive_request; var question = inbound.Questions[0]; // We *could* find a way to communicate the rejection of a // single question, but it's simpler to just reject the // whole thing if (question.QueryType == ResourceRecordType.UNSUPPORTED || question.AddressClass == AddressClass.UNSUPPORTED) { logger.Trace("{0}: Unsupported question {1}", peer, question); outbound_rtype = ResponseType.NOT_IMPLEMENTED; } else { try { var answer = query_exec.Execute(question.Name, question.QueryType, question.AddressClass, inbound.RecursiveRequest); if (answer.FoundAnswer) { logger.Trace("{0}: Resolver found answer for {1}", peer, question); outbound_rtype = ResponseType.NO_ERROR; outbound_is_authority = answer.IsAuthority; outbound_answers.AddRange(answer.Answers); outbound_additional.AddRange(answer.Additional); outbound_authoritative.AddRange(answer.Authority); } else { logger.Trace("{0}: Could not find the name {1}", peer, question.Name); outbound_rtype = ResponseType.NAME_ERROR; outbound_is_authority = answer.IsAuthority; } } catch (Exception err) { Console.WriteLine(err); logger.Error(err, "{0}: Server failure", peer); outbound_rtype = ResponseType.SERVER_FAILURE; outbound_is_authority = false; } } } } catch (InvalidDataException err) { // If this is the case, we have to at least extract the ID so // that the peer knows what we're complaining about logger.Trace("{0}: Unparsable request ({1})", peer, err.Message); var in_id = (UInt16)((buffer[0] << 8) + buffer[1]); outbound_id = in_id; outbound_qtype = QueryType.STANDARD_QUERY; outbound_is_authority = false; outbound_recursive_request = false; outbound_recursive_response = false; outbound_rtype = ResponseType.FORMAT_ERROR; } var outbound = new DNSPacket( outbound_id, false, outbound_qtype, outbound_is_authority, false, outbound_recursive_request, outbound_recursive_response, outbound_rtype, outbound_questions, outbound_answers, outbound_authoritative, outbound_additional); var outbound_bytes = outbound.ToBytes(); logger.Trace("{0}: Sending {1}-byte response {2}", peer, outbound_bytes.Length, outbound); server.SendTo(outbound_bytes, peer); }