Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Authors: |
4 | | * Lars Fenneberg <lf@elemental.net> |
5 | | * |
6 | | * This software is Copyright 1996,1997 by the above mentioned author(s), |
7 | | * All Rights Reserved. |
8 | | * |
9 | | * The license which is distributed with this software in the file COPYRIGHT |
10 | | * applies to this software. If your distribution is missing this file, you |
11 | | * may request it from <reubenhwk@gmail.com>. |
12 | | * |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | #include "includes.h" |
17 | | #include "radvd.h" |
18 | | |
19 | | #ifdef UNIT_TEST |
20 | | #include "test/util.c" |
21 | | #endif |
22 | | |
23 | | struct safe_buffer *new_safe_buffer(void) |
24 | 0 | { |
25 | 0 | struct safe_buffer *sb = malloc(sizeof(struct safe_buffer)); |
26 | 0 | *sb = SAFE_BUFFER_INIT; |
27 | 0 | sb->should_free = 1; |
28 | 0 | return sb; |
29 | 0 | } |
30 | | |
31 | | void safe_buffer_free(struct safe_buffer *sb) |
32 | 0 | { |
33 | 0 | if (sb && sb->buffer) { |
34 | 0 | free(sb->buffer); |
35 | 0 | sb->buffer = NULL; |
36 | 0 | } |
37 | |
|
38 | 0 | if (sb && sb->should_free) { |
39 | 0 | free(sb); |
40 | 0 | sb = NULL; |
41 | 0 | } |
42 | 0 | } |
43 | | |
44 | | /** |
45 | | * Requests that the safe_buffer capacity be least n bytes in size. |
46 | | * |
47 | | * If n is greater than the current capacity, the function causes the container |
48 | | * to reallocate its storage increasing its capacity to n (or greater). |
49 | | * |
50 | | * In all other cases, the function call does not cause a reallocation and the |
51 | | * capacity is not affected. |
52 | | * |
53 | | * @param sb safe_buffer to enlarge |
54 | | * @param b Minimum capacity for the safe_buffer. |
55 | | */ |
56 | | void safe_buffer_resize(struct safe_buffer *sb, size_t n) |
57 | 0 | { |
58 | 0 | const int blocksize = 1 << 6; // MUST BE POWER OF 2. |
59 | 0 | if (sb->allocated < n) { |
60 | 0 | if (n % blocksize > 0) { |
61 | 0 | n |= (blocksize - 1); // Set all the low bits |
62 | 0 | n++; |
63 | 0 | } |
64 | 0 | if (n > 64 * 1024) { |
65 | 0 | flog(LOG_ERR, "Requested buffer too large for any possible IPv6 ND, even with jumbogram. Exiting."); |
66 | 0 | exit(1); |
67 | 0 | } |
68 | 0 | sb->allocated = n; |
69 | 0 | sb->buffer = realloc(sb->buffer, sb->allocated); |
70 | 0 | } |
71 | 0 | } |
72 | | |
73 | | size_t safe_buffer_pad(struct safe_buffer *sb, size_t count) |
74 | 0 | { |
75 | 0 | safe_buffer_resize(sb, sb->used + count); |
76 | 0 | memset(&sb->buffer[sb->used], (uint8_t)0, count); |
77 | 0 | sb->used += count; |
78 | 0 | return count; |
79 | 0 | } |
80 | | |
81 | | size_t safe_buffer_append(struct safe_buffer *sb, void const *v, size_t count) |
82 | 0 | { |
83 | 0 | if (sb) { |
84 | 0 | unsigned const char *m = (unsigned const char *)v; |
85 | 0 | safe_buffer_resize(sb, sb->used + count); |
86 | 0 | memcpy(&sb->buffer[sb->used], m, count); |
87 | 0 | sb->used += count; |
88 | 0 | } |
89 | |
|
90 | 0 | return count; |
91 | 0 | } |
92 | | |
93 | | /** |
94 | | * Create a new safe_buffer_list |
95 | | * |
96 | | * @return new safe_buffer_list, with a safe_buffer on the heap. |
97 | | */ |
98 | | struct safe_buffer_list *new_safe_buffer_list(void) |
99 | 0 | { |
100 | 0 | struct safe_buffer_list *sbl = malloc(sizeof(struct safe_buffer_list)); |
101 | 0 | sbl->sb = new_safe_buffer(); |
102 | 0 | sbl->next = NULL; |
103 | 0 | return sbl; |
104 | 0 | } |
105 | | |
106 | | /** |
107 | | * Ensure list tail has an empty buffer ready to accept data. |
108 | | * |
109 | | * If the present element is empty of data, just return it. |
110 | | * Otherwise return a new safe_buffer_list ready to accept data. |
111 | | * |
112 | | * @param sbl safe_buffer_list. |
113 | | * @return new tail of list. |
114 | | */ |
115 | | struct safe_buffer_list *safe_buffer_list_append(struct safe_buffer_list *sbl) |
116 | 0 | { |
117 | | // Only allocate a new entry if this one has bytes in it. |
118 | 0 | if (sbl->sb && sbl->sb->used > 0) { |
119 | 0 | struct safe_buffer_list *next = new_safe_buffer_list(); |
120 | 0 | sbl->next = next; |
121 | 0 | sbl = next; |
122 | 0 | } |
123 | 0 | return sbl; |
124 | 0 | } |
125 | | |
126 | | /** |
127 | | * Convert an entire safe_buffer_list to a single safe_buffer. |
128 | | * |
129 | | * @param sbl safe_buffer_list source. |
130 | | * @param sb safe_buffer destination. |
131 | | */ |
132 | | void safe_buffer_list_to_safe_buffer(struct safe_buffer_list *sbl, struct safe_buffer *sb) |
133 | 0 | { |
134 | 0 | struct safe_buffer_list *cur; |
135 | 0 | for (cur = sbl; cur; cur = cur->next) { |
136 | 0 | if (cur->sb) |
137 | 0 | safe_buffer_append(sb, cur->sb->buffer, cur->sb->used); |
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | | /** |
142 | | * Free all memory used by a safe_buffer_list |
143 | | * |
144 | | * @param sbl safe_buffer_list to free. |
145 | | */ |
146 | | void safe_buffer_list_free(struct safe_buffer_list *sbl) |
147 | 0 | { |
148 | 0 | struct safe_buffer_list *next; |
149 | 0 | for (struct safe_buffer_list *current = sbl; current; current = next) { |
150 | 0 | if (current->sb) { |
151 | 0 | safe_buffer_free(current->sb); |
152 | 0 | current->sb = NULL; |
153 | 0 | } |
154 | 0 | next = current->next; |
155 | 0 | free(current); |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | __attribute__((format(printf, 1, 2))) char *strdupf(char const *format, ...) |
160 | 0 | { |
161 | 0 | va_list va; |
162 | 0 | va_start(va, format); |
163 | 0 | char *strp = 0; |
164 | 0 | int rc = vasprintf(&strp, format, va); |
165 | 0 | if (rc == -1 || !strp) { |
166 | 0 | flog(LOG_ERR, "vasprintf failed: %s", strerror(errno)); |
167 | 0 | exit(-1); |
168 | 0 | } |
169 | 0 | va_end(va); |
170 | |
|
171 | 0 | return strp; |
172 | 0 | } |
173 | | |
174 | 0 | double rand_between(double lower, double upper) { return ((upper - lower) / (RAND_MAX + 1.0) * rand() + lower); } |
175 | | |
176 | | /* This assumes that str is not null and str_size > 0 */ |
177 | | void addrtostr(struct in6_addr const *addr, char *str, size_t str_size) |
178 | 0 | { |
179 | 0 | const char *res; |
180 | |
|
181 | 0 | res = inet_ntop(AF_INET6, (void const *)addr, str, str_size); |
182 | |
|
183 | 0 | if (res == NULL) { |
184 | 0 | flog(LOG_ERR, "addrtostr: inet_ntop: %s", strerror(errno)); |
185 | 0 | strncpy(str, "[invalid address]", str_size); |
186 | 0 | str[str_size - 1] = '\0'; |
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | | /* Check if an in6_addr exists in the rdnss list */ |
191 | | int check_rdnss_presence(struct AdvRDNSS *rdnss, struct in6_addr *addr) |
192 | 0 | { |
193 | 0 | while (rdnss) { |
194 | 0 | for (int i = 0; i < rdnss->AdvRDNSSNumber; i++) { |
195 | 0 | if (!memcmp(&rdnss->AdvRDNSSAddr[i], addr, sizeof(struct in6_addr))) |
196 | 0 | return 1; /* rdnss address found in the list */ |
197 | 0 | } |
198 | 0 | rdnss = rdnss->next; |
199 | 0 | } |
200 | 0 | return 0; |
201 | 0 | } |
202 | | |
203 | | /* Check if a suffix exists in the dnssl list */ |
204 | | int check_dnssl_presence(struct AdvDNSSL *dnssl, const char *suffix) |
205 | 0 | { |
206 | 0 | while (dnssl) { |
207 | 0 | for (int i = 0; i < dnssl->AdvDNSSLNumber; ++i) { |
208 | 0 | if (0 == strcmp(dnssl->AdvDNSSLSuffixes[i], suffix)) |
209 | 0 | return 1; /* suffix found in the list */ |
210 | 0 | } |
211 | 0 | dnssl = dnssl->next; |
212 | 0 | } |
213 | 0 | return 0; |
214 | 0 | } |
215 | | |
216 | | /* Like read(), but retries in case of partial read */ |
217 | | ssize_t readn(int fd, void *buf, size_t count) |
218 | 0 | { |
219 | 0 | size_t n = 0; |
220 | 0 | while (count > 0) { |
221 | 0 | int r = read(fd, buf, count); |
222 | 0 | if (r < 0) { |
223 | 0 | if (errno == EINTR) |
224 | 0 | continue; |
225 | 0 | return r; |
226 | 0 | } |
227 | 0 | if (r == 0) |
228 | 0 | return n; |
229 | 0 | buf = (char *)buf + r; |
230 | 0 | count -= r; |
231 | 0 | n += r; |
232 | 0 | } |
233 | 0 | return n; |
234 | 0 | } |
235 | | |
236 | | /* Like write(), but retries in case of partial write */ |
237 | | ssize_t writen(int fd, const void *buf, size_t count) |
238 | 0 | { |
239 | 0 | size_t n = 0; |
240 | 0 | while (count > 0) { |
241 | 0 | int r = write(fd, buf, count); |
242 | 0 | if (r < 0) { |
243 | 0 | if (errno == EINTR) |
244 | 0 | continue; |
245 | 0 | return r; |
246 | 0 | } |
247 | 0 | if (r == 0) |
248 | 0 | return n; |
249 | 0 | buf = (const char *)buf + r; |
250 | 0 | count -= r; |
251 | 0 | n += r; |
252 | 0 | } |
253 | 0 | return n; |
254 | 0 | } |
255 | | |
256 | | int countbits(int b) |
257 | 0 | { |
258 | 0 | int count; |
259 | |
|
260 | 0 | for (count = 0; b != 0; count++) { |
261 | 0 | b &= b - 1; // this clears the LSB-most set bit |
262 | 0 | } |
263 | |
|
264 | 0 | return (count); |
265 | 0 | } |
266 | | |
267 | | int count_mask(struct sockaddr_in6 *m) |
268 | 0 | { |
269 | 0 | struct in6_addr *in6 = &m->sin6_addr; |
270 | 0 | int i; |
271 | 0 | int count = 0; |
272 | |
|
273 | 0 | for (i = 0; i < 16; ++i) { |
274 | 0 | count += countbits(in6->s6_addr[i]); |
275 | 0 | } |
276 | 0 | return count; |
277 | 0 | } |
278 | | |
279 | | struct in6_addr get_prefix6(struct in6_addr const *addr, struct in6_addr const *mask) |
280 | 0 | { |
281 | 0 | struct in6_addr prefix = *addr; |
282 | 0 | int i = 0; |
283 | |
|
284 | 0 | for (; i < 16; ++i) { |
285 | 0 | prefix.s6_addr[i] &= mask->s6_addr[i]; |
286 | 0 | } |
287 | |
|
288 | 0 | return prefix; |
289 | 0 | } |