Example #1
0
static void test_packet_from_file(const char* filename, bool canonical) {
        _cleanup_free_ char *data = NULL;
        size_t data_size, packet_size, offset;

        assert_se(read_full_file(filename, &data, &data_size) >= 0);
        assert_se(data);
        assert_se(data_size > 8);

        log_info("============== %s %s==============", filename, canonical ? "canonical " : "");

        for (offset = 0; offset < data_size; offset += 8 + packet_size) {
                _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL, *p2 = NULL;
                _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL, *rr2 = NULL;
                const char *s, *s2;
                uint64_t hash1, hash2;

                packet_size = le64toh( *(uint64_t*)(data + offset) );
                assert_se(packet_size > 0);
                assert_se(offset + 8 + packet_size <= data_size);

                assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0) >= 0);

                assert_se(dns_packet_append_blob(p, data + offset + 8, packet_size, NULL) >= 0);
                assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0);

                s = dns_resource_record_to_string(rr);
                assert_se(s);
                puts(s);

                hash1 = hash(rr);

                assert_se(dns_resource_record_to_wire_format(rr, canonical) >= 0);

                assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0) >= 0);
                assert_se(dns_packet_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0);
                assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0);

                s2 = dns_resource_record_to_string(rr);
                assert_se(s2);
                assert_se(streq(s, s2));

                hash2 = hash(rr);
                assert_se(hash1 == hash2);
        }
}
static void test_dns_packet_new(void) {
        size_t i;
         _cleanup_(dns_packet_unrefp) DnsPacket *p2 = NULL;

        for (i = 0; i <= DNS_PACKET_SIZE_MAX; i++) {
                _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;

                assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i, DNS_PACKET_SIZE_MAX) == 0);

                log_debug("dns_packet_new: %zu → %zu", i, p->allocated);
                assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));

                if (i > DNS_PACKET_SIZE_START + 10 && i < DNS_PACKET_SIZE_MAX - 10)
                        i = MIN(i * 2, DNS_PACKET_SIZE_MAX - 10);
        }

        assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1, DNS_PACKET_SIZE_MAX) == -EFBIG);
}
Example #3
0
static int dns_stub_make_reply_packet(
                DnsPacket **p,
                size_t max_size,
                DnsQuestion *q,
                DnsAnswer *answer,
                bool *ret_truncated) {

        bool truncated = false;
        DnsResourceRecord *rr;
        unsigned c = 0;
        int r;

        assert(p);

        /* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence
         * roundtrips aren't expensive. */

        if (!*p) {
                r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size);
                if (r < 0)
                        return r;

                r = dns_packet_append_question(*p, q);
                if (r < 0)
                        return r;

                DNS_PACKET_HEADER(*p)->qdcount = htobe16(dns_question_size(q));
        }

        DNS_ANSWER_FOREACH(rr, answer) {

                r = dns_question_matches_rr(q, rr, NULL);
                if (r < 0)
                        return r;
                if (r > 0)
                        goto add;

                r = dns_question_matches_cname_or_dname(q, rr, NULL);
                if (r < 0)
                        return r;
                if (r > 0)
                        goto add;

                continue;
        add:
                r = dns_packet_append_rr(*p, rr, 0, NULL, NULL);
                if (r == -EMSGSIZE) {
                        truncated = true;
                        break;
                }
                if (r < 0)
                        return r;

                c++;
        }
static int dns_stub_make_reply_packet(
    uint16_t id,
    int rcode,
    DnsQuestion *q,
    DnsAnswer *answer,
    bool add_opt,   /* add an OPT RR to this packet */
    bool edns0_do,  /* set the EDNS0 DNSSEC OK bit */
    bool ad,        /* set the DNSSEC authenticated data bit */
    DnsPacket **ret) {

    _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
    DnsResourceRecord *rr;
    unsigned c = 0;
    int r;

    /* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence
     * roundtrips aren't expensive. */

    r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
    if (r < 0)
        return r;

    /* If the client didn't do EDNS, clamp the rcode to 4 bit */
    if (!add_opt && rcode > 0xF)
        rcode = DNS_RCODE_SERVFAIL;

    DNS_PACKET_HEADER(p)->id = id;
    DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
            1 /* qr */,
            0 /* opcode */,
            0 /* aa */,
            0 /* tc */,
            1 /* rd */,
            1 /* ra */,
            ad /* ad */,
            0 /* cd */,
            rcode));

    r = dns_packet_append_question(p, q);
    if (r < 0)
        return r;
    DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q));

    DNS_ANSWER_FOREACH(rr, answer) {
        r = dns_question_matches_rr(q, rr, NULL);
        if (r < 0)
            return r;
        if (r > 0)
            goto add;

        r = dns_question_matches_cname_or_dname(q, rr, NULL);
        if (r < 0)
            return r;
        if (r > 0)
            goto add;

        continue;
add:
        r = dns_packet_append_rr(p, rr, NULL, NULL);
        if (r < 0)
            return r;

        c++;
    }
Example #5
0
int main(int argc, char **argv) {
  char *main_config_file = argv[1] != NULL ? argv[1] : "config.pdns";

  g_message("picodns starting...");
  int read_config_result = 0;
  if((read_config_result = read_config(main_config_file)) != 0) {
    g_error("Could not read the main configuration file %s", main_config_file);
  } else {
    g_message("Read main configuration file %s", main_config_file);
  }

  g_message("loading LUT from file %s...", main_records_file);

  //load the lookup table
  dns_lut lut = dns_lut_new(main_records_file);
  
  g_message("LUT loaded (%d entries)", g_hash_table_size(lut.table));

  int sockfd;
  struct addrinfo hints, *servinfo, *p;
  int rv;
  int numbytes;
  struct sockaddr_storage their_addr;
  socklen_t addr_len;
  char s[INET6_ADDRSTRLEN];

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_flags = AI_PASSIVE; // use my IP

  char port[7] = {0};
  sprintf(port, "%d", udp_port);
  if ((rv = getaddrinfo(NULL, port, &hints, &servinfo)) == -1) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return 1;
  }
  
  // loop through all the results and bind to the first we can
  for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
			 p->ai_protocol)) == -1) {
      perror("listener: socket");
      continue;
    }

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
      close(sockfd);
      perror("listener: bind");
      continue;
    }

    break;
  }

  if (p == NULL) {
    g_error("could not bind to socket");
  }
  
  g_message("picodns loaded, waiting for requests");
  
  addr_len = sizeof their_addr;

  while(1) {
    //create the gbytearray for storage of incoming udp packet
    GByteArray *packet_data = g_byte_array_sized_new(max_incoming_udp_packet_size);
    if ((numbytes = recvfrom(sockfd, packet_data->data, max_incoming_udp_packet_size, 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) {
      g_warning("Error receiving data: ");
      perror("recvfrom");
      continue;
    }
    g_byte_array_set_size(packet_data, numbytes);

    //set s to contain string rep of src address
    inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
    g_debug("dns request from %s", s);
    if(localhost_only == TRUE) {
      if((strcmp(s, "127.0.0.1") != 0) &&
	 (strcmp(s, "::1") != 0) &&
	 (strcmp(s, "::ffff:127.0.0.1") != 0)) {
	//this is not from localhost, and only localhost is allowed,
	// so ignore it
	continue;
      }
    }
    
    //now we parse apart he packet into its respective parts.
    dns_packet packet = dns_packet_parse(packet_data);
    //dns_packet_print(&packet);
    
    //extract the target hostname from the packet
    if(packet.QuestionRRCount > 1) {
      g_warning("got a dns packet with more than one question in it, ignoring");
      continue;
    } else if (packet.QuestionRRCount  == 0) {
      g_warning("got a dns packet without a question, ignoring");
      continue;
    }
    
    dns_rr question = g_array_index(packet.QuestionRRs, dns_rr, 0);    

    gchar *target_host = g_strconcat(dns_name_to_ascii(question.name), ":", dns_type_to_ascii(question.Type), NULL);
    
    g_message("got a query for %s", target_host);
    
    //now, we resolve the packet into a responce packet
    dns_resolver_record *resolved = dns_lut_lookup(lut, target_host);
    
    //make a new dns_packet with the question as well as the answer
    dns_packet reply = dns_packet_new();
    reply.TransactionID = packet.TransactionID;
    
    //flags start as a mirror of the recv'd packets flags
    reply.flags = packet.flags;
    reply.flags.Responce = DNS_RESPONCE;
    reply.flags.Authoritative = 0;
    reply.flags.Truncated = 0;
    reply.flags.RecursionAvailable = 0;
    reply.flags.AnswerAuthenticated = 0;
    reply.flags.ReplyCode = 0;


    //add the query
    reply.QuestionRRCount = 1;
    dns_rr question_rr = g_array_index(packet.QuestionRRs, dns_rr, 0);
    g_array_append_val(reply.QuestionRRs, question_rr);

    if(resolved == NULL) {
      g_message("DNS LUT has no entry for %s", target_host);
    } else {
      //if NonAuthOK is 0, then Authentication is required - in this
      //case, we can only reply if the resolver_record states that
      //request_authenticated is set. If it isnt, then the record isnt
      //considered authenticated, and isnt an appropriate responce.
      
      if((resolved->request_authenticated && !packet.flags.NonAuthOK) ||
	 (packet.flags.NonAuthOK) || 
	 (!packet.flags.NonAuthOK && resolved->ignore_non_auth_ok)) {
	//set the requested flags
	reply.flags.Authoritative = (resolved->request_authoratative)?1:0;
	reply.flags.AnswerAuthenticated = (resolved->request_authenticated)?1:0;
	//now, insert each one of the answers into the reply packet
	reply.AnswerRRCount = resolved->Answers->len;
	g_array_append_vals(reply.AnswerRRs, resolved->Answers->data, resolved->Answers->len);
	g_message("DNS LUT has %d answer(s) matching %s", resolved->Answers->len, target_host);
      } else {
	g_message("DNS LUT has no appropriate entry for %s", target_host);
      }
    }
    
    //now, pack the responce packet into a GByteArray
    GByteArray *reply_data = dns_packet_pack(&reply);
    
    //now, we transmit the responce packet
    if ((numbytes = sendto(sockfd, reply_data->data, reply_data->len, 0,
    		   (struct sockaddr *)&their_addr, addr_len)) == -1) {
      perror("talker: sendto");
     exit(1);
    }

    //now we clean up!
    g_byte_array_free(packet_data, TRUE);
  } /* end main server loop */

  freeaddrinfo(servinfo);  
 
  //close the DNS socket file descriptor
  close(sockfd);

  free_config();  

  return 0;
}
Example #6
0
static void bus_method_resolve_record_complete(DnsQuery *q) {
        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
        unsigned added = 0, i;
        int r;

        assert(q);

        if (q->state != DNS_TRANSACTION_SUCCESS) {
                r = reply_query_state(q);
                goto finish;
        }

        r = sd_bus_message_new_method_return(q->request, &reply);
        if (r < 0)
                goto finish;

        r = sd_bus_message_append(reply, "i", q->answer_ifindex);
        if (r < 0)
                goto finish;

        r = sd_bus_message_open_container(reply, 'a', "(qqay)");
        if (r < 0)
                goto finish;

        if (q->answer) {
                answer = dns_answer_ref(q->answer);

                for (i = 0; i < answer->n_rrs; i++) {
                        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
                        size_t start;

                        r = dns_question_matches_rr(q->question, answer->rrs[i]);
                        if (r < 0)
                                goto finish;
                        if (r == 0)
                                continue;

                        r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
                        if (r < 0)
                                goto finish;

                        r = dns_packet_append_rr(p, answer->rrs[i], &start);
                        if (r < 0)
                                goto finish;

                        r = sd_bus_message_open_container(reply, 'r', "qqay");
                        if (r < 0)
                                goto finish;

                        r = sd_bus_message_append(reply, "qq", answer->rrs[i]->key->class, answer->rrs[i]->key->type);
                        if (r < 0)
                                goto finish;

                        r = sd_bus_message_append_array(reply, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
                        if (r < 0)
                                goto finish;

                        r = sd_bus_message_close_container(reply);
                        if (r < 0)
                                goto finish;

                        added ++;
                }
        }