Annotation of embedaddon/pciutils/lib/names-net.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     The PCI Library -- Resolving ID's via DNS
                      3:  *
                      4:  *     Copyright (c) 2007--2008 Martin Mares <mj@ucw.cz>
                      5:  *
                      6:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      7:  */
                      8: 
                      9: #include <string.h>
                     10: #include <stdlib.h>
                     11: 
                     12: #include "internal.h"
                     13: #include "names.h"
                     14: 
                     15: #ifdef PCI_USE_DNS
                     16: 
                     17: #include <netinet/in.h>
                     18: #include <arpa/nameser.h>
                     19: #include <resolv.h>
                     20: #include <netdb.h>
                     21: 
                     22: /*
                     23:  * Unfortunately, there are no portable functions for DNS RR parsing,
                     24:  * so we will do the bit shuffling with our own bare hands.
                     25:  */
                     26: 
                     27: #define GET16(x) do { if (p+2 > end) goto err; x = (p[0] << 8) | p[1]; p += 2; } while (0)
                     28: #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)
                     29: 
                     30: enum dns_section {
                     31:   DNS_SEC_QUESTION,
                     32:   DNS_SEC_ANSWER,
                     33:   DNS_SEC_AUTHORITY,
                     34:   DNS_SEC_ADDITIONAL,
                     35:   DNS_NUM_SECTIONS
                     36: };
                     37: 
                     38: struct dns_state {
                     39:   u16 counts[DNS_NUM_SECTIONS];
                     40:   byte *sections[DNS_NUM_SECTIONS+1];
                     41:   byte *sec_ptr, *sec_end;
                     42: 
                     43:   /* Result of dns_parse_rr(): */
                     44:   u16 rr_type;
                     45:   u16 rr_class;
                     46:   u32 rr_ttl;
                     47:   u16 rr_len;
                     48:   byte *rr_data;
                     49: };
                     50: 
                     51: static byte *
                     52: dns_skip_name(byte *p, byte *end)
                     53: {
                     54:   while (p < end)
                     55:     {
                     56:       unsigned int x = *p++;
                     57:       if (!x)
                     58:        return p;
                     59:       switch (x & 0xc0)
                     60:        {
                     61:        case 0:         /* Uncompressed: x = length */
                     62:          p += x;
                     63:          break;
                     64:        case 0xc0:      /* Indirection: 1 byte more for offset */
                     65:          p++;
                     66:          return (p < end) ? p : NULL;
                     67:        default:        /* RFU */
                     68:          return NULL;
                     69:        }
                     70:     }
                     71:   return NULL;
                     72: }
                     73: 
                     74: static int
                     75: dns_parse_packet(struct dns_state *s, byte *p, unsigned int plen)
                     76: {
                     77:   byte *end = p + plen;
                     78:   unsigned int i, j, x, len;
                     79: 
                     80: #if 0
                     81:   /* Dump the packet */
                     82:   for (i=0; i<plen; i++)
                     83:     {
                     84:       if (!(i%16)) printf("%04x:", i);
                     85:       printf(" %02x", p[i]);
                     86:       if ((i%16)==15 || i==plen-1) putchar('\n');
                     87:     }
                     88: #endif
                     89: 
                     90:   GET32(x);                            /* ID and flags are ignored */
                     91:   for (i=0; i<DNS_NUM_SECTIONS; i++)
                     92:     GET16(s->counts[i]);
                     93:   for (i=0; i<DNS_NUM_SECTIONS; i++)
                     94:     {
                     95:       s->sections[i] = p;
                     96:       for (j=0; j < s->counts[i]; j++)
                     97:        {
                     98:          p = dns_skip_name(p, end);    /* Name */
                     99:          if (!p)
                    100:            goto err;
                    101:          GET32(x);                     /* Type and class */
                    102:          if (i != DNS_SEC_QUESTION)
                    103:            {
                    104:              GET32(x);                 /* TTL */
                    105:              GET16(len);               /* Length of data */
                    106:              p += len;
                    107:              if (p > end)
                    108:                goto err;
                    109:            }
                    110:        }
                    111:     }
                    112:   s->sections[i] = p;
                    113:   return 0;
                    114: 
                    115: err:
                    116:   return -1;
                    117: }
                    118: 
                    119: static void
                    120: dns_init_section(struct dns_state *s, int i)
                    121: {
                    122:   s->sec_ptr = s->sections[i];
                    123:   s->sec_end = s->sections[i+1];
                    124: }
                    125: 
                    126: static int
                    127: dns_parse_rr(struct dns_state *s)
                    128: {
                    129:   byte *p = s->sec_ptr;
                    130:   byte *end = s->sec_end;
                    131: 
                    132:   if (p == end)
                    133:     return 0;
                    134:   p = dns_skip_name(p, end);
                    135:   if (!p)
                    136:     goto err;
                    137:   GET16(s->rr_type);
                    138:   GET16(s->rr_class);
                    139:   GET32(s->rr_ttl);
                    140:   GET16(s->rr_len);
                    141:   s->rr_data = p;
                    142:   s->sec_ptr = p + s->rr_len;
                    143:   return 1;
                    144: 
                    145: err:
                    146:   return -1;
                    147: }
                    148: 
                    149: char
                    150: *pci_id_net_lookup(struct pci_access *a, int cat, int id1, int id2, int id3, int id4)
                    151: {
                    152:   static int resolver_inited;
                    153:   char name[256], dnsname[256], txt[256], *domain;
                    154:   byte answer[4096];
                    155:   const byte *data;
                    156:   int res, j, dlen;
                    157:   struct dns_state ds;
                    158: 
                    159:   domain = pci_get_param(a, "net.domain");
                    160:   if (!domain || !domain[0])
                    161:     return NULL;
                    162: 
                    163:   switch (cat)
                    164:     {
                    165:     case ID_VENDOR:
                    166:       sprintf(name, "%04x", id1);
                    167:       break;
                    168:     case ID_DEVICE:
                    169:       sprintf(name, "%04x.%04x", id2, id1);
                    170:       break;
                    171:     case ID_SUBSYSTEM:
                    172:       sprintf(name, "%04x.%04x.%04x.%04x", id4, id3, id2, id1);
                    173:       break;
                    174:     case ID_GEN_SUBSYSTEM:
                    175:       sprintf(name, "%04x.%04x.s", id2, id1);
                    176:       break;
                    177:     case ID_CLASS:
                    178:       sprintf(name, "%02x.c", id1);
                    179:       break;
                    180:     case ID_SUBCLASS:
                    181:       sprintf(name, "%02x.%02x.c", id2, id1);
                    182:       break;
                    183:     case ID_PROGIF:
                    184:       sprintf(name, "%02x.%02x.%02x.c", id3, id2, id1);
                    185:       break;
                    186:     default:
                    187:       return NULL;
                    188:     }
                    189:   sprintf(dnsname, "%s.%s", name, domain);
                    190: 
                    191:   a->debug("Resolving %s\n", dnsname);
                    192:   if (!resolver_inited)
                    193:     {
                    194:       resolver_inited = 1;
                    195:       res_init();
                    196:     }
                    197:   res = res_query(dnsname, ns_c_in, ns_t_txt, answer, sizeof(answer));
                    198:   if (res < 0)
                    199:     {
                    200:       a->debug("\tfailed, h_errno=%d\n", h_errno);
                    201:       return NULL;
                    202:     }
                    203:   if (dns_parse_packet(&ds, answer, res) < 0)
                    204:     {
                    205:       a->debug("\tMalformed DNS packet received\n");
                    206:       return NULL;
                    207:     }
                    208:   dns_init_section(&ds, DNS_SEC_ANSWER);
                    209:   while (dns_parse_rr(&ds) > 0)
                    210:     {
                    211:       if (ds.rr_class != ns_c_in || ds.rr_type != ns_t_txt)
                    212:        {
                    213:          a->debug("\tUnexpected RR in answer: class %d, type %d\n", ds.rr_class, ds.rr_type);
                    214:          continue;
                    215:        }
                    216:       data = ds.rr_data;
                    217:       dlen = ds.rr_len;
                    218:       j = 0;
                    219:       while (j < dlen && j+1+data[j] <= dlen)
                    220:        {
                    221:          memcpy(txt, &data[j+1], data[j]);
                    222:          txt[data[j]] = 0;
                    223:          j += 1+data[j];
                    224:          a->debug("\t\"%s\"\n", txt);
                    225:          if (txt[0] == 'i' && txt[1] == '=')
                    226:            return strdup(txt+2);
                    227:        }
                    228:     }
                    229: 
                    230:   return NULL;
                    231: }
                    232: 
                    233: #else
                    234: 
                    235: char *pci_id_net_lookup(struct pci_access *a UNUSED, int cat UNUSED, int id1 UNUSED, int id2 UNUSED, int id3 UNUSED, int id4 UNUSED)
                    236: {
                    237:   return NULL;
                    238: }
                    239: 
                    240: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>