/** Resolve name and wait for the result. * This will lookup a name from the cache and return the value if available. * If there is no entry in the cache this will order a concurrent lookup of the * name and wait for the result. * @param name name to resolve * @param addr contains a pointer to the address record upon return, this record * is in the cache, so you may not free the resulting address! The address is * always of type struct sockaddr_in (IPv4) at the moment. * @param addrlen contains the length of addr in bytes upon return * @return true if resolution was successful, false otherwise */ bool NetworkNameResolver::resolve_name_blocking(const char *name, struct sockaddr **addr, socklen_t *addrlen) { if ( resolve_name(name, addr, addrlen) ) { return true; } else { struct sockaddr *_addr; socklen_t _addrlen; if ( resolver_thread->resolve_name_immediately(name, &_addr, &_addrlen) ) { name_resolved(strdup(name), _addr, _addrlen); *addr = _addr; *addrlen = _addrlen; return true; } else { return false; } } }
int main(void) { int cfd; int ifd; struct hosts hostlist[NUM_CACHE_ENTRIES]; char logmsg[160]; unsigned int hostindex = 0; unsigned int lastfree = 0; unsigned int hi = 0; int readyidx = 0; int fr = 0; int maxlogged = 0; struct rvn rvnpacket; int br; int ss = 0; fd_set sockset; struct sockaddr_un csa, isa; /* child and iptraf comm sockets */ struct sockaddr_un fromaddr; socklen_t fromlen; FILE *logfile; /* Daemonization Sequence */ #ifndef DEBUG switch (fork()) { case -1: exit(1); case 0: break; default: exit(0); } setsid(); int i = chdir("/"); (void) i; #endif signal(SIGCHLD, childreap); logfile = fopen(RVNDLOGFILE, "a"); if (logfile == NULL) logfile = fopen("/dev/null", "a"); writervnlog(logfile, "******** rvnamed started ********"); writervnlog(logfile, "Clearing socket names"); /* * Get rid of any residue socket names in case of a previous * abormal termination of rvnamed. */ unlink(CHILDSOCKNAME); unlink(IPTSOCKNAME); writervnlog(logfile, "Opening sockets"); csa.sun_family = AF_UNIX; strcpy(csa.sun_path, CHILDSOCKNAME); isa.sun_family = AF_UNIX; strcpy(isa.sun_path, IPTSOCKNAME); cfd = socket(PF_UNIX, SOCK_DGRAM, 0); if (cfd < 0) { writervnlog(logfile, "Unable to open child communication socket, aborting"); exit(1); } if (bind (cfd, (struct sockaddr *) &csa, sizeof(csa.sun_family) + strlen(csa.sun_path)) < 0) { writervnlog(logfile, "Error binding child communication socket, aborting"); exit(1); } ifd = socket(PF_UNIX, SOCK_DGRAM, 0); if (ifd < 0) { writervnlog(logfile, "Unable to open client communication socket, aborting"); exit(1); } if (bind (ifd, (struct sockaddr *) &isa, sizeof(isa.sun_family) + strlen(isa.sun_path)) < 0) { writervnlog(logfile, "Error binding client communication socket, aborting"); exit(1); } while (1) { FD_ZERO(&sockset); FD_SET(cfd, &sockset); FD_SET(ifd, &sockset); do { ss = select(ifd + 1, &sockset, NULL, NULL, NULL); } while ((ss < 0) && (errno != ENOMEM)); if (errno == ENOMEM) { writervnlog(logfile, "Fatal error: no memory for descriptor monitoring"); close(ifd); close(cfd); fclose(logfile); exit(1); } /* * Code to process packets coming from the forked child. */ if (FD_ISSET(cfd, &sockset)) { fromlen = sizeof(fromaddr.sun_family) + strlen(fromaddr.sun_path); br = recvfrom(cfd, &rvnpacket, sizeof(struct rvn), 0, (struct sockaddr *) &fromaddr, &fromlen); if (br > 0) { hi = 0; while (hi <= lastfree) { if ((hostlist[hi].addr == rvnpacket.saddr.s_addr) && !memcmp(rvnpacket.s6addr.s6_addr, hostlist[hi].addr6, sizeof(hostlist[hi]. addr6))) break; hi++; } if (hi == lastfree) { /* Address not in cache */ memset(&(hostlist[hi]), 0, sizeof(struct hosts)); hi = hostindex; hostindex++; if (hostindex == NUM_CACHE_ENTRIES) hostindex = 0; hostlist[hi].addr = rvnpacket.saddr.s_addr; memcpy(hostlist[hi].addr6, rvnpacket.s6addr.s6_addr, sizeof(hostlist[hi].addr6)); } strncpy(hostlist[hi].fqdn, rvnpacket.fqdn, 44); hostlist[hi].ready = RESOLVED; } } /* * This code section processes packets received from the IPTraf * program. */ if (FD_ISSET(ifd, &sockset)) { fromlen = sizeof(struct sockaddr_un); br = recvfrom(ifd, &rvnpacket, sizeof(struct rvn), 0, (struct sockaddr *) &fromaddr, &fromlen); if (br > 0) { switch (rvnpacket.type) { case RVN_HELLO: sendto(ifd, &rvnpacket, sizeof(struct rvn), 0, (struct sockaddr *) &fromaddr, sizeof(fromaddr.sun_family) + strlen(fromaddr.sun_path)); break; case RVN_QUIT: #ifndef DEBUG writervnlog(logfile, "Received quit instruction"); writervnlog(logfile, "Closing sockets"); close(ifd); close(cfd); writervnlog(logfile, "Clearing socket names"); unlink(IPTSOCKNAME); unlink(CHILDSOCKNAME); sprintf(logmsg, "rvnamed terminating: max processes spawned: %d", max_fork_count); writervnlog(logfile, logmsg); writervnlog(logfile, "******** rvnamed terminated ********"); fclose(logfile); exit(0); #endif case RVN_REQUEST: readyidx = name_resolved(&rvnpacket, hostlist, lastfree); if (readyidx >= 0) { rvnpacket.type = RVN_REPLY; memset(rvnpacket.fqdn, 0, 45); strncpy(rvnpacket.fqdn, hostlist[readyidx].fqdn, 44); rvnpacket.ready = RESOLVED; br = sendto(ifd, &rvnpacket, sizeof(struct rvn), 0, (struct sockaddr *) &fromaddr, sizeof(fromaddr. sun_family) + strlen(fromaddr. sun_path)); } else { /* * Add this IP address to the cache if this is a * new one. */ if (addrstat (&rvnpacket, hostlist, lastfree) == NOTRESOLVED) { fflush(logfile); /* flush all data prior */ /* to fork() */ if (fork_count <= MAX_RVNAMED_CHILDREN) { /* * If we can still fork(), we add the data * to the cache array, but we don't update * the indexes until after the fork() * succeeds. If the fork() fails, we'll * just reuse this slot for the next query. * * This is so that if the fork() fails due * to a temporary condition, rvnamed won't * think it's RESOLVING while there isn't * any actual child doing the resolution * before the entry expires. * * However, we'll still tell IPTraf that the * address is RESOLVING. * */ hostlist [hostindex]. addr = rvnpacket. saddr. s_addr; memcpy(hostlist [hostindex]. addr6, rvnpacket. s6addr. s6_addr, sizeof (hostlist [hostindex]. addr6)); hostlist [hostindex]. ready = RESOLVING; maxlogged = 0; fr = fork(); } else { fr = -1; if (!maxlogged) writervnlog (logfile, "Maximum child process limit reached"); maxlogged = 1; } switch (fr) { case 0: /* spawned child */ fclose(logfile); /* no logging in child */ close(ifd); /* no comm with client */ /* * Set auto-terminate timeout */ signal(SIGALRM, auto_terminate); alarm(300); process_rvn_packet (&rvnpacket); exit(0); case -1: if (!maxlogged) writervnlog (logfile, "Error on fork, returning IP address"); break; default: /* parent */ if (fork_count > max_fork_count) max_fork_count = fork_count; /* * Increase cache indexes only if fork() * succeeded, otherwise the previously * allocated slots will be used for the * next query. */ hostindex++; if (hostindex == NUM_CACHE_ENTRIES) hostindex = 0; if (lastfree < NUM_CACHE_ENTRIES) lastfree++; fork_count++; break; } } rvnpacket.type = RVN_REPLY; memset(rvnpacket.fqdn, 0, 45); if (rvnpacket.saddr.s_addr != 0) strcpy(rvnpacket.fqdn, inet_ntoa (rvnpacket. saddr)); else inet_ntop(AF_INET6, &rvnpacket. s6addr, rvnpacket. fqdn, sizeof (rvnpacket. fqdn)); rvnpacket.ready = RESOLVING; br = sendto(ifd, &rvnpacket, sizeof(struct rvn), 0, (struct sockaddr *) &fromaddr, sizeof(fromaddr. sun_family) + strlen(fromaddr. sun_path)); } } } } /* end block for packets from IPTraf */ } }