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


Ignore:
Timestamp:
2015-06-17T23:45:24Z (9 years ago)
Author:
Michal Koutný <xm.koutny+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
523b17a
Parents:
fc7bf19 (diff), 2654afb (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:

Sync with mainline

File:
1 edited

Legend:

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

    rfc7bf19 rcf3aee19  
    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')
     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
     333static 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
     418success:
     419        raddr->version = ip_v6;
     420        memcpy(raddr->addr6, data, 16);
     421        return EOK;
     422}
     423
    345424/** Parse node address.
    346425 *
     
    353432int inet_addr_parse(const char *text, inet_addr_t *addr)
    354433{
    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;
     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;
    377445}
    378446
     
    387455int inet_naddr_parse(const char *text, inet_naddr_t *naddr)
    388456{
    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)
     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
     476static 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
     488static 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)
    413541                        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        
     542
     543                cur += ret;
     544                rest -= ret;
     545        }
     546
     547        if (tail_zero)
     548                (void) snprintf(cur, rest, ":");
     549
    433550        return EOK;
    434551}
     
    446563int inet_addr_format(const inet_addr_t *addr, char **bufp)
    447564{
    448         int rc = 0;
    449        
     565        int rc;
     566
     567        rc = ENOTSUP;
     568
    450569        switch (addr->version) {
    451570        case ip_any:
    452571                rc = asprintf(bufp, "none");
     572                if (rc < 0)
     573                        return ENOMEM;
     574                rc = EOK;
    453575                break;
    454576        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);
     577                rc = inet_addr_format_v4(addr->addr, bufp);
    458578                break;
    459579        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;
     580                rc = inet_addr_format_v6(addr->addr6, bufp);
     581                break;
     582        }
     583
     584        return rc;
    473585}
    474586
     
    485597int inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
    486598{
    487         int rc = 0;
    488         char prefix[INET_PREFIXSTRSIZE];
    489        
     599        int rc;
     600        char *astr;
     601
     602        rc = ENOTSUP;
     603
    490604        switch (naddr->version) {
    491605        case ip_any:
    492606                rc = asprintf(bufp, "none");
     607                if (rc < 0)
     608                        return ENOMEM;
     609                rc = EOK;
    493610                break;
    494611        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)
     612                rc = inet_addr_format_v4(naddr->addr, &astr);
     613                if (rc != EOK)
    503614                        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);
     615
     616                rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
    514617                if (rc < 0) {
    515                         free(*bufp);
     618                        free(astr);
    516619                        return ENOMEM;
    517620                }
    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;
     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;
    530640}
    531641
     
    586696}
    587697
    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 
    594698void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
    595699{
     
    605709}
    606710
    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 
    679711/** @}
    680712 */
Note: See TracChangeset for help on using the changeset viewer.