BOOL GetMX ( char *pszQuery, char *pszServer, OUT t_Ary_MXHostInfos &Ary_MXHostInfos ) { SOCKET hSocket; SOCKADDR_IN stSockAddr; // socket address structures int nAddrLen = sizeof( SOCKADDR_IN ); HOSTENT *pHostEnt; char achBufOut[ BUFSIZE ] = { 0 }; char achBufIn[ BUFSIZE ] = { 0 }; int nQueryLen = 0; int nRC; char *p, *np, name[128], *eom; int count, j, i, n; memset( &stSockAddr, ASCII_NULL, sizeof( stSockAddr ) ); stSockAddr.sin_family = AF_INET; stSockAddr.sin_port = htons( 53); stSockAddr.sin_addr.s_addr = inet_addr( pszServer ); if ( stSockAddr.sin_addr.s_addr == INADDR_NONE ) { pHostEnt = gethostbyname( pszServer ); if ( pHostEnt ) { stSockAddr.sin_addr.s_addr = *((ULONG *)pHostEnt->h_addr_list[0]); } else { return FALSE; } // end if } // end if /*------------------------------------------------------------ * Get a DGRAM socket */ hSocket = socket( AF_INET, SOCK_DGRAM, 0 ); if ( hSocket == INVALID_SOCKET ) { return FALSE; } // end if /*----------------------------------------------------------- * Format DNS Query */ pDNShdr = (PDNS_HDR)&( achBufOut[ 0 ] ); pDNShdr->dns_id = htons( 0xDEAD ); pDNShdr->dns_flags = htons( DNS_FLAG_RD ); // do recurse pDNShdr->dns_q_count = htons( 1 ); // one query pDNShdr->dns_rr_count = 0; // none in query pDNShdr->dns_auth_count = 0; // none in query pDNShdr->dns_add_count = 0; // none in query nQueryLen = PutQName( pszQuery, &(achBufOut[ DNS_HDR_LEN ] ) ); nQueryLen += DNS_HDR_LEN; achBufOut[ nQueryLen++ ] = 0; achBufOut[ nQueryLen++ ] = 0; achBufOut[ nQueryLen ] = DNS_RRTYPE_MX; achBufOut[ nQueryLen + 1 ] = 0; achBufOut[ nQueryLen + 2 ] = DNS_RRCLASS_IN; achBufOut[ nQueryLen + 3 ] = 0; nQueryLen += 4; /*----------------------------------------------------------- * Send DNS Query to server */ nRC = sendto( hSocket, achBufOut, nQueryLen, 0, (LPSOCKADDR)&stSockAddr, sizeof( SOCKADDR_IN ) ); if ( nRC == SOCKET_ERROR ) { closesocket( hSocket ); return FALSE; } else { } // VERIFY ( SetBlockingMode ( hSocket, TRUE ) ); // 用 select 模型实现连接超时 struct timeval timeout; fd_set r; FD_ZERO(&r); FD_SET(hSocket, &r); timeout.tv_sec = 5; //连接超时秒 timeout.tv_usec =0; int ret = select(0, &r, 0, 0, &timeout); if ( ret == SOCKET_ERROR ) { ::closesocket(hSocket); hSocket = SOCKET_ERROR; return FALSE; } // 得到可读的数据长度 long cmd = FIONREAD; u_long argp = 0; BOOL err = ioctlsocket ( hSocket, cmd, (u_long*)&argp ); if ( err || argp < 1 ) { ::closesocket(hSocket); hSocket = SOCKET_ERROR; return FALSE; } nRC = recvfrom( hSocket, achBufIn, BUFSIZE, 0, (LPSOCKADDR)&stSockAddr, &nAddrLen ); if ( nRC == SOCKET_ERROR ) { int nWSAErr = WSAGetLastError(); if ( nWSAErr != WSAETIMEDOUT ) { closesocket( hSocket ); return FALSE; } else { closesocket( hSocket ); return FALSE; } } else { pDNShdr = (PDNS_HDR)&( achBufIn[ 0 ] ); p = (char *)&pDNShdr[0]; p+=12; count = (int)*p; // Parse the Question... for (i = 0; i< ntohs(pDNShdr->dns_q_count); i++) { np = name; eom = (char *)pDNShdr+nRC; if ( (n = dn_expand((char *)pDNShdr, eom, p, name, 127)) < 0 ) { return FALSE; } p += n + QFIXEDSZ; } for (i = 0; i< ntohs(pDNShdr->dns_rr_count); i++) { // The Question Name appears Again... if ((n = dn_expand((char *)pDNShdr, eom, p, name, 127)) < 0) { return FALSE; } p+=n; j = _getshort(p);; //TYPE p+=2; //printf("%s\tType:%d", name, j); j = _getshort(p); //CLASS p+=2; // printf("\tClass:%d", j); j = _getlong(p); //TTL p+=4; // printf("\tTTL:%d", j); j = _getshort(p); //RDLENGTH p+=2; // printf("\tRDLENGTH:%d", j); j = _getshort(p); //N?? p+=2; // This should be an MX Name... if ( (n = dn_expand((char *)pDNShdr, eom, p, name, 127)) < 0 ) { return FALSE; } t_MXHostInfo tMXHostInfo = {0}; strncpy ( (char*)tMXHostInfo.szMXHost, name, _countof(tMXHostInfo.szMXHost)); tMXHostInfo.N = j; Ary_MXHostInfos.Add ( tMXHostInfo ); TRACE ( _T("%s\t%d\r\n"), name, j ); p += n; } return TRUE; } closesocket( hSocket ); return FALSE; }
/* * Print resource record fields in human readable form. */ static char * p_rr(char *cp, char *msg, FILE *file) { int type, class, dlen, n, c; struct in_addr inaddr; char *cp1, *cp2; if ((cp = p_cdname(cp, msg, file)) == NULL) return (NULL); /* compression error */ fprintf(file,"\n\ttype = %s", __p_type(type = _getshort(cp))); cp += sizeof(u_short); fprintf(file,", class = %s", __p_class(class = _getshort(cp))); cp += sizeof(u_short); fprintf(file,", ttl = %s", __p_time(_getlong(cp))); cp += sizeof(u_long); fprintf(file,", dlen = %d\n", dlen = _getshort(cp)); cp += sizeof(u_short); cp1 = cp; /* * Print type specific data, if appropriate */ switch (type) { case T_A: switch (class) { case C_IN: case C_HS: bcopy(cp, (char *)&inaddr, sizeof(inaddr)); if (dlen == 4) { fprintf(file,"\tinternet address = %s\n", inet_ntoa(inaddr)); cp += dlen; } else if (dlen == 7) { fprintf(file,"\tinternet address = %s", inet_ntoa(inaddr)); fprintf(file,", protocol = %d", cp[4]); fprintf(file,", port = %d\n", (cp[5] << 8) + cp[6]); cp += dlen; } break; default: cp += dlen; } break; case T_CNAME: case T_MB: case T_MG: case T_MR: case T_NS: case T_PTR: fprintf(file,"\tdomain name = "); cp = p_cdname(cp, msg, file); fprintf(file,"\n"); break; case T_HINFO: if (n = *cp++) { fprintf(file,"\tCPU=%.*s\n", n, cp); cp += n; } if (n = *cp++) { fprintf(file,"\tOS=%.*s\n", n, cp); cp += n; } break; case T_SOA: fprintf(file,"\torigin = "); cp = p_cdname(cp, msg, file); fprintf(file,"\n\tmail addr = "); cp = p_cdname(cp, msg, file); fprintf(file,"\n\tserial = %ld", _getlong(cp)); cp += sizeof(u_long); fprintf(file,"\n\trefresh = %s", __p_time(_getlong(cp))); cp += sizeof(u_long); fprintf(file,"\n\tretry = %s", __p_time(_getlong(cp))); cp += sizeof(u_long); fprintf(file,"\n\texpire = %s", __p_time(_getlong(cp))); cp += sizeof(u_long); fprintf(file,"\n\tmin = %s\n", __p_time(_getlong(cp))); cp += sizeof(u_long); break; case T_MX: fprintf(file,"\tpreference = %ld,",_getshort(cp)); cp += sizeof(u_short); fprintf(file," name = "); cp = p_cdname(cp, msg, file); break; case T_TXT: (void) fputs("\t\"", file); cp2 = cp1 + dlen; while (cp < cp2) { if (n = (unsigned char) *cp++) { for (c = n; c > 0 && cp < cp2; c--) if (*cp == '\n') { (void) putc('\\', file); (void) putc(*cp++, file); } else (void) putc(*cp++, file); } } (void) fputs("\"\n", file); break; case T_MINFO: fprintf(file,"\trequests = "); cp = p_cdname(cp, msg, file); fprintf(file,"\n\terrors = "); cp = p_cdname(cp, msg, file); break; case T_UINFO: fprintf(file,"\t%s\n", cp); cp += dlen; break; case T_UID: case T_GID: if (dlen == 4) { fprintf(file,"\t%ld\n", _getlong(cp)); cp += sizeof(int); } break; case T_WKS: if (dlen < sizeof(u_long) + 1) break; bcopy(cp, (char *)&inaddr, sizeof(inaddr)); cp += sizeof(u_long); fprintf(file,"\tinternet address = %s, protocol = %d\n\t", inet_ntoa(inaddr), *cp++); n = 0; while (cp < cp1 + dlen) { c = *cp++; do { if (c & 0200) fprintf(file," %d", n); c <<= 1; } while (++n & 07); } putc('\n',file); break; #ifdef ALLOW_T_UNSPEC case T_UNSPEC: { int NumBytes = 8; char *DataPtr; int i; if (dlen < NumBytes) NumBytes = dlen; fprintf(file, "\tFirst %d bytes of hex data:", NumBytes); for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++) fprintf(file, " %x", *DataPtr); fputs("\n", file); cp += dlen; } break; #endif /* ALLOW_T_UNSPEC */ default: fprintf(file,"\t???\n"); cp += dlen; } if (cp != cp1 + dlen) { fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen); cp = NULL; } fprintf(file,"\n"); return (cp); }
/* * parse_rr: * Extract and parse a resource record * * returns a pointer to the RR (or NULL on failure). */ s_rr * parse_rr( char **cpp, char *msg) { s_rr *ptr; int dlen; union u_rdata *rd; /* * Set up the RR-independent information */ if ((ptr = (s_rr *)malloc(sizeof(s_rr))) == NULL ) return(NULL); if ((ptr->name = expand_cdname(cpp,msg)) == NULL ) { free(ptr); return(NULL); } ptr->type = _getshort(*cpp); *cpp += sizeof(u_short); ptr->rclass = _getshort(*cpp); *cpp += sizeof(u_short); ptr->ttl = _getlong(*cpp); /* Size on the network is 4 bytes so use u_int not u_long as * u_long is architecture dependent (e.g. 8 bytes on 64 bit). */ *cpp += sizeof(u_int); dlen = _getshort(*cpp); ptr->dlen = dlen; *cpp += sizeof(u_short); rd = &ptr->rdata; /* * Handle RR-specifics * * (No indication of failures here is * passed back to the calling procedure) */ switch(ptr->type) { case T_A: /* Address */ switch (ptr->rclass) { case C_IN: memcpy((void *)&rd->address, (void *)*cpp, sizeof(struct in_addr)); *cpp += dlen; break; default: /* Can't really handle this - just skip it */ *cpp += dlen; } break; case T_NS: /* Name Server */ case T_MD: /* Mail Destination (OBS) */ case T_MF: /* Mail Forwarder (OBS) */ case T_CNAME: /* Canonical Name */ rd->string = expand_cdname(cpp, msg); break; case T_SOA: /* Start of Authority */ rd->soa.mname = expand_cdname(cpp, msg); rd->soa.rname = expand_cdname(cpp, msg); rd->soa.serial = _getlong(*cpp); *cpp += sizeof(u_long); rd->soa.refresh = _getlong(*cpp); *cpp += sizeof(u_long); rd->soa.retry = _getlong(*cpp); *cpp += sizeof(u_long); rd->soa.expire = _getlong(*cpp); *cpp += sizeof(u_long); rd->soa.minimum = _getlong(*cpp); *cpp += sizeof(u_long); break; case T_MB: /* Mail Box */ case T_MG: /* Mail Group */ case T_MR: /* Mail Rename */ rd->string = expand_cdname(cpp, msg); break; /* Following modification taken from VxWorks --GAT */ /* 01b,29apr97,jag Changed T_NULL to T_NULL_RR to fix conflict with loadCoffLib.h */ case T_NULL_RR: /* Null RR */ if ((rd->null.anything = (char *)malloc(dlen)) != NULL ) memcpy((void *)rd->null.anything, (void *)*cpp, dlen); rd->null.length = dlen; *cpp += dlen; break; case T_WKS: /* Well Known Services */ memcpy((void *)&rd->wks.address, (void *)*cpp, sizeof(struct in_addr)); *cpp += sizeof(struct in_addr); rd->wks.protocol = **cpp; (*cpp)++; rd->wks.maplength = dlen-(sizeof(struct in_addr) +1); if ((rd->wks.bitmap = (char *)malloc(rd->wks.maplength)) != NULL ) memcpy((void *)rd->wks.bitmap, (void *)*cpp, rd->wks.maplength); *cpp += rd->wks.maplength; break; case T_PTR: /* Domain Name Pointer */ rd->string = expand_cdname(cpp, msg); break; case T_HINFO: /* Host Info */ if (( rd->hinfo.cpu = expand_charstring(cpp, msg)) == NULL ) { cpp += dlen; break; } if (( rd->hinfo.os = expand_charstring(cpp, msg)) == NULL ) { cpp -= (strlen(rd->hinfo.cpu) +1); cpp += dlen; break; } break; case T_MINFO: /* Mailbox Info */ rd->minfo.rmailbx = expand_cdname(cpp, msg); rd->minfo.emailbx = expand_cdname(cpp, msg); break; case T_MX: /* Mail Exchanger */ rd->mx.preference = _getshort(*cpp); *cpp += sizeof(u_short); rd->mx.exchange = expand_cdname(cpp, msg); break; case T_SRV: /* Service location */ rd->srv.priority = _getshort(*cpp); *cpp += sizeof(u_short); rd->srv.weight = _getshort(*cpp); *cpp += sizeof(u_short); rd->srv.port = _getshort(*cpp); *cpp += sizeof(u_short); rd->srv.target = expand_cdname(cpp, msg); break; case T_NAPTR: /* Naming authority pointer */ { // This is copied from the other cases, but I think that // all cases should be setting *cpp += dlen, not // cpp += dlen. char **cpp_end = cpp + dlen; rd->naptr.order = _getshort(*cpp); *cpp += sizeof(u_short); rd->naptr.preference = _getshort(*cpp); *cpp += sizeof(u_short); if (( rd->naptr.flags = expand_charstring(cpp, msg)) == NULL ) { cpp = cpp_end; break; } if (( rd->naptr.services = expand_charstring(cpp, msg)) == NULL ) { cpp = cpp_end; break; } if (( rd->naptr.regexp = expand_charstring(cpp, msg)) == NULL ) { cpp = cpp_end; break; } rd->naptr.replacement = expand_cdname(cpp, msg); } break; case T_TXT: /* Text string */ rd->txt.len = **cpp; rd->txt.next = NULL; if ((rd->txt.text = expand_charstring(cpp, msg)) == NULL ) { cpp += dlen; break; } /* * Multiple strings * add onto a linked list */ if ( rd->txt.len+1 < dlen ) { struct s_TXT *txtp; char **cpp2; int n; n = rd->txt.len+1; txtp = &(rd->txt); cpp2 = cpp; while ( n < dlen ) { if ((txtp->next = (struct s_TXT *)malloc(sizeof(struct s_TXT))) == NULL ) { cpp += (dlen - rd->txt.len); break; } txtp = txtp->next; txtp->len = **cpp2; n += txtp->len+1; txtp->next = NULL; if ((txtp->text = expand_charstring(cpp2, msg)) == NULL ) { cpp += (dlen - rd->txt.len); break; } } } break; /* * RFC 1183 Additional types */ case T_AFSDB: /* AFS Server */ rd->afsdb.subtype = _getshort(*cpp); *cpp += sizeof(u_short); rd->afsdb.hostname = expand_cdname(cpp, msg); break; case T_RP: /* Responsible Person */ rd->rp.mbox_dname = expand_cdname(cpp, msg); rd->rp.txt_dname = expand_cdname(cpp, msg); break; case T_X25: /* X25 Address */ rd->string = expand_charstring(cpp, msg); break; case T_ISDN: /* ISDN Address */ if ( **cpp == dlen ) { rd->isdn.address = expand_charstring(cpp, msg); rd->isdn.sa = NULL; } else { rd->isdn.address = expand_charstring(cpp, msg); rd->isdn.sa = expand_charstring(cpp, msg); } break; case T_RT: /* Route Through */ rd->rt.preference = _getshort(*cpp); *cpp += sizeof(u_short); rd->rt.int_host = expand_cdname(cpp, msg); break; /* * Additional Non-standard types */ case T_UINFO: /* User (finger) info */ if ((rd->string = (char *)malloc(dlen+1)) != NULL ) { memcpy((void *)rd->string, (void *)*cpp, dlen); rd->string[dlen] = '\0'; } *cpp += dlen; break; case T_UID: /* User ID */ case T_GID: /* Group ID */ rd->number = _getlong(*cpp); *cpp += sizeof(u_long); break; case T_UNSPEC: /* Unspecified info */ default: /* Unrecognised */ if ((rd->string = (char *)malloc(dlen+1)) != NULL ) memcpy((void *)rd->string, (void *)*cpp, dlen); *cpp += dlen; break; } return(ptr); }