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