2019-11-30 05:10:25 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2019 by John D. Robertson *
|
|
|
|
* john@rrci.com *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
#define _GNU_SOURCE
|
2019-12-01 02:30:17 +00:00
|
|
|
#include <arpa/inet.h>
|
2019-11-30 05:10:25 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#include "ez_es.h"
|
|
|
|
#include "ez_libc.h"
|
|
|
|
#include "msgqueue.h"
|
|
|
|
#include "pdns.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
enum vsignals {
|
2019-11-30 19:14:42 +00:00
|
|
|
/* All vsigs before this are used to indicate worker ready to join */
|
2019-11-30 14:35:29 +00:00
|
|
|
EXIT_VSIG= PDNS_MAX_THREADS,
|
2019-11-30 05:10:25 +00:00
|
|
|
CHECK_INBOX_VSIG
|
|
|
|
};
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/*============================================================*/
|
|
|
|
/*=========== Forward declarations ===========================*/
|
|
|
|
/*============================================================*/
|
2019-12-01 02:30:17 +00:00
|
|
|
static const char* addrinfo2addr(const struct addrinfo *ai);
|
|
|
|
static int addrinfo_is_match(const struct addrinfo *ai, const char *addr);
|
2019-11-30 19:14:42 +00:00
|
|
|
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);
|
2019-11-30 05:10:25 +00:00
|
|
|
static int join_f(void *data, int signo);
|
2019-12-01 02:30:17 +00:00
|
|
|
static int print_addrinfo(struct addrinfo *ai, FILE *fh);
|
2019-11-30 19:14:42 +00:00
|
|
|
static void stop_remaining_workers(void);
|
2019-11-30 05:10:25 +00:00
|
|
|
static int timeout_f(void *data);
|
2019-11-30 14:35:29 +00:00
|
|
|
static int shutdown_f(void *data);
|
|
|
|
static unsigned nThreads_joined(void);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/*============================================================*/
|
|
|
|
/*=========== Static data ====================================*/
|
|
|
|
/*============================================================*/
|
|
|
|
static struct {
|
|
|
|
|
|
|
|
enum {
|
2019-11-30 19:14:42 +00:00
|
|
|
EXIT_FLG= 1<<0,
|
|
|
|
ORPHAN_FLG= 1<<1
|
2019-11-30 05:10:25 +00:00
|
|
|
} flags;
|
|
|
|
|
2019-11-30 14:35:29 +00:00
|
|
|
int64_t start_ms;
|
|
|
|
|
2019-11-30 05:10:25 +00:00
|
|
|
int timeoutKey,
|
2019-11-30 14:35:29 +00:00
|
|
|
shutdownKey,
|
2019-11-30 05:10:25 +00:00
|
|
|
inboxKey,
|
2019-11-30 14:35:29 +00:00
|
|
|
joinKeyArr[PDNS_MAX_THREADS];
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
pthread_t tid;
|
|
|
|
MSGQUEUE inbox;
|
2019-11-30 14:35:29 +00:00
|
|
|
LOGENTRY **lePtrArr;
|
2019-11-30 19:14:42 +00:00
|
|
|
unsigned processedNdx,
|
2019-11-30 14:35:29 +00:00
|
|
|
nThreads,
|
|
|
|
nItems;
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* One of these for each worker thread */
|
|
|
|
struct worker {
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
int is_joined;
|
|
|
|
|
|
|
|
pthread_t tid;
|
|
|
|
MSGQUEUE inbox;
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
} workerArr[PDNS_MAX_THREADS];
|
2019-12-01 02:30:17 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
pthread_mutex_t prt_mtx;
|
|
|
|
#endif
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-12-01 02:30:17 +00:00
|
|
|
} S= {
|
|
|
|
#ifdef DEBUG
|
|
|
|
.prt_mtx= PTHREAD_MUTEX_INITIALIZER
|
|
|
|
#endif
|
|
|
|
};
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/*============================================================*/
|
|
|
|
/*=========== PDNS ===========================================*/
|
|
|
|
/*============================================================*/
|
|
|
|
int
|
2019-11-30 14:35:29 +00:00
|
|
|
PDNS_lookup(LOGENTRY *lePtrArr[], unsigned nItems, unsigned timeout_ms)
|
2019-11-30 05:10:25 +00:00
|
|
|
/**************************************************************
|
|
|
|
* Perform parallel DNS reverse lookups on all LOGENTRY objects
|
2019-11-30 14:35:29 +00:00
|
|
|
* referenced in lePtrArr.
|
2019-11-30 05:10:25 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
int rtn= -1;
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Check for trivial case */
|
2019-11-30 14:35:29 +00:00
|
|
|
if(!nItems)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Note when we start */
|
|
|
|
S.start_ms= clock_gettime_ms(CLOCK_REALTIME);
|
|
|
|
|
2019-11-30 05:10:25 +00:00
|
|
|
/* Publish our thread ID */
|
|
|
|
S.tid= pthread_self();
|
|
|
|
|
|
|
|
/* Prepare our inbox */
|
2019-11-30 19:14:42 +00:00
|
|
|
MSGQUEUE_constructor(&S.inbox, sizeof(struct mgrMsg), PDNS_MGR_INBOX_SZ);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/* Stash this where it's easy to get to */
|
|
|
|
S.nItems= nItems;
|
2019-11-30 14:35:29 +00:00
|
|
|
S.nThreads= MIN(nItems, PDNS_MAX_THREADS);
|
|
|
|
S.lePtrArr= lePtrArr;
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/* 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 */
|
2019-11-30 19:14:42 +00:00
|
|
|
S.inboxKey= ez_ES_registerVSignal(CHECK_INBOX_VSIG, mgr_check_inbox_f, NULL);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Start worker threads */
|
2019-11-30 14:35:29 +00:00
|
|
|
for(unsigned i= 0; i < S.nThreads; ++i) {
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
struct worker *wrk= S.workerArr + i;
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/* Register the join handler on vsig= array index */
|
2019-11-30 14:35:29 +00:00
|
|
|
S.joinKeyArr[i]= ez_ES_registerVSignal(i, join_f, NULL);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Pass the worker's array index in to worker_main() */
|
|
|
|
wrk->tid= ES_spawn_thread(worker_main, (void*)(long unsigned)i);
|
2019-11-30 14:35:29 +00:00
|
|
|
}
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Give worker threads something to do */
|
|
|
|
for(; S.processedNdx < S.nThreads; ++S.processedNdx) {
|
2019-11-30 14:35:29 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
struct worker *wrk= S.workerArr + S.processedNdx;
|
|
|
|
struct workerMsg worker_msg= {.e= S.lePtrArr[S.processedNdx]};
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* 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);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for something to happen */
|
|
|
|
ES_run();
|
|
|
|
|
|
|
|
/* Unregister signal handlers for this thread */
|
|
|
|
if(S.timeoutKey)
|
|
|
|
ez_ES_unregister(S.timeoutKey);
|
|
|
|
|
2019-11-30 14:35:29 +00:00
|
|
|
if(S.shutdownKey)
|
|
|
|
ez_ES_unregister(S.shutdownKey);
|
|
|
|
|
2019-11-30 05:10:25 +00:00
|
|
|
ez_ES_unregister(S.inboxKey);
|
|
|
|
|
|
|
|
/* Release all the join registrations */
|
2019-11-30 14:35:29 +00:00
|
|
|
for(unsigned i= 0; i < S.nThreads; ++i) {
|
2019-11-30 05:10:25 +00:00
|
|
|
ez_ES_unregister(S.joinKeyArr[i]);
|
|
|
|
}
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
rtn= S.processedNdx;
|
2019-11-30 05:10:25 +00:00
|
|
|
abort:
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2019-11-30 19:14:42 +00:00
|
|
|
mgr_check_inbox_f(void *data, int signo)
|
2019-11-30 05:10:25 +00:00
|
|
|
/*********************************************************
|
|
|
|
* Parent was prompted to check the inbox to see which
|
2019-11-30 19:14:42 +00:00
|
|
|
* worker is ready for another task.
|
2019-11-30 05:10:25 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
int rtn= -1;
|
2019-11-30 19:14:42 +00:00
|
|
|
struct mgrMsg msg;
|
|
|
|
|
|
|
|
while(EOF != MSGQUEUE_extractTypedMsg(&S.inbox, msg)) {
|
|
|
|
|
|
|
|
/* 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) {
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* If we've finished up, start pruning worker threads */
|
|
|
|
if(S.processedNdx == S.nItems) {
|
|
|
|
pthread_kill(wrk->tid, SIGTERM);
|
|
|
|
continue;
|
|
|
|
}
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
worker_msg.e= S.lePtrArr[S.processedNdx];
|
|
|
|
++S.processedNdx;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Perform forward lookup next */
|
|
|
|
worker_msg.e= msg.e;
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Give worker another task */
|
|
|
|
ez_MSGQUEUE_submitTypedMsg(&wrk->inbox, worker_msg);
|
|
|
|
ES_VSignal(wrk->tid, CHECK_INBOX_VSIG);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
rtn= 0;
|
|
|
|
abort:
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
2019-11-30 14:35:29 +00:00
|
|
|
static unsigned
|
|
|
|
nThreads_joined(void)
|
|
|
|
/*********************************************************
|
|
|
|
* Return the number of threads which have already joined.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
unsigned rtn= 0;
|
|
|
|
for(unsigned i= 0; i < S.nThreads; ++i) {
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
struct worker *wrk= S.workerArr + i;
|
|
|
|
if(!wrk->is_joined) continue;
|
2019-11-30 14:35:29 +00:00
|
|
|
++rtn;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:10:25 +00:00
|
|
|
static int
|
|
|
|
join_f(void *data, int signo)
|
|
|
|
/*********************************************************
|
2019-11-30 19:14:42 +00:00
|
|
|
* Worker prompted us to join
|
2019-11-30 05:10:25 +00:00
|
|
|
*/
|
|
|
|
{
|
2019-11-30 19:14:42 +00:00
|
|
|
struct worker *wrk= S.workerArr + signo;
|
2019-11-30 05:10:25 +00:00
|
|
|
void *pRtn;
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
pthread_join(wrk->tid, &pRtn);
|
2019-11-30 14:35:29 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
wrk->is_joined= 1;
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/* This will naturally terminate when we are done.*/
|
2019-11-30 14:35:29 +00:00
|
|
|
return S.nThreads == nThreads_joined() ? -1 : 0;
|
2019-11-30 05:10:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-11-30 19:14:42 +00:00
|
|
|
stop_remaining_workers(void)
|
2019-11-30 05:10:25 +00:00
|
|
|
/*********************************************************
|
2019-11-30 19:14:42 +00:00
|
|
|
* Signal any remaining workers to stop.
|
2019-11-30 05:10:25 +00:00
|
|
|
*/
|
|
|
|
{
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Tell all remaining worker threads to exit now */
|
2019-11-30 05:10:25 +00:00
|
|
|
unsigned i;
|
2019-11-30 14:35:29 +00:00
|
|
|
for(i= 0; i < S.nThreads; ++i) {
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
struct worker *wrk= S.workerArr + i;
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/* If it has already joined, skip it */
|
2019-11-30 19:14:42 +00:00
|
|
|
if(wrk->is_joined) continue;
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Prompt worker to shut down now */
|
|
|
|
pthread_kill(wrk->tid, SIGTERM);
|
2019-11-30 05:10:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
timeout_f(void *data)
|
|
|
|
/*********************************************************
|
|
|
|
* Countdown timer has expired.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
/* Note that the countdown timer fired */
|
|
|
|
S.timeoutKey= 0;
|
|
|
|
|
|
|
|
/* Post notice that it is time to shut down */
|
|
|
|
S.flags |= EXIT_FLG;
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
eprintf("Timed out with %u threads remaining", S.nThreads - nThreads_joined());
|
|
|
|
#endif
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
stop_remaining_workers();
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 14:35:29 +00:00
|
|
|
/* Register a countdown timer to know when to forcefully
|
|
|
|
* stop remaining threads.
|
|
|
|
*/
|
|
|
|
S.shutdownKey= ez_ES_registerTimer(PDNS_SHUTDOWN_PAUSE_MS, 0, shutdown_f, NULL);
|
|
|
|
|
2019-11-30 05:10:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-30 14:35:29 +00:00
|
|
|
static int
|
|
|
|
shutdown_f(void *data)
|
|
|
|
/*********************************************************
|
|
|
|
* Terminate any remaining threads.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
S.shutdownKey= 0;
|
2019-11-30 19:14:42 +00:00
|
|
|
#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;
|
2019-11-30 14:35:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-11-30 05:10:25 +00:00
|
|
|
/*============================================================*/
|
2019-11-30 19:14:42 +00:00
|
|
|
/*================= Worker threads ============================*/
|
2019-11-30 05:10:25 +00:00
|
|
|
/*============================================================*/
|
|
|
|
|
|
|
|
static void*
|
2019-11-30 19:14:42 +00:00
|
|
|
worker_main (void *vp_ndx)
|
2019-11-30 05:10:25 +00:00
|
|
|
/*********************************************************
|
2019-11-30 19:14:42 +00:00
|
|
|
* Workers begin execution here.
|
2019-11-30 05:10:25 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
unsigned ndx= (long unsigned)vp_ndx;
|
2019-11-30 19:14:42 +00:00
|
|
|
struct worker *self= S.workerArr + ndx;
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Prepare worker's static data */
|
|
|
|
MSGQUEUE_constructor(&self->inbox, sizeof(struct workerMsg), PDNS_WORKER_INBOX_SZ);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/* Register to exit when prompted */
|
2019-11-30 19:14:42 +00:00
|
|
|
ez_ES_registerSignal(SIGTERM, worker_exit_f, NULL);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/* Register to check inbox when prompted */
|
2019-11-30 19:14:42 +00:00
|
|
|
ez_ES_registerVSignal(CHECK_INBOX_VSIG, worker_check_inbox_f, vp_ndx);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
/* Parent has been blocked waiting for this call */
|
|
|
|
ES_release_parent();
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Respond to directives from mgr */
|
2019-11-30 05:10:25 +00:00
|
|
|
ES_run();
|
2019-11-30 19:14:42 +00:00
|
|
|
#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
|
2019-11-30 14:35:29 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* 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);
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2019-11-30 19:14:42 +00:00
|
|
|
worker_check_inbox_f(void *vp_ndx, int signo)
|
2019-11-30 05:10:25 +00:00
|
|
|
/*********************************************************
|
2019-11-30 19:14:42 +00:00
|
|
|
* Worker was prompted to check the inbox for tasks.
|
2019-11-30 05:10:25 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
int rtn= -1;
|
|
|
|
unsigned ndx= (long unsigned)vp_ndx;
|
2019-11-30 19:14:42 +00:00
|
|
|
struct worker *self= S.workerArr + ndx;
|
|
|
|
struct workerMsg msg;
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
while(!(S.flags & EXIT_FLG) &&
|
2019-11-30 19:14:42 +00:00
|
|
|
EOF != MSGQUEUE_extractTypedMsg(&self->inbox, msg))
|
2019-11-30 05:10:25 +00:00
|
|
|
{
|
2019-11-30 19:14:42 +00:00
|
|
|
assert(msg.e);
|
2019-11-30 14:35:29 +00:00
|
|
|
int64_t ms= clock_gettime_ms(CLOCK_REALTIME) - S.start_ms;
|
2019-11-30 19:14:42 +00:00
|
|
|
|
2019-12-01 02:30:17 +00:00
|
|
|
/* Check to see if we've finished the reverse DNS lookup */
|
2019-11-30 19:14:42 +00:00
|
|
|
if(msg.e->dns.flags & PDNS_REV_DNS_FLG) {
|
|
|
|
|
|
|
|
const static struct addrinfo hints= {
|
2019-12-01 02:30:17 +00:00
|
|
|
.ai_family= AF_UNSPEC, /* Allow IPv4 or IPv6 */
|
|
|
|
.ai_socktype= SOCK_DGRAM,
|
|
|
|
.ai_protocol= IPPROTO_UDP
|
2019-11-30 19:14:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Get a populated addrinfo object */
|
|
|
|
struct addrinfo *res= NULL;
|
|
|
|
int rc= ez_getaddrinfo(msg.e->dns.name, NULL, &hints, &res);
|
|
|
|
|
2019-12-01 02:30:17 +00:00
|
|
|
#ifdef qqDEBUG
|
|
|
|
if(!strcmp(msg.e->addr, "50.116.38.131")) {
|
|
|
|
pthread_mutex_lock(&S.prt_mtx);
|
|
|
|
ez_fprintf(stderr, "%s (%s) ----------------------------------\n", msg.e->addr, msg.e->dns.name);
|
|
|
|
print_addrinfo(res, stderr);
|
|
|
|
fflush(stderr);
|
|
|
|
pthread_mutex_unlock(&S.prt_mtx);
|
|
|
|
}
|
|
|
|
#endif
|
2019-11-30 19:14:42 +00:00
|
|
|
msg.e->dns.getaddrinfo_rtn= rc;
|
|
|
|
|
|
|
|
switch(rc) {
|
|
|
|
case 0:
|
2019-12-01 02:30:17 +00:00
|
|
|
if(!addrinfo_is_match(res, msg.e->addr))
|
|
|
|
msg.e->dns.flags |= PDNS_FWD_MISMATCH_FLG;
|
2019-11-30 19:14:42 +00:00
|
|
|
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;
|
|
|
|
|
2019-12-01 02:30:17 +00:00
|
|
|
if(res) freeaddrinfo(res);
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
} else { /* reverse lookup */
|
|
|
|
|
|
|
|
const static struct addrinfo hints= {
|
2019-12-01 02:30:17 +00:00
|
|
|
.ai_flags = AI_NUMERICHOST, /* doing reverse lookups */
|
2019-11-30 19:14:42 +00:00
|
|
|
.ai_family = AF_UNSPEC, /* Allow IPv4 or IPv6 */
|
2019-12-01 02:30:17 +00:00
|
|
|
.ai_socktype= SOCK_DGRAM,
|
|
|
|
.ai_protocol= IPPROTO_UDP
|
2019-11-30 19:14:42 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* 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);
|
2019-12-01 02:30:17 +00:00
|
|
|
|
|
|
|
#ifdef qqDEBUG
|
|
|
|
if(!strcmp(msg.e->addr, "50.116.38.131")) {
|
|
|
|
pthread_mutex_lock(&S.prt_mtx);
|
|
|
|
ez_fprintf(stderr, "%s ----------------------------------\n", msg.e->addr);
|
|
|
|
print_addrinfo(res, stderr);
|
|
|
|
fflush(stderr);
|
|
|
|
pthread_mutex_unlock(&S.prt_mtx);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if(res) freeaddrinfo(res);
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
switch(rc) {
|
|
|
|
case 0:
|
|
|
|
msg.e->dns.name= strdup(hostBuf);
|
|
|
|
msg.e->dns.flags |= PDNS_REV_DNS_FLG;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAI_NONAME:
|
2019-11-30 19:32:12 +00:00
|
|
|
msg.e->dns.name= "3(NXDOMAIN)";
|
2019-11-30 19:14:42 +00:00
|
|
|
msg.e->dns.flags |= PDNS_NXDOMAIN_FLG;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAI_AGAIN:
|
2019-11-30 19:32:12 +00:00
|
|
|
msg.e->dns.name= "2(SERVFAIL)";
|
2019-11-30 19:14:42 +00:00
|
|
|
msg.e->dns.flags |= PDNS_SERVFAIL_FLG;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
eprintf("FATAL: getnameinfo() returned %d", rc);
|
|
|
|
abort();
|
|
|
|
}
|
2019-12-01 02:30:17 +00:00
|
|
|
|
2019-11-30 05:10:25 +00:00
|
|
|
}
|
2019-11-30 19:14:42 +00:00
|
|
|
|
|
|
|
/* Catch being bumped out of blocking call by signal */
|
|
|
|
if(S.flags & EXIT_FLG) break;
|
2019-11-30 05:10:25 +00:00
|
|
|
}
|
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
/* Only do follow up if we are not exiting */
|
|
|
|
if(!(S.flags & EXIT_FLG)) {
|
2019-11-30 05:10:25 +00:00
|
|
|
|
2019-11-30 19:14:42 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-11-30 05:10:25 +00:00
|
|
|
|
|
|
|
abort:
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2019-11-30 19:14:42 +00:00
|
|
|
worker_exit_f(void *vp_ndx, int signo)
|
|
|
|
/**************************************************************************
|
|
|
|
* Worker was prompted to exit now, so return -1 causing worker_main() return
|
|
|
|
* from ES_run().
|
2019-11-30 05:10:25 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2019-12-01 02:30:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*============================================================*/
|
|
|
|
/*================ Misc. =====================================*/
|
|
|
|
/*============================================================*/
|
|
|
|
const static struct bitTuple ai_flags_btArr[]= {
|
|
|
|
{.name= "AI_ADDRCONFIG", .bit= AI_ADDRCONFIG},
|
|
|
|
{.name= "AI_ALL", .bit= AI_ALL},
|
|
|
|
{.name= "AI_CANONNAME", .bit= AI_CANONNAME},
|
|
|
|
{.name= "AI_NUMERICHOST", .bit= AI_NUMERICHOST},
|
|
|
|
{.name= "AI_NUMERICSERV", .bit= AI_NUMERICSERV},
|
|
|
|
{.name= "AI_PASSIVE", .bit= AI_PASSIVE},
|
|
|
|
{.name= "AI_V4MAPPED", .bit= AI_V4MAPPED},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
const static struct enumTuple ai_family_etArr[]= {
|
|
|
|
{.name= "AF_INET", .enumVal= AF_INET},
|
|
|
|
{.name= "AF_INET6", .enumVal= AF_INET6},
|
|
|
|
{.name= "AF_UNSPEC", .enumVal= AF_UNSPEC},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
const static struct enumTuple ai_socktype_etArr[]= {
|
|
|
|
{.name= "SOCK_DGRAM", .enumVal= SOCK_DGRAM},
|
|
|
|
{.name= "SOCK_RAW", .enumVal= SOCK_RAW},
|
|
|
|
{.name= "SOCK_STREAM", .enumVal= SOCK_STREAM},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
const static struct enumTuple ai_protocol_etArr[]= {
|
|
|
|
{.name= "IPPROTO_TCP", .enumVal= IPPROTO_TCP},
|
|
|
|
{.name= "IPPROTO_UDP", .enumVal= IPPROTO_UDP},
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
print_addrinfo(struct addrinfo *ai, FILE *fh)
|
|
|
|
/*************************************************************
|
|
|
|
* Print a legible rendition of a struct addrinfo.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
for(; ai; ai= ai->ai_next) {
|
|
|
|
const char *addr= addrinfo2addr(ai);
|
|
|
|
ez_fprintf(fh,
|
|
|
|
"struct addressinfo {\n"
|
|
|
|
"\tai_flags= %s\n"
|
|
|
|
"\tai_family= %s\n"
|
|
|
|
"\tai_socktype= %s\n"
|
|
|
|
"\tai_protocol= %s\n"
|
|
|
|
"\tai_addrlen= %d\n"
|
|
|
|
"\tai_addr= %s\n"
|
|
|
|
"\tai_cannonname= %s\n"
|
|
|
|
"}\n"
|
|
|
|
, bits2str(ai->ai_flags, ai_flags_btArr)
|
|
|
|
, enum2str(ai->ai_family, ai_family_etArr)
|
|
|
|
, enum2str(ai->ai_socktype, ai_socktype_etArr)
|
|
|
|
, enum2str(ai->ai_protocol, ai_protocol_etArr)
|
|
|
|
, (int)ai->ai_addrlen
|
|
|
|
, addr ? addr : "NULL"
|
|
|
|
, ai->ai_canonname ? ai->ai_canonname : "NULL"
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
addrinfo_is_match(const struct addrinfo *ai, const char *addr)
|
|
|
|
/***********************************************************************
|
|
|
|
* Search all members in linked list for a match.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
for(; ai; ai= ai->ai_next) {
|
|
|
|
const char *this_addr= addrinfo2addr(ai);
|
|
|
|
if(!strcmp(this_addr, addr)) return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char*
|
|
|
|
addrinfo2addr(const struct addrinfo *ai)
|
|
|
|
/***********************************************************************
|
|
|
|
* Get address in static string buffer
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
#define BUF_SZ 43
|
|
|
|
const char *rtn= NULL;
|
|
|
|
if(!ai->ai_addr) goto abort;
|
|
|
|
|
|
|
|
static _Thread_local char buf[BUF_SZ];
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
|
|
|
switch(ai->ai_family) {
|
|
|
|
case AF_INET: {
|
|
|
|
struct sockaddr_in *sin= (struct sockaddr_in*)ai->ai_addr;
|
|
|
|
rtn= inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)-1);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case AF_INET6: {
|
|
|
|
struct sockaddr_in6 *sin6= (struct sockaddr_in6*)ai->ai_addr;
|
|
|
|
rtn= inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf)-1);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
abort:
|
|
|
|
return rtn;
|
|
|
|
}
|
|
|
|
|