1/* $NetBSD: sockaddr_snprintf.c,v 1.8 2007/07/24 08:45:45 dyoung Exp $ */ 2 3/*- 4 * Copyright (c) 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31#include <sys/cdefs.h> 32#if defined(LIBC_SCCS) && !defined(lint) 33__RCSID("$NetBSD: sockaddr_snprintf.c,v 1.8 2007/07/24 08:45:45 dyoung Exp $"); 34#endif /* LIBC_SCCS and not lint */ 35 36#include <sys/types.h> 37#include <sys/socket.h> 38#include <sys/un.h> 39 40#include <netinet/in.h> 41#include <netatalk/at.h> 42#include <net/if_dl.h> 43 44#include <stdio.h> 45#include <string.h> 46#include <errno.h> 47#include <util.h> 48#include <netdb.h> 49 50int 51sockaddr_snprintf(char * const sbuf, const size_t len, const char * const fmt, 52 const struct sockaddr * const sa) 53{ 54 const void *a = NULL; 55 char abuf[1024], nbuf[1024], *addr = NULL, *w = NULL; 56 char Abuf[1024], pbuf[32], *name = NULL, *port = NULL; 57 char *ebuf = &sbuf[len - 1], *buf = sbuf; 58 const char *ptr, *s; 59 int p = -1; 60 const struct sockaddr_at *sat = NULL; 61 const struct sockaddr_in *sin4 = NULL; 62 const struct sockaddr_in6 *sin6 = NULL; 63 const struct sockaddr_un *sun = NULL; 64 const struct sockaddr_dl *sdl = NULL; 65 int na = 1; 66 67#define ADDC(c) do { if (buf < ebuf) *buf++ = c; else buf++; } \ 68 while (/*CONSTCOND*/0) 69#define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \ 70 while (/*CONSTCOND*/0) 71#define ADDNA() do { if (na) ADDS("N/A"); } \ 72 while (/*CONSTCOND*/0) 73 74 switch (sa->sa_family) { 75 case AF_UNSPEC: 76 goto done; 77 case AF_APPLETALK: 78 sat = ((const struct sockaddr_at *)(const void *)sa); 79 p = ntohs(sat->sat_port); 80 (void)snprintf(addr = abuf, sizeof(abuf), "%u.%u", 81 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 82 (void)snprintf(port = pbuf, sizeof(pbuf), "%d", p); 83 break; 84 case AF_LOCAL: 85 sun = ((const struct sockaddr_un *)(const void *)sa); 86 (void)strlcpy(addr = abuf, sun->sun_path, SUN_LEN(sun)); 87 break; 88 case AF_INET: 89 sin4 = ((const struct sockaddr_in *)(const void *)sa); 90 p = ntohs(sin4->sin_port); 91 a = &sin4->sin_addr; 92 break; 93 case AF_INET6: 94 sin6 = ((const struct sockaddr_in6 *)(const void *)sa); 95 p = ntohs(sin6->sin6_port); 96 a = &sin6->sin6_addr; 97 break; 98 case AF_LINK: 99 sdl = ((const struct sockaddr_dl *)(const void *)sa); 100 (void)strlcpy(addr = abuf, link_ntoa(sdl), sizeof(abuf)); 101 if ((w = strchr(addr, ':')) != 0) { 102 *w++ = '\0'; 103 addr = w; 104 } 105 break; 106 default: 107 errno = EAFNOSUPPORT; 108 return -1; 109 } 110 111 if (addr == abuf) 112 name = addr; 113 114 if (a && getnameinfo(sa, (socklen_t)sa->sa_len, addr = abuf, 115 (unsigned int)sizeof(abuf), NULL, 0, 116 NI_NUMERICHOST|NI_NUMERICSERV) != 0) 117 return -1; 118 119 for (ptr = fmt; *ptr; ptr++) { 120 if (*ptr != '%') { 121 ADDC(*ptr); 122 continue; 123 } 124 next_char: 125 switch (*++ptr) { 126 case '?': 127 na = 0; 128 goto next_char; 129 case 'a': 130 ADDS(addr); 131 break; 132 case 'p': 133 if (p != -1) { 134 (void)snprintf(nbuf, sizeof(nbuf), "%d", p); 135 ADDS(nbuf); 136 } else 137 ADDNA(); 138 break; 139 case 'f': 140 (void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_family); 141 ADDS(nbuf); 142 break; 143 case 'l': 144 (void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_len); 145 ADDS(nbuf); 146 break; 147 case 'A': 148 if (name) 149 ADDS(name); 150 else if (!a) 151 ADDNA(); 152 else { 153 getnameinfo(sa, (socklen_t)sa->sa_len, 154 name = Abuf, 155 (unsigned int)sizeof(nbuf), NULL, 0, 0); 156 ADDS(name); 157 } 158 break; 159 case 'P': 160 if (port) 161 ADDS(port); 162 else if (p == -1) 163 ADDNA(); 164 else { 165 getnameinfo(sa, (socklen_t)sa->sa_len, NULL, 0, 166 port = pbuf, 167 (unsigned int)sizeof(pbuf), 0); 168 ADDS(port); 169 } 170 break; 171 case 'I': 172 if (sdl && addr != abuf) { 173 ADDS(abuf); 174 } else { 175 ADDNA(); 176 } 177 break; 178 case 'F': 179 if (sin6) { 180 (void)snprintf(nbuf, sizeof(nbuf), "%d", 181 sin6->sin6_flowinfo); 182 ADDS(nbuf); 183 break; 184 } else { 185 ADDNA(); 186 } 187 break; 188 case 'S': 189 if (sin6) { 190 (void)snprintf(nbuf, sizeof(nbuf), "%d", 191 sin6->sin6_scope_id); 192 ADDS(nbuf); 193 break; 194 } else { 195 ADDNA(); 196 } 197 break; 198 case 'R': 199 if (sat) { 200 const struct netrange *n = 201 &sat->sat_range.r_netrange; 202 (void)snprintf(nbuf, sizeof(nbuf), 203 "%d:[%d,%d]", n->nr_phase , n->nr_firstnet, 204 n->nr_lastnet); 205 ADDS(nbuf); 206 } else { 207 ADDNA(); 208 } 209 break; 210 default: 211 ADDC('%'); 212 if (na == 0) 213 ADDC('?'); 214 if (*ptr == '\0') 215 goto done; 216 /*FALLTHROUGH*/ 217 case '%': 218 ADDC(*ptr); 219 break; 220 } 221 na = 1; 222 } 223done: 224 if (buf < ebuf) 225 *buf = '\0'; 226 else if (len != 0) 227 sbuf[len - 1] = '\0'; 228 return (int)(buf - sbuf); 229} 230