blob: 4aacfa1d59b548b07be0ea2a96be3dde3752b01f [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
Simon Kelley98c098b2014-01-08 17:31:16 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17#include "dnsmasq.h"
18
19#ifdef HAVE_DNSSEC
20
Simon Kelley82e3f452014-01-31 21:05:48 +000021static struct blockdata *keyblock_free;
22static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
23
Simon Kelley8d718cb2014-02-03 16:27:37 +000024static void blockdata_expand(int n)
25{
26 struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
27
Simon Kelleyad9c6f02017-10-27 22:13:49 +010028 if (new)
Simon Kelley8d718cb2014-02-03 16:27:37 +000029 {
30 int i;
31
32 new[n-1].next = keyblock_free;
33 keyblock_free = new;
34
35 for (i = 0; i < n - 1; i++)
36 new[i].next = &new[i+1];
37
38 blockdata_alloced += n;
39 }
40}
41
Simon Kelley82e3f452014-01-31 21:05:48 +000042/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
43void blockdata_init(void)
44{
Simon Kelley8d718cb2014-02-03 16:27:37 +000045 keyblock_free = NULL;
46 blockdata_alloced = 0;
Simon Kelley82e3f452014-01-31 21:05:48 +000047 blockdata_count = 0;
48 blockdata_hwm = 0;
Simon Kelleyb692f232014-05-09 10:29:43 +010049
50 /* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
51 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelley6340ca72018-01-30 21:39:01 +000052 blockdata_expand(daemon->cachesize);
Simon Kelley82e3f452014-01-31 21:05:48 +000053}
Simon Kelleyc2207682014-01-08 18:04:20 +000054
55void blockdata_report(void)
56{
Simon Kelleyb692f232014-05-09 10:29:43 +010057 if (option_bool(OPT_DNSSEC_VALID))
58 my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"),
59 blockdata_count * sizeof(struct blockdata),
60 blockdata_hwm * sizeof(struct blockdata),
61 blockdata_alloced * sizeof(struct blockdata));
Simon Kelleyc2207682014-01-08 18:04:20 +000062}
Simon Kelley98c098b2014-01-08 17:31:16 +000063
Simon Kelleya799ca02018-10-18 19:35:29 +010064static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
Simon Kelley98c098b2014-01-08 17:31:16 +000065{
66 struct blockdata *block, *ret = NULL;
67 struct blockdata **prev = &ret;
68 size_t blen;
69
70 while (len > 0)
71 {
Simon Kelley8d718cb2014-02-03 16:27:37 +000072 if (!keyblock_free)
73 blockdata_expand(50);
74
Simon Kelley98c098b2014-01-08 17:31:16 +000075 if (keyblock_free)
76 {
77 block = keyblock_free;
78 keyblock_free = block->next;
Simon Kelleyc2207682014-01-08 18:04:20 +000079 blockdata_count++;
Simon Kelley98c098b2014-01-08 17:31:16 +000080 }
Simon Kelley5f938532014-02-03 16:44:32 +000081 else
Simon Kelley98c098b2014-01-08 17:31:16 +000082 {
83 /* failed to alloc, free partial chain */
84 blockdata_free(ret);
85 return NULL;
86 }
Simon Kelley82e3f452014-01-31 21:05:48 +000087
88 if (blockdata_hwm < blockdata_count)
89 blockdata_hwm = blockdata_count;
Simon Kelley98c098b2014-01-08 17:31:16 +000090
91 blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
Simon Kelleya799ca02018-10-18 19:35:29 +010092 if (data)
93 {
94 memcpy(block->key, data, blen);
95 data += blen;
96 }
97 else if (!read_write(fd, block->key, blen, 1))
98 {
99 /* failed read free partial chain */
100 blockdata_free(ret);
101 return NULL;
102 }
Simon Kelley98c098b2014-01-08 17:31:16 +0000103 len -= blen;
104 *prev = block;
105 prev = &block->next;
106 block->next = NULL;
107 }
108
109 return ret;
110}
111
Simon Kelleya799ca02018-10-18 19:35:29 +0100112struct blockdata *blockdata_alloc(char *data, size_t len)
113{
114 return blockdata_alloc_real(0, data, len);
115}
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100116
Simon Kelley98c098b2014-01-08 17:31:16 +0000117void blockdata_free(struct blockdata *blocks)
118{
119 struct blockdata *tmp;
Simon Kelley82e3f452014-01-31 21:05:48 +0000120
Simon Kelley98c098b2014-01-08 17:31:16 +0000121 if (blocks)
122 {
Simon Kelleyc2207682014-01-08 18:04:20 +0000123 for (tmp = blocks; tmp->next; tmp = tmp->next)
124 blockdata_count--;
Simon Kelley98c098b2014-01-08 17:31:16 +0000125 tmp->next = keyblock_free;
Simon Kelleyc2207682014-01-08 18:04:20 +0000126 keyblock_free = blocks;
127 blockdata_count--;
Simon Kelley98c098b2014-01-08 17:31:16 +0000128 }
129}
130
Simon Kelley86bec2d2014-01-13 21:31:20 +0000131/* if data == NULL, return pointer to static block of sufficient size */
132void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
Simon Kelley98c098b2014-01-08 17:31:16 +0000133{
134 size_t blen;
135 struct blockdata *b;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000136 void *new, *d;
Simon Kelley98c098b2014-01-08 17:31:16 +0000137
Simon Kelley86bec2d2014-01-13 21:31:20 +0000138 static unsigned int buff_len = 0;
139 static unsigned char *buff = NULL;
140
141 if (!data)
142 {
143 if (len > buff_len)
144 {
145 if (!(new = whine_malloc(len)))
146 return NULL;
147 if (buff)
148 free(buff);
149 buff = new;
150 }
151 data = buff;
152 }
153
154 for (d = data, b = block; len > 0 && b; b = b->next)
Simon Kelley98c098b2014-01-08 17:31:16 +0000155 {
156 blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000157 memcpy(d, b->key, blen);
158 d += blen;
Simon Kelley98c098b2014-01-08 17:31:16 +0000159 len -= blen;
160 }
Simon Kelleyb6e9e7c2014-01-08 21:21:20 +0000161
Simon Kelley86bec2d2014-01-13 21:31:20 +0000162 return data;
Simon Kelley98c098b2014-01-08 17:31:16 +0000163}
Simon Kelleya799ca02018-10-18 19:35:29 +0100164
165
166void blockdata_write(struct blockdata *block, size_t len, int fd)
167{
168 for (; len > 0 && block; block = block->next)
169 {
170 size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
171 read_write(fd, block->key, blen, 0);
172 len -= blen;
173 }
174}
175
176struct blockdata *blockdata_read(int fd, size_t len)
177{
178 return blockdata_alloc_real(fd, NULL, len);
179}
180
Simon Kelley98c098b2014-01-08 17:31:16 +0000181#endif