root/net/sunrpc/addr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rpc_ntop6_noscopeid
  2. rpc_ntop6
  3. rpc_ntop6_noscopeid
  4. rpc_ntop6
  5. rpc_ntop4
  6. rpc_ntop
  7. rpc_pton4
  8. rpc_parse_scope_id
  9. rpc_pton6
  10. rpc_pton6
  11. rpc_pton
  12. rpc_sockaddr2uaddr
  13. rpc_uaddr2sockaddr

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

/* [<][>][^][v][top][bottom][index][help] */