LCOV - code coverage report
Current view: top level - net/sunrpc - addr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 95 0.0 %
Date: 2014-04-07 Functions: 0 9 0.0 %
Branches: 0 83 0.0 %

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

Generated by: LCOV version 1.9