1 /* Convert a DNS packet to a human-readable representation.
2 Copyright (C) 2016-2020 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <support/format_nss.h>
21 #include <arpa/inet.h>
24 #include <support/check.h>
25 #include <support/support.h>
26 #include <support/xmemstream.h>
30 const unsigned char *data
;
35 extract_8 (struct in_buffer
*in
, unsigned char *value
)
46 extract_16 (struct in_buffer
*in
, unsigned short *value
)
50 *value
= (in
->data
[0] << 8) | in
->data
[1];
57 extract_32 (struct in_buffer
*in
, unsigned *value
)
61 unsigned a
= in
->data
[0];
62 unsigned b
= in
->data
[1];
63 unsigned c
= in
->data
[2];
64 unsigned d
= in
->data
[3];
65 *value
= (a
<< 24) | (b
<< 16) | (c
<< 8) | d
;
72 extract_bytes (struct in_buffer
*in
, size_t length
, struct in_buffer
*value
)
74 if (in
->size
< length
)
76 *value
= (struct in_buffer
) {in
->data
, length
};
84 char name
[MAXDNAME
+ 1];
88 extract_name (struct in_buffer full
, struct in_buffer
*in
, struct dname
*value
)
90 const unsigned char *full_end
= full
.data
+ full
.size
;
91 /* Sanity checks; these indicate buffer misuse. */
93 (!(in
->data
< full
.data
|| in
->data
> full_end
94 || in
->size
> (size_t) (full_end
- in
->data
)));
95 int ret
= dn_expand (full
.data
, full_end
, in
->data
,
96 value
->name
, sizeof (value
->name
));
105 support_format_dns_packet (const unsigned char *buffer
, size_t length
)
107 struct in_buffer full
= { buffer
, length
};
108 struct in_buffer in
= full
;
109 struct xmemstream mem
;
110 xopen_memstream (&mem
);
112 unsigned short txnid
;
113 unsigned short flags
;
114 unsigned short qdcount
;
115 unsigned short ancount
;
116 unsigned short nscount
;
117 unsigned short adcount
;
118 if (!(extract_16 (&in
, &txnid
)
119 && extract_16 (&in
, &flags
)
120 && extract_16 (&in
, &qdcount
)
121 && extract_16 (&in
, &ancount
)
122 && extract_16 (&in
, &nscount
)
123 && extract_16 (&in
, &adcount
)))
125 fprintf (mem
.out
, "error: could not parse DNS header\n");
130 fprintf (mem
.out
, "error: question count is %d, not 1\n", qdcount
);
134 if (!extract_name (full
, &in
, &qname
))
136 fprintf (mem
.out
, "error: malformed QNAME\n");
139 unsigned short qtype
;
140 unsigned short qclass
;
141 if (!(extract_16 (&in
, &qtype
)
142 && extract_16 (&in
, &qclass
)))
144 fprintf (mem
.out
, "error: malformed question\n");
147 if (qtype
!= T_A
&& qtype
!= T_AAAA
&& qtype
!= T_PTR
)
149 fprintf (mem
.out
, "error: unsupported QTYPE %d\n", qtype
);
153 fprintf (mem
.out
, "name: %s\n", qname
.name
);
155 for (int i
= 0; i
< ancount
; ++i
)
158 if (!extract_name (full
, &in
, &rname
))
160 fprintf (mem
.out
, "error: malformed record name\n");
163 unsigned short rtype
;
164 unsigned short rclass
;
166 unsigned short rdlen
;
167 struct in_buffer rdata
;
168 if (!(extract_16 (&in
, &rtype
)
169 && extract_16 (&in
, &rclass
)
170 && extract_32 (&in
, &ttl
)
171 && extract_16 (&in
, &rdlen
)
172 && extract_bytes (&in
, rdlen
, &rdata
)))
174 fprintf (mem
.out
, "error: malformed record header\n");
177 /* Skip non-matching record types. */
178 if ((rtype
!= qtype
&& rtype
!= T_CNAME
) || rclass
!= qclass
)
184 fprintf (mem
.out
, "address: %d.%d.%d.%d\n",
190 fprintf (mem
.out
, "error: A record of size %d: %s\n",
198 if (inet_ntop (AF_INET6
, rdata
.data
, buf
, sizeof (buf
)) == NULL
)
199 fprintf (mem
.out
, "error: AAAA record decoding failed: %m\n");
201 fprintf (mem
.out
, "address: %s\n", buf
);
204 fprintf (mem
.out
, "error: AAAA record of size %d: %s\n",
212 if (extract_name (full
, &rdata
, &name
))
213 fprintf (mem
.out
, "name: %s\n", name
.name
);
215 fprintf (mem
.out
, "error: malformed CNAME/PTR record\n");
221 xfclose_memstream (&mem
);