xref: /openbsd/sbin/unwind/dns64_synth.c (revision 00b0420e)
1 /*	$OpenBSD: dns64_synth.c,v 1.1 2021/01/24 18:29:15 florian Exp $	*/
2 
3 /*
4  * dns64/dns64.h - DNS64 module
5  *
6  * Copyright (c) 2009, Viagénie. All rights reserved.
7  *
8  * This software is open source.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * Redistributions of source code must retain the above copyright notice,
15  * this list of conditions and the following disclaimer.
16  *
17  * Redistributions in binary form must reproduce the above copyright notice,
18  * this list of conditions and the following disclaimer in the documentation
19  * and/or other materials provided with the distribution.
20  *
21  * Neither the name of the NLNET LABS nor the names of its contributors may
22  * be used to endorse or promote products derived from this software without
23  * specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
29  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Copyright (c) 2021 Florian Obser <florian@openbsd.org>
40  *
41  * Permission to use, copy, modify, and distribute this software for any
42  * purpose with or without fee is hereby granted, provided that the above
43  * copyright notice and this permission notice appear in all copies.
44  *
45  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
46  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
47  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
48  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
49  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
50  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
51  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
52  */
53 
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 
57 #include <netinet/in.h>
58 #include <net/route.h>
59 
60 #include <string.h>
61 
62 #include "libunbound/config.h"
63 #include "libunbound/util/regional.h"
64 #include "libunbound/util/data/msgencode.h"
65 #include "libunbound/util/data/msgparse.h"
66 #include "libunbound/util/data/msgreply.h"
67 
68 #include "log.h"
69 #include "unwind.h"
70 #include "frontend.h"
71 #include "dns64_synth.h"
72 
73 extern struct dns64_prefix	*dns64_prefixes;
74 extern int			 dns64_prefix_count;
75 
76 static void
synthesize_aaaa(const struct in6_addr * in6,int prefixlen,const uint8_t * a,size_t a_len,uint8_t * aaaa,size_t aaaa_len)77 synthesize_aaaa(const struct in6_addr *in6, int prefixlen, const uint8_t *a,
78     size_t a_len, uint8_t *aaaa, size_t aaaa_len)
79 {
80 	size_t i, pos;
81 	memcpy(aaaa, in6->s6_addr, sizeof(in6->s6_addr));
82 	for (i = 0, pos = prefixlen / 8; i < a_len && pos < aaaa_len;
83 	    i++, pos++) {
84 		if (pos == 8)
85 			aaaa[pos++] = 0;
86 		aaaa[pos] = a[i];
87 	}
88 }
89 
90 /*
91  * Copied from unbound/dns64/dns64.c and slightly extended to work with more
92  * than one IPv6 prefix.
93  */
94 
95 void
dns64_synth_aaaa_data(const struct ub_packed_rrset_key * fk,const struct packed_rrset_data * fd,struct ub_packed_rrset_key * dk,struct packed_rrset_data ** dd_out,struct regional * region)96 dns64_synth_aaaa_data(const struct ub_packed_rrset_key* fk, const struct
97     packed_rrset_data* fd, struct ub_packed_rrset_key *dk, struct
98     packed_rrset_data **dd_out, struct regional *region)
99 {
100 	struct packed_rrset_data	*dd;
101 	size_t				 i, pos;
102 	int				 j;
103 
104 	/*
105 	 * Create synthesized AAAA RR set data. We need to allocated extra
106 	 * memory for the RRs themselves. Each RR has a length, TTL, pointer to
107 	 * wireformat data, 2 bytes of data length, and 16 bytes of IPv6
108 	 * address.
109 	 */
110 	if(fd->count > RR_COUNT_MAX) {
111 		*dd_out = NULL;
112 		return; /* integer overflow protection in alloc */
113 	}
114 	if (!(dd = *dd_out = regional_alloc(region, sizeof(struct
115 	    packed_rrset_data) + fd->count * dns64_prefix_count *
116 	    (sizeof(size_t) + sizeof(time_t) + sizeof(uint8_t*) + 2 + 16)))) {
117 		log_warnx("out of memory");
118 		return;
119 	}
120 
121 	/* Copy attributes from A RR set. */
122 	dd->ttl = fd->ttl;
123 	dd->count = fd->count * dns64_prefix_count;
124 	dd->rrsig_count = 0;
125 	dd->trust = fd->trust;
126 	dd->security = fd->security;
127 
128 	/* Synthesize AAAA records. Adjust pointers in structure. */
129 	dd->rr_len = (size_t*)((uint8_t*)dd + sizeof(struct packed_rrset_data));
130 	dd->rr_data = (uint8_t**)&dd->rr_len[dd->count];
131 	dd->rr_ttl = (time_t*)&dd->rr_data[dd->count];
132 	for(i = 0, pos = 0; i < fd->count; ++i) {
133 		if (fd->rr_len[i] != 6 || fd->rr_data[i][0] != 0 ||
134 		    fd->rr_data[i][1] != 4) {
135 			*dd_out = NULL;
136 			return;
137 		}
138 		for (j = 0; j < dns64_prefix_count; j++, pos++) {
139 			dd->rr_len[pos] = 18;
140 			dd->rr_ttl[pos] = fd->rr_ttl[i];
141 			dd->rr_data[pos] = (uint8_t*)&dd->rr_ttl[dd->count] +
142 			    18 * pos;
143 			dd->rr_data[pos][0] = 0;
144 			dd->rr_data[pos][1] = 16;
145 			synthesize_aaaa(&dns64_prefixes[j].in6,
146 			    dns64_prefixes[j].prefixlen, &fd->rr_data[i][2],
147 			    fd->rr_len[i]-2, &dd->rr_data[pos][2],
148 			    dd->rr_len[pos]-2);
149 		}
150 	}
151 
152 	/*
153 	 * Create synthesized AAAA RR set key. This is mostly just bookkeeping,
154 	 * nothing interesting here.
155 	 */
156 	if(!dk) {
157 		log_warnx("no key");
158 		*dd_out = NULL;
159 		return;
160 	}
161 
162 	dk->rk.dname = (uint8_t*)regional_alloc_init(region, fk->rk.dname,
163 	    fk->rk.dname_len);
164 
165 	if(!dk->rk.dname) {
166 		log_warnx("out of memory");
167 		*dd_out = NULL;
168 		return;
169 	}
170 
171 	dk->rk.type = htons(LDNS_RR_TYPE_AAAA);
172 	memset(&dk->entry, 0, sizeof(dk->entry));
173 	dk->entry.key = dk;
174 	dk->entry.hash = rrset_key_hash(&dk->rk);
175 	dk->entry.data = dd;
176 }
177