1/*	$OpenBSD: util.c,v 1.3 2019/07/03 03:24:03 deraadt Exp $	*/
2
3/*
4 * Copyright (c) 2013 Internet Initiative Japan Inc.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <netinet/in.h>
21
22#include <netdb.h>
23#include <string.h>
24#include <stdio.h>
25
26#include "util.h"
27
28/*
29 * Convert argument like "192.168.160.1:1723/tcp" or "[::1]:1723/tcp" to
30 * match getaddrinfo(3)'s specification and pass them to getaddrinfo(3).
31 */
32int
33addrport_parse(const char *addrport, int proto, struct addrinfo **p_ai)
34{
35	char		*servp, *nodep, *slash, buf[256];
36	struct addrinfo	 hints;
37
38	strlcpy(buf, addrport, sizeof(buf));
39	if (buf[0] == '[' && (servp = strchr(buf, ']')) != NULL) {
40		nodep = buf + 1;
41		*servp++ = '\0';
42		if (*servp != ':')
43			servp = NULL;
44	} else {
45		nodep = buf;
46		servp = strrchr(nodep, ':');
47	}
48	if (servp != NULL) {
49		*servp = '\0';
50		servp++;
51		slash = strrchr(servp, '/');
52		if (slash != NULL) {
53			/*
54			 * Ignore like "/tcp"
55			 */
56			*slash = '\0';
57			slash++;
58		}
59	} else
60		servp = NULL;
61	memset(&hints, 0, sizeof(hints));
62	hints.ai_flags = AI_NUMERICHOST;
63	hints.ai_family = AF_UNSPEC;
64	switch (proto) {
65	case IPPROTO_TCP:
66		hints.ai_socktype = SOCK_STREAM;
67		break;
68	case IPPROTO_UDP:
69		hints.ai_socktype = SOCK_DGRAM;
70		break;
71	}
72	hints.ai_protocol = proto;
73
74	return (getaddrinfo(nodep, servp, &hints, p_ai));
75}
76
77/*
78 * Make a string like "192.168.160.1:1723" or "[::1]:1723" from a struct
79 * sockaddr
80 */
81const char *
82addrport_tostring(struct sockaddr *sa, socklen_t salen, char *buf, size_t lbuf)
83{
84	char	 hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
85	int	 ret;
86
87	if (getnameinfo(sa, salen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
88	    NI_NUMERICHOST | NI_NUMERICSERV) != 0)
89		return (NULL);
90
91	switch (sa->sa_family) {
92	case AF_INET6:
93		ret = snprintf(buf, lbuf, "[%s]:%s", hbuf, sbuf);
94		break;
95
96	case AF_INET:
97		ret = snprintf(buf, lbuf, "%s:%s", hbuf, sbuf);
98		break;
99
100	default:
101		return "error";
102	}
103
104	if (ret < 0 || ret >= (int)lbuf)
105		return "(error)";
106	return (buf);
107}
108