diff --git a/ban2fail.c b/ban2fail.c index 2353fb8..0c071b4 100644 --- a/ban2fail.c +++ b/ban2fail.c @@ -88,7 +88,7 @@ struct Global G= { .version= { .major= 0, .minor= 12, - .patch= 1 + .patch= 2 }, .bitTuples.flags= GlobalFlagBitTuples @@ -430,7 +430,7 @@ main(int argc, char **argv) int rc= PDNS_lookup(S.lePtrArr, nItems, DFLT_DNS_PAUSE_SEC*1000); assert(-1 != rc); - ez_fprintf(G.listing_fh, "\tCompleted %d of %u lookups\n", rc, nItems); + ez_fprintf(G.listing_fh, "\t==> Completed %d of %u lookups\n", rc, nItems); } /* Process each LOGENTRY item */ @@ -467,16 +467,25 @@ main(int argc, char **argv) /* Print out only for list option */ if(G.flags & GLB_LIST_ADDR_FLG) { - const static char *dns_fmt= "%-15s\t%5u/%-4d offenses %s (%s) %s\n", +// const static char *dns_fmt= "%-15s\t%5u/%-4d offenses %s (%s) %s%s %d\n", + const static char *dns_fmt= "%-15s\t%5u/%-4d offenses %s (%s) %s%s\n", *fmt= "%-15s\t%5u/%-4d offenses %s (%s)\n"; - ez_fprintf(G.listing_fh, e->dnsName ? dns_fmt : fmt + const char *failStat= ""; + if(e->dns.flags & PDNS_FWD_FAIL_FLG) + failStat= " ~"; + if(e->dns.flags & PDNS_FWD_NONE_FLG) + failStat= " *"; + + ez_fprintf(G.listing_fh, e->dns.name ? dns_fmt : fmt , e->addr , e->count , nAllowed , e->cntry[0] ? e->cntry : "--" , bits2str(flags, BlockBitTuples) - , e->dnsName + , e->dns.name + , failStat + , e->dns.getaddrinfo_rtn ); } diff --git a/ban2fail.h b/ban2fail.h index e89d2f8..0dee519 100644 --- a/ban2fail.h +++ b/ban2fail.h @@ -40,7 +40,11 @@ #define BUCKET_DEPTH_HINT 10 /* How long to wait for reverse DNS lookups before bailing out */ -#define DFLT_DNS_PAUSE_SEC 60 +#ifdef DEBUG +# define DFLT_DNS_PAUSE_SEC 10 +#else +# define DFLT_DNS_PAUSE_SEC 60 +#endif /* Where to find stuff */ #define CONFIGFILE "/etc/ban2fail/ban2fail.cfg" diff --git a/es.c b/es.c index 62ba70f..abf922e 100644 --- a/es.c +++ b/es.c @@ -21,7 +21,11 @@ enum ES_type { #define NUMSIGS 30 -#define VSIG_QUEUE_MAX 100 +/* NOTE: if this queue becomes full, it + * can wreak havok on your mutlithreading + * logic! + */ +#define VSIG_QUEUE_MAX 1000 /**************************************************** * We get one of these anonymous structs per-process. @@ -852,6 +856,9 @@ ES_spawn_thread_sched( /* Spawn the new thread */ memset(&tid, 0, sizeof(tid)); + /* JDR Sat 30 Nov 2019 10:39:04 AM EST + * it appears that this fails at 300 threads. + */ rtn = pthread_create (&tid, &attr, user_main, arg); if(rtn) { sys_eprintf("ERROR: pthread_create()"); @@ -965,11 +972,7 @@ ES_VSignal (pthread_t tid, int signum) assert(tid == ts->tid); /* Place virtual signal in message queue */ - int rc= MSGQUEUE_submitMsg(&ts->vsig.mq, &signum); - if(rc) { - rtn= EOF; - goto abort; - } + ez_MSGQUEUE_submitMsg(&ts->vsig.mq, &signum); /* And finally tell the target thread to check it's message queue */ if(pthread_kill(tid, SIGUSR2)) { diff --git a/ez_libc.c b/ez_libc.c index 6033d7a..352ce45 100644 --- a/ez_libc.c +++ b/ez_libc.c @@ -407,9 +407,8 @@ int _ez_getaddrinfo( case 0: case EAI_AGAIN: case EAI_FAIL: -#ifdef EAI_NODATA case EAI_NODATA: -#endif + case EAI_NONAME: return rtn; case EAI_SYSTEM: diff --git a/logEntry.c b/logEntry.c index e1e6fd0..f87d554 100644 --- a/logEntry.c +++ b/logEntry.c @@ -94,11 +94,11 @@ LOGENTRY_destructor(LOGENTRY *self) * Free resources. */ { - /* Sometimes this is assigned a static string, - * so just let it leak. - */ -// if(self->dnsName) -// free(self->dnsName); + /* Sometimes this is assigned a static string */ + if(self->dns.flags & PDNS_REV_DNS_FLG && self->dns.name) + { + free(self->dns.name); + } return self; } diff --git a/logEntry.h b/logEntry.h index bcfea08..50ff181 100644 --- a/logEntry.h +++ b/logEntry.h @@ -23,6 +23,7 @@ #include #include "map.h" +#include "pdns.h" /* One of these for each offense found in a log file */ typedef struct _LOGENTRY { @@ -30,7 +31,14 @@ typedef struct _LOGENTRY { char addr[46], cntry[3]; unsigned count; - char *dnsName; + + /* This data populated by PDNS_lookup() */ + struct { + enum PDNS_flags flags; + char *name; + int getaddrinfo_rtn; + } dns; + } LOGENTRY; #ifdef __cplusplus diff --git a/msgqueue.c b/msgqueue.c index 9e8148e..1ac117b 100644 --- a/msgqueue.c +++ b/msgqueue.c @@ -75,7 +75,7 @@ MSGQUEUE_submitMsg (MSGQUEUE * self, const void *msgBuf) eprintf("WARNING: %p queue full.", self); #endif rtn = EOF; - goto done; + goto abort; } /* If this is not the first item to be added */ @@ -84,9 +84,9 @@ MSGQUEUE_submitMsg (MSGQUEUE * self, const void *msgBuf) memcpy (self->buff_ptr + self->tail * self->msgSize, msgBuf, self->msgSize); - self->numItems++; + ++self->numItems; -done: +abort: if (pthread_mutex_unlock (&self->mtx)) assert (0); return rtn; @@ -105,7 +105,7 @@ MSGQUEUE_extractMsg (MSGQUEUE * self, void *msgBuf) if (!self->numItems) { rtn = EOF; - goto done; + goto abort; } self->numItems--; @@ -114,7 +114,7 @@ MSGQUEUE_extractMsg (MSGQUEUE * self, void *msgBuf) if (self->numItems) self->head = (self->head + 1) % self->maxItems; -done: +abort: if (pthread_mutex_unlock (&self->mtx)) assert (0); return rtn; @@ -139,19 +139,36 @@ MSGQUEUE_checkQueue (MSGQUEUE * self, assert (0); if (!self->numItems) - goto done; + goto abort; for (i = 0, ptr = self->buff_ptr + self->head * self->msgSize; i < self->numItems; - i++, ptr = + ++i, ptr = self->buff_ptr + ((self->head + i) % self->maxItems) * self->msgSize) { if ((rtn = (*check) (ptr, arg))) break; } -done: +abort: if (pthread_mutex_unlock (&self->mtx)) assert (0); return rtn; } + +/************************************************************/ +int _ez_MSGQUEUE_submitMsg( + const char *fileName, + int lineNo, + const char *funcName, + MSGQUEUE *self, + const void *msgBuf + ) +{ + int rtn= MSGQUEUE_submitMsg (self, msgBuf); + + if(!rtn) return 0; + + _eprintf(fileName, lineNo, funcName, "MSGQUEUE_submitMsg() failed"); + abort(); +} diff --git a/msgqueue.h b/msgqueue.h index 69d9265..621b1fb 100644 --- a/msgqueue.h +++ b/msgqueue.h @@ -22,7 +22,7 @@ #include -typedef struct +typedef struct _MSGQUEUE /******************************* * Necessary info for circular message * ring. @@ -99,9 +99,23 @@ MSGQUEUE_submitMsg ( * * Returns: 0 for success, non-zero otherwise. */ +#define ez_MSGQUEUE_submitMsg(self, msgBuf) \ + _ez_MSGQUEUE_submitMsg(__FILE__, __LINE__, __FUNCTION__, self, msgBuf) +int _ez_MSGQUEUE_submitMsg( + const char *fileName, + int lineNo, + const char *funcName, + MSGQUEUE *self, + const void *msgBuf + ); + #define MSGQUEUE_submitTypedMsg(self, msg) \ MSGQUEUE_submitMsg(self, &(msg)) +#define ez_MSGQUEUE_submitTypedMsg(self, msg) \ + ez_MSGQUEUE_submitMsg(self, &(msg)) + + int MSGQUEUE_extractMsg ( MSGQUEUE *self, diff --git a/pdns.c b/pdns.c index 86e1546..46d7b24 100644 --- a/pdns.c +++ b/pdns.c @@ -17,13 +17,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -/* - * JDR Sat 30 Nov 2019 08:27:23 AM EST - * Performs DNS reverse lookups in parallel. Having to use a bunch of threads - * to overcome serialization inherent in a blocking call is a travesty, but I - * couldn't find a non-blocking version of getnameinfo(). - */ - +#define _GNU_SOURCE #include #include #include @@ -35,21 +29,37 @@ #include "util.h" enum vsignals { - /* All vsigs before this are used to indicate child ready to join */ + /* All vsigs before this are used to indicate worker ready to join */ EXIT_VSIG= PDNS_MAX_THREADS, CHECK_INBOX_VSIG }; +enum lookupType { + FWD_LOOKUP, + REV_LOOKUP +}; + +/* Messages in the mgr inbox look like this */ +struct mgrMsg { + LOGENTRY *e; + unsigned worker_ndx; +}; + +/* Messages in the worker inbox look like this */ +struct workerMsg { + LOGENTRY *e; +}; + /*============================================================*/ /*=========== Forward declarations ===========================*/ /*============================================================*/ -static int check_inbox_f(void *data, int signo); -static int child_check_inbox_f(void *vp_ndx, int signo); -static void* child_main (void *data); -static int child_exit_f(void *data, int signo); +static int mgr_check_inbox_f(void *data, int signo); +static int worker_check_inbox_f(void *vp_ndx, int signo); +static void* worker_main (void *data); +static int worker_exit_f(void *data, int signo); static int join_f(void *data, int signo); -static void stop_remaining_children(void); +static void stop_remaining_workers(void); static int timeout_f(void *data); static int shutdown_f(void *data); static unsigned nThreads_joined(void); @@ -60,7 +70,8 @@ static unsigned nThreads_joined(void); static struct { enum { - EXIT_FLG= 1<<0 + EXIT_FLG= 1<<0, + ORPHAN_FLG= 1<<1 } flags; int64_t start_ms; @@ -73,21 +84,19 @@ static struct { pthread_t tid; MSGQUEUE inbox; LOGENTRY **lePtrArr; - unsigned ndx, + unsigned processedNdx, nThreads, nItems; - unsigned nCompleted; - - /* One of these for each child thread */ - struct child { + /* One of these for each worker thread */ + struct worker { int is_joined; pthread_t tid; MSGQUEUE inbox; - } childArr[PDNS_MAX_THREADS]; + } workerArr[PDNS_MAX_THREADS]; } S; @@ -103,7 +112,7 @@ PDNS_lookup(LOGENTRY *lePtrArr[], unsigned nItems, unsigned timeout_ms) { int rtn= -1; - /* Check for nothing-to-do case */ + /* Check for trivial case */ if(!nItems) return 0; @@ -114,7 +123,7 @@ PDNS_lookup(LOGENTRY *lePtrArr[], unsigned nItems, unsigned timeout_ms) S.tid= pthread_self(); /* Prepare our inbox */ - MSGQUEUE_constructor(&S.inbox, sizeof(unsigned), PDNS_INBOX_SZ); + MSGQUEUE_constructor(&S.inbox, sizeof(struct mgrMsg), PDNS_MGR_INBOX_SZ); /* Stash this where it's easy to get to */ S.nItems= nItems; @@ -124,36 +133,35 @@ PDNS_lookup(LOGENTRY *lePtrArr[], unsigned nItems, unsigned timeout_ms) /* Register a countdown timer to know when to stop */ S.timeoutKey= ez_ES_registerTimer(timeout_ms, 0, timeout_f, NULL); /* Check inbox on CHECK_INBOX_VSIG */ - S.inboxKey= ez_ES_registerVSignal(CHECK_INBOX_VSIG, check_inbox_f, NULL); + S.inboxKey= ez_ES_registerVSignal(CHECK_INBOX_VSIG, mgr_check_inbox_f, NULL); - /* Start child threads */ + /* Start worker threads */ for(unsigned i= 0; i < S.nThreads; ++i) { - struct child *ch= S.childArr + i; + struct worker *wrk= S.workerArr + i; /* Register the join handler on vsig= array index */ S.joinKeyArr[i]= ez_ES_registerVSignal(i, join_f, NULL); - /* Pass the child's array index in to child_main() */ - ch->tid= ES_spawn_thread(child_main, (void*)(long unsigned)i); + /* Pass the worker's array index in to worker_main() */ + wrk->tid= ES_spawn_thread(worker_main, (void*)(long unsigned)i); } - /* Give child threads something to do */ - for(; S.ndx < S.nThreads; ++S.ndx) { + /* Give worker threads something to do */ + for(; S.processedNdx < S.nThreads; ++S.processedNdx) { - struct child *ch= S.childArr + S.ndx; + struct worker *wrk= S.workerArr + S.processedNdx; + struct workerMsg worker_msg= {.e= S.lePtrArr[S.processedNdx]}; - /* Give the child something to do */ - int rc= MSGQUEUE_submitTypedMsg(&ch->inbox, S.lePtrArr[S.ndx]); - assert(0 == rc); - /* Prompt child to check inbox */ - ES_VSignal(ch->tid, CHECK_INBOX_VSIG); + /* Give the worker something to do */ + ez_MSGQUEUE_submitTypedMsg(&wrk->inbox, worker_msg); + /* Prompt worker to check inbox */ + ES_VSignal(wrk->tid, CHECK_INBOX_VSIG); } /* Wait for something to happen */ ES_run(); -//eprintf("------------ ALL THREADS TERMINATED ------------"); /* Unregister signal handlers for this thread */ if(S.timeoutKey) @@ -169,40 +177,49 @@ PDNS_lookup(LOGENTRY *lePtrArr[], unsigned nItems, unsigned timeout_ms) ez_ES_unregister(S.joinKeyArr[i]); } - rtn= S.nCompleted; + rtn= S.processedNdx; abort: return rtn; } static int -check_inbox_f(void *data, int signo) +mgr_check_inbox_f(void *data, int signo) /********************************************************* * Parent was prompted to check the inbox to see which - * child is ready for another task. + * worker is ready for another task. */ { int rtn= -1; - unsigned child_ndx; + struct mgrMsg msg; - while(EOF != MSGQUEUE_extractTypedMsg(&S.inbox, child_ndx)) { + while(EOF != MSGQUEUE_extractTypedMsg(&S.inbox, msg)) { - /* Get pointer to child */ - struct child *ch= S.childArr + child_ndx; + /* Get pointer to worker */ + struct worker *wrk= S.workerArr + msg.worker_ndx; + struct workerMsg worker_msg= {.e= NULL}; + + if(msg.e->dns.flags & PDNS_DONE_MASK) { + + /* If we've finished up, start pruning worker threads */ + if(S.processedNdx == S.nItems) { + pthread_kill(wrk->tid, SIGTERM); + continue; + } + + worker_msg.e= S.lePtrArr[S.processedNdx]; + ++S.processedNdx; + + } else { + + /* Perform forward lookup next */ + worker_msg.e= msg.e; - /* Noting left to do here */ - if(S.ndx == S.nItems) { -//eprintf("Killing thread %u early", child_ndx); - pthread_kill(ch->tid, SIGTERM); - continue; } - /* Tell child to work on next task */ - int rc= MSGQUEUE_submitTypedMsg(&ch->inbox, S.lePtrArr[S.ndx]); - assert(0 == rc); - ES_VSignal(ch->tid, CHECK_INBOX_VSIG); + /* Give worker another task */ + ez_MSGQUEUE_submitTypedMsg(&wrk->inbox, worker_msg); + ES_VSignal(wrk->tid, CHECK_INBOX_VSIG); - /* Move the "todo" ndx forward */ - ++S.ndx; } rtn= 0; @@ -219,8 +236,8 @@ nThreads_joined(void) unsigned rtn= 0; for(unsigned i= 0; i < S.nThreads; ++i) { - struct child *ch= S.childArr + i; - if(!ch->is_joined) continue; + struct worker *wrk= S.workerArr + i; + if(!wrk->is_joined) continue; ++rtn; } @@ -230,39 +247,37 @@ nThreads_joined(void) static int join_f(void *data, int signo) /********************************************************* - * Child prompted us to join + * Worker prompted us to join */ { - struct child *ch= S.childArr + signo; + struct worker *wrk= S.workerArr + signo; void *pRtn; -//eprintf("joining thread %d", signo); + pthread_join(wrk->tid, &pRtn); - pthread_join(ch->tid, &pRtn); - - ch->is_joined= 1; + wrk->is_joined= 1; /* This will naturally terminate when we are done.*/ return S.nThreads == nThreads_joined() ? -1 : 0; } static void -stop_remaining_children(void) +stop_remaining_workers(void) /********************************************************* - * Signal any remaining children to stop. + * Signal any remaining workers to stop. */ { - /* Tell all remaining child threads to exit now */ + /* Tell all remaining worker threads to exit now */ unsigned i; for(i= 0; i < S.nThreads; ++i) { - struct child *ch= S.childArr + i; + struct worker *wrk= S.workerArr + i; /* If it has already joined, skip it */ - if(ch->is_joined) continue; + if(wrk->is_joined) continue; - /* Prompt child to shut down now */ - pthread_kill(ch->tid, SIGTERM); + /* Prompt worker to shut down now */ + pthread_kill(wrk->tid, SIGTERM); } } @@ -278,11 +293,11 @@ timeout_f(void *data) /* Post notice that it is time to shut down */ S.flags |= EXIT_FLG; -eprintf("Timed out with %u threads remaining", S.nThreads - nThreads_joined()); +#ifdef DEBUG + eprintf("Timed out with %u threads remaining", S.nThreads - nThreads_joined()); +#endif -//eprintf("EXTERMINATE!!!!"); - - stop_remaining_children(); + stop_remaining_workers(); /* Register a countdown timer to know when to forcefully * stop remaining threads. @@ -299,115 +314,175 @@ shutdown_f(void *data) */ { S.shutdownKey= 0; -eprintf("WTF? %u threads _still_ remain", S.nThreads - nThreads_joined()); +#ifdef DEBUG + eprintf("WTF: %u threads *still* remain!", S.nThreads - nThreads_joined()); +#endif + /* Let workerren know not to signal for a join */ + S.flags |= ORPHAN_FLG; return -1; } /*============================================================*/ -/*================= Child threads ============================*/ +/*================= Worker threads ============================*/ /*============================================================*/ static void* -child_main (void *vp_ndx) +worker_main (void *vp_ndx) /********************************************************* - * Children begin execution here. + * Workers begin execution here. */ { unsigned ndx= (long unsigned)vp_ndx; - struct child *self= S.childArr + ndx; + struct worker *self= S.workerArr + ndx; - /* Prepare child's static data */ - MSGQUEUE_constructor(&self->inbox, sizeof(LOGENTRY*), PDNS_CHILD_INBOX_SZ); + /* Prepare worker's static data */ + MSGQUEUE_constructor(&self->inbox, sizeof(struct workerMsg), PDNS_WORKER_INBOX_SZ); /* Register to exit when prompted */ - ez_ES_registerSignal(SIGTERM, child_exit_f, NULL); + ez_ES_registerSignal(SIGTERM, worker_exit_f, NULL); /* Register to check inbox when prompted */ - ez_ES_registerVSignal(CHECK_INBOX_VSIG, child_check_inbox_f, vp_ndx); + ez_ES_registerVSignal(CHECK_INBOX_VSIG, worker_check_inbox_f, vp_ndx); /* Parent has been blocked waiting for this call */ ES_release_parent(); - /* Respond to directives from parent */ + /* Respond to directives from mgr */ ES_run(); - int64_t ms= clock_gettime_ms(CLOCK_REALTIME) - S.start_ms; +#ifdef qqDEBUG +int64_t ms= clock_gettime_ms(CLOCK_REALTIME) - S.start_ms; +eprintf("thread %u exiting at %f seconds", ndx, (double)ms/1000.); +#endif -//eprintf("thread %u exiting at %f seconds", ndx, (double)ms/1000.); - - /* Let the main thread know we are ready to join */ - ES_VSignal(S.tid, ndx); + /* Parent thread may have moved on. In that case, don't join. */ + if(!(S.flags & ORPHAN_FLG)) + /* Let the main thread know we are ready to join */ + ES_VSignal(S.tid, ndx); return NULL; } static int -child_check_inbox_f(void *vp_ndx, int signo) +worker_check_inbox_f(void *vp_ndx, int signo) /********************************************************* - * Child was prompted to check the inbox for tasks. + * Worker was prompted to check the inbox for tasks. */ { int rtn= -1; unsigned ndx= (long unsigned)vp_ndx; - struct child *self= S.childArr + ndx; - char hostBuf[PATH_MAX]; - LOGENTRY *e; - const static struct addrinfo hints= { - .ai_family = AF_UNSPEC, /* Allow IPv4 or IPv6 */ - .ai_flags = AI_NUMERICHOST /* doing reverse lookups */ - }; + struct worker *self= S.workerArr + ndx; + struct workerMsg msg; while(!(S.flags & EXIT_FLG) && - EOF != MSGQUEUE_extractTypedMsg(&self->inbox, e)) + EOF != MSGQUEUE_extractTypedMsg(&self->inbox, msg)) { - assert(e); + assert(msg.e); int64_t ms= clock_gettime_ms(CLOCK_REALTIME) - S.start_ms; //eprintf("thread %u doing lookup at %f seconds", ndx, (double)ms/1000.); - /* Get a populated addrinfo object */ - struct addrinfo *res= NULL; - int rc= ez_getaddrinfo(e->addr, NULL, &hints, &res); - assert(0 == rc); - assert(res && res->ai_addr && res->ai_addrlen); - /* Now do blocking reverse lookup */ - rc= ez_getnameinfo(res->ai_addr, res->ai_addrlen, hostBuf, sizeof(hostBuf)-1, NULL, 0, NI_NAMEREQD); - switch(rc) { - case 0: - e->dnsName= strdup(hostBuf); - break; - case EAI_NONAME: - e->dnsName= "[3(NXDOMAIN)]"; - break; + if(msg.e->dns.flags & PDNS_REV_DNS_FLG) { - case EAI_AGAIN: - e->dnsName= "[2(SERVFAIL)]"; - break; + const static struct addrinfo hints= { + .ai_family = AF_UNSPEC, /* Allow IPv4 or IPv6 */ +// .ai_flags = AI_CANONNAME /* get the forward lookup result */ + }; - default: - eprintf("FATAL: getnameinfo() returned %d", rc); - abort(); + /* Get a populated addrinfo object */ + struct addrinfo *res= NULL; + int rc= ez_getaddrinfo(msg.e->dns.name, NULL, &hints, &res); + + msg.e->dns.getaddrinfo_rtn= rc; + + switch(rc) { + case 0: +// assert(res && res->ai_canonname); + break; + + case EAI_NONAME: + msg.e->dns.flags |= PDNS_FWD_NONE_FLG; + break; + + case EAI_FAIL: + case EAI_NODATA: + case EAI_AGAIN: + msg.e->dns.flags |= PDNS_FWD_FAIL_FLG; + break; + + default: + eprintf("rc= %d", rc); + assert(0); + + } + + /* In any case, we are done */ + msg.e->dns.flags |= PDNS_FWD_DNS_FLG; + + } else { /* reverse lookup */ + + const static struct addrinfo hints= { + .ai_family = AF_UNSPEC, /* Allow IPv4 or IPv6 */ + .ai_flags = AI_NUMERICHOST /* doing reverse lookups */ + }; + + /* Place to which getnameinfo can copy result */ + char hostBuf[PATH_MAX]; + + /* Get a populated addrinfo object */ + struct addrinfo *res= NULL; + int rc= ez_getaddrinfo(msg.e->addr, NULL, &hints, &res); + assert(0 == rc); + assert(res && res->ai_addr && res->ai_addrlen); + /* Now do blocking reverse lookup */ + rc= ez_getnameinfo(res->ai_addr, res->ai_addrlen, hostBuf, sizeof(hostBuf)-1, NULL, 0, NI_NAMEREQD); + switch(rc) { + case 0: + msg.e->dns.name= strdup(hostBuf); + msg.e->dns.flags |= PDNS_REV_DNS_FLG; + break; + + case EAI_NONAME: + msg.e->dns.name= "[3(NXDOMAIN)]"; + msg.e->dns.flags |= PDNS_NXDOMAIN_FLG; + break; + + case EAI_AGAIN: + msg.e->dns.name= "[2(SERVFAIL)]"; + msg.e->dns.flags |= PDNS_SERVFAIL_FLG; + break; + + default: + eprintf("FATAL: getnameinfo() returned %d", rc); + abort(); + } } + + /* Catch being bumped out of blocking call by signal */ + if(S.flags & EXIT_FLG) break; } - ++S.nCompleted; - if(S.flags & EXIT_FLG) return -1; + /* Only do follow up if we are not exiting */ + if(!(S.flags & EXIT_FLG)) { - /* Submit the child's array ndx to main parent - * thread's inbox to indicate we are ready for - * more. - */ - MSGQUEUE_submitTypedMsg(&S.inbox, ndx); - ES_VSignal(S.tid, CHECK_INBOX_VSIG); + struct mgrMsg mgr_msg= {.e= msg.e, .worker_ndx= ndx}; + /* Submit the worker's message to main mgr + * thread's inbox to indicate we are ready for + * more. + */ + ez_MSGQUEUE_submitTypedMsg(&S.inbox, mgr_msg); + ES_VSignal(S.tid, CHECK_INBOX_VSIG); + + rtn= 0; + } - rtn= 0; abort: return rtn; } static int -child_exit_f(void *vp_ndx, int signo) -/********************************************************* - * Child was prompted to exit now, so return -1 so child_main() - * will return from ES_run(). +worker_exit_f(void *vp_ndx, int signo) +/************************************************************************** + * Worker was prompted to exit now, so return -1 causing worker_main() return + * from ES_run(). */ { return -1; diff --git a/pdns.h b/pdns.h index c072b48..c8e941c 100644 --- a/pdns.h +++ b/pdns.h @@ -16,23 +16,48 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +/* + * JDR Sat 30 Nov 2019 08:27:23 AM EST + * Performs DNS reverse + fwd lookups in parallel. Having to use a bunch of threads + * to overcome the serialization inherent in blocking calls is a travesty, but + * I couldn't find a non-blocking version of getnameinfo(). + * + * Oh yeah, and I'm not in the mood to write it myself ;-) + */ + #ifndef PARALLEL_DNS_H #define PARALLEL_DNS_H + +/* Number of threads to use in parallel */ +#define PDNS_MAX_THREADS 200 +#define PDNS_MGR_INBOX_SZ PDNS_MAX_THREADS*2 +#define PDNS_WORKER_INBOX_SZ 1 +/* Give worker threads a chance to join */ +#define PDNS_SHUTDOWN_PAUSE_MS 500 + +enum PDNS_flags { + PDNS_SERVFAIL_FLG= 1<<0, + PDNS_NXDOMAIN_FLG= 1<<1, + PDNS_REV_DNS_FLG= 1<<2, + PDNS_FWD_DNS_FLG= 1<<3, + PDNS_FWD_FAIL_FLG= 1<<4, + PDNS_FWD_NONE_FLG= 1<<5, + PDNS_DONE_MASK= PDNS_SERVFAIL_FLG|PDNS_NXDOMAIN_FLG|PDNS_FWD_DNS_FLG +}; + +#define _GNU_SOURCE #include "logEntry.h" #ifdef __cplusplus extern "C" { #endif -/* Number of threads to use in parallel */ -#define PDNS_MAX_THREADS 100 -#define PDNS_INBOX_SZ (PDNS_MAX_THREADS*3) -#define PDNS_CHILD_INBOX_SZ 1 -#define PDNS_SHUTDOWN_PAUSE_MS 500 +/* Fix recursive #include dependency */ +struct _LOGENTRY; int -PDNS_lookup(LOGENTRY *lePtrArr[], unsigned nItems, unsigned timeout_ms); +PDNS_lookup(struct _LOGENTRY *lePtrArr[], unsigned nItems, unsigned timeout_ms); /************************************************************** * Perform parallel DNS reverse lookups on all LOGENTRY objects * referenced in lePtrArr until finished, or timeout_ms has lapsed.