1 /*
2 * Copyright (c) 2013, Dustin Lundquist <dustin@null-ptr.net>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26 #include <stddef.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h> /* tolower */
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h> /* inet_pton */
35 #include <sys/un.h>
36 #include <assert.h>
37 #include "address.h"
38
39
40 struct Address {
41 enum {
42 HOSTNAME,
43 SOCKADDR,
44 WILDCARD,
45 } type;
46
47 size_t len; /* length of data */
48 uint16_t port; /* for hostname and wildcard */
49 char data[];
50 };
51
52
53 static const char valid_label_bytes[] =
54 "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
55
56
57 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
58
59
60 static int valid_hostname(const char *);
61
62
63 struct Address *
new_address(const char * hostname_or_ip)64 new_address(const char *hostname_or_ip) {
65 struct sockaddr_storage sa;
66 char ip_buf[ADDRESS_BUFFER_SIZE];
67 char *port;
68 size_t len;
69
70 if (hostname_or_ip == NULL)
71 return NULL;
72
73 /* IPv6 address */
74 /* we need to test for raw IPv6 address for IPv4 port combinations since a
75 * colon would give false positives
76 */
77 memset(&sa, 0, sizeof(sa));
78 if (inet_pton(AF_INET6, hostname_or_ip,
79 &((struct sockaddr_in6 *)&sa)->sin6_addr) == 1) {
80 ((struct sockaddr_in6 *)&sa)->sin6_family = AF_INET6;
81
82 return new_address_sa(
83 (struct sockaddr *)&sa,
84 sizeof(struct sockaddr_in6));
85 }
86
87 /* Unix socket */
88 memset(&sa, 0, sizeof(sa));
89 if (strncmp("unix:", hostname_or_ip, 5) == 0) {
90 /* XXX: only supporting pathname unix sockets */
91 ((struct sockaddr_un *)&sa)->sun_family = AF_UNIX;
92 strncpy(((struct sockaddr_un *)&sa)->sun_path,
93 hostname_or_ip + 5, sizeof(struct sockaddr_un) -
94 offsetof(struct sockaddr_un, sun_path));
95
96 return new_address_sa(
97 (struct sockaddr *)&sa, offsetof(struct sockaddr_un, sun_path) +
98 strlen(((struct sockaddr_un *)&sa)->sun_path) + 1);
99 }
100
101 /* Trailing port */
102 if ((port = strrchr(hostname_or_ip, ':')) != NULL &&
103 is_numeric(port + 1)) {
104 len = (size_t)(port - hostname_or_ip);
105 int port_num = atoi(port + 1);
106
107 if (len < sizeof(ip_buf) && port_num >= 0 && port_num <= 65535) {
108 strncpy(ip_buf, hostname_or_ip, len);
109 ip_buf[len] = '\0';
110
111 struct Address *addr = new_address(ip_buf);
112 if (addr != NULL)
113 address_set_port(addr, (uint16_t) port_num);
114
115 return addr;
116 }
117 }
118
119 /* Wildcard */
120 if (strcmp("*", hostname_or_ip) == 0) {
121 struct Address *addr = malloc(sizeof(struct Address));
122 if (addr != NULL) {
123 addr->type = WILDCARD;
124 addr->len = 0;
125 address_set_port(addr, 0);
126 }
127 return addr;
128 }
129
130 /* IPv4 address */
131 memset(&sa, 0, sizeof(sa));
132 if (inet_pton(AF_INET, hostname_or_ip,
133 &((struct sockaddr_in *)&sa)->sin_addr) == 1) {
134 ((struct sockaddr_in *)&sa)->sin_family = AF_INET;
135
136 return new_address_sa(
137 (struct sockaddr *)&sa,
138 sizeof(struct sockaddr_in));
139 }
140
141 /* [IPv6 address] */
142 memset(&sa, 0, sizeof(sa));
143 if (hostname_or_ip[0] == '[' &&
144 (port = strchr(hostname_or_ip, ']')) != NULL) {
145 len = (size_t)(port - hostname_or_ip - 1);
146
147 /* inet_pton() will not parse the IP correctly unless it is in a
148 * separate string.
149 */
150 strncpy(ip_buf, hostname_or_ip + 1, len);
151 ip_buf[len] = '\0';
152
153 if (inet_pton(AF_INET6, ip_buf,
154 &((struct sockaddr_in6 *)&sa)->sin6_addr) == 1) {
155 ((struct sockaddr_in6 *)&sa)->sin6_family = AF_INET6;
156
157 return new_address_sa(
158 (struct sockaddr *)&sa,
159 sizeof(struct sockaddr_in6));
160 }
161 }
162
163 /* hostname */
164 if (valid_hostname(hostname_or_ip)) {
165 len = strlen(hostname_or_ip);
166 struct Address *addr = malloc(
167 offsetof(struct Address, data) + len + 1);
168 if (addr != NULL) {
169 addr->type = HOSTNAME;
170 addr->port = 0;
171 addr->len = len;
172 memcpy(addr->data, hostname_or_ip, len);
173 addr->data[addr->len] = '\0';
174
175 /* Store address in lower case */
176 for (char *c = addr->data; *c != '\0'; c++)
177 *c = tolower(*c);
178 }
179
180 return addr;
181 }
182
183 return NULL;
184 }
185
186 struct Address *
new_address_sa(const struct sockaddr * sa,socklen_t sa_len)187 new_address_sa(const struct sockaddr *sa, socklen_t sa_len) {
188 struct Address *addr = NULL;
189
190 addr = malloc(offsetof(struct Address, data) + sa_len);
191 if (addr != NULL) {
192 addr->type = SOCKADDR;
193 addr->len = sa_len;
194 memcpy(addr->data, sa, sa_len);
195 addr->port = address_port(addr);
196 }
197
198 return addr;
199 }
200
201 struct Address *
copy_address(const struct Address * addr)202 copy_address(const struct Address *addr) {
203 size_t len = address_len(addr);
204 struct Address *new_addr = malloc(len);
205
206 if (new_addr != NULL)
207 memcpy(new_addr, addr, len);
208
209 return new_addr;
210 }
211
212 size_t
address_len(const struct Address * addr)213 address_len(const struct Address *addr) {
214 switch (addr->type) {
215 case HOSTNAME:
216 /* include trailing null byte */
217 return offsetof(struct Address, data) + addr->len + 1;
218 case SOCKADDR:
219 return offsetof(struct Address, data) + addr->len;
220 case WILDCARD:
221 return sizeof(struct Address);
222 default:
223 assert(0);
224 return 0;
225 }
226 }
227
228 int
address_compare(const struct Address * addr_1,const struct Address * addr_2)229 address_compare(const struct Address *addr_1, const struct Address *addr_2) {
230 if (addr_1 == NULL && addr_2 == NULL)
231 return 0;
232 if (addr_1 == NULL && addr_2 != NULL)
233 return -1;
234 if (addr_1 != NULL && addr_2 == NULL)
235 return 1;
236
237 if (addr_1->type < addr_2->type)
238 return -1;
239 if (addr_1->type > addr_2->type)
240 return 1;
241
242 size_t addr1_len = addr_1->len;
243 size_t addr2_len = addr_2->len;
244 int result = memcmp(addr_1->data, addr_2->data, MIN(addr1_len, addr2_len));
245
246 if (result == 0) { /* they match, find a tie breaker */
247 if (addr1_len < addr2_len)
248 return -1;
249 if (addr1_len > addr2_len)
250 return 1;
251
252 if (addr_1->port < addr_2->port)
253 return -1;
254 if (addr_1->port > addr_2->port)
255 return 1;
256 }
257
258 return result;
259 }
260
261 int
address_is_hostname(const struct Address * addr)262 address_is_hostname(const struct Address *addr) {
263 return addr != NULL && addr->type == HOSTNAME;
264 }
265
266 int
address_is_sockaddr(const struct Address * addr)267 address_is_sockaddr(const struct Address *addr) {
268 return addr != NULL && addr->type == SOCKADDR;
269 }
270
271 int
address_is_wildcard(const struct Address * addr)272 address_is_wildcard(const struct Address *addr) {
273 return addr != NULL && addr->type == WILDCARD;
274 }
275
276 const char *
address_hostname(const struct Address * addr)277 address_hostname(const struct Address *addr) {
278 if (addr->type != HOSTNAME)
279 return NULL;
280
281 return addr->data;
282 }
283
284 const struct sockaddr *
address_sa(const struct Address * addr)285 address_sa(const struct Address *addr) {
286 if (addr->type != SOCKADDR)
287 return NULL;
288
289 return (struct sockaddr *)addr->data;
290 }
291
292 socklen_t
address_sa_len(const struct Address * addr)293 address_sa_len(const struct Address *addr) {
294 if (addr->type != SOCKADDR)
295 return 0;
296
297 return addr->len;
298 }
299
300 uint16_t
address_port(const struct Address * addr)301 address_port(const struct Address *addr) {
302 switch (addr->type) {
303 case HOSTNAME:
304 return addr->port;
305 case SOCKADDR:
306 switch (address_sa(addr)->sa_family) {
307 case AF_INET:
308 return ntohs(((struct sockaddr_in *)addr->data)
309 ->sin_port);
310 case AF_INET6:
311 return ntohs(((struct sockaddr_in6 *)addr->data)
312 ->sin6_port);
313 case AF_UNIX:
314 case AF_UNSPEC:
315 return 0;
316 default:
317 assert(0);
318 return 0;
319 }
320 case WILDCARD:
321 return addr->port;
322 default:
323 /* invalid Address type */
324 assert(0);
325 return 0;
326 }
327 }
328
329 void
address_set_port(struct Address * addr,uint16_t port)330 address_set_port(struct Address *addr, uint16_t port) {
331 switch (addr->type) {
332 case SOCKADDR:
333 switch (address_sa(addr)->sa_family) {
334 case AF_INET:
335 (((struct sockaddr_in *)addr->data) ->sin_port) =
336 htons(port);
337 break;
338 case AF_INET6:
339 (((struct sockaddr_in6 *)addr->data) ->sin6_port) =
340 htons(port);
341 break;
342 case AF_UNIX:
343 case AF_UNSPEC:
344 /* no op */
345 break;
346 default:
347 assert(0);
348 }
349 /* fall through */
350 case HOSTNAME:
351 case WILDCARD:
352 addr->port = port;
353 break;
354 default:
355 /* invalid Address type */
356 assert(0);
357 }
358 }
359
360 int
address_set_port_str(struct Address * addr,const char * str)361 address_set_port_str(struct Address *addr, const char* str) {
362 int port = atoi(str);
363 if (port < 0 || port > 65535) {
364 return 0;
365 }
366 address_set_port(addr, (uint16_t) port);
367 return 1;
368 }
369
370 const char *
display_address(const struct Address * addr,char * buffer,size_t buffer_len)371 display_address(const struct Address *addr, char *buffer, size_t buffer_len) {
372 if (addr == NULL || buffer == NULL)
373 return NULL;
374
375 switch (addr->type) {
376 case HOSTNAME:
377 if (addr->port != 0)
378 snprintf(buffer, buffer_len, "%s:%" PRIu16,
379 addr->data,
380 addr->port);
381 else
382 snprintf(buffer, buffer_len, "%s",
383 addr->data);
384 return buffer;
385 case SOCKADDR:
386 return display_sockaddr(addr->data, buffer, buffer_len);
387 case WILDCARD:
388 if (addr->port != 0)
389 snprintf(buffer, buffer_len, "*:%" PRIu16,
390 addr->port);
391 else
392 snprintf(buffer, buffer_len, "*");
393 return buffer;
394 default:
395 assert(0);
396 return NULL;
397 }
398 }
399
400 const char *
display_sockaddr(const void * sa,char * buffer,size_t buffer_len)401 display_sockaddr(const void *sa, char *buffer, size_t buffer_len) {
402 char ip[INET6_ADDRSTRLEN];
403 if (sa == NULL || buffer == NULL)
404 return NULL;
405
406 switch (((const struct sockaddr *)sa)->sa_family) {
407 case AF_INET:
408 inet_ntop(AF_INET,
409 &((const struct sockaddr_in *)sa)->sin_addr,
410 ip, sizeof(ip));
411
412 if (((struct sockaddr_in *)sa)->sin_port != 0)
413 snprintf(buffer, buffer_len, "%s:%" PRIu16, ip,
414 ntohs(((struct sockaddr_in *)sa)->sin_port));
415 else
416 snprintf(buffer, buffer_len, "%s", ip);
417
418 break;
419 case AF_INET6:
420 inet_ntop(AF_INET6,
421 &((const struct sockaddr_in6 *)sa)->sin6_addr,
422 ip, sizeof(ip));
423
424 if (((struct sockaddr_in6 *)sa)->sin6_port != 0)
425 snprintf(buffer, buffer_len, "[%s]:%" PRIu16, ip,
426 ntohs(((struct sockaddr_in6 *)sa)->sin6_port));
427 else
428 snprintf(buffer, buffer_len, "[%s]", ip);
429
430 break;
431 case AF_UNIX:
432 snprintf(buffer, buffer_len, "unix:%s",
433 ((struct sockaddr_un *)sa)->sun_path);
434 break;
435 case AF_UNSPEC:
436 snprintf(buffer, buffer_len, "NONE");
437 break;
438 default:
439 /* unexpected AF */
440 assert(0);
441 }
442 return buffer;
443 }
444
445 int
is_numeric(const char * s)446 is_numeric(const char *s) {
447 char *p;
448
449 if (s == NULL || *s == '\0')
450 return 0;
451
452 int n = strtod(s, &p);
453 (void)n; /* unused */
454
455 return *p == '\0'; /* entire string was numeric */
456 }
457
458 static int
valid_hostname(const char * hostname)459 valid_hostname(const char *hostname) {
460 if (hostname == NULL)
461 return 0;
462
463 size_t hostname_len = strlen(hostname);
464 if (hostname_len < 1 || hostname_len > 255)
465 return 0;
466
467 if (hostname[0] == '.')
468 return 0;
469
470 const char *hostname_end = hostname + hostname_len;
471 for (const char *label = hostname; label < hostname_end;) {
472 size_t label_len = (size_t)(hostname_end - label);
473 char *next_dot = strchr(label, '.');
474 if (next_dot != NULL)
475 label_len = (size_t)(next_dot - label);
476 assert(label + label_len <= hostname_end);
477
478 if (label_len > 63 || label_len < 1)
479 return 0;
480
481 if (label[0] == '-' || label[label_len - 1] == '-')
482 return 0;
483
484 if (strspn(label, valid_label_bytes) < label_len)
485 return 0;
486
487 label += label_len + 1;
488 }
489
490 return 1;
491 }
492