linux/net/sunrpc/addr.c
<<
>>
Prefs
   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
  24static 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
  70static 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
 101static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
 102                                  char *buf, const int buflen)
 103{
 104        return 0;
 105}
 106
 107static 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
 115static 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 */
 132size_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}
 143EXPORT_SYMBOL_GPL(rpc_ntop);
 144
 145static 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)
 164static 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
 206static 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
 229static 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 */
 250size_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}
 260EXPORT_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 */
 270char *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}
 300EXPORT_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 * @uaddr does not have to be '\0'-terminated, but strict_strtoul() and
 310 * rpc_pton() require proper string termination to be successful.
 311 *
 312 * Returns the size of the socket address if successful; otherwise
 313 * zero is returned.
 314 */
 315size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len,
 316                          struct sockaddr *sap, const size_t salen)
 317{
 318        char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')];
 319        unsigned long 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(strict_strtoul(c + 1, 10, &portlo) != 0))
 332                return 0;
 333        if (unlikely(portlo > 255))
 334                return 0;
 335
 336        *c = '\0';
 337        c = strrchr(buf, '.');
 338        if (unlikely(c == NULL))
 339                return 0;
 340        if (unlikely(strict_strtoul(c + 1, 10, &porthi) != 0))
 341                return 0;
 342        if (unlikely(porthi > 255))
 343                return 0;
 344
 345        port = (unsigned short)((porthi << 8) | portlo);
 346
 347        *c = '\0';
 348        if (rpc_pton(buf, strlen(buf), sap, salen) == 0)
 349                return 0;
 350
 351        switch (sap->sa_family) {
 352        case AF_INET:
 353                ((struct sockaddr_in *)sap)->sin_port = htons(port);
 354                return sizeof(struct sockaddr_in);
 355        case AF_INET6:
 356                ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
 357                return sizeof(struct sockaddr_in6);
 358        }
 359
 360        return 0;
 361}
 362EXPORT_SYMBOL_GPL(rpc_uaddr2sockaddr);
 363