📄 ch13.check_soa.c
字号:
nsList[nsNum]); continue; /* nsNum for-loop */ } /* * Now get ready for the real fun. host contains IP * addresses for the name server we're testing. * Store the first address for host in the _res * structure. Soon, we'll look up the SOA record... */ (void) memcpy((void *)&_res.nsaddr_list[0].sin_addr, (void *)host->h_addr_list[0], (size_t)host->h_length); _res.nscount = 1; /* * Turn off recursion. We don't want the name server * querying another server for the SOA record; this name * server ought to be authoritative for this data. */ _res.options &= ~RES_RECURSE; /* * Reduce the number of retries. We may be checking * several name servers, so we don't want to wait too * long for any one server. With two retries and only * one address to query, we'll wait at most 15 seconds. */ _res.retry = 2; /* * We want to see the response code in the next * response, so we must make the query packet and * send it ourselves instead of having res_query() * do it for us. If res_query() returned -1, there * might not be a response to look at. * * There is no need to check for res_mkquery() * returning -1. If the compression was going to * fail, it would have failed when we called * res_query() earlier with this domain name. */ queryLen = res_mkquery( QUERY, /* regular query */ domain, /* the domain to look up */ C_IN, /* Internet type */ T_SOA, /* Look up an SOA record */ (char *)NULL, /* always NULL */ 0, /* length of NULL */ (struct rrec *)NULL, /* always NULL */ (char *)&query, /* buffer for the query */ sizeof(query)); /* size of the buffer */ /* * Send the query packet. If there is no name server * running on the target host, res_send() returns -1 * and errno is ECONNREFUSED. First, clear out errno. */ errno = 0; if((responseLen = res_send((char *)&query, /* the query */ queryLen, /* true length*/ (char *)&response, /*buffer */ sizeof(response))) /*buf size*/ < 0){ /* error */ if(errno == ECONNREFUSED) { /* no server on the host */ (void) fprintf(stderr, "There is no name server running on %s\n", nsList[nsNum]); } else { /* anything else: no response */ (void) fprintf(stderr, "There was no response from %s\n", nsList[nsNum]); } continue; /* nsNum for-loop */ } /* * Set up the pointers to parse the response. * We set up two pointers: one to the end of the message * (so we can test for overruns) and one to the question * section (which we'll move as we parse the response). */ endOfMsg = response.buf + responseLen; cp = response.buf + sizeof(HEADER); /* * If the response reports an error, issue a message * and proceed to the next server in the list. */ if(response.hdr.rcode != NOERROR){ returnCodeError((int)response.hdr.rcode, nsList[nsNum]); continue; /* nsNum for-loop */ } /* * Did we receive an authoritative response? Check the * authoritative answer bit. If the server isn't * authoritative, report it, and go on to the next server. */ if(!response.hdr.aa){ (void) fprintf(stderr, "%s is not authoritative for %s\n", nsList[nsNum], domain); continue; /* nsNum for-loop */ } /* * The response should only contain one answer; if more, * report the error, and proceed to the next server. */ if(ntohs(response.hdr.ancount) != 1){ (void) fprintf(stderr, "%s: expected 1 answer, got %d\n", nsList[nsNum], ntohs(response.hdr.ancount)); continue; /* nsNum for-loop */ } /* * Skip the question section (we know what we asked, * don't we?). cp now points to the answer section. */ cp += skipName(cp, endOfMsg) + QFIXEDSZ; /* * cp is now pointing at a resource record in the answer * section. Skip to the data portion of this record; * in the process, extract the type, class, etc. */ cp += skipToData(cp, &type, &class, &ttl, &dlen, endOfMsg); /* * We asked for an SOA record; if we got something else, * report the error and proceed to the next server. */ if (type != T_SOA) { (void) fprintf(stderr, "%s: expected answer type %d, got %d\n", nsList[nsNum], T_SOA, type); continue; /* nsNum for-loop */ } /* * Skip the SOA origin and mail address, which we don't * care about. Both are standard "compressed names." */ cp += skipName(cp, endOfMsg); cp += skipName(cp, endOfMsg); /* cp now points to the serial number; print it. */ (void) printf("%s has serial number %d\n", nsList[nsNum], _getlong(cp)); } /* end of nsNum for-loop */}/**************************************************************** * skipName -- This routine skips over a domain name. If the * * domain name expansion fails, it reports an error and * * exits. dn_skipname() is probably not on your manual * * page; it is similar to dn_expand() except that it just * * skips over the name. dn_skipname() is in res_comp.c if * * you need to find it. * ****************************************************************/intskipName(cp, endOfMsg)u_char *cp;u_char *endOfMsg;{ int n; if((n = dn_skipname(cp, endOfMsg)) < 0){ (void) fprintf(stderr, "dn_skipname failed\n"); exit(1); } return(n);}/**************************************************************** * skipToData -- This routine advances the cp pointer to the * * start of the resource record data portion. On the way, * * it fills in the type, class, ttl, and data length * ****************************************************************/intskipToData(cp, type, class, ttl, dlen, endOfMsg)u_char *cp;u_short *type;u_short *class;u_long *ttl;u_short *dlen;u_char *endOfMsg;{ u_char *tmp_cp = cp; /* temporary version of cp */ /* Skip the domain name; it matches the name we looked up */ tmp_cp += skipName(tmp_cp, endOfMsg); /* * Grab the type, class, and ttl. The routines called * _getshort() and _getlong() are also resolver routines * you may not find in a manual page. They are in * res_comp.c if you want to see them. */ *type = _getshort(tmp_cp); tmp_cp += sizeof(u_short); *class = _getshort(tmp_cp); tmp_cp += sizeof(u_short); *ttl = _getlong(tmp_cp); tmp_cp += sizeof(u_long); *dlen = _getshort(tmp_cp); tmp_cp += sizeof(u_short); return(tmp_cp - cp);}/**************************************************************** * nsError -- Print an error message from h_errno for a failure * * looking up NS records. res_query() converts the DNS * * packet return code to a smaller list of errors and * * places the error value in h_errno. There is a routine * * called herror() for printing out strings from h_errno * * like perror() does for errno. Unfortunately, the * * herror() messages assume you are looking up address * * records for hosts. In this program, we are looking up * * NS records for domains, so we need our own list of error * * strings. * ****************************************************************/voidnsError(error, domain)int error;char *domain;{ switch(error){ case HOST_NOT_FOUND: (void) fprintf(stderr, "Unknown domain: %s\n", domain); break; case NO_DATA: (void) fprintf(stderr, "No NS records for %s\n", domain); break; case TRY_AGAIN: (void) fprintf(stderr, "No response for NS query\n"); break; default: (void) fprintf(stderr, "Unexpected error\n"); break; }}/**************************************************************** * returnCodeError -- print out an error message from a DNS * * response return code. * ****************************************************************/voidreturnCodeError(rcode, nameserver)int rcode;char *nameserver;{ (void) fprintf(stderr, "%s: ", nameserver); switch(rcode){ case FORMERR: (void) fprintf(stderr, "FORMERR response\n"); break; case SERVFAIL: (void) fprintf(stderr, "SERVFAIL response\n"); break; case NXDOMAIN: (void) fprintf(stderr, "NXDOMAIN response\n"); break; case NOTIMP: (void) fprintf(stderr, "NOTIMP response\n"); break; case REFUSED: (void) fprintf(stderr, "REFUSED response\n"); break; default: (void) fprintf(stderr, "unexpected return code\n"); break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -