📄 ch13.check_soa.c
字号:
/**************************************************************** * check_soa -- Retrieve the SOA record from each name server * * for a given domain and print out the serial number. * * * * usage: check_soa domain * * * * The following errors are reported: * * o There is no address for a server. * * o There is no server running on this host. * * o There was no response from a server. * * o The server is not authoritative for the domain. * * o The response had an error response code. * * o The response had more than one answer. * * o The response answer did not contain an SOA record. * * o The expansion of a compressed domain name failed. * ****************************************************************//* Various header files */#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <arpa/inet.h>#include <arpa/nameser.h>#include <resolv.h>#include <string.h>/* Error variables */extern int h_errno; /* for resolver errors */extern int errno; /* general system errors *//* Our own routines; code included later in this chapter */void nsError(); /* report resolver errors */void findNameServers(); /* find a domain's name servers */void queryNameServers(); /* grab SOA records from servers */void returnCodeError(); /* report response packet errors */int skipToData(); /* skip to the resource record data */int skipName(); /* skip a compressed name *//* Maximum number of name servers we will check */#define NSLIMIT 20main(argc, argv)int argc;char *argv[];{ char *nsList[NSLIMIT]; /* list of name servers */ int nsNum = 0; /* number of name servers in list */ /* sanity check: one (and only one) argument? */ if(argc != 2){ (void) fprintf(stderr, "usage: %s domain\n", argv[0]); exit(1); } (void) res_init(); /* * Find the name servers for the domain. * The name servers are written into nsList. */ findNameServers(argv[1], nsList, &nsNum); /* * Query each name server for the domain's SOA record. * The name servers are read from nsList. */ queryNameServers(argv[1], nsList, nsNum); exit(0);}/**************************************************************** * findNameServers -- find all of the name servers for the * * given domain and store their names in nsList. nsNum is * * the number of servers in the nsList array. * ****************************************************************/voidfindNameServers(domain, nsList, nsNum)char *domain;char *nsList[];int *nsNum;{ union { HEADER hdr; /* defined in resolv.h */ u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */ } response; /* response buffers */ int responseLen; /* buffer length */ u_char *cp; /* character pointer to parse DNS packet */ u_char *endOfMsg; /* need to know the end of the message */ u_short class; /* classes defined in arpa/nameser.h */ u_short type; /* types defined in arpa/nameser.h */ u_long ttl; /* resource record time to live */ u_short dlen; /* size of resource record data */ int i, count, dup; /* misc variables */ /* * Look up the NS records for the given domain name. * We expect the domain to be a fully qualified name, so * we use res_query(). If we wanted the resolver search * algorithm, we would have used res_search() instead. */ if((responseLen = res_query(domain, /* the domain we care about */ C_IN, /* Internet class records */ T_NS, /* Look up name server records*/ (u_char *)&response, /*response buffer*/ sizeof(response))) /*buffer size */ < 0){ /*If negative */ nsError(h_errno, domain); /* report the error */ exit(1); /* and quit */ } /* * Keep track of the end of the message so we don't * pass it while parsing the response. responseLen is * the value returned by res_query. */ endOfMsg = response.buf + responseLen; /* * Set a pointer to the start of the question section, * which begins immediately AFTER the header. */ cp = response.buf + sizeof(HEADER); /* * Skip over the whole question section. The question * section is comprised of a name, a type, and a class. * QFIXEDSZ (defined in arpa/nameser.h) is the size of * the type and class portions, which is fixed. Therefore, * we can skip the question section by skipping the * name (at the beginning) and then advancing QFIXEDSZ. * After this calculation, cp points to the start of the * answer section, which is a list of NS records. */ cp += skipName(cp, endOfMsg) + QFIXEDSZ; /* * Create a list of name servers from the response. * NS records may be in the answer section and/or in the * authority section depending on the DNS implementation. * Walk through both. The name server addresses may be in * the additional records section, but we will ignore them * since it is much easier to call gethostbyname() later * than to parse and store the addresses here. */ count = ntohs(response.hdr.ancount) + ntohs(response.hdr.nscount); while ( (--count >= 0) /* still more records */ && (cp < endOfMsg) /* still inside the packet*/ && (*nsNum < NSLIMIT)) { /* still under our limit */ /* Skip to the data portion of the resource record */ cp += skipToData(cp, &type, &class, &ttl, &dlen, endOfMsg); if (type == T_NS) { /* * Allocate storage for the name. Like any good * programmer should, we test malloc's return value, * and quit if it fails. */ nsList[*nsNum] = (char *) malloc (MAXDNAME); if(nsList[*nsNum] == NULL){ (void) fprintf(stderr, "malloc failed\n"); exit(1); } /* Expand the name server's name */ if (dn_expand(response.buf, /* Start of the packet */ endOfMsg, /* End of the packet */ cp, /* Position in the packet*/ (u_char *)nsList[*nsNum], /* Result */ MAXDNAME) /* size of nsList buffer */ < 0) { /* Negative: error */ (void) fprintf(stderr, "dn_expand failed\n"); exit(1); } /* * Check the name we've just unpacked and add it to * the list of servers if it is not a duplicate. * If it is a duplicate, just ignore it. */ for(i = 0, dup=0; (i < *nsNum) && !dup; i++) dup = !strcasecmp(nsList[i], nsList[*nsNum]); if(dup) free(nsList[*nsNum]); else (*nsNum)++; } /* Advance the pointer over the resource record data */ cp += dlen; } /* end of while */}/**************************************************************** * queryNameServers -- Query each of the name servers in nsList * * for the SOA record of the given domain. Report any * * errors encountered. (e.g., a name server not running or * * the response not being an authoritative response.) If * * there are no errors, print out the serial number for the * * domain. * ****************************************************************/voidqueryNameServers(domain, nsList, nsNum)char *domain;char *nsList[];int nsNum;{ union { HEADER hdr; /* defined in resolv.h */ u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */ } query, response; /* query and response buffers */ int responseLen, queryLen; /* buffer lengths */ u_char *cp; /* character pointer to parse DNS packet */ u_char *endOfMsg; /* need to know the end of the message */ u_short class; /* classes defined in arpa/nameser.h */ u_short type; /* types defined in arpa/nameser.h */ u_long ttl; /* resource record time to live */ u_short dlen; /* size of resource record data */ struct in_addr saveNsAddr[MAXNS]; /* addrs saved from _res */ int nsCount; /* count of addresses saved from _res */ struct hostent *host; /* structure for looking up ns addr */ int i; /* counter variable */ /* * Save the _res name server list since * we will need to restore it later. */ nsCount = _res.nscount; for(i = 0; i < nsCount; i++) saveNsAddr[i] = _res.nsaddr_list[i].sin_addr; /* * Turn off the search algorithm and turn off appending * the default domain before we call gethostbyname(); the * name server names will be fully qualified. */ _res.options &= ~(RES_DNSRCH | RES_DEFNAMES); /* * Query each name server for an SOA record. */ for(nsNum-- ; nsNum >= 0; nsNum--){ /* * First, we have to get the IP address of every server. * So far, all we have are names. We use gethostbyname * to get the addresses, rather than anything fancy. * But first, we have to restore certain values in _res * because _res affects gethostbyname(). (We altered * _res in the previous iteration through the loop.) * * We can't just call res_init() again to restore * these values since some of the _res fields are * initialized when the variable is declared, not when * res_init() is called. */ _res.options |= RES_RECURSE; /* recursion on (default) */ _res.retry = 4; /* 4 retries (default) */ _res.nscount = nsCount; /* original name servers */ for(i = 0; i < nsCount; i++) _res.nsaddr_list[i].sin_addr = saveNsAddr[i]; /* Look up the name server's address */ host = gethostbyname(nsList[nsNum]); if (host == NULL) { (void) fprintf(stderr,"There is no address for %s\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -