1 /* 2 * Copyright 2009, Oracle. All rights reserved. 3 * 4 * Convert socket addresses to presentation addresses and universal 5 * addresses, and vice versa. 6 * 7 * Universal addresses are introduced by RFC 1833 and further refined by 8 * recent RFCs describing NFSv4. The universal address format is part 9 * of the external (network) interface provided by rpcbind version 3 10 * and 4, and by NFSv4. Such an address is a string containing a 11 * presentation format IP address followed by a port number in 12 * "hibyte.lobyte" format. 13 * 14 * IPv6 addresses can also include a scope ID, typically denoted by 15 * a '%' followed by a device name or a non-negative integer. Refer to 16 * RFC 4291, Section 2.2 for details on IPv6 presentation formats. 17 */ 18 19 #include <net/ipv6.h> 20 #include <linux/sunrpc/clnt.h> 21 22 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 23 24 static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap, 25 char *buf, const int buflen) 26 { 27 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; 28 const struct in6_addr *addr = &sin6->sin6_addr; 29 30 /* 31 * RFC 4291, Section 2.2.2 32 * 33 * Shorthanded ANY address 34 */ 35 if (ipv6_addr_any(addr)) 36 return snprintf(buf, buflen, "::"); 37 38 /* 39 * RFC 4291, Section 2.2.2 40 * 41 * Shorthanded loopback address 42 */ 43 if (ipv6_addr_loopback(addr)) 44 return snprintf(buf, buflen, "::1"); 45 46 /* 47 * RFC 4291, Section 2.2.3 48 * 49 * Special presentation address format for mapped v4 50 * addresses. 51 */ 52 if (ipv6_addr_v4mapped(addr)) 53 return snprintf(buf, buflen, "::ffff:%pI4", 54 &addr->s6_addr32[3]); 55 56 /* 57 * RFC 4291, Section 2.2.1 58 * 59 * To keep the result as short as possible, especially 60 * since we don't shorthand, we don't want leading zeros 61 * in each halfword, so avoid %pI6. 62 */ 63 return snprintf(buf, buflen, "%x:%x:%x:%x:%x:%x:%x:%x", 64 ntohs(addr->s6_addr16[0]), ntohs(addr->s6_addr16[1]), 65 ntohs(addr->s6_addr16[2]), ntohs(addr->s6_addr16[3]), 66 ntohs(addr->s6_addr16[4]), ntohs(addr->s6_addr16[5]), 67 ntohs(addr->s6_addr16[6]), ntohs(addr->s6_addr16[7])); 68 } 69 70 static size_t rpc_ntop6(const struct sockaddr *sap, 71 char *buf, const size_t buflen) 72 { 73 const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; 74 char scopebuf[IPV6_SCOPE_ID_LEN]; 75 size_t len; 76 int rc; 77 78 len = rpc_ntop6_noscopeid(sap, buf, buflen); 79 if (unlikely(len == 0)) 80 return len; 81 82 if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && 83 !(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_SITELOCAL)) 84 return len; 85 86 rc = snprintf(scopebuf, sizeof(scopebuf), "%c%u", 87 IPV6_SCOPE_DELIMITER, sin6->sin6_scope_id); 88 if (unlikely((size_t)rc > sizeof(scopebuf))) 89 return 0; 90 91 len += rc; 92 if (unlikely(len > buflen)) 93 return 0; 94 95 strcat(buf, scopebuf); 96 return len; 97 } 98 99 #else /* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */ 100 101 static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap, 102 char *buf, const int buflen) 103 { 104 return 0; 105 } 106 107 static size_t rpc_ntop6(const struct sockaddr *sap, 108 char *buf, const size_t buflen) 109 { 110 return 0; 111 } 112 113 #endif /* !(defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)) */ 114 115 static int rpc_ntop4(const struct sockaddr *sap, 116 char *buf, const size_t buflen) 117 { 118 const struct sockaddr_in *sin = (struct sockaddr_in *)sap; 119 120 return snprintf(buf, buflen, "%pI4", &sin->sin_addr); 121 } 122 123 /** 124 * rpc_ntop - construct a presentation address in @buf 125 * @sap: socket address 126 * @buf: construction area 127 * @buflen: size of @buf, in bytes 128 * 129 * Plants a %NUL-terminated string in @buf and returns the length 130 * of the string, excluding the %NUL. Otherwise zero is returned. 131 */ 132 size_t rpc_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) 133 { 134 switch (sap->sa_family) { 135 case AF_INET: 136 return rpc_ntop4(sap, buf, buflen); 137 case AF_INET6: 138 return rpc_ntop6(sap, buf, buflen); 139 } 140 141 return 0; 142 } 143 EXPORT_SYMBOL_GPL(rpc_ntop); 144 145 static size_t rpc_pton4(const char *buf, const size_t buflen, 146 struct sockaddr *sap, const size_t salen) 147 { 148 struct sockaddr_in *sin = (struct sockaddr_in *)sap; 149 u8 *addr = (u8 *)&sin->sin_addr.s_addr; 150 151 if (buflen > INET_ADDRSTRLEN || salen < sizeof(struct sockaddr_in)) 152 return 0; 153 154 memset(sap, 0, sizeof(struct sockaddr_in)); 155 156 if (in4_pton(buf, buflen, addr, '\0', NULL) == 0) 157 return 0; 158 159 sin->sin_family = AF_INET; 160 return sizeof(struct sockaddr_in);; 161 } 162 163 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 164 static int rpc_parse_scope_id(const char *buf, const size_t buflen, 165 const char *delim, struct sockaddr_in6 *sin6) 166 { 167 char *p; 168 size_t len; 169 170 if ((buf + buflen) == delim) 171 return 1; 172 173 if (*delim != IPV6_SCOPE_DELIMITER) 174 return 0; 175 176 if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && 177 !(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_SITELOCAL)) 178 return 0; 179 180 len = (buf + buflen) - delim - 1; 181 p = kstrndup(delim + 1, len, GFP_KERNEL); 182 if (p) { 183 unsigned long scope_id = 0; 184 struct net_device *dev; 185 186 dev = dev_get_by_name(&init_net, p); 187 if (dev != NULL) { 188 scope_id = dev->ifindex; 189 dev_put(dev); 190 } else { 191 if (strict_strtoul(p, 10, &scope_id) == 0) { 192 kfree(p); 193 return 0; 194 } 195 } 196 197 kfree(p); 198 199 sin6->sin6_scope_id = scope_id; 200 return 1; 201 } 202 203 return 0; 204 } 205 206 static size_t rpc_pton6(const char *buf, const size_t buflen, 207 struct sockaddr *sap, const size_t salen) 208 { 209 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; 210 u8 *addr = (u8 *)&sin6->sin6_addr.in6_u; 211 const char *delim; 212 213 if (buflen > (INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN) || 214 salen < sizeof(struct sockaddr_in6)) 215 return 0; 216 217 memset(sap, 0, sizeof(struct sockaddr_in6)); 218 219 if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0) 220 return 0; 221 222 if (!rpc_parse_scope_id(buf, buflen, delim, sin6)) 223 return 0; 224 225 sin6->sin6_family = AF_INET6; 226 return sizeof(struct sockaddr_in6); 227 } 228 #else 229 static size_t rpc_pton6(const char *buf, const size_t buflen, 230 struct sockaddr *sap, const size_t salen) 231 { 232 return 0; 233 } 234 #endif 235 236 /** 237 * rpc_pton - Construct a sockaddr in @sap 238 * @buf: C string containing presentation format IP address 239 * @buflen: length of presentation address in bytes 240 * @sap: buffer into which to plant socket address 241 * @salen: size of buffer in bytes 242 * 243 * Returns the size of the socket address if successful; otherwise 244 * zero is returned. 245 * 246 * Plants a socket address in @sap and returns the size of the 247 * socket address, if successful. Returns zero if an error 248 * occurred. 249 */ 250 size_t rpc_pton(const char *buf, const size_t buflen, 251 struct sockaddr *sap, const size_t salen) 252 { 253 unsigned int i; 254 255 for (i = 0; i < buflen; i++) 256 if (buf[i] == ':') 257 return rpc_pton6(buf, buflen, sap, salen); 258 return rpc_pton4(buf, buflen, sap, salen); 259 } 260 EXPORT_SYMBOL_GPL(rpc_pton); 261 262 /** 263 * rpc_sockaddr2uaddr - Construct a universal address string from @sap. 264 * @sap: socket address 265 * 266 * Returns a %NUL-terminated string in dynamically allocated memory; 267 * otherwise NULL is returned if an error occurred. Caller must 268 * free the returned string. 269 */ 270 char *rpc_sockaddr2uaddr(const struct sockaddr *sap) 271 { 272 char portbuf[RPCBIND_MAXUADDRPLEN]; 273 char addrbuf[RPCBIND_MAXUADDRLEN]; 274 unsigned short port; 275 276 switch (sap->sa_family) { 277 case AF_INET: 278 if (rpc_ntop4(sap, addrbuf, sizeof(addrbuf)) == 0) 279 return NULL; 280 port = ntohs(((struct sockaddr_in *)sap)->sin_port); 281 break; 282 case AF_INET6: 283 if (rpc_ntop6_noscopeid(sap, addrbuf, sizeof(addrbuf)) == 0) 284 return NULL; 285 port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port); 286 break; 287 default: 288 return NULL; 289 } 290 291 if (snprintf(portbuf, sizeof(portbuf), 292 ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf)) 293 return NULL; 294 295 if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf)) 296 return NULL; 297 298 return kstrdup(addrbuf, GFP_KERNEL); 299 } 300 EXPORT_SYMBOL_GPL(rpc_sockaddr2uaddr); 301 302 /** 303 * rpc_uaddr2sockaddr - convert a universal address to a socket address. 304 * @uaddr: C string containing universal address to convert 305 * @uaddr_len: length of universal address string 306 * @sap: buffer into which to plant socket address 307 * @salen: size of buffer 308 * 309 * Returns the size of the socket address if successful; otherwise 310 * zero is returned. 311 */ 312 size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, 313 struct sockaddr *sap, const size_t salen) 314 { 315 char *c, buf[RPCBIND_MAXUADDRLEN]; 316 unsigned long portlo, porthi; 317 unsigned short port; 318 319 if (uaddr_len > sizeof(buf)) 320 return 0; 321 322 memcpy(buf, uaddr, uaddr_len); 323 324 buf[uaddr_len] = '\n'; 325 buf[uaddr_len + 1] = '\0'; 326 327 c = strrchr(buf, '.'); 328 if (unlikely(c == NULL)) 329 return 0; 330 if (unlikely(strict_strtoul(c + 1, 10, &portlo) != 0)) 331 return 0; 332 if (unlikely(portlo > 255)) 333 return 0; 334 335 c[0] = '\n'; 336 c[1] = '\0'; 337 338 c = strrchr(buf, '.'); 339 if (unlikely(c == NULL)) 340 return 0; 341 if (unlikely(strict_strtoul(c + 1, 10, &porthi) != 0)) 342 return 0; 343 if (unlikely(porthi > 255)) 344 return 0; 345 346 port = (unsigned short)((porthi << 8) | portlo); 347 348 c[0] = '\0'; 349 350 if (rpc_pton(buf, strlen(buf), sap, salen) == 0) 351 return 0; 352 353 switch (sap->sa_family) { 354 case AF_INET: 355 ((struct sockaddr_in *)sap)->sin_port = htons(port); 356 return sizeof(struct sockaddr_in); 357 case AF_INET6: 358 ((struct sockaddr_in6 *)sap)->sin6_port = htons(port); 359 return sizeof(struct sockaddr_in6); 360 } 361 362 return 0; 363 } 364 EXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr); 365