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