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