2 * Copyright (c) 2018, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <tr_name_internal.h>
36 #include <arpa/inet.h>
41 #include <tr_inet_util.h>
44 * Determine whether a string is a valid address of a given family
46 * @param s string to check
47 * @param af address family (probably AF_INET or AF_INET6)
48 * @return 1 if string is a valid address in the given family, 0 if not, -1 on error (errno set)
50 static int is_valid_address(int af, const char *s)
52 unsigned char buf[sizeof(struct in6_addr)];
56 return inet_pton(af, s, buf);
60 * Determine whether a string is a valid IPv6 address reference
62 * I.e., an IPv6 address in brackets
64 * @param s string to validate
65 * @return 1 if a valid reference, 0 otherwise
67 static int tr_valid_ipv6_reference(const char *s)
73 /* check that it starts with an open bracket */
77 /* check that it ends with a close bracket */
79 if (*(s+len-1) != ']')
82 /* make a null-terminated copy of the string omitting the brackets */
83 cpy = talloc_strndup(NULL, s+1, len-2);
85 return 0; /* an error occurred - fail safe */
87 valid_ipv6 = is_valid_address(AF_INET6, cpy);
94 * Validate a host string
96 * The intention is to reject strings that may appear to contain a ':port' spec.
97 * Takes a permissive view of valid: a hostname is valid if either it is a
98 * bracketed IPv6 address reference ([address]) or has no brackets or colons.
99 * This accepts all valid DNS names and IPv4 addresses, as well as many invalid
100 * hostnames. This is ok for accepting a hostname that will later be resolved
101 * because invalid names will fail to resolve. It should *not* be used to ensure
102 * a hostname is compliant with RFC!
104 * Ignores a trailing colon followed by decimal digits.
106 * @param s string to validate
107 * @return 1 if a valid host specification, 0 otherwise
109 static int tr_valid_host(const char *s)
111 if (strchr(s, '[') || strchr(s, ']') || strchr(s, ':'))
112 return tr_valid_ipv6_reference(s);
118 * Check that all characters are decimal digits
121 * @return 1 if all digits, 0 otherwise
123 static int tr_str_all_digits(const char *s)
129 if ( (*s < '0') || (*s > '9'))
137 * Validate and parse a hostname or hostname/port
139 * If port_out is not null, accepts a port as well. This is
140 * stored in *port_out. If no port is given, a 0 is stored.
141 * If an invalid port is given, -1 is stored.
143 * If the hostname is invalid, null is returned and no value
144 * is written to *port_out.
146 * If port_out is null, null will be returned if the string
149 * The return value must be freed with talloc_free unless
152 * @param mem_ctx talloc context for hostname result
153 * @param s string to parse
154 * @param port_out pointer to an allocated integer, or NULL
155 * @return pointer to the hostname or null on error
157 char *tr_parse_host(TALLOC_CTX *mem_ctx, const char *s, int *port_out)
166 /* If we are accepting a port, find the last colon. */
167 if (port_out == NULL)
170 colon = strrchr(s, ':');
172 /* Get a copy of the hostname portion, which may be the entire string. */
174 hostname = talloc_strdup(NULL, s);
176 hostname = talloc_strndup(NULL, s, colon-s);
178 if (hostname == NULL)
179 return NULL; /* failed to dup the hostname */
181 /* Check that the hostname is valid; if not, return null and ignore the port. */
182 if (! tr_valid_host(hostname)) {
183 talloc_free(hostname);
187 /* If we are accepting a port, parse and validate it. */
188 if (port_out != NULL) {
192 port = strtol(colon+1, NULL, 10);
193 if (tr_str_all_digits(colon+1) && (port > 0) && (port <= 65535))
194 *port_out = (int) port;
203 TR_NAME *tr_hostname_and_port_to_name(TR_NAME *hn, int port)
205 TR_NAME *retval = NULL;
207 char *hn_s = tr_name_strdup(hn);
212 s = talloc_asprintf(NULL, "%s:%d", hn_s, port);
216 retval = tr_new_name(s);