Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/inet/addr.c

    r683e584 r26de91a  
    11/*
    22 * Copyright (c) 2013 Jiri Svoboda
    3  * Copyright (c) 2013 Martin Decky
    43 * All rights reserved.
    54 *
     
    3736#include <errno.h>
    3837#include <unistd.h>
     38#include <net/socket_codes.h>
    3939#include <inet/addr.h>
     40#include <net/inet.h>
    4041#include <stdio.h>
    4142#include <malloc.h>
     
    4344
    4445#define INET_PREFIXSTRSIZE  5
    45 
    46 #define INET6_ADDRSTRLEN (8 * 4 + 7 + 1)
    4746
    4847#if !(defined(__BE__) ^ defined(__LE__))
     
    181180}
    182181
     182/** Determine address version.
     183 *
     184 * @param text Address in common notation.
     185 * @param af   Place to store address version.
     186 *
     187 * @return EOK on success, EINVAL if input is not in valid format.
     188 *
     189 */
     190static int inet_addr_version(const char *text, ip_ver_t *ver)
     191{
     192        char *dot = str_chr(text, '.');
     193        if (dot != NULL) {
     194                *ver = ip_v4;
     195                return EOK;
     196        }
     197
     198        char *collon = str_chr(text, ':');
     199        if (collon != NULL) {
     200                *ver = ip_v6;
     201                return EOK;
     202        }
     203
     204        return EINVAL;
     205}
     206
     207static int ipver_af(ip_ver_t ver)
     208{
     209        switch (ver) {
     210        case ip_any:
     211                return AF_NONE;
     212        case ip_v4:
     213                return AF_INET;
     214        case ip_v6:
     215                return AF_INET6;
     216        default:
     217                assert(false);
     218                return EINVAL;
     219        }
     220}
     221
     222ip_ver_t ipver_from_af(int af)
     223{
     224        switch (af) {
     225        case AF_NONE:
     226                return ip_any;
     227        case AF_INET:
     228                return ip_v4;
     229        case AF_INET6:
     230                return ip_v6;
     231        default:
     232                assert(false);
     233                return EINVAL;
     234        }
     235}
     236
    183237void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr)
    184238{
     
    234288        if (naddr->version != addr->version)
    235289                return 0;
    236 
     290       
    237291        switch (naddr->version) {
    238292        case ip_v4:
     
    261315                if (naddr->prefix > 128)
    262316                        return 0;
    263 
     317               
    264318                size_t pos = 0;
    265319                for (size_t i = 0; i < 16; i++) {
     
    267321                        if (naddr->prefix < pos)
    268322                                break;
    269 
     323                       
    270324                        if (naddr->prefix - pos > 8) {
    271325                                /* Comparison without masking */
     
    279333                                        return 0;
    280334                        }
    281 
     335                       
    282336                        pos += 8;
    283337                }
    284 
     338               
    285339                return 1;
    286340        default:
    287341                return 0;
    288342        }
    289 }
    290 
    291 static int inet_addr_parse_v4(const char *str, inet_addr_t *raddr,
    292     int *prefix)
    293 {
    294         uint32_t a = 0;
    295         uint8_t b;
    296         char *cur = (char *)str;
    297         size_t i = 0;
    298 
    299         while (i < 4) {
    300                 int rc = str_uint8_t(cur, (const char **)&cur, 10, false, &b);
    301                 if (rc != EOK)
    302                         return rc;
    303 
    304                 a = (a << 8) + b;
    305 
    306                 i++;
    307 
    308                 if (*cur == '\0')
    309                         break;
    310 
    311                 if (*cur != '.')
    312                         return EINVAL;
    313 
    314                 if (i < 4)
    315                         cur++;
    316         }
    317 
    318         if (prefix != NULL) {
    319                 *prefix = strtoul(cur, &cur, 10);
    320                 if (*prefix > 32)
    321                         return EINVAL;
    322         }
    323 
    324         if (i != 4 || (*cur != '\0'))
    325                 return EINVAL;
    326 
    327         raddr->version = ip_v4;
    328         raddr->addr = a;
    329 
    330         return EOK;
    331 }
    332 
    333 static int inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix)
    334 {
    335         uint8_t data[16];
    336 
    337         memset(data, 0, 16);
    338 
    339         const char *cur = str;
    340         size_t i = 0;
    341         size_t wildcard_pos = (size_t) -1;
    342         size_t wildcard_size = 0;
    343 
    344         /* Handle initial wildcard */
    345         if ((str[0] == ':') && (str[1] == ':')) {
    346                 cur = str + 2;
    347                 wildcard_pos = 0;
    348                 wildcard_size = 16;
    349 
    350                 /* Handle the unspecified address */
    351                 if (*cur == '\0')
    352                         goto success;
    353         }
    354 
    355         while (i < 16) {
    356                 uint16_t bioctet;
    357                 int rc = str_uint16_t(cur, &cur, 16, false, &bioctet);
    358                 if (rc != EOK)
    359                         return rc;
    360 
    361                 data[i] = (bioctet >> 8) & 0xff;
    362                 data[i + 1] = bioctet & 0xff;
    363 
    364                 if (wildcard_pos != (size_t) -1) {
    365                         if (wildcard_size < 2)
    366                                 return EINVAL;
    367 
    368                         wildcard_size -= 2;
    369                 }
    370 
    371                 i += 2;
    372 
    373                 if (*cur != ':')
    374                         break;
    375 
    376                 if (i < 16) {
    377                         cur++;
    378 
    379                         /* Handle wildcard */
    380                         if (*cur == ':') {
    381                                 if (wildcard_pos != (size_t) -1)
    382                                         return EINVAL;
    383 
    384                                 wildcard_pos = i;
    385                                 wildcard_size = 16 - i;
    386                                 cur++;
    387 
    388                                 if (*cur == '\0' || *cur == '/')
    389                                         break;
    390                         }
    391                 }
    392         }
    393 
    394         if (prefix != NULL) {
    395                 if (*cur != '/')
    396                         return EINVAL;
    397                 cur++;
    398 
    399                 *prefix = strtoul(cur, (char **)&cur, 10);
    400                 if (*prefix > 128)
    401                         return EINVAL;
    402         }
    403 
    404         if (*cur != '\0')
    405                 return EINVAL;
    406 
    407         /* Create wildcard positions */
    408         if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) {
    409                 size_t wildcard_shift = 16 - wildcard_size;
    410 
    411                 for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) {
    412                         size_t j = i - 1;
    413                         data[j + wildcard_size] = data[j];
    414                         data[j] = 0;
    415                 }
    416         }
    417 
    418 success:
    419         raddr->version = ip_v6;
    420         memcpy(raddr->addr6, data, 16);
    421         return EOK;
    422343}
    423344
     
    432353int inet_addr_parse(const char *text, inet_addr_t *addr)
    433354{
    434         int rc;
    435 
    436         rc = inet_addr_parse_v4(text, addr, NULL);
    437         if (rc == EOK)
    438                 return EOK;
    439 
    440         rc = inet_addr_parse_v6(text, addr, NULL);
    441         if (rc == EOK)
    442                 return EOK;
    443 
    444         return EINVAL;
     355        int rc = inet_addr_version(text, &addr->version);
     356        if (rc != EOK)
     357                return rc;
     358       
     359        uint8_t buf[16];
     360        rc = inet_pton(ipver_af(addr->version), text, buf);
     361        if (rc != EOK)
     362                return rc;
     363       
     364        switch (addr->version) {
     365        case ip_v4:
     366                addr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
     367                    buf[3];
     368                break;
     369        case ip_v6:
     370                memcpy(addr->addr6, buf, 16);
     371                break;
     372        default:
     373                return EINVAL;
     374        }
     375       
     376        return EOK;
    445377}
    446378
     
    455387int inet_naddr_parse(const char *text, inet_naddr_t *naddr)
    456388{
    457         int rc;
    458         inet_addr_t addr;
    459         int prefix;
    460 
    461         rc = inet_addr_parse_v4(text, &addr, &prefix);
    462         if (rc == EOK) {
    463                 inet_addr_naddr(&addr, prefix, naddr);
    464                 return EOK;
    465         }
    466 
    467         rc = inet_addr_parse_v6(text, &addr, &prefix);
    468         if (rc == EOK) {
    469                 inet_addr_naddr(&addr, prefix, naddr);
    470                 return EOK;
    471         }
    472 
    473         return EINVAL;
    474 }
    475 
    476 static int inet_addr_format_v4(addr32_t addr, char **bufp)
    477 {
    478         int rc;
    479 
    480         rc = asprintf(bufp, "%u.%u.%u.%u", (addr >> 24) & 0xff,
    481             (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
    482         if (rc < 0)
    483                 return ENOMEM;
    484 
    485         return EOK;
    486 }
    487 
    488 static int inet_addr_format_v6(const addr128_t addr, char **bufp)
    489 {
    490         *bufp = (char *) malloc(INET6_ADDRSTRLEN);
    491         if (*bufp == NULL)
    492                 return ENOMEM;
    493 
    494         /* Find the longest zero subsequence */
    495 
    496         uint16_t zeroes[8];
    497         uint16_t bioctets[8];
    498 
    499         for (size_t i = 8; i > 0; i--) {
    500                 size_t j = i - 1;
    501 
    502                 bioctets[j] = (addr[j << 1] << 8) | addr[(j << 1) + 1];
    503 
    504                 if (bioctets[j] == 0) {
    505                         zeroes[j] = 1;
    506                         if (j < 7)
    507                                 zeroes[j] += zeroes[j + 1];
    508                 } else
    509                         zeroes[j] = 0;
    510         }
    511 
    512         size_t wildcard_pos = (size_t) -1;
    513         size_t wildcard_size = 0;
    514 
    515         for (size_t i = 0; i < 8; i++) {
    516                 if (zeroes[i] > wildcard_size) {
    517                         wildcard_pos = i;
    518                         wildcard_size = zeroes[i];
    519                 }
    520         }
    521 
    522         char *cur = *bufp;
    523         size_t rest = INET6_ADDRSTRLEN;
    524         bool tail_zero = false;
    525         int ret;
    526 
    527         for (size_t i = 0; i < 8; i++) {
    528                 if ((i == wildcard_pos) && (wildcard_size > 1)) {
    529                         ret = snprintf(cur, rest, ":");
    530                         i += wildcard_size - 1;
    531                         tail_zero = true;
    532                 } else if (i == 0) {
    533                         ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]);
    534                         tail_zero = false;
    535                 } else {
    536                         ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]);
    537                         tail_zero = false;
    538                 }
    539 
    540                 if (ret < 0)
     389        char *slash = str_chr(text, '/');
     390        if (slash == NULL)
     391                return EINVAL;
     392       
     393        *slash = 0;
     394       
     395        int rc = inet_addr_version(text, &naddr->version);
     396        if (rc != EOK)
     397                return rc;
     398       
     399        uint8_t buf[16];
     400        rc = inet_pton(ipver_af(naddr->version), text, buf);
     401        *slash = '/';
     402       
     403        if (rc != EOK)
     404                return rc;
     405       
     406        slash++;
     407        uint8_t prefix;
     408       
     409        switch (naddr->version) {
     410        case ip_v4:
     411                prefix = strtoul(slash, &slash, 10);
     412                if (prefix > 32)
    541413                        return EINVAL;
    542 
    543                 cur += ret;
    544                 rest -= ret;
    545         }
    546 
    547         if (tail_zero)
    548                 (void) snprintf(cur, rest, ":");
    549 
     414               
     415                naddr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
     416                    buf[3];
     417                naddr->prefix = prefix;
     418               
     419                break;
     420        case ip_v6:
     421                prefix = strtoul(slash, &slash, 10);
     422                if (prefix > 128)
     423                        return EINVAL;
     424               
     425                memcpy(naddr->addr6, buf, 16);
     426                naddr->prefix = prefix;
     427               
     428                break;
     429        default:
     430                return ENOTSUP;
     431        }
     432       
    550433        return EOK;
    551434}
     
    563446int inet_addr_format(const inet_addr_t *addr, char **bufp)
    564447{
    565         int rc;
    566 
    567         rc = ENOTSUP;
    568 
     448        int rc = 0;
     449       
    569450        switch (addr->version) {
    570451        case ip_any:
    571452                rc = asprintf(bufp, "none");
    572                 if (rc < 0)
     453                break;
     454        case ip_v4:
     455                rc = asprintf(bufp, "%u.%u.%u.%u", (addr->addr >> 24) & 0xff,
     456                    (addr->addr >> 16) & 0xff, (addr->addr >> 8) & 0xff,
     457                    addr->addr & 0xff);
     458                break;
     459        case ip_v6:
     460                *bufp = (char *) malloc(INET6_ADDRSTRLEN);
     461                if (*bufp == NULL)
    573462                        return ENOMEM;
    574                 rc = EOK;
    575                 break;
    576         case ip_v4:
    577                 rc = inet_addr_format_v4(addr->addr, bufp);
    578                 break;
    579         case ip_v6:
    580                 rc = inet_addr_format_v6(addr->addr6, bufp);
    581                 break;
    582         }
    583 
    584         return rc;
     463               
     464                return inet_ntop(AF_INET6, addr->addr6, *bufp, INET6_ADDRSTRLEN);
     465        default:
     466                return ENOTSUP;
     467        }
     468       
     469        if (rc < 0)
     470                return ENOMEM;
     471       
     472        return EOK;
    585473}
    586474
     
    597485int inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
    598486{
    599         int rc;
    600         char *astr;
    601 
    602         rc = ENOTSUP;
    603 
     487        int rc = 0;
     488        char prefix[INET_PREFIXSTRSIZE];
     489       
    604490        switch (naddr->version) {
    605491        case ip_any:
    606492                rc = asprintf(bufp, "none");
    607                 if (rc < 0)
     493                break;
     494        case ip_v4:
     495                rc = asprintf(bufp, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8
     496                    "/%" PRIu8, (naddr->addr >> 24) & 0xff,
     497                    (naddr->addr >> 16) & 0xff, (naddr->addr >> 8) & 0xff,
     498                    naddr->addr & 0xff, naddr->prefix);
     499                break;
     500        case ip_v6:
     501                *bufp = (char *) malloc(INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
     502                if (*bufp == NULL)
    608503                        return ENOMEM;
    609                 rc = EOK;
    610                 break;
    611         case ip_v4:
    612                 rc = inet_addr_format_v4(naddr->addr, &astr);
    613                 if (rc != EOK)
    614                         return ENOMEM;
    615 
    616                 rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
     504               
     505                rc = inet_ntop(AF_INET6, naddr->addr6, *bufp,
     506                    INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
     507                if (rc != EOK) {
     508                        free(*bufp);
     509                        return rc;
     510                }
     511               
     512                rc = snprintf(prefix, INET_PREFIXSTRSIZE, "/%" PRIu8,
     513                    naddr->prefix);
    617514                if (rc < 0) {
    618                         free(astr);
     515                        free(*bufp);
    619516                        return ENOMEM;
    620517                }
    621 
    622                 rc = EOK;
    623                 break;
    624         case ip_v6:
    625                 rc = inet_addr_format_v6(naddr->addr6, &astr);
    626                 if (rc != EOK)
    627                         return ENOMEM;
    628 
    629                 rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
    630                 if (rc < 0) {
    631                         free(astr);
    632                         return ENOMEM;
    633                 }
    634 
    635                 rc = EOK;
    636                 break;
    637         }
    638 
    639         return rc;
     518               
     519                str_append(*bufp, INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE, prefix);
     520               
     521                break;
     522        default:
     523                return ENOTSUP;
     524        }
     525       
     526        if (rc < 0)
     527                return ENOMEM;
     528       
     529        return EOK;
    640530}
    641531
     
    696586}
    697587
     588void inet_sockaddr_in_addr(const sockaddr_in_t *sockaddr_in, inet_addr_t *addr)
     589{
     590        addr->version = ip_v4;
     591        addr->addr = uint32_t_be2host(sockaddr_in->sin_addr.s_addr);
     592}
     593
    698594void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
    699595{
     
    709605}
    710606
     607void inet_sockaddr_in6_addr(const sockaddr_in6_t *sockaddr_in6,
     608    inet_addr_t *addr)
     609{
     610        addr->version = ip_v6;
     611        addr128_t_be2host(sockaddr_in6->sin6_addr.s6_addr, addr->addr6);
     612}
     613
     614uint16_t inet_addr_sockaddr_in(const inet_addr_t *addr,
     615    sockaddr_in_t *sockaddr_in, sockaddr_in6_t *sockaddr_in6)
     616{
     617        switch (addr->version) {
     618        case ip_v4:
     619                if (sockaddr_in != NULL) {
     620                        sockaddr_in->sin_family = AF_INET;
     621                        sockaddr_in->sin_addr.s_addr = host2uint32_t_be(addr->addr);
     622                }
     623                break;
     624        case ip_v6:
     625                if (sockaddr_in6 != NULL) {
     626                        sockaddr_in6->sin6_family = AF_INET6;
     627                        host2addr128_t_be(addr->addr6, sockaddr_in6->sin6_addr.s6_addr);
     628                }
     629                break;
     630        default:
     631                assert(false);
     632                break;
     633        }
     634
     635        return ipver_af(addr->version);
     636}
     637
     638int inet_addr_sockaddr(const inet_addr_t *addr, uint16_t port,
     639    sockaddr_t **nsockaddr, socklen_t *naddrlen)
     640{
     641        sockaddr_in_t *sa4;
     642        sockaddr_in6_t *sa6;
     643
     644        switch (addr->version) {
     645        case ip_v4:
     646                sa4 = calloc(1, sizeof(sockaddr_in_t));
     647                if (sa4 == NULL)
     648                        return ENOMEM;
     649
     650                sa4->sin_family = AF_INET;
     651                sa4->sin_port = host2uint16_t_be(port);
     652                sa4->sin_addr.s_addr = host2uint32_t_be(addr->addr);
     653                if (nsockaddr != NULL)
     654                        *nsockaddr = (sockaddr_t *)sa4;
     655                if (naddrlen != NULL)
     656                        *naddrlen = sizeof(*sa4);
     657                break;
     658        case ip_v6:
     659                sa6 = calloc(1, sizeof(sockaddr_in6_t));
     660                if (sa6 == NULL)
     661                        return ENOMEM;
     662
     663                sa6->sin6_family = AF_INET6;
     664                sa6->sin6_port = host2uint16_t_be(port);
     665                host2addr128_t_be(addr->addr6, sa6->sin6_addr.s6_addr);
     666                if (nsockaddr != NULL)
     667                        *nsockaddr = (sockaddr_t *)sa6;
     668                if (naddrlen != NULL)
     669                        *naddrlen = sizeof(*sa6);
     670                break;
     671        default:
     672                assert(false);
     673                break;
     674        }
     675
     676        return EOK;
     677}
     678
    711679/** @}
    712680 */
Note: See TracChangeset for help on using the changeset viewer.