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>