LCOV - code coverage report
Current view: top level - net/sunrpc - addr.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 118 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 9 0.0 %
Branches: 0 71 0.0 %

           Branch data     Line data    Source code
       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                 :          0 : static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
      29                 :            :                                   char *buf, const int buflen)
      30                 :            : {
      31                 :          0 :         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
      32                 :          0 :         const struct in6_addr *addr = &sin6->sin6_addr;
      33                 :            : 
      34                 :            :         /*
      35                 :            :          * RFC 4291, Section 2.2.2
      36                 :            :          *
      37                 :            :          * Shorthanded ANY address
      38                 :            :          */
      39         [ #  # ]:          0 :         if (ipv6_addr_any(addr))
      40                 :          0 :                 return snprintf(buf, buflen, "::");
      41                 :            : 
      42                 :            :         /*
      43                 :            :          * RFC 4291, Section 2.2.2
      44                 :            :          *
      45                 :            :          * Shorthanded loopback address
      46                 :            :          */
      47         [ #  # ]:          0 :         if (ipv6_addr_loopback(addr))
      48                 :          0 :                 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         [ #  # ]:          0 :         if (ipv6_addr_v4mapped(addr))
      57                 :          0 :                 return snprintf(buf, buflen, "::ffff:%pI4",
      58                 :            :                                         &addr->s6_addr32[3]);
      59                 :            : 
      60                 :            :         /*
      61                 :            :          * RFC 4291, Section 2.2.1
      62                 :            :          */
      63                 :          0 :         return snprintf(buf, buflen, "%pI6c", addr);
      64                 :            : }
      65                 :            : 
      66                 :          0 : static size_t rpc_ntop6(const struct sockaddr *sap,
      67                 :            :                         char *buf, const size_t buflen)
      68                 :            : {
      69                 :          0 :         const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
      70                 :          0 :         char scopebuf[IPV6_SCOPE_ID_LEN];
      71                 :          0 :         size_t len;
      72                 :          0 :         int rc;
      73                 :            : 
      74                 :          0 :         len = rpc_ntop6_noscopeid(sap, buf, buflen);
      75         [ #  # ]:          0 :         if (unlikely(len == 0))
      76                 :            :                 return len;
      77                 :            : 
      78         [ #  # ]:          0 :         if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
      79                 :            :                 return len;
      80         [ #  # ]:          0 :         if (sin6->sin6_scope_id == 0)
      81                 :            :                 return len;
      82                 :            : 
      83                 :          0 :         rc = snprintf(scopebuf, sizeof(scopebuf), "%c%u",
      84                 :            :                         IPV6_SCOPE_DELIMITER, sin6->sin6_scope_id);
      85         [ #  # ]:          0 :         if (unlikely((size_t)rc > sizeof(scopebuf)))
      86                 :            :                 return 0;
      87                 :            : 
      88                 :          0 :         len += rc;
      89         [ #  # ]:          0 :         if (unlikely(len > buflen))
      90                 :            :                 return 0;
      91                 :            : 
      92                 :          0 :         strcat(buf, scopebuf);
      93                 :          0 :         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                 :          0 : static int rpc_ntop4(const struct sockaddr *sap,
     113                 :            :                      char *buf, const size_t buflen)
     114                 :            : {
     115                 :          0 :         const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
     116                 :            : 
     117                 :          0 :         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                 :          0 : size_t rpc_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
     130                 :            : {
     131      [ #  #  # ]:          0 :         switch (sap->sa_family) {
     132                 :            :         case AF_INET:
     133                 :          0 :                 return rpc_ntop4(sap, buf, buflen);
     134                 :          0 :         case AF_INET6:
     135                 :          0 :                 return rpc_ntop6(sap, buf, buflen);
     136                 :            :         }
     137                 :            : 
     138                 :            :         return 0;
     139                 :            : }
     140                 :            : EXPORT_SYMBOL_GPL(rpc_ntop);
     141                 :            : 
     142                 :          0 : static size_t rpc_pton4(const char *buf, const size_t buflen,
     143                 :            :                         struct sockaddr *sap, const size_t salen)
     144                 :            : {
     145                 :          0 :         struct sockaddr_in *sin = (struct sockaddr_in *)sap;
     146                 :          0 :         u8 *addr = (u8 *)&sin->sin_addr.s_addr;
     147                 :            : 
     148         [ #  # ]:          0 :         if (buflen > INET_ADDRSTRLEN || salen < sizeof(struct sockaddr_in))
     149                 :            :                 return 0;
     150                 :            : 
     151                 :          0 :         memset(sap, 0, sizeof(struct sockaddr_in));
     152                 :            : 
     153         [ #  # ]:          0 :         if (in4_pton(buf, buflen, addr, '\0', NULL) == 0)
     154                 :            :                 return 0;
     155                 :            : 
     156                 :          0 :         sin->sin_family = AF_INET;
     157                 :          0 :         return sizeof(struct sockaddr_in);
     158                 :            : }
     159                 :            : 
     160                 :            : #if IS_ENABLED(CONFIG_IPV6)
     161                 :          0 : 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                 :          0 :         char *p;
     166                 :          0 :         size_t len;
     167                 :            : 
     168         [ #  # ]:          0 :         if ((buf + buflen) == delim)
     169                 :            :                 return 1;
     170                 :            : 
     171         [ #  # ]:          0 :         if (*delim != IPV6_SCOPE_DELIMITER)
     172                 :            :                 return 0;
     173                 :            : 
     174         [ #  # ]:          0 :         if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
     175                 :            :                 return 0;
     176                 :            : 
     177                 :          0 :         len = (buf + buflen) - delim - 1;
     178                 :          0 :         p = kmemdup_nul(delim + 1, len, GFP_KERNEL);
     179         [ #  # ]:          0 :         if (p) {
     180                 :          0 :                 u32 scope_id = 0;
     181                 :          0 :                 struct net_device *dev;
     182                 :            : 
     183                 :          0 :                 dev = dev_get_by_name(net, p);
     184         [ #  # ]:          0 :                 if (dev != NULL) {
     185                 :          0 :                         scope_id = dev->ifindex;
     186                 :          0 :                         dev_put(dev);
     187                 :            :                 } else {
     188         [ #  # ]:          0 :                         if (kstrtou32(p, 10, &scope_id) == 0) {
     189                 :          0 :                                 kfree(p);
     190                 :          0 :                                 return 0;
     191                 :            :                         }
     192                 :            :                 }
     193                 :            : 
     194                 :          0 :                 kfree(p);
     195                 :            : 
     196                 :          0 :                 sin6->sin6_scope_id = scope_id;
     197                 :          0 :                 return 1;
     198                 :            :         }
     199                 :            : 
     200                 :            :         return 0;
     201                 :            : }
     202                 :            : 
     203                 :          0 : 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                 :          0 :         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
     207                 :          0 :         u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
     208                 :          0 :         const char *delim;
     209                 :            : 
     210                 :          0 :         if (buflen > (INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN) ||
     211         [ #  # ]:          0 :             salen < sizeof(struct sockaddr_in6))
     212                 :            :                 return 0;
     213                 :            : 
     214                 :          0 :         memset(sap, 0, sizeof(struct sockaddr_in6));
     215                 :            : 
     216         [ #  # ]:          0 :         if (in6_pton(buf, buflen, addr, IPV6_SCOPE_DELIMITER, &delim) == 0)
     217                 :            :                 return 0;
     218                 :            : 
     219         [ #  # ]:          0 :         if (!rpc_parse_scope_id(net, buf, buflen, delim, sin6))
     220                 :            :                 return 0;
     221                 :            : 
     222                 :          0 :         sin6->sin6_family = AF_INET6;
     223                 :          0 :         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                 :          0 : size_t rpc_pton(struct net *net, const char *buf, const size_t buflen,
     249                 :            :                 struct sockaddr *sap, const size_t salen)
     250                 :            : {
     251                 :          0 :         unsigned int i;
     252                 :            : 
     253         [ #  # ]:          0 :         for (i = 0; i < buflen; i++)
     254         [ #  # ]:          0 :                 if (buf[i] == ':')
     255                 :          0 :                         return rpc_pton6(net, buf, buflen, sap, salen);
     256                 :          0 :         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                 :          0 : char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags)
     270                 :            : {
     271                 :          0 :         char portbuf[RPCBIND_MAXUADDRPLEN];
     272                 :          0 :         char addrbuf[RPCBIND_MAXUADDRLEN];
     273                 :          0 :         unsigned short port;
     274                 :            : 
     275      [ #  #  # ]:          0 :         switch (sap->sa_family) {
     276                 :            :         case AF_INET:
     277         [ #  # ]:          0 :                 if (rpc_ntop4(sap, addrbuf, sizeof(addrbuf)) == 0)
     278                 :            :                         return NULL;
     279                 :          0 :                 port = ntohs(((struct sockaddr_in *)sap)->sin_port);
     280                 :          0 :                 break;
     281                 :          0 :         case AF_INET6:
     282         [ #  # ]:          0 :                 if (rpc_ntop6_noscopeid(sap, addrbuf, sizeof(addrbuf)) == 0)
     283                 :            :                         return NULL;
     284                 :          0 :                 port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
     285                 :          0 :                 break;
     286                 :            :         default:
     287                 :            :                 return NULL;
     288                 :            :         }
     289                 :            : 
     290         [ #  # ]:          0 :         if (snprintf(portbuf, sizeof(portbuf),
     291                 :            :                      ".%u.%u", port >> 8, port & 0xff) > (int)sizeof(portbuf))
     292                 :            :                 return NULL;
     293                 :            : 
     294         [ #  # ]:          0 :         if (strlcat(addrbuf, portbuf, sizeof(addrbuf)) > sizeof(addrbuf))
     295                 :            :                 return NULL;
     296                 :            : 
     297                 :          0 :         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                 :          0 : 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                 :          0 :         char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')];
     319                 :          0 :         u8 portlo, porthi;
     320                 :          0 :         unsigned short port;
     321                 :            : 
     322         [ #  # ]:          0 :         if (uaddr_len > RPCBIND_MAXUADDRLEN)
     323                 :            :                 return 0;
     324                 :            : 
     325                 :          0 :         memcpy(buf, uaddr, uaddr_len);
     326                 :            : 
     327                 :          0 :         buf[uaddr_len] = '\0';
     328                 :          0 :         c = strrchr(buf, '.');
     329         [ #  # ]:          0 :         if (unlikely(c == NULL))
     330                 :            :                 return 0;
     331         [ #  # ]:          0 :         if (unlikely(kstrtou8(c + 1, 10, &portlo) != 0))
     332                 :            :                 return 0;
     333                 :            : 
     334                 :          0 :         *c = '\0';
     335                 :          0 :         c = strrchr(buf, '.');
     336         [ #  # ]:          0 :         if (unlikely(c == NULL))
     337                 :            :                 return 0;
     338         [ #  # ]:          0 :         if (unlikely(kstrtou8(c + 1, 10, &porthi) != 0))
     339                 :            :                 return 0;
     340                 :            : 
     341                 :          0 :         port = (unsigned short)((porthi << 8) | portlo);
     342                 :            : 
     343                 :          0 :         *c = '\0';
     344         [ #  # ]:          0 :         if (rpc_pton(net, buf, strlen(buf), sap, salen) == 0)
     345                 :            :                 return 0;
     346                 :            : 
     347      [ #  #  # ]:          0 :         switch (sap->sa_family) {
     348                 :          0 :         case AF_INET:
     349                 :          0 :                 ((struct sockaddr_in *)sap)->sin_port = htons(port);
     350                 :          0 :                 return sizeof(struct sockaddr_in);
     351                 :          0 :         case AF_INET6:
     352                 :          0 :                 ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
     353                 :          0 :                 return sizeof(struct sockaddr_in6);
     354                 :            :         }
     355                 :            : 
     356                 :            :         return 0;
     357                 :            : }
     358                 :            : EXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr);

Generated by: LCOV version 1.14