/*****************************************************************************/ /* lookupAgent.c This is a WASD agent for resolving IP address->name and name->address. It executes as a CGIplus script though does not use CGI variables or provide a CGI compliant response. Performs its job via callouts. It relies on the WASD v12 and later AGENT-BEGIN: and AGENT-END: callouts to provide the agent request parameter and response. AGENT-BEGIN: (reply) HOST: to resolve name->address AGENT-BEGIN: (reply) ADDR: to resolve address->name !AGENT-END: ADDR: to return resolve name->address !AGENT-END: HOST: to return resolve address->name !AGENT-END: [] to the agent functionality only !AGENT-END: [%X ] if a to-be -E-NOTICED error VERSION LOG ----------- 01-JUN-2021 MGD initial */ /*****************************************************************************/ #define SOFTWAREVN "1.0.0" #define SOFTWARENM "LOOKUPAGENT" #ifdef __ALPHA # define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN #endif #ifdef __ia64 # define SOFTWAREID SOFTWARENM " IA64-" SOFTWAREVN #endif #ifdef __VAX # error VAX not implemented #endif #ifdef __x86_64 # define SOFTWAREID SOFTWARENM " X86-" SOFTWAREVN #endif /* ensure BSD 4.4 structures */ #define _SOCKADDR_LEN /* BUT MultiNet BG driver does not support BSD 4.4 AF_INET addresses */ #define NO_SOCKADDR_LEN_4 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int CgiPlusUsageCount; char SoftwareId[] = SOFTWAREID; #define LOOKUP_RETRY 10 char* TcpIpLookup (char*, char*); char* ScriptCallout (char *fmt, ...); /*****************************************************************************/ /* */ int main (int argc, char *argv[]) { int status; char *cptr, *sptr; if (argc > 1) { if (!strcasecmp (argv[1], "/version")) fprintf (stdout, "%%%s-I-VERSION, %s\n", SOFTWARENM, SOFTWAREID); exit (SS$_NORMAL); } CgiLibEnvironmentInit (0, NULL, 0); /* MUST only be executed in a CGIplus environment! */ if (!CgiLibEnvironmentIsCgiPlus ()) { CgiLibResponseHeader (502, "text/plain"); fputs ("Not CGIplus!\n", stdout); CgiLibCgiPlusEOF (); exit (SS$_NORMAL); } for (;;) { /* block waiting for the next request */ CgiLibVar (""); CgiPlusUsageCount++; if (cptr = CgiLibVarNull("REQUEST_METHOD")) if (!*cptr) { /* proctored into existance */ CgiLibResponseHeader (204, "application/proctor"); CgiLibCgiPlusEOF (); continue; } cptr = ScriptCallout ("AGENT-BEGIN: %s usage:%d", SoftwareId, CgiPlusUsageCount); if (*cptr != '2') { /* if callout response not "200 ..." */ status = atoi(cptr); CgiLibResponseHeader (status, "text/plain"); fprintf (stdout, "%d!\n", status); CgiLibCgiPlusEOF (); continue; } /* skip over response status (e.g. "200") */ for (sptr = cptr; isdigit(*sptr); sptr++); while (*sptr && *sptr == ' ') sptr++; cptr = sptr; /* not interested in any agent-specific directive */ if (*sptr == '[') { while (*sptr && *sptr != ']') sptr++; if (*sptr) sptr++; while (*sptr == ' ') sptr++; cptr = sptr; } if (!memcmp (cptr, "ADDR:", 5)) { cptr = TcpIpLookup (NULL, cptr+5); sptr = "HOST:"; } else if (!memcmp (cptr, "HOST:", 5)) { cptr = TcpIpLookup (cptr+5, NULL); sptr = "ADDR:"; } else cptr = "[request not understood]"; if (*cptr == '[') ScriptCallout ("!AGENT-END: %s", cptr); else ScriptCallout ("!AGENT-END: %s%s", sptr, cptr); CgiLibCgiPlusEOF (); } } /*****************************************************************************/ /* If |name| is non-NULL lookup the IP address using the host name. If |addr| is non-NULL lookup the host name using the address. */ char* TcpIpLookup ( char *name, char *addr ) { static char buf [1024]; int retry, retval; char *cptr, *sptr, *zptr; void *addptr; struct sockaddr_in addr4; struct sockaddr_in6 addr6; struct addrinfo hints; struct addrinfo *aiptr, *resaiptr; /*********/ /* begin */ /*********/ if (addr) { retval = 0; memset (&addr4, 0, sizeof(addr4)); if (inet_pton (AF_INET, addr, &addr4.sin_addr) > 0) { /* MultiNet does not support BSD 4.4 AF_INET addresses */ #ifdef NO_SOCKADDR_LEN_4 /* this kludge seems to work for both! */ *(USHORTPTR)&addr4 = AF_INET; #else addr4.sin_len = sizeof(struct sockaddr_in); addr4.sin_family = AF_INET; #endif for (retry = LOOKUP_RETRY; retry; retry--) { retval = getnameinfo ((struct sockaddr*)&addr4, sizeof(addr4), buf, sizeof(buf), NULL, 0, NI_NAMEREQD); if (retval != EINTR && retval != EAI_AGAIN) break; sleep (1); } if (retval) { if (retval == EAI_NONAME) strcpy (buf, "[unknown]"); else if (retval == EAI_FAIL || retval == EAI_AGAIN) strcpy (buf, "[failed]"); else sprintf (buf, "[%s]", gai_strerror(retval)); } return (buf); } else { memset (&addr6, 0, sizeof(addr6)); if (inet_pton (AF_INET6, addr, &addr6.sin6_addr) > 0) { addr6.sin6_len = sizeof(struct sockaddr_in6); addr6.sin6_family = AF_INET6; for (retry = LOOKUP_RETRY; retry; retry--) { retval = getnameinfo ((struct sockaddr*)&addr6, addr6.sin6_len, buf, sizeof(buf), NULL, 0, NI_NAMEREQD); if (retval != EINTR && retval != EAI_AGAIN) break; sleep (1); } if (retval) { if (retval == EAI_NONAME) strcpy (buf, "[unknown]"); else if (retval == EAI_FAIL || retval == EAI_AGAIN) strcpy (buf, "[failed]"); else sprintf (buf, "[%s]", gai_strerror(retval)); } } return (buf); } } if (name) { aiptr = NULL; memset (&hints, 0, sizeof(hints)); hints.ai_flags |= AI_CANONNAME; retval = 0; for (retry = LOOKUP_RETRY; retry; retry--) { retval = getaddrinfo (name, NULL, &hints, &resaiptr); if (retval != EINTR && retval != EAI_AGAIN) break; sleep (1); } if (retval) { if (retval == EAI_NONAME) sprintf (buf, "[unknown]"); else if (retval == EAI_FAIL || retval == EAI_AGAIN) sprintf (buf, "[failed]"); else sprintf (buf, "[%s]", gai_strerror(retval)); return (buf); } else { /* potentially multiple addresses for the one host name */ zptr = (sptr = buf) + sizeof(buf)-8; for (aiptr = resaiptr; aiptr; aiptr = aiptr->ai_next) { if (aiptr->ai_family == AF_INET) { /* IPv4 */ addptr = &((struct sockaddr_in *)aiptr->ai_addr)->sin_addr; } else { /* must be IPv6 */ addptr = &((struct sockaddr_in6 *)aiptr->ai_addr)->sin6_addr; } if (sptr > buf) *sptr++ = ' '; if (!inet_ntop (aiptr->ai_family, addptr, sptr, sptr - buf)) { sprintf (buf, "[%s]", strerror(errno)); break; } while (*sptr) sptr++; } } /* free the addrinfo */ freeaddrinfo(aiptr); return (buf); } return ("[bugcheck]"); } /*****************************************************************************/ /* Provide a callout to WASD server. */ char* ScriptCallout (char *fmt, ...) { static char CalloutResponse [256]; int retval; char *cptr; char buf [256]; va_list ap; CgiLibCgiPlusESC(); va_start (ap, fmt); retval = vsnprintf (buf, sizeof(buf), fmt, ap); va_end (ap); if (retval >= 0) fputs (buf, stdout); CgiLibCgiPlusEOT(); if (buf[0] == '!' || buf[0] == '#') return (NULL); memset (CalloutResponse, 0, sizeof(CalloutResponse)); CgiLibCgiPlusInGets (CalloutResponse, sizeof(CalloutResponse)); *(strchr (CalloutResponse, '\n')) = '\0'; return (CalloutResponse); } /*****************************************************************************/