return ret_addr;
}
+
+flxAddress *flx_address_from_sockaddr(const struct sockaddr* sa, flxAddress *ret_addr) {
+ g_assert(sa);
+ g_assert(ret_addr);
+
+ g_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
+
+ ret_addr->family = sa->sa_family;
+
+ if (sa->sa_family == AF_INET)
+ memcpy(&ret_addr->ipv4, &((struct sockaddr_in*) sa)->sin_addr, sizeof(ret_addr->ipv4));
+ else
+ memcpy(&ret_addr->ipv6, &((struct sockaddr_in6*) sa)->sin6_addr, sizeof(ret_addr->ipv6));
+
+ return ret_addr;
+}
#include <glib.h>
+#include <sys/socket.h>
+
typedef struct {
guint32 address;
} flxIPv4Address;
flxAddress *flx_address_parse(const char *s, guchar family, flxAddress *ret_addr);
+flxAddress *flx_address_from_sockaddr(const struct sockaddr* sa, flxAddress *ret_addr);
+
gchar* flx_reverse_lookup_name_ipv4(const flxIPv4Address *a);
gchar* flx_reverse_lookup_name_ipv6_arpa(const flxIPv6Address *a);
gchar* flx_reverse_lookup_name_ipv6_int(const flxIPv6Address *a);
if ((e = flx_cache_lookup_record(c, r)))
remove_entry(c, e, TRUE);
}
+
+static void func(gpointer key, gpointer data, gpointer userdata) {
+ flxCacheEntry *e = data;
+ flxKey *k = key;
+
+ gchar *s, *t;
+
+ s = flx_key_to_string(k);
+ t = flx_record_to_string(e->record);
+
+ fprintf((FILE*) userdata, "%s %s\n", s, t);
+
+ g_free(s);
+ g_free(t);
+}
+
+void flx_cache_dump(flxCache *c, FILE *f) {
+ g_assert(c);
+ g_assert(f);
+
+ fprintf(f, ";;; CACHE DUMP FOLLOWS ;;;\n");
+ g_hash_table_foreach(c->hash_table, func, f);
+}
struct _flxCache {
flxServer *server;
+
flxInterface *interface;
GHashTable *hash_table;
void flx_cache_drop_key(flxCache *c, flxKey *k);
void flx_cache_drop_record(flxCache *c, flxRecord *r);
+void flx_cache_dump(flxCache *c, FILE *f);
+
#endif
return 0;
}
-gint flx_dns_packet_check_valid_response(flxDnsPacket *p) {
- guint16 flags;
+gint flx_dns_packet_is_query(flxDnsPacket *p) {
g_assert(p);
- if (flx_dns_packet_check_valid(p) < 0)
- return -1;
-
- flags = flx_dns_packet_get_field(p, DNS_FIELD_FLAGS);
-
- if (!(flags & DNS_FLAG_QR))
- return -1;
-
- if (flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT) > 0)
- return -1;
-
- return 0;
+ return !(flx_dns_packet_get_field(p, DNS_FIELD_FLAGS) & DNS_FLAG_QR);
}
static gint consume_labels(flxDnsPacket *p, guint index, gchar *ret_name, guint l) {
return 0;
}
+gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p) {
+ g_assert(p);
+
+ if (p->rindex >= p->size)
+ return NULL;
+
+ return p->data + p->rindex;
+}
+
gint flx_dns_packet_skip(flxDnsPacket *p, guint length) {
g_assert(p);
p->rindex += length;
return 0;
}
+
+flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush) {
+ gchar name[256];
+ guint16 type, class;
+ guint32 ttl;
+ guint16 rdlength;
+ gconstpointer data;
+
+ g_assert(p);
+ g_assert(ret_cache_flush);
+
+ if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
+ flx_dns_packet_consume_uint16(p, &type) < 0 ||
+ flx_dns_packet_consume_uint16(p, &class) < 0 ||
+ flx_dns_packet_consume_uint32(p, &ttl) < 0 ||
+ flx_dns_packet_consume_uint16(p, &rdlength) < 0 ||
+ !(data = flx_dns_packet_get_rptr(p)) ||
+ flx_dns_packet_skip(p, rdlength) < 0)
+ return NULL;
+
+ *ret_cache_flush = !!(class & MDNS_CACHE_FLUSH);
+ class &= ~ MDNS_CACHE_FLUSH;
+
+ return flx_record_new_full(name, class, type, data, rdlength, ttl);
+}
+
+flxKey* flx_dns_packet_consume_key(flxDnsPacket *p) {
+ gchar name[256];
+ guint16 type, class;
+
+ g_assert(p);
+
+ if (flx_dns_packet_consume_name(p, name, sizeof(name)) < 0 ||
+ flx_dns_packet_consume_uint16(p, &type) < 0 ||
+ flx_dns_packet_consume_uint16(p, &class) < 0)
+ return NULL;
+
+ class &= ~ MDNS_CACHE_FLUSH;
+
+ return flx_key_new(name, class, type);
+}
+
+guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k) {
+ guint8 *t;
+
+ g_assert(p);
+ g_assert(k);
+
+ if (!(t = flx_dns_packet_append_name(p, k->name)) ||
+ !flx_dns_packet_append_uint16(p, k->type) ||
+ !flx_dns_packet_append_uint16(p, k->class))
+ return NULL;
+
+ return t;
+}
+
+guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush) {
+
+
+}
#include <glib.h>
+#include "rr.h"
+
#define FLX_DNS_MAX_PACKET_SIZE 9000
typedef struct _flxDnsPacket {
guint8 *flx_dns_packet_append_name(flxDnsPacket *p, const gchar *name);
guint8 *flx_dns_packet_append_name_compressed(flxDnsPacket *p, const gchar *name, guint8 *prev);
guint8 *flx_dns_packet_extend(flxDnsPacket *p, guint l);
-gint flx_dns_packet_check_valid_response(flxDnsPacket *p);
+gint flx_dns_packet_is_query(flxDnsPacket *p);
gint flx_dns_packet_check_valid(flxDnsPacket *p);
gint flx_dns_packet_consume_name(flxDnsPacket *p, gchar *ret_name, guint l);
gint flx_dns_packet_consume_uint16(flxDnsPacket *p, guint16 *ret_v);
gint flx_dns_packet_consume_uint32(flxDnsPacket *p, guint32 *ret_v);
gint flx_dns_packet_consume_bytes(flxDnsPacket *p, gpointer ret_data, guint l);
+
+gconstpointer flx_dns_packet_get_rptr(flxDnsPacket *p);
+
+flxKey* flx_dns_packet_consume_key(flxDnsPacket *p);
+flxRecord* flx_dns_packet_consume_record(flxDnsPacket *p, gboolean *ret_cache_flush);
+
+guint8* flx_dns_packet_append_key(flxDnsPacket *p, flxKey *k);
+guint8* flx_dns_packet_append_record(flxDnsPacket *p, flxRecord *r, gboolean cache_flush);
+
gint flx_dns_packet_skip(flxDnsPacket *p, guint length);
#define DNS_FIELD_ID 0
((guint16) (rd & 15)))
+#define MDNS_CACHE_FLUSH 0x8000
+
#endif
flx_dns_packet_free(p);
}
+
+void flx_interface_send_response(flxinterface *i, guchar protocol, flxRecord *rr) {
+ flxDnsPacket+p;
+
+ g_assert(i);
+ g_assert(rr);
+
+ p = flx_dns_packet_new();
+ flx_dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(1, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+ flx_dns_packet_append_name(p, rr->key->name);
+ flx_dns_packet_append_uint16(p, rr->key->type);
+ flx_dns_packet_append_uint16(p, rr->key->class);
+ flx_dns_packet_append_uint16
+}
+
+
+
+void flx_dump_caches(flxServer *s, FILE *f) {
+ flxInterface *i;
+ g_assert(s);
+
+ for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->interface_next) {
+ if (!flx_interface_is_relevant(i))
+ continue;
+
+ if (i->n_ipv4_addrs > 0) {
+ fprintf(f, ";;; INTERFACE %s; IPv4 ;;;\n", i->name);
+ flx_cache_dump(i->ipv4_cache, f);
+ }
+
+ if (i->n_ipv6_addrs > 0) {
+ fprintf(f, ";;; INTERFACE %s; IPv6 ;;;\n", i->name);
+ flx_cache_dump(i->ipv6_cache, f);
+ }
+ }
+}
int flx_address_is_relevant(flxInterfaceAddress *a);
void flx_interface_send_query(flxInterface *i, guchar protocol, flxKey *k);
-
+
+void flx_dump_caches(flxServer *s, FILE *f);
+
#endif
flxRecord *flx_record_ref(flxRecord *r);
void flx_record_unref(flxRecord *r);
-const gchar *flxdns_class_to_string(guint16 class);
+const gchar *flx_dns_class_to_string(guint16 class);
const gchar *flx_dns_type_to_string(guint16 type);
gchar *flx_key_to_string(flxKey *k); /* g_free() the result! */
#include "iface.h"
#include "socket.h"
+static void post_response(flxServer *s, flxRecord *r, gint iface, const flxAddress *a) {
+}
+
+static void handle_query_key(flxServer *s, flxKey *k, gint iface, const flxAddress *a) {
+ flxEntry *e;
+
+ g_assert(s);
+ g_assert(k);
+ g_assert(a);
+
+ for (e = g_hash_table_lookup(s->rrset_by_name, k); e; e = e->next_by_name) {
+
+ if ((e->interface <= 0 || e->interface == iface) &&
+ (e->protocol == AF_UNSPEC || e->protocol == a->family))
+ post_response(s, e->record, iface, a);
+ }
+}
+
+static void handle_query(flxServer *s, flxDnsPacket *p, gint iface, const flxAddress *a) {
+ guint n;
+
+ g_assert(s);
+ g_assert(p);
+ g_assert(a);
+
+ for (n = flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT); n > 0; n --) {
+
+ flxKey *key;
+
+ if (!(key = flx_dns_packet_consume_query(p))) {
+ g_warning("Packet too short");
+ return;
+ }
+
+ handle_query_key(s, key, iface, a);
+ flx_key_unref(key);
+ }
+}
+
+static void add_response_to_cache(flxCache *c, flxDnsPacket *p, const flxAddress *a) {
+ guint n;
+
+ g_assert(c);
+ g_assert(p);
+ g_assert(a);
+ for (n = flx_dns_packet_get_field(p, DNS_FIELD_ANCOUNT); n > 0; n--) {
+
+ flxRecord *rr;
+ gboolean cache_flush = FALSE;
+
+ if (!(rr = flx_dns_packet_consume_rr(p, &cache_flush))) {
+ g_warning("Packet too short");
+ return;
+ }
+
+ flx_cache_update(c, rr, cache_flush, a);
+ flx_record_unref(rr);
+ }
+}
+
static void dispatch_packet(flxServer *s, flxDnsPacket *p, struct sockaddr *sa, gint iface, gint ttl) {
+ flxInterface *i;
+ flxAddress a;
+
g_assert(s);
g_assert(p);
g_assert(sa);
g_assert(iface > 0);
-
+
+ if (!(i = flx_interface_monitor_get_interface(s->monitor, iface))) {
+ g_warning("Recieved packet from invalid interface.");
+ return;
+ }
+
if (ttl != 255) {
- flxInterface *i = flx_interface_monitor_get_interface(s->monitor, iface);
- g_warning("Recieved packet with invalid TTL on interface '%s'.", i ? i->name : "unknown");
+ g_warning("Recieved packet with invalid TTL on interface '%s'.", i->name);
return;
}
}
}
- g_message("Recieved packet");
+ if (flx_dns_packet_check_valid(p) < 0) {
+ g_warning("Recieved invalid packet.");
+ return;
+ }
+
+ flx_address_from_sockaddr(sa, &a);
+
+ if (flx_dns_packet_is_query(p)) {
+
+ if (flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT) == 0 ||
+ flx_dns_packet_get_field(p, DNS_FIELD_ARCOUNT) != 0
+ flx_dns_packet_get_field(p, DNS_FIELD_NSCOUNT) != 0) {
+ g_warning("Invalid query packet.");
+ return;
+ }
+
+ handle_query(s, p, iface, &a);
+ g_message("Handled query");
+ } else {
+ flxCache *c;
+
+ if (flx_dns_packet_get_field(p, DNS_FIELD_QDCOUNT) != 0 ||
+ flx_dns_packet_get_field(p, DNS_FIELD_ANCOUNT) == 0 ||
+ flx_dns_packet_get_field(p, DNS_FIELD_NSCOUNT) != 0 ||
+ flx_dns_packet_get_field(p, DNS_FIELD_ARCOUNT) != 0) {
+ g_warning("Invalid response packet.");
+ return;
+ }
+
+ c = a.family == AF_INET ? i->ipv4_cache : i->ipv6_cache;
+ add_response_to_cache(c, p, &a);
+
+ g_message("Handled responnse");
+ }
}
static gboolean work(flxServer *s) {
g_assert(s);
g_assert(f);
+ fprintf(f, ";;; ZONE DUMP FOLLOWS ;;;\n");
+
for (e = s->entries; e; e = e->entry_next) {
gchar *t;
fprintf(f, "%s\n", t);
g_free(t);
}
+
+ flx_dump_caches(s, f);
}
void flx_server_add_address(
GPollFD pollfd_ipv4, pollfd_ipv6;
GSource *source;
+
};