X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Futils_dns.c;h=80a2ee577f7213c4182a57b70e5f220d6d4d92fa;hp=2899bd4140223229a1ae45533429d186572ddd35;hb=b4c8f3f762d666742c774ab3b45815e5a416e5da;hpb=77f03c91b3074b5abd3e602002b7fc7ce28ea612 diff --git a/src/utils_dns.c b/src/utils_dns.c index 2899bd41..80a2ee57 100644 --- a/src/utils_dns.c +++ b/src/utils_dns.c @@ -45,6 +45,12 @@ #if HAVE_NETINET_IN_H # include #endif +#if HAVE_NETINET_IP6_H +# include +#endif +#if HAVE_NETINET_IP_COMPAT_H +# include +#endif #if HAVE_ARPA_INET_H # include #endif @@ -291,13 +297,18 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns off_t no = 0; unsigned char c; size_t len; - assert(ns > 0); + static int loop_detect = 0; + if (loop_detect > 2) + return 4; /* compression loop */ + if (ns <= 0) + return 4; /* probably compression loop */ do { if ((*off) >= sz) break; c = *(buf + (*off)); if (c > 191) { /* blasted compression */ + int rc; unsigned short s; off_t ptr; memcpy(&s, buf + (*off), sizeof(s)); @@ -305,18 +316,23 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns (*off) += sizeof(s); /* Sanity check */ if ((*off) >= sz) - return 1; + return 1; /* message too short */ ptr = s & 0x3FFF; /* Make sure the pointer is inside this message */ if (ptr >= sz) - return 2; - return rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no); + return 2; /* bad compression ptr */ + if (ptr < DNS_MSG_HDR_SZ) + return 2; /* bad compression ptr */ + loop_detect++; + rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no); + loop_detect--; + return rc; } else if (c > RFC1035_MAXLABELSZ) { /* * "(The 10 and 01 combinations are reserved for future use.)" */ + return 3; /* reserved label/compression flags */ break; - return 3; } else { (*off)++; len = (size_t) c; @@ -324,15 +340,18 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns break; if (len > (ns - 1)) len = ns - 1; - if ((*off) + len > sz) /* message is too short */ - return 4; + if ((*off) + len > sz) + return 4; /* message is too short */ + if (no + len + 1 > ns) + return 5; /* qname would overflow name buffer */ memcpy(name + no, buf + (*off), len); (*off) += len; no += len; *(name + (no++)) = '.'; } } while (c > 0); - *(name + no - 1) = '\0'; + if (no > 0) + *(name + no - 1) = '\0'; /* make sure we didn't allow someone to overflow the name buffer */ assert(no <= ns); return 0; @@ -345,10 +364,10 @@ handle_dns(const char *buf, int len) uint16_t us; off_t offset; char *t; - int x; + int status; /* The DNS header is 12 bytes long */ - if (len < 12) + if (len < DNS_MSG_HDR_SZ) return 0; memcpy(&us, buf + 0, 2); @@ -379,11 +398,15 @@ handle_dns(const char *buf, int len) memcpy(&us, buf + 10, 2); qh.arcount = ntohs(us); - offset = 12; + offset = DNS_MSG_HDR_SZ; memset(qh.qname, '\0', MAX_QNAME_SZ); - x = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ); - if (0 != x) + status = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ); + if (status != 0) + { + INFO ("utils_dns: handle_dns: rfc1035NameUnpack failed " + "with status %i.", status); return 0; + } if ('\0' == qh.qname[0]) sstrncpy (qh.qname, ".", sizeof (qh.qname)); while ((t = strchr(qh.qname, '\n'))) @@ -424,6 +447,7 @@ handle_udp(const struct udphdr *udp, int len) return 1; } +#if HAVE_NETINET_IP6_H static int handle_ipv6 (struct ip6_hdr *ipv6, int len) { @@ -492,6 +516,16 @@ handle_ipv6 (struct ip6_hdr *ipv6, int len) return (1); /* Success */ } /* int handle_ipv6 */ +/* #endif HAVE_NETINET_IP6_H */ + +#else /* if !HAVE_NETINET_IP6_H */ +static int +handle_ipv6 (__attribute__((unused)) void *pkg, + __attribute__((unused)) int len) +{ + return (0); +} +#endif /* !HAVE_NETINET_IP6_H */ static int handle_ip(const struct ip *ip, int len) @@ -502,7 +536,7 @@ handle_ip(const struct ip *ip, int len) struct in6_addr c_dst_addr; if (ip->ip_v == 6) - return (handle_ipv6 ((struct ip6_hdr *) ip, len)); + return (handle_ipv6 ((void *) ip, len)); in6_addr_from_buffer (&c_src_addr, &ip->ip_src.s_addr, sizeof (ip->ip_src.s_addr), AF_INET); in6_addr_from_buffer (&c_dst_addr, &ip->ip_dst.s_addr, sizeof (ip->ip_dst.s_addr), AF_INET); @@ -600,7 +634,7 @@ handle_ether(const u_char * pkt, int len) return 0; memcpy(buf, pkt, len); if (ETHERTYPE_IPV6 == etype) - return (handle_ipv6 ((struct ip6_hdr *) buf, len)); + return (handle_ipv6 ((void *) buf, len)); else return handle_ip((struct ip *) buf, len); } @@ -633,7 +667,7 @@ handle_linux_sll (const u_char *pkt, int len) return 0; if (ETHERTYPE_IPV6 == etype) - return (handle_ipv6 ((struct ip6_hdr *) pkt, len)); + return (handle_ipv6 ((void *) pkt, len)); else return handle_ip((struct ip *) pkt, len); } @@ -644,10 +678,6 @@ void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr, const u_char *pkt { int status; - DEBUG ("handle_pcap (udata = %p, hdr = %p, pkt = %p): hdr->caplen = %i\n", - (void *) udata, (void *) hdr, (void *) pkt, - hdr->caplen); - if (hdr->caplen < ETHER_HDR_LEN) return; @@ -681,7 +711,7 @@ void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr, const u_char *pkt break; default: - ERROR ("handle_pcap: unsupported data link type %d\n", + ERROR ("handle_pcap: unsupported data link type %d", pcap_datalink(pcap_obj)); status = 0; break;