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