#include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <xmlobj.h> #include "wftk_session.h" #include |
adaptor_info
structure is used to pass adaptor info (duh) back to the
config module when it's building an adaptor instance. Here's what it contains:
static char *names[] = { "init", "free", "info", "do" }; XML * ACTION_dns_init (WFTK_ADAPTOR * ad, va_list args); XML * ACTION_dns_free (WFTK_ADAPTOR * ad, va_list args); XML * ACTION_dns_info (WFTK_ADAPTOR * ad, va_list args); XML * ACTION_dns_do (WFTK_ADAPTOR * ad, va_list args); static WFTK_API_FUNC vtab[] = { ACTION_dns_init, ACTION_dns_free, ACTION_dns_info, ACTION_dns_do }; static struct wftk_adaptor_info _ACTION_dns_info = { 4, names, vtab }; |
struct wftk_adaptor_info * ACTION_dns_get_info () { return & _ACTION_dns_info; } |
XML * ACTION_dns_init (WFTK_ADAPTOR * ad, va_list args) { xml_set (ad->parms, "spec", "wftk"); return (XML *) 0; } XML * ACTION_dns_free (WFTK_ADAPTOR * ad, va_list args) { return (XML *) 0; } |
XML * ACTION_dns_info (WFTK_ADAPTOR * ad, va_list args) { XML * info; info = xml_create ("info"); xml_set (info, "type", "action"); xml_set (info, "name", "dns"); xml_set (info, "ver", "1.0.0"); xml_set (info, "compiled", __TIME__ " " __DATE__); xml_set (info, "author", "Michael Roberts"); xml_set (info, "contact", "wftk@vivtek.com"); xml_set (info, "extra_functions", "0"); return (info); } |
<action handler="dns" action="lookup"> <field id="ip">12.34.56.78</field> </action>Something we'll be using a lot is our list of recognized DNS record types:
struct type_str_match { char* str; int type; }; struct type_str_match types[] = { {"A", T_A}, {"NS", T_NS}, {"MD", T_MD}, {"MF", T_MF}, {"CNAME", T_CNAME}, {"SOA", T_SOA}, {"MB", T_MB}, {"MG", T_MG}, {"MR", T_MR}, {"NULL", T_NULL}, {"WKS", T_WKS}, {"PTR", T_PTR}, {"HINFO", T_HINFO}, {"MINFO", T_MINFO}, {"MX", T_MX}, {"TXT", T_TXT}, {"RP", T_RP}, {"AFSDBB", T_AFSDB}, {"X25", T_X25}, {"ISDN", T_ISDN}, {"RT", T_RT}, {"NSAP", T_NSAP}, {"NSAP_PTR", T_NSAP_PTR}, {"SIG", T_SIG}, {"KEY", T_KEY}, {"PX", T_PX}, {"GPOS", T_GPOS}, {"AAAA", T_AAAA}, {"LOC", T_LOC}, {"AXFR", T_AXFR}, {"MAILB", T_MAILB}, {"MAILA", T_MAILA}, {"ANY", T_ANY}, {"SRV", 33} // From RFC 2052 }; static const char * lookup_type (int type) { int i; for (i = 0; i < (sizeof(types) / sizeof(struct type_str_match)); i++) { if (types[i].type == type) return types[i].str; } return "unknown"; } static int lookup_typestr (const char * type) { int i; for (i = 0; i < (sizeof(types) / sizeof(struct type_str_match)); i++) { #ifdef WINDOWS if (!stricmp (type, types[i].str)) return types[i].type; #else if (!strcasecmp (type, types[i].str)) return types[i].type; #endif } return T_ANY; } static const char * lookup_class (int class) { switch(class) { case 1: return "IN"; } return "unknown"; } |
typedef struct { u_int16_t type; u_int16_t class; u_int32_t ttl; u_int16_t length; } rr_header; typedef struct { u_int16_t priority; u_int16_t weight; u_int16_t port; } srv_header; |
static void unpack_answer (XML * action, char * answer, int len); XML * ACTION_dns_do (WFTK_ADAPTOR * ad, va_list args) { XML * action = (XML *) 0; XML * datasheet = NULL; XML * mark; char * answer; int len; int type; long retcode; if (args) action = va_arg (args, XML *); if (!action) { xml_set (ad->parms, "error", "No action given."); return (XML *) 0; } datasheet = va_arg (args, XML *); if (!strcmp (xml_attrval (action, "action"), "mx")) { xml_set (action, "action", "lookup"); xml_set (action, "type", "mx"); } if (!strcmp (xml_attrval (action, "action"), "lookup")) { type = lookup_typestr (xml_attrval (action, "type")); res_init (); xml_set_nodup (action, "lookup_name", xmlobj_get (action, NULL, "name")); answer = (char *) malloc (512); len = res_query (xml_attrval (action, "lookup_name"), C_IN, type, answer, 512); if (len > 512) { free ((void *)answer); answer = malloc (len); len = res_query (xml_attrval (action, "lookup_name"), C_IN, type, answer, len); } if (len == -1) { xml_set (action, "status", "fail"); xml_set (action, "status.reason", "Domain does not exist."); free ((void *)answer); return 0; } xml_setnum (action, "answerlen", len); /* Little sanity check. */ unpack_answer (action, answer, len); } else { xml_set (action, "status", "fail"); xml_setf (action, "status.reason", "Unknown action %s", xml_attrval (action, "action")); } return 0; } |
static int unpack_name(XML * action, XML * subanswer, const char * where, char** location, char* buffer, int len); static int unpack_question(XML * action, XML * subanswer, char** location, char* buffer, int len); static int unpack_rr(XML * action, XML * subanswer, char** location, char* buffer, int len); static void unpack_answer (XML * action, char * buffer, int len) { HEADER * hdr = (HEADER *) buffer; char * loc = buffer + sizeof (HEADER); XML * subanswer; int i = 0; if (len < sizeof(HEADER)) { xml_set (action, "status", "fail"); xml_set (action, "status.reason", "Faulty response received from DNS server: packet truncated."); return; } xmlobj_setnum (action, NULL, "id", hdr->id); xmlobj_setnum (action, NULL, "opcode", hdr->opcode); if (hdr->qr) xmlobj_set (action, NULL, "flag.response", "yes"); if (hdr->qr) xmlobj_setnum (action, NULL, "rcode", hdr->rcode); if (hdr->aa) xmlobj_set (action, NULL, "flag.authoritative", "yes"); if (hdr->tc) xmlobj_set (action, NULL, "flag.truncated", "yes"); if (hdr->rd) xmlobj_set (action, NULL, "flag.recursion_desired", "yes"); if (hdr->ra) xmlobj_set (action, NULL, "flag.recursion_available", "yes"); xmlobj_setnum (action, NULL, "qdcount", hdr->qdcount/256); xmlobj_setnum (action, NULL, "ancount", hdr->ancount/256); xmlobj_setnum (action, NULL, "nscount", hdr->nscount/256); xmlobj_setnum (action, NULL, "arcount", hdr->arcount/256); for (i = 0; i < hdr->qdcount/256; i++) { subanswer = xml_create ("qd"); xml_append_pretty (action, subanswer); if (unpack_question(action, subanswer, &loc, buffer, len) != 0) return; } for (i = 0; i < hdr->ancount/256; i++) { subanswer = xml_create ("an"); xml_append_pretty (action, subanswer); if (unpack_rr(action, subanswer, &loc, buffer, len) != 0) return; } for (i = 0; i < hdr->nscount/256; i++) { subanswer = xml_create ("ns"); xml_append_pretty (action, subanswer); if (unpack_rr(action, subanswer, &loc, buffer, len) != 0) return; } for (i = 0; i < hdr->arcount/256; i++) { subanswer = xml_create ("ar"); xml_append_pretty (action, subanswer); if (unpack_rr(action, subanswer, &loc, buffer, len) != 0) return; } } |
static int unpack_question(XML * action, XML * subanswer, char** location, char* buffer, int len) { if (*location >= buffer + len || *location < buffer) { xml_set (action, "status", "fail"); xml_set (action, "status.reason", "Malformed DNS query response [1]"); return -1; } if (unpack_name(action, subanswer, "name", location, buffer, len) != 0) return -2; if (*location + 2 * sizeof (u_int16_t) > buffer + len) { xml_set (action, "status", "fail"); xml_set (action, "status.reason", "Malformed DNS query response [2]"); return -4; } xmlobj_set (subanswer, NULL, "type", lookup_type ((* (u_int16_t *) * location)/256)); xml_setnum (subanswer, "type_num", (* (u_int16_t *) * location)/256); *location += sizeof(u_int16_t); xmlobj_set (subanswer, NULL, "class", lookup_class ((* (u_int16_t *) * location)/256)); xml_setnum (subanswer, "class_num", (* (u_int16_t *) * location)/256); *location += sizeof(u_int16_t); return 0; } |
static int unpack_name(XML * action, XML * subanswer, const char * where, char** location, char* buffer, int len) { char name[512]; int retval; retval = dn_expand (buffer, buffer + len, *location, name, sizeof(name)); if (retval < 1) { xml_set (action, "status", "fail"); xml_set (action, "status.reason", "Malformed DNS query response [7]"); return -1; } *location += retval; xmlobj_set (subanswer, NULL, where, name); return 0; } |
static int unpack_rr(XML * action, XML * subanswer, char** location, char* buffer, int len) { rr_header* header; char buf[16]; char * name; if (*location >= buffer + len || *location < buffer) { xml_set (action, "status", "fail"); xml_set (action, "status.reason", "Malformed DNS query response [5]"); return -1; } if (unpack_name(action, subanswer, "name", location, buffer, len) != 0) return -2; header = (rr_header*)*location; if (*location + sizeof(rr_header) >= buffer + len) { xml_set (action, "status", "fail"); xml_set (action, "status.reason", "Malformed DNS query response [6]"); return -3; } *location += sizeof(rr_header) - 2; xmlobj_set (subanswer, NULL, "type", lookup_type (ntohs(header->type))); xml_setnum (subanswer, "type_num", ntohs(header->type)); xmlobj_set (subanswer, NULL, "class", lookup_class (ntohs(header->class))); xml_setnum (subanswer, "class_num", ntohs(header->class)); xmlobj_setnum (subanswer, NULL, "ttl", ntohl(header->ttl)); xmlobj_setnum (subanswer, NULL, "length", ntohs(header->length)); switch(ntohs(header->type)) { case T_A: { xmlobj_set (subanswer, NULL, "data", (char *) inet_ntop(AF_INET, *location, &buf[0], sizeof(buf))); *location += ntohs(header->length); break; } case T_MX: { xmlobj_setnum (subanswer, NULL, "prio", (int) (*(u_int16_t *)(*location))/256); *location += sizeof (u_int16_t); } case T_NS: case T_CNAME: case T_PTR: { if (unpack_name(action, subanswer, "data", location, buffer, len) != 0) return -2; break; } case 33: // SRV { srv_header * srv = (srv_header *)*location; xmlobj_setnum (subanswer, NULL, "priority", srv->priority); xmlobj_setnum (subanswer, NULL, "weight", srv->weight); xmlobj_setnum (subanswer, NULL, "port", srv->port); *location += sizeof (srv_header); unpack_name(action, subanswer, "target", location, buffer, len); break; } default: /*printf(" data :\n"); unpack_hex(*location, ntohs(header->length));*/ *location += ntohs(header->length); break; } return 0; } |
This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2005, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. This presentation was prepared with LPML. Try literate programming. You'll like it. |