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