#define mDNSCoreReceive __MDNS__mDNSCoreReceive
#include "mDNS.c"
#undef mDNSCoreReceive
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
#include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
#include <arpa/inet.h>
#include <signal.h>
#include "mDNSClientAPI.h"// Defines the interface to the mDNS core code
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
#include "ExampleClientApp.h"
static mDNS mDNSStorage; static mDNS_PlatformSupport PlatformStorage; #define RR_CACHE_SIZE 500
static CacheRecord gRRCache[RR_CACHE_SIZE];
static volatile int StopNow; static volatile int NumAnswers, NumAddr, NumAAAA, NumHINFO;
static char hostname[MAX_ESCAPED_DOMAIN_NAME], hardware[256], software[256];
static mDNSAddr lastsrc, hostaddr, target;
static mDNSOpaque16 lastid, id;
mDNSlocal mDNSu32 mprintf(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
mDNSlocal mDNSu32 mprintf(const char *format, ...)
{
mDNSu32 length;
unsigned char buffer[512];
va_list ptr;
va_start(ptr,format);
length = mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr);
va_end(ptr);
printf("%s", buffer);
return(length);
}
mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport,
const mDNSInterfaceID InterfaceID, mDNSu8 ttl)
{
lastid = msg->h.id;
lastsrc = *srcaddr;
ttl = 255;
__MDNS__mDNSCoreReceive(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, ttl);
}
static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
(void)m; (void)question; (void)AddRecord; if (!id.NotAnInteger) id = lastid;
if (answer->rrtype == kDNSType_PTR || answer->rrtype == kDNSType_CNAME)
{
ConvertDomainNameToCString(&answer->rdata->u.name, hostname);
StopNow = 1;
mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.name.c);
}
}
static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
(void)m; (void)question; (void)AddRecord; if (answer->rrtype == kDNSType_A)
{
if (!id.NotAnInteger) id = lastid;
NumAnswers++;
NumAddr++;
mprintf("%##s %s %.4a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ip);
hostaddr.type = mDNSAddrType_IPv4; hostaddr.ip.v4 = answer->rdata->u.ip;
}
else if (answer->rrtype == kDNSType_AAAA)
{
if (!id.NotAnInteger) id = lastid;
NumAnswers++;
NumAAAA++;
mprintf("%##s %s %.16a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ipv6);
if (!hostaddr.type) {
hostaddr.type = mDNSAddrType_IPv6;
hostaddr.ip.v6 = answer->rdata->u.ipv6;
}
}
else if (answer->rrtype == kDNSType_HINFO)
{
mDNSu8 *p = answer->rdata->u.data;
strncpy(hardware, (char*)(p+1), p[0]);
hardware[p[0]] = 0;
p += 1 + p[0];
strncpy(software, (char*)(p+1), p[0]);
software[p[0]] = 0;
NumAnswers++;
NumHINFO++;
}
if (NumHINFO && (NumAddr || NumAAAA)) StopNow = 1;
}
static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
(void)m; (void)question; (void)AddRecord; if (answer->rrtype == kDNSType_PTR && mDNSSameAddress(&lastsrc, &target))
{
NumAnswers++;
NumAddr++;
mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.name.c);
StopNow = 1;
}
}
mDNSexport void WaitForAnswer(mDNS *const m, int seconds)
{
struct timeval end;
gettimeofday(&end, NULL);
end.tv_sec += seconds;
StopNow = 0;
NumAnswers = 0;
while (!StopNow)
{
int nfds = 0;
fd_set readfds;
struct timeval now, remain = end;
int result;
FD_ZERO(&readfds);
gettimeofday(&now, NULL);
if (remain.tv_usec < now.tv_usec) { remain.tv_usec += 1000000; remain.tv_sec--; }
if (remain.tv_sec < now.tv_sec) return;
remain.tv_usec -= now.tv_usec;
remain.tv_sec -= now.tv_sec;
mDNSPosixGetFDSet(m, &nfds, &readfds, &remain);
result = select(nfds, &readfds, NULL, NULL, &remain);
if (result >= 0) mDNSPosixProcessFDSet(m, &readfds);
else if (errno != EINTR) StopNow = 2;
}
}
mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback)
{
if (qname) MakeDomainNameFromDNSNameString(&q->qname, qname);
q->Target = target ? *target : zeroAddr;
q->TargetPort = MulticastDNSPort;
q->TargetQID = zeroID;
q->InterfaceID = mDNSInterface_ForceMCast;
q->qtype = qtype;
q->qclass = kDNSClass_IN;
q->QuestionCallback = callback;
q->QuestionContext = NULL;
return(mDNS_StartQuery(&mDNSStorage, q));
}
mDNSlocal void DoOneQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback)
{
mStatus status = StartQuery(q, qname, qtype, target, callback);
if (status != mStatus_NoError)
StopNow = 2;
else
{
WaitForAnswer(&mDNSStorage, 4);
mDNS_StopQuery(&mDNSStorage, q);
}
}
mDNSlocal int DoQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback)
{
DoOneQuery(q, qname, qtype, target, callback);
if (StopNow == 0 && target && target->type)
{
mprintf("%##s %s Trying multicast\n", q->qname.c, DNSTypeName(q->qtype));
DoOneQuery(q, qname, qtype, NULL, callback);
}
if (StopNow == 0 && NumAnswers == 0)
mprintf("%##s %s *** No Answer ***\n", q->qname.c, DNSTypeName(q->qtype));
return(StopNow);
}
mDNSlocal void HandleSIG(int signal)
{
(void)signal; debugf("");
debugf("HandleSIG");
StopNow = 2;
}
mDNSexport int main(int argc, char **argv)
{
int this_arg = 1;
mStatus status;
struct in_addr s4;
struct in6_addr s6;
char buffer[256];
DNSQuestion q;
if (argc < 2) goto usage;
mDNS_DebugMode = mDNStrue;
status = mDNS_Init(&mDNSStorage, &PlatformStorage,
gRRCache, RR_CACHE_SIZE,
mDNS_Init_DontAdvertiseLocalAddresses,
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); }
signal(SIGINT, HandleSIG); signal(SIGTERM, HandleSIG);
while (this_arg < argc)
{
char *arg = argv[this_arg++];
if (this_arg > 2) printf("\n");
lastid = id = zeroID;
hostaddr = target = zeroAddr;
hostname[0] = hardware[0] = software[0] = 0;
NumAddr = NumAAAA = NumHINFO = 0;
if (inet_pton(AF_INET, arg, &s4) == 1)
{
mDNSu8 *p = (mDNSu8 *)&s4;
mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]);
printf("%s\n", buffer);
target.type = mDNSAddrType_IPv4;
target.ip.v4.NotAnInteger = s4.s_addr;
DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
if (StopNow == 2) break;
}
else if (inet_pton(AF_INET6, arg, &s6) == 1)
{
int i;
mDNSu8 *p = (mDNSu8 *)&s6;
for (i = 0; i < 16; i++)
{
static const char hexValues[] = "0123456789ABCDEF";
buffer[i * 4 ] = hexValues[p[15-i] & 0x0F];
buffer[i * 4 + 1] = '.';
buffer[i * 4 + 2] = hexValues[p[15-i] >> 4];
buffer[i * 4 + 3] = '.';
}
mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
target.type = mDNSAddrType_IPv6;
bcopy(&s6, &target.ip.v6, sizeof(target.ip.v6));
DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback);
if (StopNow == 2) break;
}
else
strcpy(hostname, arg);
if (hostname[0]) DoQuery(&q, hostname, kDNSQType_ANY, &target, InfoCallback);
if (StopNow == 2) break;
if (hardware[0] || software[0])
{
DNSQuestion q1, q2;
printf("HINFO Hardware: %s\n", hardware);
printf("HINFO Software: %s\n", software);
if (target.type == 0) target = hostaddr;
StartQuery(&q1, "_services._mdns._udp.local.", kDNSQType_ANY, &target, ServicesCallback);
StartQuery(&q2, "_services._dns-sd._udp.local.", kDNSQType_ANY, &target, ServicesCallback);
WaitForAnswer(&mDNSStorage, 4);
mDNS_StopQuery(&mDNSStorage, &q1);
mDNS_StopQuery(&mDNSStorage, &q2);
if (StopNow == 2) break;
}
else if (NumAnswers)
{
printf("Host has no HINFO record; Best guess is ");
if (id.b[1]) printf("mDNSResponder-%d\n", id.b[1]);
else if (NumAAAA) printf("very early Panther build (mDNSResponder-33 or earlier)\n");
else printf("Jaguar version of mDNSResponder with no IPv6 support\n");
}
else
printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n");
}
mDNS_Close(&mDNSStorage);
return(0);
usage:
fprintf(stderr, "%s <dot-local hostname> or <IPv4 address> or <IPv6 address> ...\n", argv[0]);
return(-1);
}