Example #1
0
void DNS::add_record(const Resource &resource, const sections_type &sections) {
    // We need to check that the data provided is correct. Otherwise, the sections
    // will end up being inconsistent.
    IPv4Address v4_addr;
    IPv6Address v6_addr;
    std::string buffer = encode_domain_name(resource.dname()), encoded_data;
    // By default the data size is the length of the data field.
    uint32_t data_size = resource.data().size();
    if(resource.type() == A) {
        v4_addr = resource.data();
        data_size = 4;
    }
    else if(resource.type() == AAAA) {
        v6_addr = resource.data();
        data_size = IPv6Address::address_size;
    }
    else if(contains_dname(resource.type())) { 
        encoded_data = encode_domain_name(resource.data());
        data_size = encoded_data.size();
    }
    uint32_t offset = buffer.size() + sizeof(uint16_t) * 3 + sizeof(uint32_t) + data_size, 
            threshold = sections.empty() ? records_data.size() : *sections.front().first;
    // Skip the preference field
    if(resource.type() == MX) {
        offset += sizeof(uint16_t);
    }
    for(size_t i = 0; i < sections.size(); ++i) {
        update_records(*sections[i].first, sections[i].second, threshold, offset);
    }
    
    records_data.insert(
        records_data.begin() + threshold,
        offset,
        0
    );
    uint8_t *ptr = std::copy(
        buffer.begin(),
        buffer.end(),
        &records_data[threshold]
    );

    uint16_t uint16_t_buffer;
    uint32_t uint32_t_buffer;

    uint16_t_buffer = Endian::host_to_be(resource.type());
    std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
    ptr += sizeof(uint16_t);
    uint16_t_buffer = Endian::host_to_be(resource.query_class());
    std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
    ptr += sizeof(uint16_t);
    uint32_t_buffer = Endian::host_to_be(resource.ttl());
    std::memcpy(ptr, &uint32_t_buffer, sizeof(uint32_t));
    ptr += sizeof(uint32_t);
    uint16_t_buffer = Endian::host_to_be<uint16_t>(
        data_size + (resource.type() == MX ? 2 : 0)
    );
    std::memcpy(ptr, &uint16_t_buffer, sizeof(uint16_t));
    ptr += sizeof(uint16_t);
    if(resource.type() == MX) {
        ptr += sizeof(uint16_t);
    }
    if(resource.type() == A) {
        uint32_t ip_int = v4_addr;
        std::memcpy(ptr, &ip_int, sizeof(ip_int));
    }
    else if(resource.type() == AAAA) {
        std::copy(v6_addr.begin(), v6_addr.end(), ptr);
    }
    else if(!encoded_data.empty()) {
        std::copy(encoded_data.begin(), encoded_data.end(), ptr);
    }
    else {
        std::copy(resource.data().begin(), resource.data().end(), ptr);
    }
}