chiark / gitweb /
resolved: when sending fails, don't try connecting to the next DNS server if we actua...
[elogind.git] / src / resolve / resolved-dns-rr.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <math.h>
23
24 #include "strv.h"
25
26 #include "resolved-dns-domain.h"
27 #include "resolved-dns-rr.h"
28 #include "resolved-dns-packet.h"
29 #include "dns-type.h"
30
31 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
32         DnsResourceKey *k;
33         size_t l;
34
35         assert(name);
36
37         l = strlen(name);
38         k = malloc0(sizeof(DnsResourceKey) + l + 1);
39         if (!k)
40                 return NULL;
41
42         k->n_ref = 1;
43         k->class = class;
44         k->type = type;
45
46         strcpy((char*) k + sizeof(DnsResourceKey), name);
47
48         return k;
49 }
50
51 DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
52         DnsResourceKey *k;
53
54         assert(name);
55
56         k = new0(DnsResourceKey, 1);
57         if (!k)
58                 return NULL;
59
60         k->n_ref = 1;
61         k->class = class;
62         k->type = type;
63         k->_name = name;
64
65         return k;
66 }
67
68 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
69
70         if (!k)
71                 return NULL;
72
73         assert(k->n_ref > 0);
74         k->n_ref++;
75
76         return k;
77 }
78
79 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
80         if (!k)
81                 return NULL;
82
83         assert(k->n_ref > 0);
84
85         if (k->n_ref == 1) {
86                 free(k->_name);
87                 free(k);
88         } else
89                 k->n_ref--;
90
91         return NULL;
92 }
93
94 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
95         int r;
96
97         r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
98         if (r <= 0)
99                 return r;
100
101         if (a->class != b->class)
102                 return 0;
103
104         if (a->type != b->type)
105                 return 0;
106
107         return 1;
108 }
109
110 int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
111         assert(key);
112         assert(rr);
113
114         if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
115                 return 0;
116
117         if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
118                 return 0;
119
120         return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
121 }
122
123 int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
124         assert(key);
125         assert(rr);
126
127         if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
128                 return 0;
129
130         if (rr->key->type != DNS_TYPE_CNAME)
131                 return 0;
132
133         return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
134 }
135
136 unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
137         const DnsResourceKey *k = i;
138         unsigned long ul;
139
140         ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
141         ul = ul * hash_key[0] + ul + k->class;
142         ul = ul * hash_key[1] + ul + k->type;
143
144         return ul;
145 }
146
147 int dns_resource_key_compare_func(const void *a, const void *b) {
148         const DnsResourceKey *x = a, *y = b;
149         int ret;
150
151         ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
152         if (ret != 0)
153                 return ret;
154
155         if (x->type < y->type)
156                 return -1;
157         if (x->type > y->type)
158                 return 1;
159
160         if (x->class < y->class)
161                 return -1;
162         if (x->class > y->class)
163                 return 1;
164
165         return 0;
166 }
167
168 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
169         char cbuf[DECIMAL_STR_MAX(uint16_t)], tbuf[DECIMAL_STR_MAX(uint16_t)];
170         const char *c, *t;
171         char *s;
172
173         c = dns_class_to_string(key->class);
174         if (!c) {
175                 sprintf(cbuf, "%i", key->class);
176                 c = cbuf;
177         }
178
179         t = dns_type_to_string(key->type);
180         if (!t){
181                 sprintf(tbuf, "%i", key->type);
182                 t = tbuf;
183         }
184
185         if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
186                 return -ENOMEM;
187
188         *ret = s;
189         return 0;
190 }
191
192 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
193         DnsResourceRecord *rr;
194
195         rr = new0(DnsResourceRecord, 1);
196         if (!rr)
197                 return NULL;
198
199         rr->n_ref = 1;
200         rr->key = dns_resource_key_ref(key);
201
202         return rr;
203 }
204
205 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
206         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
207
208         key = dns_resource_key_new(class, type, name);
209         if (!key)
210                 return NULL;
211
212         return dns_resource_record_new(key);
213 }
214
215 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
216         if (!rr)
217                 return NULL;
218
219         assert(rr->n_ref > 0);
220         rr->n_ref++;
221
222         return rr;
223 }
224
225 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
226         if (!rr)
227                 return NULL;
228
229         assert(rr->n_ref > 0);
230
231         if (rr->n_ref > 1) {
232                 rr->n_ref--;
233                 return NULL;
234         }
235
236         if (rr->key) {
237                 switch(rr->key->type) {
238
239                 case DNS_TYPE_SRV:
240                         free(rr->srv.name);
241                         break;
242
243                 case DNS_TYPE_PTR:
244                 case DNS_TYPE_NS:
245                 case DNS_TYPE_CNAME:
246                 case DNS_TYPE_DNAME:
247                         free(rr->ptr.name);
248                         break;
249
250                 case DNS_TYPE_HINFO:
251                         free(rr->hinfo.cpu);
252                         free(rr->hinfo.os);
253                         break;
254
255                 case DNS_TYPE_TXT:
256                 case DNS_TYPE_SPF:
257                         strv_free(rr->txt.strings);
258                         break;
259
260                 case DNS_TYPE_SOA:
261                         free(rr->soa.mname);
262                         free(rr->soa.rname);
263                         break;
264
265                 case DNS_TYPE_MX:
266                         free(rr->mx.exchange);
267                         break;
268
269                 case DNS_TYPE_SSHFP:
270                         free(rr->sshfp.key);
271                         break;
272
273                 case DNS_TYPE_DNSKEY:
274                         free(rr->dnskey.key);
275                         break;
276
277                 case DNS_TYPE_RRSIG:
278                         free(rr->rrsig.signer);
279                         free(rr->rrsig.signature);
280                         break;
281
282                 case DNS_TYPE_LOC:
283                 case DNS_TYPE_A:
284                 case DNS_TYPE_AAAA:
285                         break;
286
287                 default:
288                         free(rr->generic.data);
289                 }
290
291                 dns_resource_key_unref(rr->key);
292         }
293
294         free(rr);
295
296         return NULL;
297 }
298
299 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
300         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
301         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
302         _cleanup_free_ char *ptr = NULL;
303         int r;
304
305         assert(ret);
306         assert(address);
307         assert(hostname);
308
309         r = dns_name_reverse(family, address, &ptr);
310         if (r < 0)
311                 return r;
312
313         key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
314         if (!key)
315                 return -ENOMEM;
316
317         ptr = NULL;
318
319         rr = dns_resource_record_new(key);
320         if (!rr)
321                 return -ENOMEM;
322
323         rr->ptr.name = strdup(hostname);
324         if (!rr->ptr.name)
325                 return -ENOMEM;
326
327         *ret = rr;
328         rr = NULL;
329
330         return 0;
331 }
332
333 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
334         int r;
335
336         assert(a);
337         assert(b);
338
339         r = dns_resource_key_equal(a->key, b->key);
340         if (r <= 0)
341                 return r;
342
343         if (a->unparseable != b->unparseable)
344                 return 0;
345
346         switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
347
348         case DNS_TYPE_SRV:
349                 r = dns_name_equal(a->srv.name, b->srv.name);
350                 if (r <= 0)
351                         return r;
352
353                 return a->srv.priority == b->srv.priority &&
354                        a->srv.weight == b->srv.weight &&
355                        a->srv.port == b->srv.port;
356
357         case DNS_TYPE_PTR:
358         case DNS_TYPE_NS:
359         case DNS_TYPE_CNAME:
360         case DNS_TYPE_DNAME:
361                 return dns_name_equal(a->ptr.name, b->ptr.name);
362
363         case DNS_TYPE_HINFO:
364                 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
365                        strcaseeq(a->hinfo.os, b->hinfo.os);
366
367         case DNS_TYPE_SPF: /* exactly the same as TXT */
368         case DNS_TYPE_TXT: {
369                 int i;
370
371                 for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
372                         if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
373                                 return false;
374                 return true;
375         }
376
377         case DNS_TYPE_A:
378                 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
379
380         case DNS_TYPE_AAAA:
381                 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
382
383         case DNS_TYPE_SOA:
384                 r = dns_name_equal(a->soa.mname, b->soa.mname);
385                 if (r <= 0)
386                         return r;
387                 r = dns_name_equal(a->soa.rname, b->soa.rname);
388                 if (r <= 0)
389                         return r;
390
391                 return a->soa.serial  == b->soa.serial &&
392                        a->soa.refresh == b->soa.refresh &&
393                        a->soa.retry   == b->soa.retry &&
394                        a->soa.expire  == b->soa.expire &&
395                        a->soa.minimum == b->soa.minimum;
396
397         case DNS_TYPE_MX:
398                 if (a->mx.priority != b->mx.priority)
399                         return 0;
400
401                 return dns_name_equal(a->mx.exchange, b->mx.exchange);
402
403         case DNS_TYPE_LOC:
404                 assert(a->loc.version == b->loc.version);
405
406                 return a->loc.size == b->loc.size &&
407                        a->loc.horiz_pre == b->loc.horiz_pre &&
408                        a->loc.vert_pre == b->loc.vert_pre &&
409                        a->loc.latitude == b->loc.latitude &&
410                        a->loc.longitude == b->loc.longitude &&
411                        a->loc.altitude == b->loc.altitude;
412
413         case DNS_TYPE_SSHFP:
414                 return a->sshfp.algorithm == b->sshfp.algorithm &&
415                        a->sshfp.fptype == b->sshfp.fptype &&
416                        a->sshfp.key_size == b->sshfp.key_size &&
417                        memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
418
419         case DNS_TYPE_DNSKEY:
420                 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
421                        a->dnskey.sep_flag == b->dnskey.sep_flag &&
422                        a->dnskey.algorithm == b->dnskey.algorithm &&
423                        a->dnskey.key_size == b->dnskey.key_size &&
424                        memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
425
426         case DNS_TYPE_RRSIG:
427                 /* do the fast comparisons first */
428                 if (a->rrsig.type_covered != a->rrsig.type_covered ||
429                     a->rrsig.algorithm != a->rrsig.algorithm ||
430                     a->rrsig.labels != a->rrsig.labels ||
431                     a->rrsig.original_ttl != a->rrsig.original_ttl ||
432                     a->rrsig.expiration != a->rrsig.expiration ||
433                     a->rrsig.inception != a->rrsig.inception ||
434                     a->rrsig.key_tag != a->rrsig.key_tag ||
435                     a->rrsig.signature_size != b->rrsig.signature_size ||
436                     memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
437                         return false;
438
439                 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
440
441         default:
442                 return a->generic.size == b->generic.size &&
443                         memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
444         }
445 }
446
447 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
448                              uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
449         char *s;
450         char NS = latitude >= 1U<<31 ? 'N' : 'S';
451         char EW = longitude >= 1U<<31 ? 'E' : 'W';
452
453         int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
454         int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
455         double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
456         double siz = (size >> 4) * exp10((double) (size & 0xF));
457         double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
458         double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
459
460         if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
461                      (lat / 60000 / 60),
462                      (lat / 60000) % 60,
463                      (lat % 60000) / 1000.,
464                      NS,
465                      (lon / 60000 / 60),
466                      (lon / 60000) % 60,
467                      (lon % 60000) / 1000.,
468                      EW,
469                      alt / 100.,
470                      siz / 100.,
471                      hor / 100.,
472                      ver / 100.) < 0)
473                 return NULL;
474
475         return s;
476 }
477
478 int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
479         _cleanup_free_ char *k = NULL, *t = NULL;
480         char *s;
481         int r;
482
483         assert(rr);
484
485         r = dns_resource_key_to_string(rr->key, &k);
486         if (r < 0)
487                 return r;
488
489         switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
490
491         case DNS_TYPE_SRV:
492                 r = asprintf(&s, "%s %u %u %u %s",
493                              k,
494                              rr->srv.priority,
495                              rr->srv.weight,
496                              rr->srv.port,
497                              strna(rr->srv.name));
498                 if (r < 0)
499                         return -ENOMEM;
500                 break;
501
502         case DNS_TYPE_PTR:
503         case DNS_TYPE_NS:
504         case DNS_TYPE_CNAME:
505         case DNS_TYPE_DNAME:
506                 s = strjoin(k, " ", rr->ptr.name, NULL);
507                 if (!s)
508                         return -ENOMEM;
509
510                 break;
511
512         case DNS_TYPE_HINFO:
513                 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
514                 if (!s)
515                         return -ENOMEM;
516                 break;
517
518         case DNS_TYPE_SPF: /* exactly the same as TXT */
519         case DNS_TYPE_TXT:
520                 t = strv_join_quoted(rr->txt.strings);
521                 if (!t)
522                         return -ENOMEM;
523
524                 s = strjoin(k, " ", t, NULL);
525                 if (!s)
526                         return -ENOMEM;
527
528                 break;
529
530         case DNS_TYPE_A: {
531                 _cleanup_free_ char *x = NULL;
532
533                 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
534                 if (r < 0)
535                         return r;
536
537                 s = strjoin(k, " ", x, NULL);
538                 if (!s)
539                         return -ENOMEM;
540                 break;
541         }
542
543         case DNS_TYPE_AAAA:
544                 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
545                 if (r < 0)
546                         return r;
547
548                 s = strjoin(k, " ", t, NULL);
549                 if (!s)
550                         return -ENOMEM;
551                 break;
552
553         case DNS_TYPE_SOA:
554                 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
555                              k,
556                              strna(rr->soa.mname),
557                              strna(rr->soa.rname),
558                              rr->soa.serial,
559                              rr->soa.refresh,
560                              rr->soa.retry,
561                              rr->soa.expire,
562                              rr->soa.minimum);
563                 if (r < 0)
564                         return -ENOMEM;
565                 break;
566
567         case DNS_TYPE_MX:
568                 r = asprintf(&s, "%s %u %s",
569                              k,
570                              rr->mx.priority,
571                              rr->mx.exchange);
572                 if (r < 0)
573                         return -ENOMEM;
574                 break;
575
576         case DNS_TYPE_LOC:
577                 assert(rr->loc.version == 0);
578
579                 t = format_location(rr->loc.latitude,
580                                     rr->loc.longitude,
581                                     rr->loc.altitude,
582                                     rr->loc.size,
583                                     rr->loc.horiz_pre,
584                                     rr->loc.vert_pre);
585                 if (!t)
586                         return -ENOMEM;
587
588                 s = strjoin(k, " ", t, NULL);
589                 if (!s)
590                         return -ENOMEM;
591                 break;
592
593         case DNS_TYPE_SSHFP:
594                 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
595                 if (!t)
596                         return -ENOMEM;
597
598                 r = asprintf(&s, "%s %u %u %s",
599                              k,
600                              rr->sshfp.algorithm,
601                              rr->sshfp.fptype,
602                              t);
603                 if (r < 0)
604                         return -ENOMEM;
605                 break;
606
607         case DNS_TYPE_DNSKEY: {
608                 const char *alg;
609
610                 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
611
612                 t = hexmem(rr->dnskey.key, rr->dnskey.key_size);
613                 if (!t)
614                         return -ENOMEM;
615
616                 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
617                              k,
618                              dnskey_to_flags(rr),
619                              alg ? -1 : 0, alg,
620                              alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
621                              t);
622                 if (r < 0)
623                         return -ENOMEM;
624                 break;
625         }
626
627         case DNS_TYPE_RRSIG: {
628                 const char *type, *alg;
629
630                 type = dns_type_to_string(rr->rrsig.type_covered);
631                 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
632
633                 t = hexmem(rr->rrsig.signature, rr->rrsig.signature_size);
634                 if (!t)
635                         return -ENOMEM;
636
637                 /* TYPE?? follows
638                  * http://tools.ietf.org/html/rfc3597#section-5 */
639
640                 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %u %u %u %s %s",
641                              k,
642                              type ?: "TYPE",
643                              type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
644                              alg ? -1 : 0, alg,
645                              alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
646                              rr->rrsig.labels,
647                              rr->rrsig.original_ttl,
648                              rr->rrsig.expiration,
649                              rr->rrsig.inception,
650                              rr->rrsig.key_tag,
651                              rr->rrsig.signer,
652                              t);
653                 if (r < 0)
654                         return -ENOMEM;
655                 break;
656         }
657
658         default:
659                 t = hexmem(rr->generic.data, rr->generic.size);
660                 if (!t)
661                         return -ENOMEM;
662
663                 s = strjoin(k, " ", t, NULL);
664                 if (!s)
665                         return -ENOMEM;
666                 break;
667         }
668
669         *ret = s;
670         return 0;
671 }
672
673 const char *dns_class_to_string(uint16_t class) {
674
675         switch (class) {
676
677         case DNS_CLASS_IN:
678                 return "IN";
679
680         case DNS_CLASS_ANY:
681                 return "ANY";
682         }
683
684         return NULL;
685 }
686
687 int dns_class_from_string(const char *s, uint16_t *class) {
688         assert(s);
689         assert(class);
690
691         if (strcaseeq(s, "IN"))
692                 *class = DNS_CLASS_IN;
693         else if (strcaseeq(s, "ANY"))
694                 *class = DNS_TYPE_ANY;
695         else
696                 return -EINVAL;
697
698         return 0;
699 }