xref: /openbsd/usr.sbin/radiusd/util.c (revision 515e489c)
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