rfc3596.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3  *
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.
7  */
8 
9 #include "squid.h"
10 #include "dns/rfc2671.h"
11 #include "dns/rfc3596.h"
12 #include "util.h"
13 
14 #if HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #if HAVE_MEMORY_H
18 #include <memory.h>
19 #endif
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 
30 #ifndef SQUID_RFC1035_H
31 #error RFC3596 Library depends on RFC1035
32 #endif
33 
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 
58 ssize_t
59 rfc3596BuildHostQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, int qtype, ssize_t edns_sz)
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;
69  h.arcount = (edns_sz > 0 ? 1 : 0);
70  offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
71  offset += rfc1035QuestionPack(buf + offset,
72  sz - offset,
73  hostname,
74  qtype,
76  if (edns_sz > 0)
77  offset += rfc2671RROptPack(buf + offset, sz - offset, edns_sz);
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 
97 ssize_t
98 rfc3596BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
99 {
100  return rfc3596BuildHostQuery(hostname, buf, sz, qid, query, RFC1035_TYPE_A, edns_sz);
101 }
102 
111 ssize_t
112 rfc3596BuildAAAAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
113 {
114  return rfc3596BuildHostQuery(hostname, buf, sz, qid, query, RFC1035_TYPE_AAAA, edns_sz);
115 }
116 
125 ssize_t
126 rfc3596BuildPTRQuery4(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
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 
138  return rfc3596BuildHostQuery(rev, buf, sz, qid, query, RFC1035_TYPE_PTR, edns_sz);
139 }
140 
141 ssize_t
142 rfc3596BuildPTRQuery6(const struct in6_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query * query, ssize_t edns_sz)
143 {
144  static char rev[RFC1035_MAXHOSTNAMESZ];
145  const uint8_t* r = addr.s6_addr;
146  char* p = rev;
147  int i; /* NP: MUST allow signed for loop termination. */
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. */
151  for (i = 15; i >= 0; i--, p+=4) {
152  snprintf(p, 5, "%1x.%1x.", ((r[i])&0xf), (r[i]>>4)&0xf );
153  }
154 
155  snprintf(p,10,"ip6.arpa.");
156 
157  return rfc3596BuildHostQuery(rev, buf, sz, qid, query, RFC1035_TYPE_PTR, edns_sz);
158 }
159 
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>
168 
169 int
170 main(int argc, char *argv[])
171 {
172 #define PACKET_BUFSZ 1024
173  char input[PACKET_BUFSZ];
174  char buf[PACKET_BUFSZ];
175  char rbuf[PACKET_BUFSZ];
176  size_t sz = PACKET_BUFSZ;
177  unsigned short sid, sidb;
178  int s;
179  int rl;
180  ssize_t edns_max = -1;
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]);
187  exit(EXIT_FAILURE);
188  }
189 
190  setbuf(stdout, NULL);
191  setbuf(stderr, NULL);
192 
193  if (argv[var][0] == '-') {
194  if (argv[var][1] == '4')
195  prefer = AF_INET;
196  else if (argv[var][1] == '6')
197  prefer = AF_INET6;
198  else if (argv[var][1] == 'E')
199  edns_max = atoi(argv[var++]);
200  else {
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);
203  exit(EXIT_FAILURE);
204  }
205 
206  var++;
207  }
208 
209  s = socket(PF_INET, SOCK_DGRAM, 0);
210 
211  if (s < 0) {
212  perror("socket");
213  exit(EXIT_FAILURE);
214  }
215 
216  memset(&S, '\0', sizeof(S));
217 
218  if (prefer == 6) {
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 
225  if ( ! inet_pton(AF_INET6, argv[var], &((struct sockaddr_in6 *)S)->sin6_addr.s_addr) ) {
226  perror("listen address");
227  exit(EXIT_FAILURE);
228  }
229 
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));
234 
235  ((struct sockaddr_in *)S)->sin_family = AF_INET;
236  ((struct sockaddr_in *)S)->sin_port = htons(atoi(argv[var+1]));
237 
238  if ( ! inet_pton(AF_INET, argv[var], &((struct sockaddr_in *)S)->sin_addr.s_addr) ) {
239  perror("listen address");
240  exit(EXIT_FAILURE);
241  }
242  }
243 
244  while (fgets(input, PACKET_BUFSZ, stdin))
245  {
246 
247  struct in6_addr junk6;
248 
249  struct in_addr junk4;
250  strtok(input, "\r\n");
251  memset(buf, '\0', PACKET_BUFSZ);
252  sz = PACKET_BUFSZ;
253 
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  }
264 
265  sendto(s, buf, sz, 0, S, sizeof(*S));
266 
267  do {
268  fd_set R;
269 
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);
277 
278  if (rl < 1) {
279  printf("TIMEOUT\n");
280  continue;
281  }
282 
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  }
328  }
329  }
330  }
331  }
332 
333  return EXIT_SUCCESS;
334 }
335 
336 #endif
337 
unsigned short id
Definition: rfc1035.h:56
#define assert(EX)
Definition: assert.h:17
int main(int, char *[])
Definition: unitTestMain.h:25
int type
Definition: errorpage.cc:79
#define RFC1035_MAXHOSTNAMESZ
Definition: rfc1035.h:32
int i
Definition: membanger.c:49
#define RFC1035_TYPE_CNAME
Definition: rfc1035.h:94
unsigned int qr
Definition: rfc1035.h:57
char * p
Definition: membanger.c:43
int rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message *hdr)
Definition: rfc1035.cc:60
#define inet_pton
Definition: inet_pton.h:28
ssize_t rfc3596BuildPTRQuery6(const struct in6_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query *query, ssize_t edns_sz)
Definition: rfc3596.cc:142
#define inet_ntop
Definition: inet_ntop.h:25
#define RFC1035_CLASS_IN
Definition: rfc1035.h:96
#define RFC1035_TYPE_A
Definition: rfc1035.h:93
void * addr
Definition: membanger.c:46
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
#define RFC1035_TYPE_PTR
Definition: rfc1035.h:95
ssize_t rfc3596BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query *query, ssize_t edns_sz)
Definition: rfc3596.cc:98
unsigned short qdcount
Definition: rfc1035.h:64
unsigned short arcount
Definition: rfc1035.h:67
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
unsigned short qtype
Definition: rfc1035.h:50
unsigned short qclass
Definition: rfc1035.h:51
unsigned int opcode
Definition: rfc1035.h:58
ssize_t rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query *query, ssize_t edns_sz)
Definition: rfc1035.cc:665
char name[RFC1035_MAXHOSTNAMESZ]
Definition: rfc1035.h:49
ssize_t rfc3596BuildHostQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query *query, int qtype, ssize_t edns_sz)
Definition: rfc3596.cc:59
int a
Definition: membanger.c:50
ssize_t rfc3596BuildPTRQuery4(const struct in_addr addr, char *buf, size_t sz, unsigned short qid, rfc1035_query *query, ssize_t edns_sz)
Definition: rfc3596.cc:126
int rfc1035QuestionPack(char *buf, const size_t sz, const char *name, const unsigned short type, const unsigned short _class)
Definition: rfc1035.cc:153
ssize_t rfc3596BuildAAAAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid, rfc1035_query *query, ssize_t edns_sz)
Definition: rfc3596.cc:112
#define NULL
Definition: types.h:166
#define RFC1035_TYPE_AAAA
Definition: rfc3596.h:53
int rfc2671RROptPack(char *buf, size_t sz, ssize_t edns_sz)
Definition: rfc2671.cc:14
unsigned int rd
Definition: rfc1035.h:61

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors