int res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) { ns_updrec *rrecp; u_char answer[PACKETSZ]; u_char *packet; struct zonegrp *zptr, tgrp; LIST(struct zonegrp) zgrps; int nzones = 0, nscount = 0, n; union res_sockaddr_union nsaddrs[MAXNS]; packet = malloc(NS_MAXMSG); if (packet == NULL) { DPRINTF(("malloc failed")); return (0); } /* Thread all of the updates onto a list of groups. */ INIT_LIST(zgrps); memset(&tgrp, 0, sizeof (tgrp)); for (rrecp = rrecp_in; rrecp; rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) { int nscnt; /* Find the origin for it if there is one. */ tgrp.z_class = rrecp->r_class; nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class, RES_EXHAUSTIVE, tgrp.z_origin, sizeof tgrp.z_origin, tgrp.z_nsaddrs, MAXNS); if (nscnt <= 0) { DPRINTF(("res_findzonecut failed (%d)", nscnt)); goto done; } tgrp.z_nscount = nscnt; /* Find the group for it if there is one. */ for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 && tgrp.z_class == zptr->z_class) break; /* Make a group for it if there isn't one. */ if (zptr == NULL) { zptr = malloc(sizeof *zptr); if (zptr == NULL) { DPRINTF(("malloc failed")); goto done; } *zptr = tgrp; zptr->z_flags = 0; INIT_LINK(zptr, z_link); INIT_LIST(zptr->z_rrlist); APPEND(zgrps, zptr, z_link); } /* Thread this rrecp onto the right group. */ APPEND(zptr->z_rrlist, rrecp, r_glink); } for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) { /* Construct zone section and prepend it. */ rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, zptr->z_class, ns_t_soa, 0); if (rrecp == NULL) { DPRINTF(("res_mkupdrec failed")); goto done; } PREPEND(zptr->z_rrlist, rrecp, r_glink); zptr->z_flags |= ZG_F_ZONESECTADDED; /* Marshall the update message. */ n = res_nmkupdate(statp, HEAD(zptr->z_rrlist), packet, NS_MAXMSG); DPRINTF(("res_mkupdate -> %d", n)); if (n < 0) goto done; /* Temporarily replace the resolver's nameserver set. */ nscount = res_getservers(statp, nsaddrs, MAXNS); res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount); /* Send the update and remember the result. */ if (key != NULL) n = res_nsendsigned(statp, packet, n, key, answer, sizeof answer); else n = res_nsend(statp, packet, n, answer, sizeof answer); if (n < 0) { DPRINTF(("res_nsend: send error, n=%d (%s)\n", n, strerror(errno))); goto done; } if (((HEADER *)answer)->rcode == NOERROR) nzones++; /* Restore resolver's nameserver set. */ res_setservers(statp, nsaddrs, nscount); nscount = 0; } done: while (!EMPTY(zgrps)) { zptr = HEAD(zgrps); if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0) res_freeupdrec(HEAD(zptr->z_rrlist)); UNLINK(zgrps, zptr, z_link); free(zptr); } if (nscount != 0) res_setservers(statp, nsaddrs, nscount); free(packet); return (nzones); }
isc_result_t res_nupdate(res_state statp, ns_updrec *rrecp_in) { ns_updrec *rrecp; double answer[PACKETSZ / sizeof (double)]; double packet[2*PACKETSZ / sizeof (double)]; struct zonegrp *zptr, tgrp; int nscount = 0; unsigned n; unsigned rval; struct sockaddr_in nsaddrs[MAXNS]; ns_tsig_key *key; void *zcookie = 0; void *zcookp = &zcookie; isc_result_t rcode; again: /* Make sure all the updates are in the same zone, and find out what zone they are in. */ zptr = NULL; for (rrecp = rrecp_in; rrecp; rrecp = ISC_LIST_NEXT(rrecp, r_link)) { /* Find the origin for it if there is one. */ tgrp.z_class = rrecp->r_class; rcode = res_findzonecut(statp, rrecp->r_dname, tgrp.z_class, RES_EXHAUSTIVE, tgrp.z_origin, sizeof tgrp.z_origin, tgrp.z_nsaddrs, MAXNS, &tgrp.z_nscount, zcookp); if (rcode != ISC_R_SUCCESS) goto done; if (tgrp.z_nscount <= 0) { rcode = ISC_R_NOTZONE; goto done; } /* Make a group for it if there isn't one. */ if (zptr == NULL) { zptr = malloc(sizeof *zptr); if (zptr == NULL) { rcode = ISC_R_NOMEMORY; goto done; } *zptr = tgrp; zptr->z_flags = 0; ISC_LIST_INIT(zptr->z_rrlist); } else if (ns_samename(tgrp.z_origin, zptr->z_origin) == 0 || tgrp.z_class != zptr->z_class) { /* Some of the records are in different zones. */ rcode = ISC_R_CROSSZONE; goto done; } /* Thread this rrecp onto the zone group. */ ISC_LIST_APPEND(zptr->z_rrlist, rrecp, r_glink); } /* Construct zone section and prepend it. */ rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, zptr->z_class, ns_t_soa, 0); if (rrecp == NULL) { rcode = ISC_R_UNEXPECTED; goto done; } ISC_LIST_PREPEND(zptr->z_rrlist, rrecp, r_glink); zptr->z_flags |= ZG_F_ZONESECTADDED; /* Marshall the update message. */ n = sizeof packet; rcode = res_nmkupdate(statp, ISC_LIST_HEAD(zptr->z_rrlist), packet, &n); if (rcode != ISC_R_SUCCESS) goto done; /* Temporarily replace the resolver's nameserver set. */ nscount = nscopy(nsaddrs, statp->nsaddr_list, statp->nscount); statp->nscount = nsprom(statp->nsaddr_list, zptr->z_nsaddrs, zptr->z_nscount); /* Send the update and remember the result. */ key = (ns_tsig_key *)0; rcode = find_tsig_key (&key, zptr->z_origin, zcookie); if (rcode == ISC_R_SUCCESS) { rcode = res_nsendsigned(statp, packet, n, key, answer, sizeof answer, &rval); tkey_free (&key); } else if (rcode == ISC_R_NOTFOUND || rcode == ISC_R_KEY_UNKNOWN) { rcode = res_nsend(statp, packet, n, answer, sizeof answer, &rval); } if (rcode != ISC_R_SUCCESS) goto undone; rcode = ns_rcode_to_isc (((HEADER *)answer)->rcode); if (zcookie && rcode == ISC_R_BADSIG) { repudiate_zone (&zcookie); } undone: /* Restore resolver's nameserver set. */ statp->nscount = nscopy(statp->nsaddr_list, nsaddrs, nscount); nscount = 0; done: if (zptr) { if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0) res_freeupdrec(ISC_LIST_HEAD(zptr->z_rrlist)); free(zptr); } /* If the update failed because we used a cached zone and it didn't work, try it again without the cached zone. */ if (zcookp && (rcode == ISC_R_NOTZONE || rcode == ISC_R_BADSIG)) { zcookp = 0; goto again; } if (zcookie) forget_zone (&zcookie); return rcode; }
int main(int argc, char **argv) { short port = htons(NAMESERVER_PORT); short lport; /* Wierd stuff for SPARC alignment, hurts nothing else. */ union { HEADER header_; u_char packet_[PACKETSZ]; } packet_; #define header (packet_.header_) #define packet (packet_.packet_) union { HEADER u; u_char b[NS_MAXMSG]; } answer; int n; char doping[90]; char pingstr[50]; char *afile; char *addrc, *addrend, *addrbegin; time_t exectime; struct timeval tv1, tv2, start_time, end_time, query_time; char *srv; int anyflag = 0; int sticky = 0; int tmp; int qtypeSet; ns_type xfr = ns_t_invalid; int bytes_out, bytes_in; char cmd[512]; char domain[MAXDNAME]; char msg[120], **vtmp; char *args[DIG_MAXARGS]; char **ax; int once = 1, dofile = 0; /* batch -vs- interactive control */ char fileq[384]; int fp; int wait=0, delay; int envset=0, envsave=0; struct __res_state res_x, res_t; int r; struct in6_addr in6; ns_tsig_key key; char *keyfile = NULL, *keyname = NULL; const char *pingfmt = NULL; UNUSED(argc); res_ninit(&res); res.pfcode = PRF_DEF; qtypeSet = 0; memset(domain, 0, sizeof domain); gethostname(myhostname, (sizeof myhostname)); #ifdef HAVE_SA_LEN myaddress.sin_len = sizeof(struct sockaddr_in); #endif myaddress.sin_family = AF_INET; myaddress.sin_addr.s_addr = INADDR_ANY; myaddress.sin_port = 0; /*INPORT_ANY*/; #ifdef HAVE_SA_LEN myaddress6.sin6_len = sizeof(struct sockaddr_in6); #endif myaddress6.sin6_family = AF_INET6; myaddress6.sin6_addr = in6addr_any; myaddress6.sin6_port = 0; /*INPORT_ANY*/; res_x = res; /* * If LOCALDEF in environment, should point to file * containing local favourite defaults. Also look for file * DiG.env (i.e. SAVEENV) in local directory. */ if ((((afile = (char *) getenv("LOCALDEF")) != (char *) NULL) && ((fp = open(afile, O_RDONLY)) > 0)) || ((fp = open(SAVEENV, O_RDONLY)) > 0)) { read(fp, (char *)&res_x, (sizeof res_x)); close(fp); res = res_x; } /* * Check for batch-mode DiG; also pre-scan for 'help'. */ vtmp = argv; ax = args; while (*vtmp != NULL) { if (strcmp(*vtmp, "-h") == 0 || strcmp(*vtmp, "-help") == 0 || strcmp(*vtmp, "-usage") == 0 || strcmp(*vtmp, "help") == 0) { Usage(); exit(0); } if (strcmp(*vtmp, "-f") == 0) { dofile++; once=0; if ((qfp = fopen(*++vtmp, "r")) == NULL) { fflush(stdout); perror("file open"); fflush(stderr); exit(10); } } else { if (ax - args == DIG_MAXARGS) { fprintf(stderr, "dig: too many arguments\n"); exit(10); } *ax++ = *vtmp; } vtmp++; } gettimeofday(&tv1, NULL); /* * Main section: once if cmd-line query * while !EOF if batch mode */ *fileq = '\0'; while ((dofile && fgets(fileq, sizeof fileq, qfp) != NULL) || (!dofile && once--)) { if (*fileq == '\n' || *fileq == '#' || *fileq==';') { printf("%s", fileq); /* echo but otherwise ignore */ continue; /* blank lines and comments */ } /* * "Sticky" requests that before current parsing args * return to current "working" environment (X******). */ if (sticky) { printf(";; (using sticky settings)\n"); res = res_x; } /* * Concat cmd-line and file args. */ stackarg(fileq, ax); /* defaults */ queryType = ns_t_ns; queryClass = ns_c_in; xfr = ns_t_invalid; *pingstr = 0; srv = NULL; sprintf(cmd, "\n; <<>> DiG %s (libbind %d) <<>> ", VSTRING, __RES); argv = args; /* argc = ax - args; */ /* * More cmd-line options than anyone should ever have to * deal with .... */ while (*(++argv) != NULL && **argv != '\0') { if (strlen(cmd) + strlen(*argv) + 2 > sizeof (cmd)) { fprintf(stderr, "Argument too large for input buffer\n"); exit(1); } strcat(cmd, *argv); strcat(cmd, " "); if (**argv == '@') { srv = (*argv+1); continue; } if (**argv == '%') continue; if (**argv == '+') { setopt(*argv+1); continue; } if (**argv == '=') { ixfr_serial = strtoul(*argv+1, NULL, 0); continue; } if (strncmp(*argv, "-nost", 5) == 0) { sticky = 0; continue; } else if (strncmp(*argv, "-st", 3) == 0) { sticky++; continue; } else if (strncmp(*argv, "-envsa", 6) == 0) { envsave++; continue; } else if (strncmp(*argv, "-envse", 6) == 0) { envset++; continue; } if (**argv == '-') { switch (argv[0][1]) { case 'T': if (*++argv == NULL) printf("; no arg for -T?\n"); else wait = atoi(*argv); break; case 'c': if(*++argv == NULL) printf("; no arg for -c?\n"); else if ((tmp = atoi(*argv)) || *argv[0] == '0') { queryClass = tmp; } else if ((tmp = StringToClass(*argv, 0, NULL) ) != 0) { queryClass = tmp; } else { printf( "; invalid class specified\n" ); } break; case 't': if (*++argv == NULL) printf("; no arg for -t?\n"); else if ((tmp = atoi(*argv)) || *argv[0]=='0') { if (ns_t_xfr_p(tmp)) { xfr = tmp; } else { queryType = tmp; qtypeSet++; } } else if ((tmp = StringToType(*argv, 0, NULL) ) != 0) { if (ns_t_xfr_p(tmp)) { xfr = tmp; } else { queryType = tmp; qtypeSet++; } } else { printf( "; invalid type specified\n" ); } break; case 'x': if (!qtypeSet) { queryType = T_ANY; qtypeSet++; } if ((addrc = *++argv) == NULL) { printf("; no arg for -x?\n"); break; } r = inet_pton(AF_INET6, addrc, &in6); if (r > 0) { reverse6(domain, &in6); break; } addrend = addrc + strlen(addrc); if (*addrend == '.') *addrend = '\0'; *domain = '\0'; while ((addrbegin = strrchr(addrc,'.'))) { strcat(domain, addrbegin+1); strcat(domain, "."); *addrbegin = '\0'; } strcat(domain, addrc); strcat(domain, ".in-addr.arpa."); break; case 'p': if (argv[0][2] != '\0') port = htons(atoi(argv[0]+2)); else if (*++argv == NULL) printf("; no arg for -p?\n"); else port = htons(atoi(*argv)); break; case 'P': if (argv[0][2] != '\0') { strcpy(pingstr, argv[0]+2); pingfmt = "%s %s 56 3 | %s -3"; } else { strcpy(pingstr, DIG_PING); pingfmt = DIG_PINGFMT; } break; case 'n': if (argv[0][2] != '\0') res.ndots = atoi(argv[0]+2); else if (*++argv == NULL) printf("; no arg for -n?\n"); else res.ndots = atoi(*argv); break; case 'b': { char *a, *p; if (argv[0][2] != '\0') a = argv[0]+2; else if (*++argv == NULL) { printf("; no arg for -b?\n"); break; } else a = *argv; if ((p = strchr(a, ':')) != NULL) { *p++ = '\0'; lport = htons(atoi(p)); } else lport = htons(0); if (inet_pton(AF_INET6, a, &myaddress6.sin6_addr) == 1) { myaddress6.sin6_port = lport; } else if (!inet_aton(a, &myaddress.sin_addr)) { fprintf(stderr, ";; bad -b addr\n"); exit(1); } else myaddress.sin_port = lport; } break; case 'k': /* -k keydir:keyname */ if (argv[0][2] != '\0') keyfile = argv[0]+2; else if (*++argv == NULL) { printf("; no arg for -k?\n"); break; } else keyfile = *argv; keyname = strchr(keyfile, ':'); if (keyname == NULL) { fprintf(stderr, "key option argument should be keydir:keyname\n"); exit(1); } *keyname++='\0'; break; } /* switch - */ continue; } /* if '-' */ if ((tmp = StringToType(*argv, -1, NULL)) != -1) { if ((T_ANY == tmp) && anyflag++) { queryClass = C_ANY; continue; } if (ns_t_xfr_p(tmp) && (tmp == ns_t_axfr || (res.options & RES_USEVC) != 0) ) { res.pfcode = PRF_ZONE; xfr = (ns_type)tmp; } else { queryType = tmp; qtypeSet++; } } else if ((tmp = StringToClass(*argv, -1, NULL)) != -1) { queryClass = tmp; } else { memset(domain, 0, sizeof domain); sprintf(domain,"%s",*argv); } } /* while argv remains */ /* process key options */ if (keyfile) { #ifdef PARSE_KEYFILE int i, n1; char buf[BUFSIZ], *p; FILE *fp = NULL; int file_major, file_minor, alg; fp = fopen(keyfile, "r"); if (fp == NULL) { perror(keyfile); exit(1); } /* Now read the header info from the file. */ i = fread(buf, 1, BUFSIZ, fp); if (i < 5) { fclose(fp); exit(1); } fclose(fp); p = buf; n=strlen(p); /* get length of strings */ n1=strlen("Private-key-format: v"); if (n1 > n || strncmp(buf, "Private-key-format: v", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ sscanf((char *)p, "%d.%d", &file_major, &file_minor); /* should do some error checking with these someday */ while (*p++!='\n'); /* skip to end of line */ n=strlen(p); /* get length of strings */ n1=strlen("Algorithm: "); if (n1 > n || strncmp(p, "Algorithm: ", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ if (sscanf((char *)p, "%d", &alg)!=1) { fprintf(stderr, "Invalid key file format\n"); exit(1); } while (*p++!='\n'); /* skip to end of line */ n=strlen(p); /* get length of strings */ n1=strlen("Key: "); if (n1 > n || strncmp(p, "Key: ", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ pp=p; while (*pp++!='\n'); /* skip to end of line, * terminate it */ *--pp='\0'; key.data=malloc(1024*sizeof(char)); key.len=b64_pton(p, key.data, 1024); strcpy(key.name, keyname); strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); #else /* use the dst* routines to parse the key files * * This requires that both the .key and the .private * files exist in your cwd, so the keyfile parmeter * here is assumed to be a path in which the * K*.{key,private} files exist. */ DST_KEY *dst_key; char cwd[PATH_MAX+1]; if (getcwd(cwd, PATH_MAX)==NULL) { perror("unable to get current directory"); exit(1); } if (chdir(keyfile)<0) { fprintf(stderr, "unable to chdir to %s: %s\n", keyfile, strerror(errno)); exit(1); } dst_init(); dst_key = dst_read_key(keyname, 0 /* not used for priv keys */, KEY_HMAC_MD5, DST_PRIVATE); if (!dst_key) { fprintf(stderr, "dst_read_key: error reading key\n"); exit(1); } key.data=malloc(1024*sizeof(char)); dst_key_to_buffer(dst_key, key.data, 1024); key.len=dst_key->dk_key_size; strcpy(key.name, keyname); strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); if (chdir(cwd)<0) { fprintf(stderr, "unable to chdir to %s: %s\n", cwd, strerror(errno)); exit(1); } #endif } if (res.pfcode & 0x80000) printf("; pfcode: %08lx, options: %08lx\n", (unsigned long)res.pfcode, (unsigned long)res.options); /* * Current env. (after this parse) is to become the * new "working" environmnet. Used in conj. with sticky. */ if (envset) { res_x = res; envset = 0; } /* * Current env. (after this parse) is to become the * new default saved environmnet. Save in user specified * file if exists else is SAVEENV (== "DiG.env"). */ if (envsave) { afile = (char *) getenv("LOCALDEF"); if ((afile && ((fp = open(afile, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) > 0)) || ((fp = open(SAVEENV, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) > 0)) { write(fp, (char *)&res, (sizeof res)); close(fp); } envsave = 0; } if (res.pfcode & RES_PRF_CMD) printf("%s\n", cmd); anyflag = 0; /* * Find address of server to query. If not dot-notation, then * try to resolve domain-name (if so, save and turn off print * options, this domain-query is not the one we want. Restore * user options when done. * Things get a bit wierd since we need to use resolver to be * able to "put the resolver to work". */ if (srv != NULL) { int nscount = 0; union res_sockaddr_union u[MAXNS]; struct addrinfo *answer = NULL; struct addrinfo *cur = NULL; struct addrinfo hint; memset(u, 0, sizeof(u)); res_t = res; res_ninit(&res); res.pfcode = 0; res.options = RES_DEFAULT; memset(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_DGRAM; if (!getaddrinfo(srv, NULL, &hint, &answer)) { res = res_t; cur = answer; for (cur = answer; cur != NULL; cur = cur->ai_next) { if (nscount == MAXNS) break; switch (cur->ai_addr->sa_family) { case AF_INET6: u[nscount].sin6 = *(struct sockaddr_in6*)cur->ai_addr; u[nscount++].sin6.sin6_port = port; break; case AF_INET: u[nscount].sin = *(struct sockaddr_in*)cur->ai_addr; u[nscount++].sin.sin_port = port; break; } } if (nscount != 0) res_setservers(&res, u, nscount); freeaddrinfo(answer); } else { res = res_t; fflush(stdout); fprintf(stderr, "; Bad server: %s -- using default server and timer opts\n", srv); fflush(stderr); srv = NULL; } printf("; (%d server%s found)\n", res.nscount, (res.nscount==1)?"":"s"); res.id += res.retry; } if (ns_t_xfr_p(xfr)) { int i; int nscount; union res_sockaddr_union u[MAXNS]; nscount = res_getservers(&res, u, MAXNS); for (i = 0; i < nscount; i++) { int x; if (keyfile) x = printZone(xfr, domain, &u[i].sin, &key); else x = printZone(xfr, domain, &u[i].sin, NULL); if (res.pfcode & RES_PRF_STATS) { exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, p_sockun(u[i], ubuf, sizeof(ubuf))); printf(";; WHEN: %s", ctime(&exectime)); } if (!x) break; /* success */ } fflush(stdout); continue; } if (*domain && !qtypeSet) { queryType = T_A; qtypeSet++; } bytes_out = n = res_nmkquery(&res, QUERY, domain, queryClass, queryType, NULL, 0, NULL, packet, sizeof packet); if (n < 0) { fflush(stderr); printf(";; res_nmkquery: buffer too small\n\n"); fflush(stdout); continue; } if (queryType == T_IXFR) { HEADER *hp = (HEADER *) packet; u_char *cpp = packet + bytes_out; hp->nscount = htons(1+ntohs(hp->nscount)); n = dn_comp(domain, cpp, (sizeof packet) - (cpp - packet), NULL, NULL); cpp += n; PUTSHORT(T_SOA, cpp); /* type */ PUTSHORT(C_IN, cpp); /* class */ PUTLONG(0, cpp); /* ttl */ PUTSHORT(22, cpp); /* dlen */ *cpp++ = 0; /* mname */ *cpp++ = 0; /* rname */ PUTLONG(ixfr_serial, cpp); PUTLONG(0xDEAD, cpp); /* Refresh */ PUTLONG(0xBEEF, cpp); /* Retry */ PUTLONG(0xABCD, cpp); /* Expire */ PUTLONG(0x1776, cpp); /* Min TTL */ bytes_out = n = cpp - packet; }; #if defined(RES_USE_EDNS0) && defined(RES_USE_DNSSEC) if (n > 0 && (res.options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) bytes_out = n = res_nopt(&res, n, packet, sizeof(packet), 4096); #endif eecode = 0; if (res.pfcode & RES_PRF_HEAD1) fp_resstat(&res, stdout); (void) gettimeofday(&start_time, NULL); if (keyfile) n = res_nsendsigned(&res, packet, n, &key, answer.b, sizeof(answer.b)); else n = res_nsend(&res, packet, n, answer.b, sizeof(answer.b)); if ((bytes_in = n) < 0) { fflush(stdout); n = 0 - n; if (keyfile) strcpy(msg, ";; res_nsendsigned"); else strcpy(msg, ";; res_nsend"); perror(msg); fflush(stderr); if (!dofile) { if (eecode) exit(eecode); else exit(9); } } (void) gettimeofday(&end_time, NULL); if (res.pfcode & RES_PRF_STATS) { union res_sockaddr_union u[MAXNS]; (void) res_getservers(&res, u, MAXNS); query_time = difftv(start_time, end_time); printf(";; Total query time: "); prnttime(query_time); putchar('\n'); exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, p_sockun(u[RES_GETLAST(res)], ubuf, sizeof(ubuf))); printf(";; WHEN: %s", ctime(&exectime)); printf(";; MSG SIZE sent: %d rcvd: %d\n", bytes_out, bytes_in); } fflush(stdout); /* * Argh ... not particularly elegant. Should put in *real* ping code. * Would necessitate root priviledges for icmp port though! */ if (*pingstr && srv != NULL) { sprintf(doping, pingfmt, pingstr, srv, DIG_TAIL); system(doping); } putchar('\n'); /* * Fairly crude method and low overhead method of keeping two * batches started at different sites somewhat synchronized. */ gettimeofday(&tv2, NULL); delay = (int)(tv2.tv_sec - tv1.tv_sec); if (delay < wait) { sleep(wait - delay); } tv1 = tv2; } return (eecode); }