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