|
|
1.1 root 1: /* mxlookup.c */
2:
3: /* Synchronet DNS MX-record lookup routines */
4:
1.1.1.2 ! root 5: /* $Id: mxlookup.c,v 1.25 2008/03/09 20:18:18 rswindell Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2005 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /* Platform-specific */
39: #ifdef _WIN32
40: #include <windows.h> /* avoid DWORD conflict */
41: #endif
42:
43: /* ANSI */
44: #include <stdio.h>
45: #include <string.h> /* strchr */
46:
47: /* Synchronet-specific */
48: #include "sockwrap.h"
49: #include "gen_defs.h"
50: #include "smbdefs.h" /* _PACK */
51:
52: #if defined(_WIN32) || defined(__BORLANDC__)
53: #pragma pack(push,1) /* Packet structures must be packed */
54: #endif
55:
56: /* Per RFC 1035 */
57: typedef struct _PACK {
58: WORD length; /* This field included when using TCP only */
59: WORD id;
60: WORD bitfields;
61: WORD qdcount; /* number of entries in the question section */
62: WORD ancount; /* number of resource records in the answer section */
63: WORD nscount; /* number of name server resource records in the authority records section */
64: WORD arcount; /* number of resource records in the additional records section */
65: } dns_msghdr_t;
66:
67: typedef struct _PACK {
68: WORD type;
69: WORD class;
70: } dns_query_t;
71:
72: typedef struct _PACK {
73: WORD type;
74: WORD class;
75: DWORD ttl;
76: WORD length;
77: } dns_rr_t;
78:
79: #if defined(_WIN32) || defined(__BORLANDC__)
80: #pragma pack(pop) /* original packing */
81: #endif
82:
83: #define DNS_QR (1<<15) /* Query/Response (0=Query, 1=Response) */
84: #define DNS_AA (1<<10) /* Authoritavie Answer */
85: #define DNS_TC (1<<9) /* Truncation due to length limits */
86: #define DNS_RD (1<<8) /* Recursion Query desired */
87: #define DNS_RA (1<<7) /* Recursion Query available */
88:
89: #define DNS_RCODE_MASK 0x000f /* Response code bit field */
90: enum {
91: DNS_RCODE_OK /* No error condition */
92: ,DNS_RCODE_FMT /* Format error */
93: ,DNS_RCODE_SERVER /* Server Failure */
94: ,DNS_RCODE_NAME /* Name error */
95: ,DNS_RCODE_NI /* Not Implemented */
96: ,DNS_RCODE_REFUSE /* Refused */
97: };
98:
99: /* DNS Resource Record Types (from RFC 1035) - subset of query types */
100: enum {
101: DNS_A=1 /* 1 a host address */
102: ,DNS_NS /* 2 an authoritative name server */
103: ,DNS_MD /* 3 a mail destination (Obsolete - use MX) */
104: ,DNS_MF /* 4 a mail forwarder (Obsolete - use MX) */
105: ,DNS_CNAME /* 5 the canonical name for an alias */
106: ,DNS_SOA /* 6 marks the start of a zone of authority */
107: ,DNS_MB /* 7 a mailbox domain name (EXPERIMENTAL) */
108: ,DNS_MG /* 8 a mail group member (EXPERIMENTAL) */
109: ,DNS_MR /* 9 a mail rename domain name (EXPERIMENTAL) */
110: ,DNS_NULL /* 10 a null RR (EXPERIMENTAL) */
111: ,DNS_WKS /* 11 a well known service description */
112: ,DNS_PTR /* 12 a domain name pointer */
113: ,DNS_HINFO /* 13 host information */
114: ,DNS_MINFO /* 14 mailbox or mail list information */
115: ,DNS_MX /* 15 mail exchange */
116: ,DNS_TXT /* 16 text strings */
117: };
118:
119: #define DNS_IN 1 /* Internet Query Class */
120: #define DNS_ALL 255 /* Query all records */
121:
122: #ifdef MX_LOOKUP_TEST
123: #define mail_open_socket(type,s) socket(AF_INET, type, IPPROTO_IP)
124: #define mail_close_socket(sock) closesocket(sock)
125: #else
126: int mail_open_socket(int type, const char* section);
127: int mail_close_socket(SOCKET sock);
128: #endif
129:
130: size_t dns_name(BYTE* name, size_t* namelen, size_t maxlen, BYTE* srcbuf, BYTE* p)
131: {
132: size_t len=0;
133: size_t plen;
134: WORD offset;
135:
136: while(p && *p && (*namelen)<maxlen) {
137: if(len)
138: name[(*namelen)++]='.'; /* insert between.names */
139: if(((*p)&0xC0)==0xC0) { /* Compresssed name */
140: (*p)&=~0xC0;
141: offset=ntohs(*(WORD*)p);
142: (*p)|=0xC0;
143: dns_name(name, namelen, maxlen, srcbuf, srcbuf+offset);
144: return(len+2);
145: }
146: plen=(*p);
147: if((*namelen)+plen>maxlen)
148: break;
149: memcpy(name+(*namelen),p+1,plen); /* don't copy length byte */
150: (*namelen)+=plen;
151: plen++; /* Increment past length byte */
152: p+=plen;
153: len+=plen;
154: }
155: name[(*namelen)++]=0;
156: return(len+1);
157: }
158:
159: #if defined(MX_LOOKUP_TEST)
160: void dump(BYTE* buf, int len)
161: {
162: int i;
163:
164: printf("%d bytes:\n",len);
165: for(i=0;i<len;i++) {
166: printf("%02X ",buf[i]);
167: if(!((i+1)%16))
168: printf("\n");
169: else if(!((i+1)%8))
170: printf(" - ");
171: }
172: printf("\n");
173: }
174: #endif
175:
176: int dns_getmx(char* name, char* mx, char* mx2
177: ,DWORD intf, DWORD ip_addr, BOOL use_tcp, int timeout)
178: {
179: BYTE* p;
180: BYTE* tp;
181: char hostname[128];
182: size_t namelen;
183: WORD pref;
184: WORD highpref=0xffff;
185: int i;
186: int rd;
187: int len;
188: int offset;
189: int result;
190: int answers;
191: SOCKET sock;
192: SOCKADDR_IN addr={0};
193: BYTE msg[512];
194: dns_msghdr_t msghdr;
195: dns_query_t query;
196: dns_rr_t* rr;
197: struct timeval tv;
198: fd_set socket_set;
199:
200: mx[0]=0;
201: mx2[0]=0;
202:
203: if(use_tcp)
204: sock = mail_open_socket(SOCK_STREAM,"dns");
205: else
206: sock = mail_open_socket(SOCK_DGRAM,"dns");
207:
208: if(sock == INVALID_SOCKET)
209: return(ERROR_VALUE);
210:
211: addr.sin_addr.s_addr = htonl(intf);
212: addr.sin_family = AF_INET;
213: addr.sin_port = 0;
214:
215: result = bind(sock,(struct sockaddr *)&addr, sizeof(addr));
216:
217: if(result != 0) {
218: mail_close_socket(sock);
219: return(ERROR_VALUE);
220: }
221:
222: memset(&addr,0,sizeof(addr));
223: addr.sin_addr.s_addr = ip_addr;
224: addr.sin_family = AF_INET;
225: addr.sin_port = htons(53);
226:
227: if((result=connect(sock, (struct sockaddr *)&addr, sizeof(addr)))!=0) {
228: mail_close_socket(sock);
229: return(ERROR_VALUE);
230: }
231:
232: memset(&msghdr,0,sizeof(msghdr));
233:
234: len=sizeof(msghdr)+strlen(name)+sizeof(query);
235: msghdr.length=htons((WORD)len);
236:
237: msghdr.bitfields=htons(DNS_RD);
238: msghdr.qdcount=htons(1);
239: query.type=htons(DNS_MX);
240: query.class=htons(DNS_IN);
241: /* Build the message */
242: memcpy(msg,&msghdr,sizeof(msghdr));
243: len=sizeof(msghdr);
244: for(p=name;*p;p+=namelen) {
245: if(*p=='.')
246: p++;
247: tp=strchr(p,'.');
248: if(tp)
249: namelen=tp-p;
250: else
251: namelen=strlen(p);
252: *(msg+len)=(BYTE)namelen;
253: len++;
254: memcpy(msg+len,p,namelen);
255: len+=namelen;
256: }
257: *(msg+len)=0; /* terminator */
258: len++;
259: memcpy(msg+len,&query,sizeof(query));
260: len+=sizeof(query);
261:
262: if(use_tcp)
263: offset=0;
264: else { /* UDP */
265: offset=sizeof(msghdr.length);
266: len-=sizeof(msghdr.length);
267: }
268:
269: /* check for writability (using select) */
270: tv.tv_sec=timeout;
271: tv.tv_usec=0;
272:
273: FD_ZERO(&socket_set);
274: FD_SET(sock,&socket_set);
275:
276: i=select(sock+1,NULL,&socket_set,NULL,&tv);
277: if(i<1) {
278: if(i==SOCKET_ERROR)
279: result=ERROR_VALUE;
280: else
281: result=-1;
282: mail_close_socket(sock);
283: return(result);
284: }
285:
286: /* send query */
287: #if defined(MX_LOOKUP_TEST)
288: printf("Sending ");
289: dump(msg+offset,len);
290: #endif
291: i=send(sock,msg+offset,len,0);
292: if(i!=len) {
293: if(i==SOCKET_ERROR)
294: result=ERROR_VALUE;
295: else
296: result=-2;
297: mail_close_socket(sock);
298: return(result);
299: }
300:
301: /* check for readability (using select) */
302: tv.tv_sec=timeout;
303: tv.tv_usec=0;
304:
305: FD_ZERO(&socket_set);
306: FD_SET(sock,&socket_set);
307:
308: i=select(sock+1,&socket_set,NULL,NULL,&tv);
309: if(i<1) {
310: if(i==SOCKET_ERROR)
311: result=ERROR_VALUE;
312: else
313: result=-1;
314: mail_close_socket(sock);
315: return(result);
316: }
317:
318: /* receive response */
319: rd=recv(sock,msg,sizeof(msg),0);
320: if(rd>0) {
321:
322: memcpy(((BYTE*)(&msghdr))+offset,msg,sizeof(msghdr)-offset);
323:
324: #if defined(MX_LOOKUP_TEST)
325: printf("Received ");
326: dump(msg,rd);
327:
328: printf("%-10s %lx\n","id",ntohs(msghdr.id));
329: printf("%-10s %lx\n","bitfields",ntohs(msghdr.bitfields));
330: printf("%-10s %lx\n","qdcount",ntohs(msghdr.qdcount));
331: printf("%-10s %lx\n","ancount",ntohs(msghdr.ancount));
332: printf("%-10s %lx\n","nscount",ntohs(msghdr.nscount));
333: printf("%-10s %lx\n","arcount",ntohs(msghdr.arcount));
334:
335: #endif
336:
337: if(!use_tcp)
338: offset=0;
339: else
340: offset=sizeof(msghdr.length);
341:
342: answers=ntohs(msghdr.ancount);
343: p=msg+len; /* Skip the header and question portion */
344:
1.1.1.2 ! root 345: for(i=0;i<answers && p<msg+sizeof(msg);i++) {
1.1 root 346: namelen=0;
347: p+=dns_name(hostname, &namelen, sizeof(hostname)-1, msg+offset, p);
348:
349: rr=(dns_rr_t*)p;
350: p+=sizeof(dns_rr_t);
351: #if defined(MX_LOOKUP_TEST)
352: printf("answer #%d\n",i+1);
353: printf("hostname='%s'\n",hostname);
354: printf("type=%x ",ntohs(rr->type));
355: printf("class=%x ",ntohs(rr->class));
356: printf("ttl=%lu ",ntohl(rr->ttl));
357: printf("length=%d\n",ntohs(rr->length));
358: #endif
359:
360: len=ntohs(rr->length);
361: if(ntohs(rr->type)==DNS_MX) {
362: pref=ntohs(*(WORD*)p);
363: p+=2;
364: namelen=0;
365: p+=dns_name(hostname, &namelen, sizeof(hostname)-1, msg+offset, p);
366: if(pref<=highpref) {
367: highpref=pref;
368: if(mx[0])
369: strcpy(mx2,mx);
370: strcpy(mx,hostname);
371: } else if(!mx2[0])
372: strcpy(mx2,hostname);
373: }
374: else
375: p+=len;
376: }
377: }
378:
379: if(!mx[0]) {
380: #if defined(MX_LOOKUP_TEST)
381: printf("No MX record found, using default name.\n");
382: #endif
383: strcpy(mx,name);
384: }
385: mail_close_socket(sock);
386: return(0);
387: }
388:
389: #ifdef MX_LOOKUP_TEST
390: void main(int argc, char **argv)
391: {
392: char mx[128],mx2[128];
393: int result;
1.1.1.2 ! root 394: DWORD bindaddr=0;
! 395: #ifdef _WIN32
1.1 root 396: WSADATA WSAData;
1.1.1.2 ! root 397: #endif
1.1 root 398:
399: printf("sizeof(dns_msghdr_t)=%d\n",sizeof(dns_msghdr_t));
400: printf("sizeof(dns_query_t)=%d\n",sizeof(dns_query_t));
401: printf("sizeof(dns_rr_t)=%d\n",sizeof(dns_rr_t));
402:
403: if(argc<3) {
1.1.1.2 ! root 404: printf("usage: mxlookup hostname dns [bindaddr]\n");
1.1 root 405: return;
406: }
407:
408:
1.1.1.2 ! root 409: #ifdef _WIN32
1.1 root 410: if((result = WSAStartup(MAKEWORD(1,1), &WSAData))!=0) {
411: printf("Error %d in WSAStartup",result);
412: return;
413: }
1.1.1.2 ! root 414: #endif
1.1 root 415:
1.1.1.2 ! root 416: if(argc > 3)
! 417: bindaddr=ntohl(inet_addr(argv[3]));
! 418:
! 419: if((result=dns_getmx(argv[1],mx,mx2,bindaddr,inet_addr(argv[2]),FALSE,60))!=0)
1.1 root 420: printf("Error %d getting mx record\n",result);
421: else {
422: printf("MX1: %s\n",mx);
423: printf("MX2: %s\n",mx2);
424: }
425:
1.1.1.2 ! root 426: #ifdef _WIN32
1.1 root 427: WSACleanup();
1.1.1.2 ! root 428: #endif
1.1 root 429: gets(mx);
430: }
431: #endif
432:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.