Skip to content

Instantly share code, notes, and snippets.

@NTag
Last active May 12, 2016 13:38
Show Gist options
  • Save NTag/ffc150ff583d39df52245ce889429bff to your computer and use it in GitHub Desktop.
Save NTag/ffc150ff583d39df52245ce889429bff to your computer and use it in GitHub Desktop.
PoC of draft-stenberg-mif-mpvd-dns-00 in C using ldns
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <ldns/ldns.h>
#include <arpa/inet.h>
#include "neat.h"
#include "neat_internal.h"
#include "neat_core.h"
#include "neat_pvd.h"
#include "neat_addr.h"
char* compute_reverse_ip(struct neat_addr *src_addr) {
struct in_addr src_addr4;
struct in6_addr src_addr6;
uint8_t family = src_addr->family;
char reverse_ip[80]; // maximum length for a reverse /128 IPv6
int i;
if (family == AF_INET6) {
// From fd17:625c:f037:2:a00:27ff:fe37:86b6/69 => _.pvd.8.0.7.3.0.f.c.5.2.6.7.1.d.f.ip6.arpa.
src_addr6 = (src_addr->u.v6.addr6).sin6_addr;
sprintf(reverse_ip, "_.pvd.");
int addr_last_part = src_addr->prefix_length & 4;
int addr_total_hex = src_addr->prefix_length >> 2;
int string_offset = 6;
int current_hex;
i = addr_total_hex-1;
// if the prefix length is not multiple of 4
if (addr_last_part != 0) {
int last_index = addr_total_hex / 2;
bool divide = (addr_total_hex % 2) == 0;
if (divide) {
current_hex = src_addr6.s6_addr[last_index] >> 4;
} else {
current_hex = src_addr6.s6_addr[last_index] & 0x0f;
}
current_hex = current_hex - (current_hex % (1 << (4 - addr_last_part)));
sprintf(reverse_ip+string_offset, "%01x.", current_hex);
string_offset = string_offset + 2;
}
for (i = i; i >= 0; i--) {
if (i % 2 == 0) {
current_hex = src_addr6.s6_addr[i/2] >> 4;
} else {
current_hex = src_addr6.s6_addr[i/2] & 0x0f;
}
sprintf(reverse_ip + string_offset + 2*(addr_total_hex - 1 - i), "%01x.", current_hex);
}
sprintf(reverse_ip + string_offset + 2*addr_total_hex, "ip6.arpa.");
} else if (family == AF_INET) {
// From 192.168.145.2/19 => _.pvd.128.168.192.in-addr.arpa.
src_addr4 = (src_addr->u.v4.addr4).sin_addr;
uint32_t src_addr4_prefix = src_addr4.s_addr & ((1 << src_addr->prefix_length) - 1);
sprintf(reverse_ip, "_.pvd.");
for (i = ((src_addr->prefix_length >> 3) << 3) - 8; i >= 0; i -= 8) {
sprintf(reverse_ip + strlen(reverse_ip), "%u.", ((src_addr4_prefix & (0xff << i)) >> i));
}
sprintf(reverse_ip + strlen(reverse_ip), "in-addr.arpa.");
}
char *out = (char *) malloc(sizeof(char) * strlen(reverse_ip));
strcpy(out, reverse_ip);
return out;
}
void add_pvd_to_addr(struct neat_addr* src_addr, ldns_rr_list *pvd_txt_list) {
int nb_txt = ldns_rr_list_rr_count(pvd_txt_list);
struct pvd_infos pvd_infos;
struct pvd_info* pvd_info;
char* txt_record;
ldns_rr *rr;
ldns_rdf *dns_record = NULL;
struct pvd* pvd = (struct pvd *) malloc(sizeof(struct pvd));
LIST_INIT(&pvd_infos);
for (int i = 0; i < nb_txt; i++) {
rr = ldns_rr_list_rr(pvd_txt_list, i);
dns_record = ldns_rr_set_rdf(rr, NULL, 0);
txt_record = strdup(ldns_rdf2str(dns_record));
// Removing quotes if any
if (txt_record[0] == '"' && txt_record[strlen(txt_record)-1] == '"') {
txt_record[strlen(txt_record)-1] = 0;
txt_record++;
}
pvd_info = (struct pvd_info *) malloc(sizeof(struct pvd_info));
pvd_info->key = strsep(&txt_record, "=");
pvd_info->value = txt_record;
LIST_INSERT_HEAD(&(pvd_infos), pvd_info, next_info);
}
if (nb_txt > 0) {
pvd->infos = pvd_infos;
LIST_INSERT_HEAD(&(src_addr->pvds), pvd, next_pvd);
}
ldns_rr_list_deep_free(pvd_txt_list);
}
static void neat_pvd_handle_newaddr(struct neat_ctx *nc,
void *p_ptr,
void *data)
{
if (LIST_EMPTY(&(nc->resolver->server_list))) {
// No DNS servers
return;
}
struct in_addr dns_addr4;
struct in6_addr dns_addr6;
struct neat_addr *src_addr = (struct neat_addr*) data;
struct neat_resolver_server *dns_server;
int i, nb_ptr;
ldns_resolver *resolver;
ldns_rdf *domain;
ldns_rdf *dns_src;
ldns_rdf *ptr;
ldns_pkt *p;
ldns_rr_list *pvd_txt_list;
ldns_rr_list *pvd_ptr_list;
ldns_rr *rr;
ldns_rdf *dns_record = NULL;
char* ptr_record;
char* reverse_ip = compute_reverse_ip(src_addr);
if (strlen(reverse_ip) == 0) {
return;
}
LIST_INIT(&(src_addr->pvds));
LIST_FOREACH(dns_server, &(nc->resolver->server_list), next_server) {
// Avoid static servers
if (dns_server->mark != NEAT_RESOLVER_SERVER_ACTIVE) {
continue;
}
struct sockaddr_storage *dns_addr = &(dns_server->server_addr);
if (dns_addr->ss_family == AF_INET6) {
dns_addr6 = ((struct sockaddr_in6*) dns_addr)->sin6_addr;
dns_src = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_AAAA, 16, &dns_addr6);
} else if (dns_addr->ss_family == AF_INET) {
dns_addr4 = ((struct sockaddr_in*) dns_addr)->sin_addr;
dns_src = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_A, 4, &dns_addr4);
} else {
continue;
}
domain = ldns_dname_new_frm_str(reverse_ip);
resolver = ldns_resolver_new();
ldns_resolver_push_nameserver(resolver, dns_src);
// Performing DNS query to 'dns_addr', for PTR records of 'reverse_ip'
p = ldns_resolver_query(resolver, domain, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN, LDNS_RD);
ldns_rdf_deep_free(domain);
if (!p) {
continue;
}
pvd_ptr_list = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_PTR, LDNS_SECTION_ANSWER);
ldns_pkt_free(p);
ldns_rr_list_sort(pvd_ptr_list);
nb_ptr = ldns_rr_list_rr_count(pvd_ptr_list);
// There can be multiple PvDs
for (i = 0; i < nb_ptr; i++) {
rr = ldns_rr_list_rr(pvd_ptr_list, i);
dns_record = ldns_rr_set_rdf(rr, NULL, 0);
ptr_record = strdup(ldns_rdf2str(dns_record));
ptr = ldns_dname_new_frm_str(ptr_record);
// Performing DNS query to 'dns_addr' for TXT records of 'ptr'
p = ldns_resolver_query(resolver, ptr, LDNS_RR_TYPE_TXT, LDNS_RR_CLASS_IN, LDNS_RD);
ldns_rdf_deep_free(ptr);
if (!p) {
continue;
}
pvd_txt_list = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_TXT, LDNS_SECTION_ANSWER);
ldns_pkt_free(p);
ldns_rr_list_sort(pvd_txt_list);
// Adding txt records as new pvd record to src_addr
add_pvd_to_addr(src_addr, pvd_txt_list);
}
ldns_rdf_deep_free(dns_src);
// ldns_rdf_deep_free(dns_record);
ldns_resolver_deep_free(resolver);
}
}
struct neat_pvd *
neat_pvd_init(struct neat_ctx *nc)
{
struct neat_pvd *pvd = calloc(sizeof(struct neat_pvd), 1);
if (!pvd)
return NULL;
pvd->nc = nc;
pvd->newaddr_cb.event_cb = neat_pvd_handle_newaddr;
pvd->newaddr_cb.data = pvd;
if (neat_add_event_cb(nc, NEAT_NEWADDR, &(pvd->newaddr_cb))) {
neat_log(NEAT_LOG_ERROR, "%s - Could not add one pvd callbacks", __func__);
return NULL;
}
return pvd;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment