]> mj.ucw.cz Git - pciutils.git/blobdiff - lib/names-net.c
lspci: Decode Precision Time Measurement capabiltity
[pciutils.git] / lib / names-net.c
index 335bf682212495d1da20b35b1850ac6d5bb1a91f..dfac7850dfbcff9b10f421d091d62b94268e8dd1 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <string.h>
 #include <stdlib.h>
 
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
 
 #include "internal.h"
 #include "names.h"
 
 #include "internal.h"
 #include "names.h"
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
+#include <netdb.h>
+
+/*
+ * Unfortunately, there are no portable functions for DNS RR parsing,
+ * so we will do the bit shuffling with our own bare hands.
+ */
+
+#define GET16(x) do { if (p+2 > end) goto err; x = (p[0] << 8) | p[1]; p += 2; } while (0)
+#define GET32(x) do { if (p+4 > end) goto err; x = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; p += 4; } while (0)
+
+enum dns_section {
+  DNS_SEC_QUESTION,
+  DNS_SEC_ANSWER,
+  DNS_SEC_AUTHORITY,
+  DNS_SEC_ADDITIONAL,
+  DNS_NUM_SECTIONS
+};
+
+struct dns_state {
+  u16 counts[DNS_NUM_SECTIONS];
+  byte *sections[DNS_NUM_SECTIONS+1];
+  byte *sec_ptr, *sec_end;
+
+  /* Result of dns_parse_rr(): */
+  u16 rr_type;
+  u16 rr_class;
+  u32 rr_ttl;
+  u16 rr_len;
+  byte *rr_data;
+};
+
+static byte *
+dns_skip_name(byte *p, byte *end)
+{
+  while (p < end)
+    {
+      unsigned int x = *p++;
+      if (!x)
+       return p;
+      switch (x & 0xc0)
+       {
+       case 0:         /* Uncompressed: x = length */
+         p += x;
+         break;
+       case 0xc0:      /* Indirection: 1 byte more for offset */
+         p++;
+         return (p < end) ? p : NULL;
+       default:        /* RFU */
+         return NULL;
+       }
+    }
+  return NULL;
+}
+
+static int
+dns_parse_packet(struct dns_state *s, byte *p, unsigned int plen)
+{
+  byte *end = p + plen;
+  unsigned int i, j, len;
+  unsigned int UNUSED x;
+
+#if 0
+  /* Dump the packet */
+  for (i=0; i<plen; i++)
+    {
+      if (!(i%16)) printf("%04x:", i);
+      printf(" %02x", p[i]);
+      if ((i%16)==15 || i==plen-1) putchar('\n');
+    }
+#endif
+
+  GET32(x);                            /* ID and flags are ignored */
+  for (i=0; i<DNS_NUM_SECTIONS; i++)
+    GET16(s->counts[i]);
+  for (i=0; i<DNS_NUM_SECTIONS; i++)
+    {
+      s->sections[i] = p;
+      for (j=0; j < s->counts[i]; j++)
+       {
+         p = dns_skip_name(p, end);    /* Name */
+         if (!p)
+           goto err;
+         GET32(x);                     /* Type and class */
+         if (i != DNS_SEC_QUESTION)
+           {
+             GET32(x);                 /* TTL */
+             GET16(len);               /* Length of data */
+             p += len;
+             if (p > end)
+               goto err;
+           }
+       }
+    }
+  s->sections[i] = p;
+  return 0;
+
+err:
+  return -1;
+}
+
+static void
+dns_init_section(struct dns_state *s, int i)
+{
+  s->sec_ptr = s->sections[i];
+  s->sec_end = s->sections[i+1];
+}
+
+static int
+dns_parse_rr(struct dns_state *s)
+{
+  byte *p = s->sec_ptr;
+  byte *end = s->sec_end;
+
+  if (p == end)
+    return 0;
+  p = dns_skip_name(p, end);
+  if (!p)
+    goto err;
+  GET16(s->rr_type);
+  GET16(s->rr_class);
+  GET32(s->rr_ttl);
+  GET16(s->rr_len);
+  s->rr_data = p;
+  s->sec_ptr = p + s->rr_len;
+  return 1;
+
+err:
+  return -1;
+}
 
 char
 *pci_id_net_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4)
 {
 
 char
 *pci_id_net_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4)
 {
+  static int resolver_inited;
   char name[256], dnsname[256], txt[256], *domain;
   byte answer[4096];
   const byte *data;
   char name[256], dnsname[256], txt[256], *domain;
   byte answer[4096];
   const byte *data;
-  int res, i, j, dlen;
-  ns_msg m;
-  ns_rr rr;
+  int res, j, dlen;
+  struct dns_state ds;
 
   domain = pci_get_param(a, "net.domain");
   if (!domain || !domain[0])
 
   domain = pci_get_param(a, "net.domain");
   if (!domain || !domain[0])
@@ -61,32 +191,39 @@ char
   sprintf(dnsname, "%s.%s", name, domain);
 
   a->debug("Resolving %s\n", dnsname);
   sprintf(dnsname, "%s.%s", name, domain);
 
   a->debug("Resolving %s\n", dnsname);
-  res_init();
+  if (!resolver_inited)
+    {
+      resolver_inited = 1;
+      res_init();
+    }
   res = res_query(dnsname, ns_c_in, ns_t_txt, answer, sizeof(answer));
   if (res < 0)
     {
   res = res_query(dnsname, ns_c_in, ns_t_txt, answer, sizeof(answer));
   if (res < 0)
     {
-      a->debug("\tfailed, h_errno=%d\n", _res.res_h_errno);
+      a->debug("\tfailed, h_errno=%d\n", h_errno);
       return NULL;
     }
       return NULL;
     }
-  if (ns_initparse(answer, res, &m) < 0)
+  if (dns_parse_packet(&ds, answer, res) < 0)
     {
     {
-      a->debug("\tinitparse failed\n");
+      a->debug("\tMalformed DNS packet received\n");
       return NULL;
     }
       return NULL;
     }
-  for (i=0; ns_parserr(&m, ns_s_an, i, &rr) >= 0; i++)
+  dns_init_section(&ds, DNS_SEC_ANSWER);
+  while (dns_parse_rr(&ds) > 0)
     {
     {
-      a->debug("\tanswer %d (class %d, type %d)\n", i, ns_rr_class(rr), ns_rr_type(rr));
-      if (ns_rr_class(rr) != ns_c_in || ns_rr_type(rr) != ns_t_txt)
-       continue;
-      data = ns_rr_rdata(rr);
-      dlen = ns_rr_rdlen(rr);
+      if (ds.rr_class != ns_c_in || ds.rr_type != ns_t_txt)
+       {
+         a->debug("\tUnexpected RR in answer: class %d, type %d\n", ds.rr_class, ds.rr_type);
+         continue;
+       }
+      data = ds.rr_data;
+      dlen = ds.rr_len;
       j = 0;
       while (j < dlen && j+1+data[j] <= dlen)
        {
          memcpy(txt, &data[j+1], data[j]);
          txt[data[j]] = 0;
          j += 1+data[j];
       j = 0;
       while (j < dlen && j+1+data[j] <= dlen)
        {
          memcpy(txt, &data[j+1], data[j]);
          txt[data[j]] = 0;
          j += 1+data[j];
-         a->debug("\t\t%s\n", txt);
+         a->debug("\t\"%s\"\n", txt);
          if (txt[0] == 'i' && txt[1] == '=')
            return strdup(txt+2);
        }
          if (txt[0] == 'i' && txt[1] == '=')
            return strdup(txt+2);
        }