1159cf9flidl/*	$NetBSD: sockaddr_snprintf.c,v 1.11 2016/06/01 22:57:51 christos Exp $	*/
27828fb4lidl
37828fb4lidl/*-
47828fb4lidl * Copyright (c) 2004 The NetBSD Foundation, Inc.
57828fb4lidl * All rights reserved.
67828fb4lidl *
77828fb4lidl * This code is derived from software contributed to The NetBSD Foundation
87828fb4lidl * by Christos Zoulas.
97828fb4lidl *
107828fb4lidl * Redistribution and use in source and binary forms, with or without
117828fb4lidl * modification, are permitted provided that the following conditions
127828fb4lidl * are met:
137828fb4lidl * 1. Redistributions of source code must retain the above copyright
147828fb4lidl *    notice, this list of conditions and the following disclaimer.
157828fb4lidl * 2. Redistributions in binary form must reproduce the above copyright
167828fb4lidl *    notice, this list of conditions and the following disclaimer in the
177828fb4lidl *    documentation and/or other materials provided with the distribution.
187828fb4lidl *
197828fb4lidl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
207828fb4lidl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
217828fb4lidl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
227828fb4lidl * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
237828fb4lidl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
247828fb4lidl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
257828fb4lidl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
267828fb4lidl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
277828fb4lidl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
287828fb4lidl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
297828fb4lidl * POSSIBILITY OF SUCH DAMAGE.
307828fb4lidl */
317828fb4lidl#ifdef HAVE_CONFIG_H
327828fb4lidl#include "config.h"
337828fb4lidl#endif
347828fb4lidl
357828fb4lidl#include <sys/cdefs.h>
367828fb4lidl#if defined(LIBC_SCCS) && !defined(lint)
37159cf9flidl__RCSID("$NetBSD: sockaddr_snprintf.c,v 1.11 2016/06/01 22:57:51 christos Exp $");
387828fb4lidl#endif /* LIBC_SCCS and not lint */
397828fb4lidl
407828fb4lidl#include <sys/param.h>
417828fb4lidl#include <sys/types.h>
427828fb4lidl#include <sys/socket.h>
437828fb4lidl#include <sys/un.h>
447828fb4lidl
457828fb4lidl#include <netinet/in.h>
467828fb4lidl#ifdef __linux__
477828fb4lidl#undef HAVE_NETATALK_AT_H
487828fb4lidl#endif
497828fb4lidl#ifdef HAVE_NETATALK_AT_H
507828fb4lidl#include <netatalk/at.h>
517828fb4lidl#endif
527828fb4lidl#ifdef HAVE_NET_IF_DL_H
537828fb4lidl#include <net/if_dl.h>
547828fb4lidl#endif
557828fb4lidl
567828fb4lidl#include <stdio.h>
577828fb4lidl#include <string.h>
587828fb4lidl#include <errno.h>
597828fb4lidl#include <stdlib.h>
607828fb4lidl#ifdef HAVE_LIBUTIL_H
617828fb4lidl#include <libutil.h>
627828fb4lidl#endif
637828fb4lidl#ifdef HAVE_UTIL_H
647828fb4lidl#include <util.h>
657828fb4lidl#endif
667828fb4lidl#include <netdb.h>
677828fb4lidl
687828fb4lidl#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
697828fb4lidl#define SLEN(a)	(a)->a ## _len
707828fb4lidl#else
717828fb4lidlstatic socklen_t
727828fb4lidlsocklen(u_int af)
737828fb4lidl{
747828fb4lidl	switch (af) {
757828fb4lidl	case AF_INET:
767828fb4lidl		return sizeof(struct sockaddr_in);
777828fb4lidl	case AF_INET6:
787828fb4lidl		return sizeof(struct sockaddr_in6);
797828fb4lidl	case AF_LOCAL:
807828fb4lidl		return sizeof(struct sockaddr_un);
817828fb4lidl#ifdef HAVE_NET_IF_DL_H
827828fb4lidl	case AF_LINK:
837828fb4lidl		return sizeof(struct sockaddr_dl);
847828fb4lidl#endif
857828fb4lidl#ifdef HAVE_NETATALK_AT_H
867828fb4lidl	case AF_APPLETALK:
877828fb4lidl		return sizeof(struct sockaddr_at);
887828fb4lidl#endif
897828fb4lidl	default:
907828fb4lidl		return sizeof(struct sockaddr_storage);
917828fb4lidl	}
927828fb4lidl}
937828fb4lidl
947828fb4lidl#define SLEN(a)	socklen((a)->a ## _family)
957828fb4lidl#endif
967828fb4lidl
977828fb4lidl#ifdef HAVE_NETATALK_AT_H
987828fb4lidlstatic int
997828fb4lidldebug_at(char *str, size_t len, const struct sockaddr_at *sat)
1007828fb4lidl{
1017828fb4lidl	return snprintf(str, len, "sat_len=%u, sat_family=%u, sat_port=%u, "
1027828fb4lidl	    "sat_addr.s_net=%u, sat_addr.s_node=%u, "
1037828fb4lidl	    "sat_range.r_netrange.nr_phase=%u, "
1047828fb4lidl	    "sat_range.r_netrange.nr_firstnet=%u, "
1057828fb4lidl	    "sat_range.r_netrange.nr_lastnet=%u",
1067828fb4lidl	    SLEN(sat), sat->sat_family, sat->sat_port,
1077828fb4lidl	    sat->sat_addr.s_net, sat->sat_addr.s_node,
1087828fb4lidl	    sat->sat_range.r_netrange.nr_phase,
1097828fb4lidl	    sat->sat_range.r_netrange.nr_firstnet,
1107828fb4lidl	    sat->sat_range.r_netrange.nr_lastnet);
1117828fb4lidl}
1127828fb4lidl#endif
1137828fb4lidl
1147828fb4lidlstatic int
1157828fb4lidldebug_in(char *str, size_t len, const struct sockaddr_in *sin)
1167828fb4lidl{
1177828fb4lidl	return snprintf(str, len, "sin_len=%u, sin_family=%u, sin_port=%u, "
1187828fb4lidl	    "sin_addr.s_addr=%08x",
1197828fb4lidl	    SLEN(sin), sin->sin_family, sin->sin_port,
1207828fb4lidl	    sin->sin_addr.s_addr);
1217828fb4lidl}
1227828fb4lidl
1237828fb4lidlstatic int
1247828fb4lidldebug_in6(char *str, size_t len, const struct sockaddr_in6 *sin6)
1257828fb4lidl{
1267828fb4lidl	const uint8_t *s = sin6->sin6_addr.s6_addr;
1277828fb4lidl
1287828fb4lidl	return snprintf(str, len, "sin6_len=%u, sin6_family=%u, sin6_port=%u, "
1297828fb4lidl	    "sin6_flowinfo=%u, "
1307828fb4lidl	    "sin6_addr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
1317828fb4lidl	    "%02x:%02x:%02x:%02x:%02x:%02x, sin6_scope_id=%u",
1327828fb4lidl	    SLEN(sin6), sin6->sin6_family, sin6->sin6_port,
1337828fb4lidl	    sin6->sin6_flowinfo, s[0x0], s[0x1], s[0x2], s[0x3], s[0x4], s[0x5],
1347828fb4lidl	    s[0x6], s[0x7], s[0x8], s[0x9], s[0xa], s[0xb], s[0xc], s[0xd],
1357828fb4lidl	    s[0xe], s[0xf], sin6->sin6_scope_id);
1367828fb4lidl}
1377828fb4lidl
1387828fb4lidlstatic int
1397828fb4lidldebug_un(char *str, size_t len, const struct sockaddr_un *sun)
1407828fb4lidl{
1417828fb4lidl	return snprintf(str, len, "sun_len=%u, sun_family=%u, sun_path=%*s",
1427828fb4lidl	    SLEN(sun), sun->sun_family, (int)sizeof(sun->sun_path),
1437828fb4lidl	    sun->sun_path);
1447828fb4lidl}
1457828fb4lidl
1467828fb4lidl#ifdef HAVE_NET_IF_DL_H
1477828fb4lidlstatic int
1487828fb4lidldebug_dl(char *str, size_t len, const struct sockaddr_dl *sdl)
1497828fb4lidl{
1507828fb4lidl	const uint8_t *s = (const void *)sdl->sdl_data;
1517828fb4lidl
1527828fb4lidl	return snprintf(str, len, "sdl_len=%u, sdl_family=%u, sdl_index=%u, "
1537828fb4lidl	    "sdl_type=%u, sdl_nlen=%u, sdl_alen=%u, sdl_slen=%u, sdl_data="
1547828fb4lidl	    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
1557828fb4lidl	    SLEN(sdl), sdl->sdl_family, sdl->sdl_index,
1567828fb4lidl	    sdl->sdl_type, sdl->sdl_nlen, sdl->sdl_alen, sdl->sdl_slen,
1577828fb4lidl	    s[0x0], s[0x1], s[0x2], s[0x3], s[0x4], s[0x5],
1587828fb4lidl	    s[0x6], s[0x7], s[0x8], s[0x9], s[0xa], s[0xb]);
1597828fb4lidl}
1607828fb4lidl#endif
1617828fb4lidl
1627828fb4lidlint
1637828fb4lidlsockaddr_snprintf(char * const sbuf, const size_t len, const char * const fmt,
1647828fb4lidl    const struct sockaddr * const sa)
1657828fb4lidl{
1667828fb4lidl	const void *a = NULL;
1677828fb4lidl	char abuf[1024], nbuf[1024], *addr = NULL;
1687828fb4lidl
1697828fb4lidl	char Abuf[1024], pbuf[32], *name = NULL, *port = NULL;
1707828fb4lidl	char *ebuf = &sbuf[len - 1], *buf = sbuf;
1717828fb4lidl	const char *ptr, *s;
1727828fb4lidl	int p = -1;
1737828fb4lidl#ifdef HAVE_NETATALK_AT_H
1747828fb4lidl	const struct sockaddr_at *sat = NULL;
1757828fb4lidl#endif
1767828fb4lidl	const struct sockaddr_in *sin4 = NULL;
1777828fb4lidl	const struct sockaddr_in6 *sin6 = NULL;
1787828fb4lidl	const struct sockaddr_un *sun = NULL;
1797828fb4lidl#ifdef HAVE_NET_IF_DL_H
1807828fb4lidl	const struct sockaddr_dl *sdl = NULL;
1817828fb4lidl	char *w = NULL;
1827828fb4lidl#endif
1837828fb4lidl	int na = 1;
1847828fb4lidl
1857828fb4lidl#define ADDC(c) do { if (buf < ebuf) *buf++ = c; else buf++; } \
1867828fb4lidl	while (/*CONSTCOND*/0)
1877828fb4lidl#define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \
1887828fb4lidl	while (/*CONSTCOND*/0)
1897828fb4lidl#define ADDNA() do { if (na) ADDS("N/A"); } \
1907828fb4lidl	while (/*CONSTCOND*/0)
1917828fb4lidl
1927828fb4lidl	switch (sa->sa_family) {
1937828fb4lidl	case AF_UNSPEC:
1947828fb4lidl		goto done;
1957828fb4lidl#ifdef HAVE_NETATALK_AT_H
1967828fb4lidl	case AF_APPLETALK:
1977828fb4lidl		sat = ((const struct sockaddr_at *)(const void *)sa);
1987828fb4lidl		p = ntohs(sat->sat_port);
1997828fb4lidl		(void)snprintf(addr = abuf, sizeof(abuf), "%u.%u",
2007828fb4lidl			ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
2017828fb4lidl		(void)snprintf(port = pbuf, sizeof(pbuf), "%d", p);
2027828fb4lidl		break;
2037828fb4lidl#endif
2047828fb4lidl	case AF_LOCAL:
2057828fb4lidl		sun = ((const struct sockaddr_un *)(const void *)sa);
2067828fb4lidl		(void)strlcpy(addr = abuf, sun->sun_path, sizeof(abuf));
2077828fb4lidl		break;
2087828fb4lidl	case AF_INET:
2097828fb4lidl		sin4 = ((const struct sockaddr_in *)(const void *)sa);
2107828fb4lidl		p = ntohs(sin4->sin_port);
2117828fb4lidl		a = &sin4->sin_addr;
2127828fb4lidl		break;
2137828fb4lidl	case AF_INET6:
2147828fb4lidl		sin6 = ((const struct sockaddr_in6 *)(const void *)sa);
2157828fb4lidl		p = ntohs(sin6->sin6_port);
2167828fb4lidl		a = &sin6->sin6_addr;
2177828fb4lidl		break;
2187828fb4lidl#ifdef HAVE_NET_IF_DL_H
2197828fb4lidl	case AF_LINK:
2207828fb4lidl		sdl = ((const struct sockaddr_dl *)(const void *)sa);
2217828fb4lidl		(void)strlcpy(addr = abuf, link_ntoa(sdl), sizeof(abuf));
222159cf9flidl		if ((w = strchr(addr, ':')) != NULL) {
2237828fb4lidl			*w++ = '\0';
2247828fb4lidl			addr = w;
2257828fb4lidl		}
2267828fb4lidl		break;
2277828fb4lidl#endif
2287828fb4lidl	default:
2297828fb4lidl		errno = EAFNOSUPPORT;
2307828fb4lidl		return -1;
2317828fb4lidl	}
2327828fb4lidl
2337828fb4lidl	if (addr == abuf)
2347828fb4lidl		name = addr;
2357828fb4lidl
2367828fb4lidl	if (a && getnameinfo(sa, (socklen_t)SLEN(sa), addr = abuf,
2377828fb4lidl	    (unsigned int)sizeof(abuf), NULL, 0,
2387828fb4lidl	    NI_NUMERICHOST|NI_NUMERICSERV) != 0)
2397828fb4lidl		return -1;
2407828fb4lidl
2417828fb4lidl	for (ptr = fmt; *ptr; ptr++) {
2427828fb4lidl		if (*ptr != '%') {
2437828fb4lidl			ADDC(*ptr);
2447828fb4lidl			continue;
2457828fb4lidl		}
2467828fb4lidl	  next_char:
2477828fb4lidl		switch (*++ptr) {
2487828fb4lidl		case '?':
2497828fb4lidl			na = 0;
2507828fb4lidl			goto next_char;
2517828fb4lidl		case 'a':
2527828fb4lidl			ADDS(addr);
2537828fb4lidl			break;
2547828fb4lidl		case 'p':
2557828fb4lidl			if (p != -1) {
2567828fb4lidl				(void)snprintf(nbuf, sizeof(nbuf), "%d", p);
2577828fb4lidl				ADDS(nbuf);
2587828fb4lidl			} else
2597828fb4lidl				ADDNA();
2607828fb4lidl			break;
2617828fb4lidl		case 'f':
2627828fb4lidl			(void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_family);
2637828fb4lidl			ADDS(nbuf);
2647828fb4lidl			break;
2657828fb4lidl		case 'l':
2667828fb4lidl			(void)snprintf(nbuf, sizeof(nbuf), "%d", SLEN(sa));
2677828fb4lidl			ADDS(nbuf);
2687828fb4lidl			break;
2697828fb4lidl		case 'A':
2707828fb4lidl			if (name)
2717828fb4lidl				ADDS(name);
2727828fb4lidl			else if (!a)
2737828fb4lidl				ADDNA();
2747828fb4lidl			else {
2757828fb4lidl				getnameinfo(sa, (socklen_t)SLEN(sa),
2767828fb4lidl					name = Abuf,
2777828fb4lidl					(unsigned int)sizeof(nbuf), NULL, 0, 0);
2787828fb4lidl				ADDS(name);
2797828fb4lidl			}
2807828fb4lidl			break;
2817828fb4lidl		case 'P':
2827828fb4lidl			if (port)
2837828fb4lidl				ADDS(port);
2847828fb4lidl			else if (p == -1)
2857828fb4lidl				ADDNA();
2867828fb4lidl			else {
2877828fb4lidl				getnameinfo(sa, (socklen_t)SLEN(sa), NULL, 0,
2887828fb4lidl					port = pbuf,
2897828fb4lidl					(unsigned int)sizeof(pbuf), 0);
2907828fb4lidl				ADDS(port);
2917828fb4lidl			}
2927828fb4lidl			break;
2937828fb4lidl		case 'I':
2947828fb4lidl#ifdef HAVE_NET_IF_DL_H
2957828fb4lidl			if (sdl && addr != abuf) {
2967828fb4lidl				ADDS(abuf);
2977828fb4lidl			} else
2987828fb4lidl#endif
2997828fb4lidl			{
3007828fb4lidl				ADDNA();
3017828fb4lidl			}
3027828fb4lidl			break;
3037828fb4lidl		case 'F':
3047828fb4lidl			if (sin6) {
3057828fb4lidl				(void)snprintf(nbuf, sizeof(nbuf), "%d",
3067828fb4lidl				    sin6->sin6_flowinfo);
3077828fb4lidl				ADDS(nbuf);
3087828fb4lidl				break;
3097828fb4lidl			} else {
3107828fb4lidl				ADDNA();
3117828fb4lidl			}
3127828fb4lidl			break;
3137828fb4lidl		case 'S':
3147828fb4lidl			if (sin6) {
3157828fb4lidl				(void)snprintf(nbuf, sizeof(nbuf), "%d",
3167828fb4lidl				    sin6->sin6_scope_id);
3177828fb4lidl				ADDS(nbuf);
3187828fb4lidl				break;
3197828fb4lidl			} else {
3207828fb4lidl				ADDNA();
3217828fb4lidl			}
3227828fb4lidl			break;
3237828fb4lidl		case 'R':
3247828fb4lidl#ifdef HAVE_NETATALK_AT_H
3257828fb4lidl			if (sat) {
3267828fb4lidl				const struct netrange *n =
3277828fb4lidl				    &sat->sat_range.r_netrange;
3287828fb4lidl				(void)snprintf(nbuf, sizeof(nbuf),
3297828fb4lidl				    "%d:[%d,%d]", n->nr_phase , n->nr_firstnet,
3307828fb4lidl				    n->nr_lastnet);
3317828fb4lidl				ADDS(nbuf);
3327828fb4lidl			} else
3337828fb4lidl#endif
3347828fb4lidl			{
3357828fb4lidl				ADDNA();
3367828fb4lidl			}
3377828fb4lidl			break;
3387828fb4lidl		case 'D':
3397828fb4lidl			switch (sa->sa_family) {
3407828fb4lidl#ifdef HAVE_NETATALK_AT_H
3417828fb4lidl			case AF_APPLETALK:
3427828fb4lidl				debug_at(nbuf, sizeof(nbuf), sat);
3437828fb4lidl				break;
3447828fb4lidl#endif
3457828fb4lidl			case AF_LOCAL:
3467828fb4lidl				debug_un(nbuf, sizeof(nbuf), sun);
3477828fb4lidl				break;
3487828fb4lidl			case AF_INET:
3497828fb4lidl				debug_in(nbuf, sizeof(nbuf), sin4);
3507828fb4lidl				break;
3517828fb4lidl			case AF_INET6:
3527828fb4lidl				debug_in6(nbuf, sizeof(nbuf), sin6);
3537828fb4lidl				break;
3547828fb4lidl#ifdef HAVE_NET_IF_DL_H
3557828fb4lidl			case AF_LINK:
3567828fb4lidl				debug_dl(nbuf, sizeof(nbuf), sdl);
3577828fb4lidl				break;
3587828fb4lidl#endif
3597828fb4lidl			default:
3607828fb4lidl				abort();
3617828fb4lidl			}
3627828fb4lidl			ADDS(nbuf);
3637828fb4lidl			break;
3647828fb4lidl		default:
3657828fb4lidl			ADDC('%');
3667828fb4lidl			if (na == 0)
3677828fb4lidl				ADDC('?');
3687828fb4lidl			if (*ptr == '\0')
3697828fb4lidl				goto done;
3707828fb4lidl			/*FALLTHROUGH*/
3717828fb4lidl		case '%':
3727828fb4lidl			ADDC(*ptr);
3737828fb4lidl			break;
3747828fb4lidl		}
3757828fb4lidl		na = 1;
3767828fb4lidl	}
3777828fb4lidldone:
3787828fb4lidl	if (buf < ebuf)
3797828fb4lidl		*buf = '\0';
3807828fb4lidl	else if (len != 0)
3817828fb4lidl		sbuf[len - 1] = '\0';
3827828fb4lidl	return (int)(buf - sbuf);
3837828fb4lidl}
384