1 #include <string.h>
2 
3 #include "dns.h"
4 
sizeit(const char * buf,unsigned int len,unsigned int pos,uint16 datalen)5 static int sizeit(const char* buf, unsigned int len, unsigned int pos, uint16 datalen)
6 {
7   char* q = 0;
8   if (!dns_packet_getname(buf,len,pos + 2,&q)) return -1;
9   len = fmt_dns_domain(0, q);
10   free(q);
11   return len + 1;
12   (void)datalen;
13 }
14 
getit(struct dns_result * out,unsigned int i,unsigned int offset,const char * buf,unsigned int len,unsigned int pos,uint16 datalen)15 static int getit(struct dns_result* out, unsigned int i, unsigned int offset,
16 		 const char* buf, unsigned int len, unsigned int pos, uint16 datalen)
17 {
18   unsigned char pref[2];
19   char* q = 0;
20   struct dns_mx* mx = &out->rr.mx[i];
21 
22   if (!dns_packet_copy(buf,len,pos,pref,2)) return -1;
23   mx->distance = uint16_get_msb(pref);
24   if (!dns_packet_getname(buf,len,pos + 2,&q)) return -1;
25   mx->name = out->__buffer + offset;
26   len = fmt_dns_domain(mx->name, q);
27   mx->name[len] = 0;
28   free(q);
29   return len + 1;
30   (void)datalen;
31 }
32 
33 /** Extract mail exchanger (MX) records from a DNS response packet. */
dns_mx_packet(struct dns_result * out,const char * buf,unsigned int len)34 int dns_mx_packet(struct dns_result* out, const char* buf, unsigned int len)
35 {
36   return dns_packet_extract(out, buf, len, DNS_T_MX, DNS_C_IN, sizeit, getit);
37 }
38 
39 /** Request the mail exchanger (MX) records for a domain name. */
dns_mx_r(struct dns_transmit * tx,struct dns_result * out,const char * fqdn)40 int dns_mx_r(struct dns_transmit* tx, struct dns_result* out, const char* fqdn)
41 {
42   char *q = 0;
43   if (!dns_domain_fromdot(&q,fqdn,strlen(fqdn))) return -1;
44   if (dns_resolve(tx,q,DNS_T_MX) == -1) { free(q); return -1; }
45   free(q);
46   if (dns_mx_packet(out,tx->packet,tx->packetlen) == -1)  return -1;
47   dns_transmit_free(tx);
48   return 0;
49 }
50 
51 /** \fn dns_mx(struct dns_result*, const char*)
52     Request the mail exchanger (MX) records for a domain name.
53 */
DNS_R_FN_WRAP(mx,const char *)54 DNS_R_FN_WRAP(mx, const char*)
55 
56 #ifdef SELFTEST_MAIN
57 #include "dns-responder.c"
58 DUMP
59 {
60   int i;
61 
62   dns_sort_mx(rr->mx, count);
63   for (i = 0; i < count; ++i)
64     obuf_putf(&outbuf, "d{ }d{: \"}s{\"\n}", i, rr->mx[i].distance, rr->mx[i].name);
65 }
66 RESPONSE responses[] = {
67   { 1, 3, 0, {
68       { "\300\014", 2, 15, 1, 86400, "2\1\2mx\vfuturequest\3net\0", 22 },
69       { "\300\014", 2, 1, 1, 123456, "\3ns2\300\061", 6 },
70       { "\300\014", 2, 1, 1, 123456, "\3ns1\300\061", 6 },
71       { "\300\014", 2, 1, 1, 123456, "\3ns3\300\061", 6 },
72     }
73   },
74   { 5, 0, 0, {
75       { "\300\014", 2, 15, 1, 86400, "\0\024\4alt1\5aspmx\1l\6google\3com\0", 27 },
76       { "\300\014", 2, 15, 1, 86400, "\0\012\5aspmx\1l\6google\3com\0", 22, },
77       { "\300\014", 2, 15, 1, 86400, "\0\036\4alt2\5aspmx\1l\6google\3com\0", 27 },
78       { "\300\014", 2, 15, 1, 86400, "\0\050\4alt3\5aspmx\1l\6google\3com\0", 27 },
79       { "\300\014", 2, 15, 1, 86400, "\0\062\4alt4\5aspmx\1l\6google\3com\0", 27 },
80     }
81   },
82 };
83 MAIN
84 {
85   const char* names[] = { "untroubled.org", "google.com", NULL };
86   do_dns_respond_tests(dns_mx, names, responses, 2);
87 }
88 #endif
89 #ifdef SELFTEST_EXP
90 32: ID=XX QR=0 opcode=0 AA=0 TC=0 RD=1 RA=0 Z=0 RCODE=0 QDCOUNT=1 ANCOUNT=0 NSCOUNT=0 ARCOUNT=0
91 Question: untroubled.org. QTYPE=15 QCLASS=1
92 result=0
93 untroubled.org: count=1
94 0 12801: "mx.futurequest.net"
95 28: ID=XX QR=0 opcode=0 AA=0 TC=0 RD=1 RA=0 Z=0 RCODE=0 QDCOUNT=1 ANCOUNT=0 NSCOUNT=0 ARCOUNT=0
96 Question: google.com. QTYPE=15 QCLASS=1
97 result=0
98 google.com: count=5
99 0 10: "aspmx.l.google.com"
100 1 20: "alt1.aspmx.l.google.com"
101 2 30: "alt2.aspmx.l.google.com"
102 3 40: "alt3.aspmx.l.google.com"
103 4 50: "alt4.aspmx.l.google.com"
104 #endif
105