|
|
1.1 ! root 1: /* mxlookup.c */ ! 2: ! 3: /* Synchronet DNS MX-record lookup routines */ ! 4: ! 5: /* $Id: mxlookup.c,v 1.22 2005/10/13 06:49:14 rswindell Exp $ */ ! 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: ! 345: for(i=0;i<answers;i++) { ! 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; ! 394: WSADATA WSAData; ! 395: ! 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: ! 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: ! 411: if((result=dns_getmx(argv[1],mx,mx2,0,inet_addr(argv[2]),FALSE,60))!=0) ! 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(); ! 419: gets(mx); ! 420: } ! 421: #endif ! 422:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.