]> git.ipfire.org Git - thirdparty/squid.git/blame - src/dns/rfc3596.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / dns / rfc3596.cc
CommitLineData
0710cbcd 1/*
77b1029d 2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
0710cbcd 3 *
0545caaa
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
0710cbcd 7 */
8
f7f3304a 9#include "squid.h"
4a3b98d7
AJ
10#include "dns/rfc2671.h"
11#include "dns/rfc3596.h"
0710cbcd 12#include "util.h"
13
0710cbcd 14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
0710cbcd 17#if HAVE_MEMORY_H
18#include <memory.h>
19#endif
0710cbcd 20#if HAVE_ASSERT_H
21#include <assert.h>
22#endif
23#if HAVE_NETINET_IN_H
24#include <netinet/in.h>
25#endif
26#if HAVE_STRINGS_H
27#include <strings.h>
28#endif
29
0710cbcd 30#ifndef SQUID_RFC1035_H
31#error RFC3596 Library depends on RFC1035
32#endif
33
0545caaa
AJ
34/*
35 * Low level DNS protocol routines
36 *
37 * Provides RFC3596 functions to handle purely IPv6 DNS.
38 * Adds AAAA and IPv6 PTR records.
39 * Other IPv6 records are not mentioned by this RFC.
40 *
41 * IPv4 equivalents are taken care of by the RFC1035 library.
42 * Where one protocol lookup must be followed by another, the caller
43 * is resposible for the order and handling of the lookups.
44 *
45 * KNOWN BUGS:
46 *
47 * UDP replies with TC set should be retried via TCP
48 */
49
0710cbcd 50/**
51 * Builds a message buffer with a QUESTION to lookup records
52 * for a hostname. Caller must allocate 'buf' which should
53 * probably be at least 512 octets. The 'szp' initially
54 * specifies the size of the buffer, on return it contains
55 * the size of the message (i.e. how much to write).
56 * Returns the size of the query
57 */
58ssize_t
e210930b 59rfc3596BuildHostQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, int qtype, ssize_t edns_sz)
0710cbcd 60{
61 static rfc1035_message h;
62 size_t offset = 0;
63 memset(&h, '\0', sizeof(h));
64 h.id = qid;
65 h.qr = 0;
66 h.rd = 1;
67 h.opcode = 0; /* QUERY */
68 h.qdcount = (unsigned int) 1;
e210930b 69 h.arcount = (edns_sz > 0 ? 1 : 0);
0710cbcd 70 offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
71 offset += rfc1035QuestionPack(buf + offset,
72 sz - offset,
73 hostname,
74 qtype,
75 RFC1035_CLASS_IN);
e210930b
AJ
76 if (edns_sz > 0)
77 offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
0710cbcd 78
79 if (query) {
80 query->qtype = qtype;
81 query->qclass = RFC1035_CLASS_IN;
82 xstrncpy(query->name, hostname, sizeof(query->name));
83 }
84
85 assert(offset <= sz);
86 return offset;
87}
88
89/**
90 * Builds a message buffer with a QUESTION to lookup A records
91 * for a hostname. Caller must allocate 'buf' which should
92 * probably be at least 512 octets. The 'szp' initially
93 * specifies the size of the buffer, on return it contains
94 * the size of the message (i.e. how much to write).
95 * \return the size of the query
96 */
97ssize_t
e210930b 98rfc3596BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
0710cbcd 99{
e210930b 100 return rfc3596BuildHostQuery(hostname, buf, sz, qid, query, RFC1035_TYPE_A, edns_sz);
0710cbcd 101}
102
103/**
104 * Builds a message buffer with a QUESTION to lookup AAAA records
105 * for a hostname. Caller must allocate 'buf' which should
106 * probably be at least 512 octets. The 'szp' initially
107 * specifies the size of the buffer, on return it contains
108 * the size of the message (i.e. how much to write).
109 * \return the size of the query
110 */
111ssize_t
e210930b 112rfc3596BuildAAAAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
0710cbcd 113{
e210930b 114 return rfc3596BuildHostQuery(hostname, buf, sz, qid, query, RFC1035_TYPE_AAAA, edns_sz);
0710cbcd 115}
116
0710cbcd 117/**
118 * Builds a message buffer with a QUESTION to lookup PTR records
119 * for an address. Caller must allocate 'buf' which should
120 * probably be at least 512 octets. The 'szp' initially
121 * specifies the size of the buffer, on return it contains
122 * the size of the message (i.e. how much to write).
123 * \return the size of the query
124 */
125ssize_t
e210930b 126rfc3596BuildPTRQuery4(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
0710cbcd 127{
128 static char rev[RFC1035_MAXHOSTNAMESZ];
129 unsigned int i;
130
131 i = (unsigned int) ntohl(addr.s_addr);
132 snprintf(rev, RFC1035_MAXHOSTNAMESZ, "%u.%u.%u.%u.in-addr.arpa.",
133 i & 255,
134 (i >> 8) & 255,
135 (i >> 16) & 255,
136 (i >> 24) & 255);
137
e210930b 138 return rfc3596BuildHostQuery(rev, buf, sz, qid, query, RFC1035_TYPE_PTR, edns_sz);
0710cbcd 139}
140
141ssize_t
e210930b 142rfc3596BuildPTRQuery6(const struct in6_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
0710cbcd 143{
144 static char rev[RFC1035_MAXHOSTNAMESZ];
145 const uint8_t* r = addr.s6_addr;
146 char* p = rev;
b8031529 147 int i; /* NP: MUST allow signed for loop termination. */
0710cbcd 148
149 /* work from the raw addr field. anything else may have representation changes. */
150 /* The sin6_port and sin6_addr members shall be in network byte order. */
26ac0430 151 for (i = 15; i >= 0; i--, p+=4) {
5c4e391c 152 snprintf(p, 5, "%1x.%1x.", ((r[i])&0xf), (r[i]>>4)&0xf );
0710cbcd 153 }
154
155 snprintf(p,10,"ip6.arpa.");
156
e210930b 157 return rfc3596BuildHostQuery(rev, buf, sz, qid, query, RFC1035_TYPE_PTR, edns_sz);
0710cbcd 158}
159
0710cbcd 160#if DRIVER
161
162/* driver needs the rfc1035 code _without_ the main() */
163# define main(a,b) rfc1035_main(a,b)
164# include "rfc1035.c"
165# undef main(a,b)
166
167#include <sys/socket.h>
0710cbcd 168
169int
170main(int argc, char *argv[])
171{
f53969cc 172#define PACKET_BUFSZ 1024
e210930b
AJ
173 char input[PACKET_BUFSZ];
174 char buf[PACKET_BUFSZ];
175 char rbuf[PACKET_BUFSZ];
176 size_t sz = PACKET_BUFSZ;
0710cbcd 177 unsigned short sid, sidb;
178 int s;
179 int rl;
e210930b 180 ssize_t edns_max = -1;
0710cbcd 181
182 struct sockaddr* S;
183 int var = 1;
184
185 if ( argc < 3 || argc > 4) {
186 fprintf(stderr, "usage: %s [-6|-4] ip port\n", argv[0]);
24885773 187 exit(EXIT_FAILURE);
0710cbcd 188 }
189
190 setbuf(stdout, NULL);
191 setbuf(stderr, NULL);
192
26ac0430
AJ
193 if (argv[var][0] == '-') {
194 if (argv[var][1] == '4')
0710cbcd 195 prefer = AF_INET;
26ac0430 196 else if (argv[var][1] == '6')
0710cbcd 197 prefer = AF_INET6;
e210930b
AJ
198 else if (argv[var][1] == 'E')
199 edns_max = atoi(argv[var++]);
0710cbcd 200 else {
e210930b
AJ
201 fprintf(stderr, "usage: %s [-6|-4] [-E packet-size] ip port\n", argv[0]);
202 fprintf(stderr, " EDNS packets my be up to %d\n", PACKET_BUFSZ);
24885773 203 exit(EXIT_FAILURE);
0710cbcd 204 }
205
206 var++;
207 }
208
209 s = socket(PF_INET, SOCK_DGRAM, 0);
210
211 if (s < 0) {
212 perror("socket");
24885773 213 exit(EXIT_FAILURE);
0710cbcd 214 }
215
0710cbcd 216 memset(&S, '\0', sizeof(S));
217
26ac0430 218 if (prefer == 6) {
0710cbcd 219 S = (struct sockaddr *) new sockaddr_in6;
220 memset(S,0,sizeof(struct sockaddr_in6));
221
222 ((struct sockaddr_in6 *)S)->sin6_family = AF_INET6;
223 ((struct sockaddr_in6 *)S)->sin6_port = htons(atoi(argv[var+1]));
224
e210930b 225 if ( ! inet_pton(AF_INET6, argv[var], &((struct sockaddr_in6 *)S)->sin6_addr.s_addr) ) {
0710cbcd 226 perror("listen address");
24885773 227 exit(EXIT_FAILURE);
24520b1b 228 }
0710cbcd 229
24520b1b
AJ
230 s = socket(PF_INET6, SOCK_DGRAM, 0);
231 } else {
232 S = (struct sockaddr *) new sockaddr_in;
233 memset(S,0,sizeof(struct sockaddr_in));
0710cbcd 234
24520b1b
AJ
235 ((struct sockaddr_in *)S)->sin_family = AF_INET;
236 ((struct sockaddr_in *)S)->sin_port = htons(atoi(argv[var+1]));
0710cbcd 237
24885773 238 if ( ! inet_pton(AF_INET, argv[var], &((struct sockaddr_in *)S)->sin_addr.s_addr) ) {
24520b1b 239 perror("listen address");
52af54dd
SM
240 exit(EXIT_FAILURE);
241 }
24520b1b 242 }
0710cbcd 243
52af54dd
SM
244 while (fgets(input, PACKET_BUFSZ, stdin))
245 {
0710cbcd 246
52af54dd 247 struct in6_addr junk6;
0710cbcd 248
52af54dd
SM
249 struct in_addr junk4;
250 strtok(input, "\r\n");
251 memset(buf, '\0', PACKET_BUFSZ);
252 sz = PACKET_BUFSZ;
0710cbcd 253
52af54dd
SM
254 if (inet_pton(AF_INET6, input, &junk6)) {
255 sid = rfc1035BuildPTRQuery6(junk6, buf, &sz, edns_max);
256 sidb=0;
257 } else if (inet_pton(AF_INET, input, &junk4)) {
258 sid = rfc1035BuildPTRQuery4(junk4, buf, &sz, edns_max);
259 sidb=0;
260 } else {
261 sid = rfc1035BuildAAAAQuery(input, buf, &sz, edns_max);
262 sidb = rfc1035BuildAQuery(input, buf, &sz, edns_max);
263 }
0710cbcd 264
52af54dd 265 sendto(s, buf, sz, 0, S, sizeof(*S));
0710cbcd 266
52af54dd
SM
267 do {
268 fd_set R;
0710cbcd 269
52af54dd
SM
270 struct timeval to;
271 FD_ZERO(&R);
272 FD_SET(s, &R);
273 to.tv_sec = 10;
274 to.tv_usec = 0;
275 rl = select(s + 1, &R, NULL, NULL, &to);
276 } while (0);
0710cbcd 277
52af54dd
SM
278 if (rl < 1) {
279 printf("TIMEOUT\n");
280 continue;
281 }
0710cbcd 282
52af54dd
SM
283 memset(rbuf, '\0', PACKET_BUFSZ);
284 rl = recv(s, rbuf, PACKET_BUFSZ, 0);
285 {
286 unsigned short rid = 0;
287 int i;
288 int n;
289 rfc1035_rr *answers = NULL;
290 n = rfc1035AnswersUnpack(rbuf,
291 rl,
292 &answers,
293 &rid);
294
295 if (n < 0) {
296 printf("ERROR %d\n", -n);
297 } else if (rid != sid && rid != sidb) {
298 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
299 printf("ERROR, ID mismatch (%#hx, %#hx)\n", sidb, rid);
300 } else {
301 printf("%d answers\n", n);
302
303 for (i = 0; i < n; i++) {
304 if (answers[i].type == RFC1035_TYPE_A) {
305
306 struct in_addr a;
307 char tmp[16];
308 memcpy(&a, answers[i].rdata, 4);
309 printf("A\t%d\t%s\n", answers[i].ttl, inet_ntop(AF_INET,&a,tmp,16));
310 } else if (answers[i].type == RFC1035_TYPE_AAAA) {
311
312 struct in6_addr a;
313 char tmp[INET6_ADDRSTRLEN];
314 memcpy(&a, answers[i].rdata, 16);
315 printf("AAAA\t%d\t%s\n", answers[i].ttl, inet_ntop(AF_INET6,&a,tmp,sizeof(tmp)));
316 } else if (answers[i].type == RFC1035_TYPE_PTR) {
317 char ptr[RFC1035_MAXHOSTNAMESZ];
318 strncpy(ptr, answers[i].rdata, answers[i].rdlength);
319 printf("PTR\t%d\t%s\n", answers[i].ttl, ptr);
320 } else if (answers[i].type == RFC1035_TYPE_CNAME) {
321 char ptr[RFC1035_MAXHOSTNAMESZ];
322 strncpy(ptr, answers[i].rdata, answers[i].rdlength);
323 printf("CNAME\t%d\t%s\n", answers[i].ttl, ptr);
324 } else {
325 fprintf(stderr, "can't print answer type %d\n",
326 (int) answers[i].type);
327 }
0710cbcd 328 }
329 }
330 }
331 }
0710cbcd 332
52af54dd 333 return EXIT_SUCCESS;
24520b1b 334}
26ac0430 335
0710cbcd 336#endif
f53969cc 337