/* Example of mxlookup auto recs = MxRecord.lookup(args[1]); foreach(rec;recs){ writefln("Got: %d %s", rec.weight, rec.name); } */ extern(C) { int __res_init (); int __res_search (char *, int, int, ubyte *, int); int *__h_errno_location (); ushort ntohs (ushort __netshort); int __dn_skipname (ubyte *, ubyte *); int __dn_expand (ubyte *, ubyte *, ubyte *, char *, int) ; } struct HEADER { short id ; ubyte td_tc_aa_opcode_qr; ubyte rcode_cd_ad_unused_ra; ushort qdcount ; ushort ancount ; ushort nscount ; ushort arcount ; } const ns_c_in = 1; const ns_t_mx = 15; import std.stdio; static this() { __res_init(); } class MxRecord { this(int w, char[] n) { this.weight = w; this.name = n; } int weight; char[] name; int opCmp( Object B) { return weight - (cast(MxRecord)B).weight; } static MxRecord[] lookup (char[] domain) { HEADER *hp; ubyte *end; MxRecord[] ret; int qdc; ubyte *cp; ushort type; ubyte ans[8192]; ushort weight = 0; int i, count; char buf[64]; if((i = __res_search(std.string.toStringz(domain), ns_c_in, ns_t_mx, ans.ptr, ans.sizeof)) < 0){ throw new Exception(nsError((*__h_errno_location ()), domain)); } if (i > ans.sizeof) { i = ans.sizeof; } hp = cast(HEADER *)(ans.ptr); cp = (ans.ptr + 12); end =(ans.ptr +i); for (qdc = ntohs(hp.qdcount); qdc --; cp = (cp + i + 4)) { if ((i = __dn_skipname(cp, end)) < 0 ) { throw new Exception("No Records found"); } } count = ntohs(hp.ancount); while (--count >= 0 && cp < end) { if ((i = __dn_skipname(cp, end)) < 0 ) { continue; } cp += i; type = (*cp << 8) | *(cp+1); cp += 8; i = (*cp << 8) | *(cp+1) ; cp += 2; if (type != ns_t_mx) { //printf("not mx %d != %d", type, ns_t_mx); cp += i; continue; } weight = (*cp << 8) | *(cp+1) ; cp += 2; if ((i = __dn_expand(ans.ptr, end, cp, buf.ptr, cast(int)buf.sizeof-1)) < 0) { throw new Exception("Invalid data returned"); } cp += i; ret ~= new MxRecord(weight, std.string.toString(buf.ptr).dup); //writefln("got %d, %s\n", weight, std.string.toString(buf.ptr)); } return ret.sort; } static char[] nsError(int error, char[] domain) { switch(error){ case 1: return "Unknown domain: "~ domain; case 4: return "No NS records for " ~ domain; case 2: return "No response for NS query"; default: return "Unexpected error"; } } }