static void do_section(const res_state statp, ns_msg *handle, ns_sect section, int pflag, FILE *file) { int n, sflag, rrnum; static int buflen = 2048; char *buf; ns_opcode opcode; ns_rr rr; /* * Print answer records. */ sflag = (statp->pfcode & pflag); if (statp->pfcode && !sflag) return; buf = malloc((size_t)buflen); if (buf == NULL) { fprintf(file, ";; memory allocation failure\n"); return; } opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode); rrnum = 0; for (;;) { if (ns_parserr(handle, section, rrnum, &rr)) { if (errno != ENODEV) fprintf(file, ";; ns_parserr: %s\n", strerror(errno)); else if (rrnum > 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) putc('\n', file); goto cleanup; } if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) fprintf(file, ";; %s SECTION:\n", p_section(section, opcode)); if (section == ns_s_qd) fprintf(file, ";;\t%s, type = %s, class = %s\n", ns_rr_name(rr), p_type(ns_rr_type(rr)), p_class(ns_rr_class(rr))); else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) { u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr); u_int32_t ttl = ns_rr_ttl(rr); fprintf(file, "; EDNS: version: %u, udp=%u, flags=%04x\n", (ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff); while (rdatalen >= 4) { const u_char *cp = ns_rr_rdata(rr); int i; GETSHORT(optcode, cp); GETSHORT(optlen, cp); if (optcode == NS_OPT_NSID) { fputs("; NSID: ", file); if (optlen == 0) { fputs("; NSID\n", file); } else { fputs("; NSID: ", file); for (i = 0; i < optlen; i++) fprintf(file, "%02x ", cp[i]); fputs(" (",file); for (i = 0; i < optlen; i++) fprintf(file, "%c", isprint(cp[i])? cp[i] : '.'); fputs(")\n", file); } } else { if (optlen == 0) { fprintf(file, "; OPT=%u\n", optcode); } else { fprintf(file, "; OPT=%u: ", optcode); for (i = 0; i < optlen; i++) fprintf(file, "%02x ", cp[i]); fputs(" (",file); for (i = 0; i < optlen; i++) fprintf(file, "%c", isprint(cp[i]) ? cp[i] : '.'); fputs(")\n", file); } } rdatalen -= 4 + optlen; } } else {
static void do_section(const res_state statp, ns_msg *handle, ns_sect section, int pflag, FILE *file) { int n, sflag, rrnum; static int buflen = 2048; char *buf; ns_opcode opcode; ns_rr rr; /* * Print answer records. */ sflag = (statp->pfcode & pflag); if (statp->pfcode && !sflag) return; buf = malloc(buflen); if (buf == NULL) { fprintf(file, ";; memory allocation failure\n"); return; } opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode); rrnum = 0; for (;;) { if (ns_parserr(handle, section, rrnum, &rr)) { if (errno != ENODEV) fprintf(file, ";; ns_parserr: %s\n", strerror(errno)); else if (rrnum > 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) putc('\n', file); goto cleanup; } if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1)) fprintf(file, ";; %s SECTION:\n", p_section(section, opcode)); if (section == ns_s_qd) fprintf(file, ";;\t%s, type = %s, class = %s\n", ns_rr_name(rr), p_type(ns_rr_type(rr)), p_class(ns_rr_class(rr))); else { n = ns_sprintrr(handle, &rr, NULL, NULL, buf, buflen); if (n < 0) { if (errno == ENOSPC) { free(buf); buf = NULL; if (buflen < 131072) buf = malloc(buflen += 1024); if (buf == NULL) { fprintf(file, ";; memory allocation failure\n"); return; } continue; } fprintf(file, ";; ns_sprintrr: %s\n", strerror(errno)); goto cleanup; } fputs(buf, file); fputc('\n', file); } rrnum++; } cleanup: free(buf); }
int srv_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { char *srv_name; size_t srv_name_size; char tgt_port[6]; #ifdef WIN32 PDNS_RECORD resp, entry; char *tgt_name; #else char tgt_name[BINKD_FQDNLEN + 1]; unsigned char resp[SRVGAI_DNSRESPLEN]; ns_msg nsb; ns_rr rrb; int rlen, i, rrlen; const unsigned char *p; struct in_addr dummy_addr; #endif int rc; struct addrinfo *ai, **ai_last = res; /* we need sensible information for all parameters */ if (!node || (node && !*node) || !service || (service && !*service) || !hints || !res) return getaddrinfo(node, service, hints, res); /* only domain names are supported */ if (hints->ai_flags & AI_NUMERICHOST) return getaddrinfo(node, service, hints, res); /* detect IP addresses */ if ((hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) && #ifdef WIN32 inet_addr(node) != INADDR_NONE #else inet_aton(node, &dummy_addr) != 0 #endif ) return getaddrinfo(node, service, hints, res); #ifdef AF_INET6 if ((hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) && strchr(node, ':')) return getaddrinfo(node, service, hints, res); #endif /* only named services are supported */ if ((hints->ai_flags & AI_NUMERICSERV) || *service == '0' || atoi(service) > 0) return getaddrinfo(node, service, hints, res); /* only TCP and UDP are supported */ if (hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM) return getaddrinfo(node, service, hints, res); /* _ <service> ._ tcp . <node> \0 */ srv_name_size = 1 + strlen(service) + 2 + 3 + 1 + strlen(node) + 1; srv_name = malloc(srv_name_size); if (!srv_name) return EAI_MEMORY; /* construct domain name for SRV query */ snprintf(srv_name, srv_name_size, "_%s._%s.%s", service, hints->ai_socktype == SOCK_STREAM ? "tcp" : "udp", node); #ifdef WIN32 rc = DnsQuery(srv_name, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &resp, NULL); #else rlen = res_search(srv_name, ns_c_in, ns_t_srv, resp, sizeof(resp)); #endif free(srv_name); /* fallback if DNS query does not return a single entry */ #ifdef WIN32 if (rc != ERROR_SUCCESS) #else if (rlen < 1) #endif return getaddrinfo(node, service, hints, res); #ifndef WIN32 /* fallback in case we cannot parse the response */ if (ns_initparse(resp, rlen, &nsb) < 0) return getaddrinfo(node, service, hints, res); #endif /* iterate through result set -- might be incomplete */ #ifdef WIN32 for (entry = resp; entry != NULL; entry = entry->pNext) { switch (entry->wType) { case DNS_TYPE_SRV: snprintf(tgt_port, sizeof(tgt_port), "%d", entry->Data.SRV.wPort); tgt_name = entry->Data.SRV.pNameTarget; #else for (i = 0; i < ns_msg_count(nsb, ns_s_an); i++) { rc = ns_parserr(&nsb, ns_s_an, i, &rrb); if (rc < 0) continue; if (ns_rr_class(rrb) != ns_c_in) continue; switch (ns_rr_type(rrb)) { case ns_t_srv: rrlen = ns_rr_rdlen(rrb); if (rrlen < 8) /* 2+2+2 and at least 2 for host */ break; /* extract host and port */ p = ns_rr_rdata(rrb); rc = dn_expand(resp, resp+rlen, p+6, tgt_name, sizeof(tgt_name)); if (rc < 2) break; snprintf(tgt_port, sizeof(tgt_port), "%u", (unsigned int)p[4] << 8 | (unsigned int)p[5]); #endif /* resolve and add to end of list */ if (getaddrinfo(tgt_name, tgt_port, hints, ai_last) != 0) break; /* get end of list */ for (ai=*ai_last; ai != NULL; ai = ai->ai_next) ai_last = &(ai->ai_next); break; default: /* someone stupid might use CNAME */ break; } } #ifdef WIN32 /* free result set */ DnsRecordListFree(resp, DnsFreeRecordList); #endif /* fallback in case no resolution via SRV is possible */ if (ai_last == res) return getaddrinfo(node, service, hints, res); return 0; }
int dns_get_mx_list(const char *host, int port, struct mx_hostentry **he, int no_mx) { char outname[MAXDNAME]; ns_msg msg; ns_rr rr; const char *searchhost; const unsigned char *cp; unsigned char *ans; struct mx_hostentry *hosts = NULL; size_t nhosts = 0; size_t anssz; int pref; int cname_recurse; int have_mx = 0; int err; int i; res_init(); searchhost = host; cname_recurse = 0; anssz = 65536; ans = malloc(anssz); if (ans == NULL) return (1); if (no_mx) goto out; repeat: err = res_search(searchhost, ns_c_in, ns_t_mx, ans, anssz); if (err < 0) { switch (h_errno) { case NO_DATA: /* * Host exists, but no MX (or CNAME) entry. * Not an error, use host name instead. */ goto out; case TRY_AGAIN: /* transient error */ goto transerr; case NO_RECOVERY: case HOST_NOT_FOUND: default: errno = ENOENT; goto err; } } if (!ns_initparse(ans, anssz, &msg)) goto transerr; switch (ns_msg_getflag(msg, ns_f_rcode)) { case ns_r_noerror: break; case ns_r_nxdomain: goto err; default: goto transerr; } for (i = 0; i < ns_msg_count(msg, ns_s_an); i++) { if (ns_parserr(&msg, ns_s_an, i, &rr)) goto transerr; cp = ns_rr_rdata(rr); switch (ns_rr_type(rr)) { case ns_t_mx: have_mx = 1; pref = ns_get16(cp); cp += 2; err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), cp, outname, sizeof(outname)); if (err < 0) goto transerr; err = add_host(pref, outname, port, &hosts, &nhosts); if (err == -1) goto err; break; case ns_t_cname: err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), cp, outname, sizeof(outname)); if (err < 0) goto transerr; /* Prevent a CNAME loop */ if (cname_recurse++ > 10) goto err; searchhost = outname; goto repeat; default: break; } } out: err = 0; if (0) { transerr: if (nhosts == 0) err = 1; } if (0) { err: err = -1; } free(ans); if (err == 0) { if (!have_mx) { /* * If we didn't find any MX, use the hostname instead. */ err = add_host(0, host, port, &hosts, &nhosts); } else if (nhosts == 0) { /* * We did get MX, but couldn't resolve any of them * due to transient errors. */ err = 1; } } if (nhosts > 0) { qsort(hosts, nhosts, sizeof(*hosts), sort_pref); /* terminate list */ *hosts[nhosts].host = 0; } else { if (hosts != NULL) free(hosts); hosts = NULL; } *he = hosts; return (err); free(ans); if (hosts != NULL) free(hosts); return (err); }
/*! \brief Returns a MEM STACK with the requested DNS records */ PKI_MEM_STACK *URL_get_data_dns_url(URL *url, ssize_t size) { PKI_MEM_STACK *ret = NULL; #ifdef HAVE_LIBRESOLV int type = T_A; PKI_MEM *obj = NULL; if( (!url) || (!url->addr)) { return NULL; } unsigned char response[NS_PACKETSZ]; ns_msg dnsMessage; ns_rr dnsRecord; int dnsRecordSection = ns_s_an; int dns_msgCount = 0; int len = 0; // Check the Type of record if ((type = URL_get_dns_type(url->attrs)) == -1) return NULL; PKI_log_debug("DNS URI: Searching for %s (%s/%d)", url->addr, url->attrs, type); if ((len = res_search(url->addr, C_IN, type, response, sizeof(response))) < 0) { // An Error Occurred PKI_log_err("DNS URI: search failed\n"); return NULL; } if (ns_initparse(response, len, &dnsMessage) < 0) { // This should not happen if the record is correct PKI_log_err("DNS URI: can not init DNS parsing of the dnsMessage\n"); return NULL; } len = ns_msg_count(dnsMessage, dnsRecordSection); PKI_log_debug("DNS_URI: msg count ==> %d\n", len); if (len <= 0) return NULL; if((ret = PKI_STACK_MEM_new()) == NULL ) { PKI_log_debug ("DNS URI: Memory Failure"); return NULL; } for (dns_msgCount = 0; dns_msgCount < len; dns_msgCount++) { PKI_log_debug("DNS URI: Retrieving DNS record #%d",dns_msgCount); if (ns_parserr(&dnsMessage, dnsRecordSection, dns_msgCount, &dnsRecord)) { // ERROR: ns_parserr failed, let's continue to the next record PKI_log_err("DNS URI: Can not parse record %d of %d", dns_msgCount, len); continue; } PKI_log_debug("DNS URI: type = %d (req: %d)\n", ns_rr_type(dnsRecord), type); if (type == pki_ns_t_address) { switch (ns_rr_type(dnsRecord)) { case T_A: case T_AAAA: case T_CNAME: break; default: continue; } } else if (type != ns_rr_type(dnsRecord)) { PKI_log_debug("DNS URI: recived type %d is different from requested (%d)", type, ns_rr_type(dnsRecord)); // continue; } // int i = 0; int rv = 0; // int len = 0; int offset = 0; char dnsRecordName[MAXDNAME]; memset(dnsRecordName, '\x0', MAXDNAME); // Parse the different types of DNS records if ((ns_rr_type(dnsRecord) == T_A) || (ns_rr_type(dnsRecord) == T_AAAA)) { // These require Translation using IPv4/IPv6 functions int family = AF_INET; if (ns_rr_type(dnsRecord) == T_A) family = AF_INET; else family = AF_INET6; if(inet_ntop(family, ns_rr_rdata(dnsRecord), dnsRecordName, sizeof(dnsRecordName)) == NULL) { // Can not convert continue; } } else if ((ns_rr_type(dnsRecord) == T_CNAME) || (ns_rr_type(dnsRecord) == T_MX) || (ns_rr_type(dnsRecord) == T_NS)) { if (ns_rr_type(dnsRecord) == T_MX) offset = NS_INT16SZ; rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage), ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME); // ERROR, can not uncompress the names if (rv < 0) continue; } else if (ns_rr_type(dnsRecord) == T_SRV) { // This requires special handling, the format is [SHORT][SHORT][SHORT][DATA] // unsigned short *pri = (unsigned short *) ns_rr_rdata(dnsRecord); // unsigned short *weight = (unsigned short *) &(ns_rr_rdata(dnsRecord)[2]); // unsigned short *port = (unsigned short *) &(ns_rr_rdata(dnsRecord)[4]); // Shall we return the additional data too ? // printf("PRI : %d\n", *pri); // printf("WEIGHT : %d\n", ntohs(*weight)); // printf("PORT : %d\n", ntohs(*port)); offset = 6; rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage), ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME); if (rv < 0) continue; } else if (ns_rr_type(dnsRecord) == T_TXT) { // Special handling required. Format is [BYTE][DATA] unsigned char *p = (unsigned char *)ns_rr_rdata(dnsRecord); snprintf(dnsRecordName, (size_t) *p+1, "%s", &ns_rr_rdata(dnsRecord)[1]); } else { PKI_log_debug("DNS URI: record type not supported [%d]", ns_rr_type(dnsRecord)); continue; } if((obj = PKI_MEM_new_null()) == NULL ) { // Memory Allocation Error, we abort break; } if (strlen(dnsRecordName) > 0) { // If it is a printable value, we add the parsed version of the // record if(PKI_MEM_add(obj, (char *) dnsRecordName, strlen(dnsRecordName)) == PKI_ERR) { /* ERROR in memory growth */; PKI_log_err("DNS URI: Memory Allocation Error"); break; } } else { // The value is not parsed/parsable, we return the raw data // the application should know what to do with the data! if(PKI_MEM_add(obj, (char *) ns_rr_rdata(dnsRecord), ns_rr_rdlen(dnsRecord)) == PKI_ERR) { /* ERROR in memory growth */; PKI_log_err("DNS URI: Memory Allocation Error"); break; } } /* printf("MSG Data [%d]:\n", ns_rr_rdlen(dnsRecord)); for (i=0; i < ns_rr_rdlen(dnsRecord); i++) { unsigned char *kk; kk = (unsigned char *) &ns_rr_rdata(dnsRecord)[i]; printf("%x:", *kk); }; printf("\n"); fprintf(stderr, "DEBUG: RV => %d (err: %d, %s)\n", rv, h_errno, hstrerror(h_errno)); fprintf(stderr, "DEBUG: name => %s (%s)\n", ns_rr_name(dnsRecord), url->addr); fprintf(stderr, "DEBUG: value => %s\n", dnsRecordName); fprintf(stderr, "DEBUG: type => %d\n", ns_rr_type(dnsRecord)); fprintf(stderr, "DEBUG: class => %d\n", ns_rr_class(dnsRecord)); */ PKI_STACK_MEM_push(ret, obj); // PKI_log_debug("DNS URI: Added object #%d to stack", PKI_STACK_MEM_elements(ret)); } #endif return ret; };
/* * Fill out host list, based on DNS lookups. * This is not reentrant. Better be called before any other threads * are started. */ int cldc_getaddr(GList **host_list, const char *thishost, struct hail_log *log) { enum { hostsz = 64 }; char cldb[hostsz]; unsigned char resp[512]; int rlen; ns_msg nsb; ns_rr rrb; int rrlen; char hostb[hostsz]; int i; struct cldc_host hp; const unsigned char *p; int rc; int search_retries = 10; /* * We must create FQDN or else the first thing the resolver does * is a lookup in the DNS root (probably the standard-compliant * dot between "_cld" and "_udp" hurts us here). */ if (cldc_make_fqdn(cldb, hostsz, "_cld._udp", thishost) != 0) { HAIL_INFO(log, "internal error in cldc_make_fqdn(%s)", thishost); return -1; } do_try_again: rc = res_search(cldb, ns_c_in, ns_t_srv, resp, 512); if (rc < 0) { switch (h_errno) { case HOST_NOT_FOUND: HAIL_INFO(log, "%s: No _cld._udp SRV record", __func__); return -1; case NO_DATA: HAIL_INFO(log, "%s: Cannot find _cld._udp" " SRV record", __func__); return -1; case TRY_AGAIN: if (search_retries-- > 0) goto do_try_again; /* fall through */ case NO_RECOVERY: default: HAIL_ERR(log, "%s: res_search error (%d): %s", __func__, h_errno, hstrerror(h_errno)); return -1; } } rlen = rc; if (rlen == 0) { HAIL_INFO(log, "%s: res_search returned empty reply", __func__); return -1; } if (ns_initparse(resp, rlen, &nsb) < 0) { HAIL_ERR(log, "%s: ns_initparse error", __func__); return -1; } for (i = 0; i < ns_msg_count(nsb, ns_s_an); i++) { rc = ns_parserr(&nsb, ns_s_an, i, &rrb); if (rc < 0) continue; if (ns_rr_class(rrb) != ns_c_in) continue; memset(&hp, 0, sizeof(hp)); switch (ns_rr_type(rrb)) { case ns_t_srv: rrlen = ns_rr_rdlen(rrb); if (rrlen < 8) { /* 2+2+2 and 2 for host */ HAIL_DEBUG(log, "%s: SRV len %d", __func__, rrlen); break; } p = ns_rr_rdata(rrb); rc = dn_expand(resp, resp+rlen, p+6, hostb, hostsz); if (rc < 0) { HAIL_DEBUG(log, "%s: dn_expand error %d", __func__, rc); break; } if (rc < 2) { HAIL_DEBUG(log, "%s: dn_expand short %d", __func__, rc); break; } if (cldc_saveaddr(&hp, ns_get16(p+0), ns_get16(p+2), ns_get16(p+4), rc, hostb, NULL)) break; HAIL_DEBUG(log, "%s: found CLD host %s port %u" " prio %d weight %d", __func__, hp.host, hp.port, hp.prio, hp.weight); push_host(host_list, &hp); break; case ns_t_cname: /* impossible, but */ HAIL_DEBUG(log, "%s: CNAME in SRV request, ignored", __func__); break; default: ; } } return 0; }
void dowse_output(const char *descr, iaddr from, iaddr to, uint8_t proto, int isfrag, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char *pkt_copy, unsigned olen, const u_char *dnspkt, unsigned dnslen) { /* dnspkt may be NULL if IP packet does not contain a valid DNS message */ char output[MAX_OUTPUT]; if (dnspkt) { ns_msg msg; int qdcount; ns_rr rr; int *val; char *sval; char *extracted; char *resolved; char *from; int res; char action = 'A'; char from_color[16]; ns_initparse(dnspkt, dnslen, &msg); if (!ns_msg_getflag(msg, ns_f_qr)) return; /* * -- flags -- * 0 1 5 6 7 8 11 15 * +----+----------------+----+----+----+-----------+----------------+ * | QR | Operation Code | AA | TC | RA | Zero | Recode | * +----+----------------+----+----+----+-----------+----------------+ * * Question/Response : ns_f_qr * Operation code : ns_f_opcode * Authoritative Answer : ns_f_aa * Truncation occurred : ns_f_tc * Recursion Desired : ns_f_rd * Recursion Available : ns_f_ra * MBZ : ns_f_z * Authentic Data (DNSSEC) : ns_f_ad * Checking Disabled (DNSSEC) : ns_f_cd * Response code : ns_f_rcode */ // logerr("msg: %p",msg); qdcount = ns_msg_count(msg, ns_s_qd); if (qdcount > 0 && 0 == ns_parserr(&msg, ns_s_qd, 0, &rr)) { // where the query comes from from = ia_resolv(to); // if its from ourselves omit it if(strncmp(from,hostname,MAX_DOMAIN)==0) return; if(own_ipv4) if(strncmp(from,own_ipv4,MAX_DOMAIN)==0) return; // not reverse resolved means not known by Dowse, code RED if(is_ip(from)) strcpy(from_color,"#FF0000"); resolved = ns_rr_name(rr); // what domain is being looked up extracted = extract_domain(resolved); res = hashmap_get(visited, extracted, (void**)(&val)); switch(res) { // TODO: fix malloc and strdup here as they grow as a leak on long term case MAP_MISSING : // never visited /* ==13150== 992 bytes in 248 blocks are definitely lost in loss record 45 of 49 */ /* ==13150== at 0x4C28C20: malloc (vg_replace_malloc.c:296) */ /* ==13150== by 0x5C3D326: dowse_output (dowse.c:417) */ /* ==13150== by 0x404CAB: output (dnscap.c:2201) */ /* ==13150== by 0x406779: network_pkt (dnscap.c:2164) */ /* ==13150== by 0x407065: dl_pkt (dnscap.c:1608) */ /* ==13150== by 0x503F5E9: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.6.2) */ /* ==13150== by 0x5043783: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.6.2) */ /* ==13150== by 0x4037E0: poll_pcaps (dnscap.c:1344) */ /* ==13150== by 0x4037E0: main (dnscap.c:406) */ val = malloc(sizeof(int)); *val = 1; // just a placeholder for now /* ==13150== 3,069 bytes in 248 blocks are definitely lost in loss record 47 of 49 */ /* ==13150== at 0x4C28C20: malloc (vg_replace_malloc.c:296) */ /* ==13150== by 0x5511A69: strdup (strdup.c:42) */ /* ==13150== by 0x5C3D34D: dowse_output (dowse.c:419) */ /* ==13150== by 0x404CAB: output (dnscap.c:2201) */ /* ==13150== by 0x406779: network_pkt (dnscap.c:2164) */ /* ==13150== by 0x407065: dl_pkt (dnscap.c:1608) */ /* ==13150== by 0x503F5E9: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.6.2) */ /* ==13150== by 0x5043783: ??? (in /usr/lib/x86_64-linux-gnu/libpcap.so.1.6.2) */ /* ==13150== by 0x4037E0: poll_pcaps (dnscap.c:1344) */ /* ==13150== by 0x4037E0: main (dnscap.c:406) */ res = hashmap_put(visited, strdup(extracted), val); break; case MAP_OK: // already visited action = 'M'; break; // TODO error checks case MAP_FULL: case MAP_OMEM: break; } // compose the path of the detected query // add category if listed if(listpath) { // add known domain list information res = hashmap_get(domainlist, extracted, (void**)(&sval)); switch(res) { case MAP_OK: /* render with the category in front of domain */ snprintf(output,MAX_OUTPUT,"%lu|%s|%c|%s/%s/%s", ts2epoch(&ts,NULL), // from our epoch.c from, action, tld, sval, extracted); break; default: /* render only the domain in root category */ snprintf(output,MAX_OUTPUT,"%lu|%s|%c|%s/%s", ts2epoch(&ts,NULL), // from our epoch.c from, action, tld, extracted); break; } } else /* render only the domain in root category */ snprintf(output,MAX_OUTPUT,"%lu|%s|%c|%s/%s", ts2epoch(&ts,NULL), // from our epoch.c from, action, tld, extracted); /* write to file */ if(fileout) { fputs(output, fileout); fputc('\n',fileout); if(fileout) fflush(fileout); } /* print fast on console for realtime */ if(console) { puts(output); fflush(stdout); } if(redis) { rreply = redisCommand(redis, "PUBLISH dns-query-channel %s", output); logerr("PUBLISH dns-query-channel: %s\n", rreply->str); freeReplyObject(rreply); } } } }
/* Returns 1 with an answer, 0 when reply was old, -1 on fatal errors */ int nb_dns_activity(struct nb_dns_info *nd, struct nb_dns_result *nr, char *errstr) { register int msglen, qtype, atype, n, i; register struct nb_dns_entry *ne, *lastne; socklen_t fromlen; struct sockaddr from; u_long msg[MAXPACKET / sizeof(u_long)]; register char *bp, *ep; register char **ap, **hap; register u_int16_t id; register const u_char *rdata; register u_int32_t rttl = 0; // make compiler happy. register struct hostent *he; register size_t rdlen; ns_msg handle; ns_rr rr; /* This comes from the second half of do_query() */ fromlen = sizeof(from); msglen = recvfrom(nd->s, (char *)msg, sizeof(msg), 0, &from, &fromlen); if (msglen <= 0) { snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): %s", my_strerror(errno)); return (-1); } if (msglen < HFIXEDSZ) { snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): undersized: %d", msglen); return (-1); } if (ns_initparse((u_char *)msg, msglen, &handle) < 0) { snprintf(errstr, NB_DNS_ERRSIZE, "ns_initparse(): %s", my_strerror(errno)); nr->host_errno = NO_RECOVERY; return (-1); } /* RES_INSECURE1 style check */ if (_nb_dns_cmpsockaddr((struct sockaddr *)&nd->server, &from, errstr) < 0) { nr->host_errno = NO_RECOVERY; return (-1); } /* Search for this request */ lastne = NULL; id = ns_msg_id(handle); for (ne = nd->list; ne != NULL; ne = ne->next) { if (ne->id == id) break; lastne = ne; } /* Not an answer to a question we care about anymore */ if (ne == NULL) return (0); /* Unlink this entry */ if (lastne == NULL) nd->list = ne->next; else lastne->next = ne->next; ne->next = NULL; /* RES_INSECURE2 style check */ /* XXX not implemented */ /* Initialize result struct */ memset(nr, 0, sizeof(*nr)); nr->cookie = ne->cookie; qtype = ne->qtype; /* Deal with various errors */ switch (ns_msg_getflag(handle, ns_f_rcode)) { case ns_r_nxdomain: nr->host_errno = HOST_NOT_FOUND; free(ne); return (1); case ns_r_servfail: nr->host_errno = TRY_AGAIN; free(ne); return (1); case ns_r_noerror: break; case ns_r_formerr: case ns_r_notimpl: case ns_r_refused: default: nr->host_errno = NO_RECOVERY; free(ne); return (1); } /* Loop through records in packet */ memset(&rr, 0, sizeof(rr)); memset(&nd->dns_hostent, 0, sizeof(nd->dns_hostent)); he = &nd->dns_hostent.hostent; /* XXX no support for aliases */ he->h_aliases = nd->dns_hostent.host_aliases; he->h_addr_list = nd->dns_hostent.h_addr_ptrs; he->h_addrtype = ne->atype; he->h_length = ne->asize; free(ne); bp = nd->dns_hostent.hostbuf; ep = bp + sizeof(nd->dns_hostent.hostbuf); hap = he->h_addr_list; ap = he->h_aliases; for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) { /* Parse next record */ if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) { if (errno != ENODEV) { nr->host_errno = NO_RECOVERY; return (1); } /* All done */ break; } /* Ignore records that don't answer our query (e.g. CNAMEs) */ atype = ns_rr_type(rr); if (atype != qtype) continue; rdata = ns_rr_rdata(rr); rdlen = ns_rr_rdlen(rr); rttl = ns_rr_ttl(rr); switch (atype) { case T_A: case T_AAAA: if (rdlen != (unsigned int) he->h_length) { snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_activity(): bad rdlen %d", (int) rdlen); nr->host_errno = NO_RECOVERY; return (-1); } if (bp + rdlen >= ep) { snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_activity(): overflow 1"); nr->host_errno = NO_RECOVERY; return (-1); } if (nd->dns_hostent.numaddrs + 1 >= MAXADDRS) { snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_activity(): overflow 2"); nr->host_errno = NO_RECOVERY; return (-1); } memcpy(bp, rdata, rdlen); *hap++ = bp; bp += rdlen; ++nd->dns_hostent.numaddrs; /* Keep looking for more A records */ break; case T_TXT: if (bp + rdlen >= ep) { snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_activity(): overflow 1 for txt"); nr->host_errno = NO_RECOVERY; return (-1); } memcpy(bp, rdata, rdlen); he->h_name = bp+1; /* First char is a control character. */ nr->hostent = he; nr->ttl = rttl; return (1); case T_PTR: n = dn_expand((const u_char *)msg, (const u_char *)msg + msglen, rdata, bp, ep - bp); if (n < 0) { /* XXX return -1 here ??? */ nr->host_errno = NO_RECOVERY; return (1); } he->h_name = bp; /* XXX check for overflow */ bp += n; /* returned len includes EOS */ /* "Find first satisfactory answer" */ nr->hostent = he; nr->ttl = rttl; return (1); } } nr->hostent = he; nr->ttl = rttl; return (1); }