Changeset fb4d788 in mainline for uspace/lib/c/generic/inet/addr.c


Ignore:
Timestamp:
2015-07-28T11:28:14Z (9 years ago)
Author:
Maurizio Lombardi <m.lombardi85@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
6accc5cf
Parents:
df2bce3 (diff), 47726b5e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge from the mainline

File:
1 edited

Legend:

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

    rdf2bce3 rfb4d788  
    11/*
    22 * Copyright (c) 2013 Jiri Svoboda
     3 * Copyright (c) 2013 Martin Decky
    34 * All rights reserved.
    45 *
     
    3637#include <errno.h>
    3738#include <unistd.h>
    38 #include <net/socket_codes.h>
    3939#include <inet/addr.h>
    40 #include <net/inet.h>
    4140#include <stdio.h>
    4241#include <malloc.h>
     
    4443
    4544#define INET_PREFIXSTRSIZE  5
     45
     46#define INET6_ADDRSTRLEN (8 * 4 + 7 + 1)
    4647
    4748#if !(defined(__BE__) ^ defined(__LE__))
     
    180181}
    181182
    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  */
    190 static 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 
    207 static 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 
    222 ip_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 
    237183void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr)
    238184{
     
    288234        if (naddr->version != addr->version)
    289235                return 0;
    290        
     236
    291237        switch (naddr->version) {
    292238        case ip_v4:
     
    315261                if (naddr->prefix > 128)
    316262                        return 0;
    317                
     263
    318264                size_t pos = 0;
    319265                for (size_t i = 0; i < 16; i++) {
     
    321267                        if (naddr->prefix < pos)
    322268                                break;
    323                        
     269
    324270                        if (naddr->prefix - pos > 8) {
    325271                                /* Comparison without masking */
     
    333279                                        return 0;
    334280                        }
    335                        
     281
    336282                        pos += 8;
    337283                }
    338                
     284
    339285                return 1;
    340286        default:
     
    343289}
    344290
     291static 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' || *cur == '/')
     309                        break;
     310
     311                if (*cur != '.')
     312                        return EINVAL;
     313
     314                if (i < 4)
     315                        cur++;
     316        }
     317
     318        if (prefix != NULL) {
     319                if (*cur != '/')
     320                        return EINVAL;
     321                cur++;
     322
     323                *prefix = strtoul(cur, &cur, 10);
     324                if (*prefix > 32)
     325                        return EINVAL;
     326        }
     327
     328        if (i != 4 || (*cur != '\0'))
     329                return EINVAL;
     330
     331        raddr->version = ip_v4;
     332        raddr->addr = a;
     333
     334        return EOK;
     335}
     336
     337static int inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix)
     338{
     339        uint8_t data[16];
     340
     341        memset(data, 0, 16);
     342
     343        const char *cur = str;
     344        size_t i = 0;
     345        size_t wildcard_pos = (size_t) -1;
     346        size_t wildcard_size = 0;
     347
     348        /* Handle initial wildcard */
     349        if ((str[0] == ':') && (str[1] == ':')) {
     350                cur = str + 2;
     351                wildcard_pos = 0;
     352                wildcard_size = 16;
     353
     354                /* Handle the unspecified address */
     355                if (*cur == '\0')
     356                        goto success;
     357        }
     358
     359        while (i < 16) {
     360                uint16_t bioctet;
     361                int rc = str_uint16_t(cur, &cur, 16, false, &bioctet);
     362                if (rc != EOK)
     363                        return rc;
     364
     365                data[i] = (bioctet >> 8) & 0xff;
     366                data[i + 1] = bioctet & 0xff;
     367
     368                if (wildcard_pos != (size_t) -1) {
     369                        if (wildcard_size < 2)
     370                                return EINVAL;
     371
     372                        wildcard_size -= 2;
     373                }
     374
     375                i += 2;
     376
     377                if (*cur != ':')
     378                        break;
     379
     380                if (i < 16) {
     381                        cur++;
     382
     383                        /* Handle wildcard */
     384                        if (*cur == ':') {
     385                                if (wildcard_pos != (size_t) -1)
     386                                        return EINVAL;
     387
     388                                wildcard_pos = i;
     389                                wildcard_size = 16 - i;
     390                                cur++;
     391
     392                                if (*cur == '\0' || *cur == '/')
     393                                        break;
     394                        }
     395                }
     396        }
     397
     398        if (prefix != NULL) {
     399                if (*cur != '/')
     400                        return EINVAL;
     401                cur++;
     402
     403                *prefix = strtoul(cur, (char **)&cur, 10);
     404                if (*prefix > 128)
     405                        return EINVAL;
     406        }
     407
     408        if (*cur != '\0')
     409                return EINVAL;
     410
     411        /* Create wildcard positions */
     412        if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) {
     413                size_t wildcard_shift = 16 - wildcard_size;
     414
     415                for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) {
     416                        size_t j = i - 1;
     417                        data[j + wildcard_size] = data[j];
     418                        data[j] = 0;
     419                }
     420        }
     421
     422success:
     423        raddr->version = ip_v6;
     424        memcpy(raddr->addr6, data, 16);
     425        return EOK;
     426}
     427
    345428/** Parse node address.
    346429 *
     
    353436int inet_addr_parse(const char *text, inet_addr_t *addr)
    354437{
    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;
     438        int rc;
     439
     440        rc = inet_addr_parse_v4(text, addr, NULL);
     441        if (rc == EOK)
     442                return EOK;
     443
     444        rc = inet_addr_parse_v6(text, addr, NULL);
     445        if (rc == EOK)
     446                return EOK;
     447
     448        return EINVAL;
    377449}
    378450
     
    387459int inet_naddr_parse(const char *text, inet_naddr_t *naddr)
    388460{
    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)
     461        int rc;
     462        inet_addr_t addr;
     463        int prefix;
     464
     465        rc = inet_addr_parse_v4(text, &addr, &prefix);
     466        if (rc == EOK) {
     467                inet_addr_naddr(&addr, prefix, naddr);
     468                return EOK;
     469        }
     470
     471        rc = inet_addr_parse_v6(text, &addr, &prefix);
     472        if (rc == EOK) {
     473                inet_addr_naddr(&addr, prefix, naddr);
     474                return EOK;
     475        }
     476
     477        return EINVAL;
     478}
     479
     480static int inet_addr_format_v4(addr32_t addr, char **bufp)
     481{
     482        int rc;
     483
     484        rc = asprintf(bufp, "%u.%u.%u.%u", (addr >> 24) & 0xff,
     485            (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
     486        if (rc < 0)
     487                return ENOMEM;
     488
     489        return EOK;
     490}
     491
     492static int inet_addr_format_v6(const addr128_t addr, char **bufp)
     493{
     494        *bufp = (char *) malloc(INET6_ADDRSTRLEN);
     495        if (*bufp == NULL)
     496                return ENOMEM;
     497
     498        /* Find the longest zero subsequence */
     499
     500        uint16_t zeroes[8];
     501        uint16_t bioctets[8];
     502
     503        for (size_t i = 8; i > 0; i--) {
     504                size_t j = i - 1;
     505
     506                bioctets[j] = (addr[j << 1] << 8) | addr[(j << 1) + 1];
     507
     508                if (bioctets[j] == 0) {
     509                        zeroes[j] = 1;
     510                        if (j < 7)
     511                                zeroes[j] += zeroes[j + 1];
     512                } else
     513                        zeroes[j] = 0;
     514        }
     515
     516        size_t wildcard_pos = (size_t) -1;
     517        size_t wildcard_size = 0;
     518
     519        for (size_t i = 0; i < 8; i++) {
     520                if (zeroes[i] > wildcard_size) {
     521                        wildcard_pos = i;
     522                        wildcard_size = zeroes[i];
     523                }
     524        }
     525
     526        char *cur = *bufp;
     527        size_t rest = INET6_ADDRSTRLEN;
     528        bool tail_zero = false;
     529        int ret;
     530
     531        for (size_t i = 0; i < 8; i++) {
     532                if ((i == wildcard_pos) && (wildcard_size > 1)) {
     533                        ret = snprintf(cur, rest, ":");
     534                        i += wildcard_size - 1;
     535                        tail_zero = true;
     536                } else if (i == 0) {
     537                        ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]);
     538                        tail_zero = false;
     539                } else {
     540                        ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]);
     541                        tail_zero = false;
     542                }
     543
     544                if (ret < 0)
    413545                        return EINVAL;
    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        
     546
     547                cur += ret;
     548                rest -= ret;
     549        }
     550
     551        if (tail_zero)
     552                (void) snprintf(cur, rest, ":");
     553
    433554        return EOK;
    434555}
     
    446567int inet_addr_format(const inet_addr_t *addr, char **bufp)
    447568{
    448         int rc = 0;
    449        
     569        int rc;
     570
     571        rc = ENOTSUP;
     572
    450573        switch (addr->version) {
    451574        case ip_any:
    452575                rc = asprintf(bufp, "none");
     576                if (rc < 0)
     577                        return ENOMEM;
     578                rc = EOK;
    453579                break;
    454580        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);
     581                rc = inet_addr_format_v4(addr->addr, bufp);
    458582                break;
    459583        case ip_v6:
    460                 *bufp = (char *) malloc(INET6_ADDRSTRLEN);
    461                 if (*bufp == NULL)
    462                         return ENOMEM;
    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;
     584                rc = inet_addr_format_v6(addr->addr6, bufp);
     585                break;
     586        }
     587
     588        return rc;
    473589}
    474590
     
    485601int inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
    486602{
    487         int rc = 0;
    488         char prefix[INET_PREFIXSTRSIZE];
    489        
     603        int rc;
     604        char *astr;
     605
     606        rc = ENOTSUP;
     607
    490608        switch (naddr->version) {
    491609        case ip_any:
    492610                rc = asprintf(bufp, "none");
     611                if (rc < 0)
     612                        return ENOMEM;
     613                rc = EOK;
    493614                break;
    494615        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)
     616                rc = inet_addr_format_v4(naddr->addr, &astr);
     617                if (rc != EOK)
    503618                        return ENOMEM;
    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);
     619
     620                rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
    514621                if (rc < 0) {
    515                         free(*bufp);
     622                        free(astr);
    516623                        return ENOMEM;
    517624                }
    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;
     625
     626                rc = EOK;
     627                break;
     628        case ip_v6:
     629                rc = inet_addr_format_v6(naddr->addr6, &astr);
     630                if (rc != EOK)
     631                        return ENOMEM;
     632
     633                rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
     634                if (rc < 0) {
     635                        free(astr);
     636                        return ENOMEM;
     637                }
     638
     639                rc = EOK;
     640                break;
     641        }
     642
     643        return rc;
    530644}
    531645
     
    586700}
    587701
    588 void 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 
    594702void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
    595703{
     
    605713}
    606714
    607 void 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 
    614 uint16_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 
    638 int 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 
    679715/** @}
    680716 */
Note: See TracChangeset for help on using the changeset viewer.