|
|
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.20 2004/05/11 01:12:42 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 2000 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 */
1.1.1.2 ! root 48: #include "sockwrap.h"
1.1 root 49: #include "gen_defs.h"
50: #include "smbdefs.h" /* _PACK */
51:
1.1.1.2 ! root 52: #if defined(_WIN32) || defined(__BORLANDC__)
! 53: #pragma pack(push,1) /* Packet structures must be packed */
1.1 root 54: #endif
55:
1.1.1.2 ! root 56: /* Per RFC 1035 */
1.1 root 57: typedef struct _PACK {
1.1.1.2 ! root 58: WORD length; /* This field included when using TCP only */
1.1 root 59: WORD id;
60: WORD bitfields;
1.1.1.2 ! root 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 */
1.1 root 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:
1.1.1.2 ! root 79: #if defined(_WIN32) || defined(__BORLANDC__)
1.1 root 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:
1.1.1.2 ! root 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:
1.1 root 119: #define DNS_IN 1 // Internet Query Class
1.1.1.2 ! root 120: #define DNS_ALL 255 // Query all records
1.1 root 121:
1.1.1.2 ! root 122: #ifdef MX_LOOKUP_TEST
! 123: #define mail_open_socket(type) socket(AF_INET, type, IPPROTO_IP)
! 124: #define mail_close_socket(sock) closesocket(sock)
! 125: #else
! 126: int mail_open_socket(int type);
! 127: int mail_close_socket(SOCKET sock);
! 128: #endif
1.1 root 129:
1.1.1.2 ! root 130: size_t dns_name(BYTE* name, size_t* namelen, size_t maxlen, BYTE* srcbuf, BYTE* p)
1.1 root 131: {
1.1.1.2 ! root 132: size_t len=0;
! 133: size_t plen;
1.1 root 134: WORD offset;
135:
1.1.1.2 ! root 136: while(p && *p && (*namelen)<maxlen) {
! 137: if(len)
! 138: name[(*namelen)++]='.'; // insert between.names
1.1 root 139: if(((*p)&0xC0)==0xC0) { // Compresssed name
140: (*p)&=~0xC0;
141: offset=ntohs(*(WORD*)p);
142: (*p)|=0xC0;
1.1.1.2 ! root 143: dns_name(name, namelen, maxlen, srcbuf, srcbuf+offset);
! 144: return(len+2);
1.1 root 145: }
146: plen=(*p);
1.1.1.2 ! root 147: if((*namelen)+plen>maxlen)
! 148: break;
! 149: memcpy(name+(*namelen),p+1,plen); // don't copy length byte
! 150: (*namelen)+=plen;
1.1 root 151: plen++; // Increment past length byte
152: p+=plen;
153: len+=plen;
154: }
1.1.1.2 ! root 155: name[(*namelen)++]=0;
1.1 root 156: return(len+1);
157: }
158:
1.1.1.2 ! root 159: #if defined(MX_LOOKUP_TEST)
! 160: void dump(BYTE* buf, int len)
1.1 root 161: {
1.1.1.2 ! root 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;
1.1 root 181: char hostname[128];
1.1.1.2 ! root 182: size_t namelen;
1.1 root 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;
1.1.1.2 ! root 197: struct timeval tv;
! 198: fd_set socket_set;
1.1 root 199:
200: mx[0]=0;
201: mx2[0]=0;
202:
203: if(use_tcp)
204: sock = mail_open_socket(SOCK_STREAM);
205: else
206: sock = mail_open_socket(SOCK_DGRAM);
207:
1.1.1.2 ! root 208: if(sock == INVALID_SOCKET)
1.1 root 209: return(ERROR_VALUE);
210:
211: addr.sin_addr.s_addr = htonl(intf);
212: addr.sin_family = AF_INET;
1.1.1.2 ! root 213: addr.sin_port = 0;
1.1 root 214:
1.1.1.2 ! root 215: result = bind(sock,(struct sockaddr *)&addr, sizeof(addr));
1.1 root 216:
1.1.1.2 ! root 217: if(result != 0) {
1.1 root 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)
1.1.1.2 ! root 249: namelen=tp-p;
1.1 root 250: else
1.1.1.2 ! root 251: namelen=strlen(p);
! 252: *(msg+len)=(BYTE)namelen;
1.1 root 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:
1.1.1.2 ! root 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 */
1.1 root 319: rd=recv(sock,msg,sizeof(msg),0);
320: if(rd>0) {
321:
1.1.1.2 ! root 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
1.1 root 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:
345: for(i=0;i<answers;i++) {
1.1.1.2 ! root 346: namelen=0;
! 347: p+=dns_name(hostname, &namelen, sizeof(hostname)-1, msg+offset, p);
1.1 root 348:
349: rr=(dns_rr_t*)p;
350: p+=sizeof(dns_rr_t);
1.1.1.2 ! root 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
1.1 root 359:
360: len=ntohs(rr->length);
361: if(ntohs(rr->type)==DNS_MX) {
362: pref=ntohs(*(WORD*)p);
363: p+=2;
1.1.1.2 ! root 364: namelen=0;
! 365: p+=dns_name(hostname, &namelen, sizeof(hostname)-1, msg+offset, p);
1.1 root 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:
1.1.1.2 ! root 379: if(!mx[0]) {
! 380: #if defined(MX_LOOKUP_TEST)
! 381: printf("No MX record found, using default name.\n");
! 382: #endif
1.1 root 383: strcpy(mx,name);
1.1.1.2 ! root 384: }
1.1 root 385: mail_close_socket(sock);
386: return(0);
387: }
388:
1.1.1.2 ! root 389: #ifdef MX_LOOKUP_TEST
1.1 root 390: void main(int argc, char **argv)
391: {
392: char mx[128],mx2[128];
393: int result;
394: WSADATA WSAData;
395:
1.1.1.2 ! root 396: printf("sizeof(dns_msghdr_t)=%d\n",sizeof(dns_msghdr_t));
! 397: printf("sizeof(dns_query_t)=%d\n",sizeof(dns_query_t));
! 398: printf("sizeof(dns_rr_t)=%d\n",sizeof(dns_rr_t));
! 399:
1.1 root 400: if(argc<3) {
401: printf("usage: mxlookup hostname dns\n");
402: return;
403: }
404:
405:
406: if((result = WSAStartup(MAKEWORD(1,1), &WSAData))!=0) {
407: printf("Error %d in WSAStartup",result);
408: return;
409: }
410:
1.1.1.2 ! root 411: if((result=dns_getmx(argv[1],mx,mx2,0,inet_addr(argv[2]),FALSE,60))!=0)
1.1 root 412: printf("Error %d getting mx record\n",result);
413: else {
414: printf("MX1: %s\n",mx);
415: printf("MX2: %s\n",mx2);
416: }
417:
418: WSACleanup();
1.1.1.2 ! root 419: gets(mx);
1.1 root 420: }
421: #endif
422:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.