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 */
32 int
addrport_parse(const char * addrport,int proto,struct addrinfo ** p_ai)33 addrport_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 */
81 const char *
addrport_tostring(struct sockaddr * sa,socklen_t salen,char * buf,size_t lbuf)82 addrport_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