Annotation of libelwix/src/net.c, revision 1.21

1.1       misho       1: /*************************************************************************
                      2: * (C) 2013 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
                      3: *  by Michael Pounov <misho@elwix.org>
                      4: *
                      5: * $Author: misho $
1.21    ! misho       6: * $Id: net.c,v 1.20.4.1 2020/05/27 15:02:33 misho Exp $
1.1       misho       7: *
                      8: **************************************************************************
                      9: The ELWIX and AITNET software is distributed under the following
                     10: terms:
                     11: 
                     12: All of the documentation and software included in the ELWIX and AITNET
                     13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
                     14: 
1.21    ! misho      15: Copyright 2004 - 2020
1.1       misho      16:        by Michael Pounov <misho@elwix.org>.  All rights reserved.
                     17: 
                     18: Redistribution and use in source and binary forms, with or without
                     19: modification, are permitted provided that the following conditions
                     20: are met:
                     21: 1. Redistributions of source code must retain the above copyright
                     22:    notice, this list of conditions and the following disclaimer.
                     23: 2. Redistributions in binary form must reproduce the above copyright
                     24:    notice, this list of conditions and the following disclaimer in the
                     25:    documentation and/or other materials provided with the distribution.
                     26: 3. All advertising materials mentioning features or use of this software
                     27:    must display the following acknowledgement:
                     28: This product includes software developed by Michael Pounov <misho@elwix.org>
                     29: ELWIX - Embedded LightWeight unIX and its contributors.
                     30: 4. Neither the name of AITNET nor the names of its contributors
                     31:    may be used to endorse or promote products derived from this software
                     32:    without specific prior written permission.
                     33: 
                     34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
                     35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     44: SUCH DAMAGE.
                     45: */
                     46: #include "global.h"
                     47: 
                     48: 
1.13      misho      49: #ifndef __linux__
1.6       misho      50: static char hexlist[] = "0123456789abcdef";
1.17      misho      51: 
                     52: #ifndef HAVE_LINK_ADDR
                     53: 
                     54: /* States*/
                     55: #define NAMING 0
                     56: #define GOTONE 1
                     57: #define GOTTWO 2
                     58: #define RESET  3
                     59: /* Inputs */
                     60: #define        DIGIT   (4*0)
                     61: #define        END     (4*1)
                     62: #define DELIM  (4*2)
                     63: #define LETTER (4*3)
                     64: 
                     65: void
                     66: link_addr(const char *addr, struct sockaddr_dl *sdl)
                     67: {
                     68:        char *cp = sdl->sdl_data;
                     69:        char *cplim = sdl->sdl_len + (char *)sdl;
1.20      misho      70:        int byte = 0, state = NAMING, new = 0;
1.17      misho      71: 
                     72:        bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1);
                     73:        sdl->sdl_family = AF_LINK;
                     74:        do {
                     75:                state &= ~LETTER;
                     76:                if ((*addr >= '0') && (*addr <= '9')) {
                     77:                        new = *addr - '0';
                     78:                } else if ((*addr >= 'a') && (*addr <= 'f')) {
                     79:                        new = *addr - 'a' + 10;
                     80:                } else if ((*addr >= 'A') && (*addr <= 'F')) {
                     81:                        new = *addr - 'A' + 10;
                     82:                } else if (*addr == 0) {
                     83:                        state |= END;
                     84:                } else if (state == NAMING &&
                     85:                           (((*addr >= 'A') && (*addr <= 'Z')) ||
                     86:                           ((*addr >= 'a') && (*addr <= 'z'))))
                     87:                        state |= LETTER;
                     88:                else
                     89:                        state |= DELIM;
                     90:                addr++;
                     91:                switch (state /* | INPUT */) {
                     92:                case NAMING | DIGIT:
                     93:                case NAMING | LETTER:
                     94:                        *cp++ = addr[-1];
                     95:                        continue;
                     96:                case NAMING | DELIM:
                     97:                        state = RESET;
                     98:                        sdl->sdl_nlen = cp - sdl->sdl_data;
                     99:                        continue;
                    100:                case GOTTWO | DIGIT:
                    101:                        *cp++ = byte;
                    102:                        /* FALLTHROUGH */
                    103:                case RESET | DIGIT:
                    104:                        state = GOTONE;
                    105:                        byte = new;
                    106:                        continue;
                    107:                case GOTONE | DIGIT:
                    108:                        state = GOTTWO;
                    109:                        byte = new + (byte << 4);
                    110:                        continue;
                    111:                default: /* | DELIM */
                    112:                        state = RESET;
                    113:                        *cp++ = byte;
                    114:                        byte = 0;
                    115:                        continue;
                    116:                case GOTONE | END:
                    117:                case GOTTWO | END:
                    118:                        *cp++ = byte;
                    119:                        /* FALLTHROUGH */
                    120:                case RESET | END:
                    121:                        break;
                    122:                }
                    123:                break;
                    124:        } while (cp < cplim);
                    125:        sdl->sdl_alen = cp - LLADDR(sdl);
                    126:        new = cp - (char *)sdl;
                    127:        if (new > sizeof(*sdl))
                    128:                sdl->sdl_len = new;
                    129:        return;
                    130: }
                    131: #endif
                    132: 
1.6       misho     133: 
                    134: /*
                    135:  * e_link_ntoa() - String ethernet address from link address
                    136:  *
                    137:  * @sdl = link address
                    138:  * return: =NULL error or !=NULL ethernet address, should be e_free()
                    139:  */
                    140: char *
                    141: e_link_ntoa(const struct sockaddr_dl *sdl)
                    142: {
                    143:        static char obuf[64];
                    144:        char *out = obuf;
                    145:        int i;
                    146:        u_char *in = (u_char*) LLADDR(sdl);
                    147:        u_char *inlim = in + sdl->sdl_alen;
                    148:        int firsttime = 1;
                    149: 
                    150:        if (sdl->sdl_nlen) {
                    151:                memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen);
                    152:                out += sdl->sdl_nlen;
                    153:                if (sdl->sdl_alen)
                    154:                        *out++ = '!';
                    155:        }
                    156: 
                    157:        while (in < inlim) {
                    158:                if (firsttime)
                    159:                        firsttime ^= firsttime;
                    160:                else
                    161:                        *out++ = ':';
1.8       misho     162: 
1.6       misho     163:                i = *in++;
                    164:                if (i > 0xf) {
                    165:                        out[1] = hexlist[i & 0xf];
                    166:                        i >>= 4;
1.8       misho     167:                } else {
                    168:                        out[1] = hexlist[i];
                    169:                        i = 0;
                    170:                }
1.6       misho     171: 
                    172:                out[0] = hexlist[i];
                    173:                out += 2;
                    174:        }
                    175: 
                    176:        *out = 0;
                    177:        return obuf;
                    178: }
                    179: 
1.1       misho     180: /*
1.11      misho     181:  * e_link_addr() - String ethernet address to link address
                    182:  *
                    183:  * @mac = ethernet address
                    184:  * @sdl = link address
                    185:  * return: -1 error or 0 ok
                    186:  */
                    187: int
                    188: e_link_addr(const char *mac, struct sockaddr_dl * __restrict sdl)
                    189: {
                    190:        if (!mac || !sdl)
                    191:                return -1;
                    192:        if (!sdl->sdl_len)
                    193:                sdl->sdl_len = sizeof(struct sockaddr_dl);
                    194: 
                    195:        link_addr(mac, sdl);
                    196:        return 0;
                    197: }
1.13      misho     198: #endif
1.11      misho     199: 
                    200: /*
1.1       misho     201:  * e_ether_ntoa() - Convert ethernet address to string
                    202:  *
                    203:  * @n = ethernet address structure, like struct ether_addr
                    204:  * @a = string
                    205:  * @len = string length
                    206:  * return: NULL error or !=NULL string a
                    207:  */
1.2       misho     208: char *
1.7       misho     209: e_ether_ntoa(const ether_addr_t * __restrict n, char * __restrict a, int len)
1.1       misho     210: {
                    211:        if (!n || !a)
                    212:                return NULL;
                    213: 
                    214:        memset(a, 0, len);
1.8       misho     215:        if (snprintf(a, len, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 
1.11      misho     216:                        n->octet[0], n->octet[1], 
                    217:                        n->octet[2], n->octet[3], 
                    218:                        n->octet[4], n->octet[5]) < 17)
1.1       misho     219:                return NULL;
                    220: 
                    221:        return a;
                    222: }
                    223: 
                    224: /*
                    225:  * e_ether_aton() - Convert string to ethernet address
                    226:  *
                    227:  * @a = string
                    228:  * @e = ethernet address structure, like struct ether_addr
                    229:  * return: NULL error or !=NULL ethernet address structure
                    230:  */
1.7       misho     231: ether_addr_t *
                    232: e_ether_aton(const char *a, ether_addr_t * __restrict e)
1.1       misho     233: {                       
                    234:        int i;
                    235: 
                    236:        if (!a || !e)
                    237:                return NULL;
                    238: 
1.8       misho     239:        i = sscanf(a, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 
1.11      misho     240:                        &e->octet[0], 
                    241:                        &e->octet[1], 
                    242:                        &e->octet[2], 
                    243:                        &e->octet[3], 
                    244:                        &e->octet[4], 
                    245:                        &e->octet[5]);
1.1       misho     246:        if (i != 6)
                    247:                return NULL;
                    248: 
                    249:        return e;
                    250: }
                    251: 
                    252: /*
                    253:  * e_n2port() - Extract port from network structure
                    254:  *
                    255:  * @addr = Address
                    256:  * return: 0 not supported family type or port number
                    257:  */
1.2       misho     258: u_short
1.1       misho     259: e_n2port(sockaddr_t * __restrict addr)
                    260: {
                    261:        u_short port = 0;
                    262: 
                    263:        if (!addr)
                    264:                return port;
                    265: 
                    266:        switch (addr->sa.sa_family) {
                    267:                case AF_INET:
                    268:                        return ntohs(addr->sin.sin_port);
                    269:                case AF_INET6:
                    270:                        return ntohs(addr->sin6.sin6_port);
                    271:                default:
                    272:                        break;
                    273:        }
                    274: 
                    275:        return port;
                    276: }
                    277: 
                    278: /*
                    279:  * e_n2addr() - Extract address from network structure
                    280:  *
                    281:  * @addr = Address
                    282:  * @val = Value for store string address
                    283:  * return: NULL error or !=NULL string address from val
                    284:  */
                    285: const char *
                    286: e_n2addr(sockaddr_t * __restrict addr, ait_val_t * __restrict val)
                    287: {
1.13      misho     288: #ifndef __linux__
                    289:        char *s;
                    290: #endif
                    291:        char str[INET6_ADDRSTRLEN] = { 0 };
1.1       misho     292:        const char *ret = NULL;
                    293: 
                    294:        if (!addr || !val)
                    295:                return ret;
                    296: 
                    297:        AIT_INIT_VAL(val);
                    298:        switch (addr->sa.sa_family) {
                    299:                case AF_INET:
                    300:                        if (!inet_ntop(AF_INET, &addr->sin.sin_addr, str, INET_ADDRSTRLEN)) {
                    301:                                LOGERR;
                    302:                                return ret;
                    303:                        } else
                    304:                                ret = str;
                    305:                        break;
                    306:                case AF_INET6:
                    307:                        if (!inet_ntop(AF_INET6, &addr->sin6.sin6_addr, str, INET6_ADDRSTRLEN)) {
                    308:                                LOGERR;
                    309:                                return ret;
                    310:                        } else
                    311:                                ret = str;
                    312:                        break;
                    313:                case AF_LOCAL:
                    314:                        ret = addr->sun.sun_path;
                    315:                        break;
1.13      misho     316: #ifndef __linux__
1.5       misho     317:                case AF_LINK:
1.6       misho     318:                        if (!(s = e_link_ntoa(&addr->sdl))) {
1.5       misho     319:                                LOGERR;
                    320:                                return ret;
                    321:                        } else
                    322:                                ret = s;
                    323:                        break;
1.13      misho     324: #endif
1.1       misho     325:                default:
                    326:                        elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d", 
                    327:                                        addr->sa.sa_family);
                    328:                        return ret;
                    329:        }
                    330: 
                    331:        AIT_SET_STR(val, ret);
                    332:        return (const char*) AIT_GET_STR(val);
                    333: }
                    334: 
                    335: /*
                    336:  * e_gethostbyname() - Get host and port and make network structure
                    337:  *
                    338:  * @psHost = Hostname
                    339:  * @port = Port
                    340:  * @addr = Network address structure
1.15      misho     341:  * return: 0 is error or >0 length of network structure
1.1       misho     342:  */
1.14      misho     343: socklen_t 
1.1       misho     344: e_gethostbyname(const char *psHost, u_short port, sockaddr_t * __restrict addr)
                    345: {
                    346:        struct hostent *host = NULL;
                    347: 
                    348:        if (!psHost || !addr)
1.14      misho     349:                return 0;
1.1       misho     350: 
                    351:        if (*psHost != '/') {
                    352:                /* resolver */
1.10      misho     353:                host = gethostbyname2(psHost, !strchr(psHost, ':') ? AF_INET : AF_INET6);
1.1       misho     354:                if (!host) {
                    355:                        elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
1.14      misho     356:                        return 0;
1.1       misho     357:                } else {
                    358:                        memset(addr, 0, sizeof(sockaddr_t));
                    359:                        addr->sa.sa_family = host->h_addrtype;
                    360:                }
                    361:        } else {
                    362:                memset(addr, 0, sizeof(sockaddr_t));
                    363:                addr->sa.sa_family = AF_LOCAL;
                    364:        }
                    365:                
                    366: 
                    367:        switch (addr->sa.sa_family) {
                    368:                case AF_INET:
1.13      misho     369: #ifndef __linux__
1.1       misho     370:                        addr->sin.sin_len = sizeof(struct sockaddr_in);
1.13      misho     371: #endif
1.1       misho     372:                        addr->sin.sin_family = AF_INET;
                    373:                        addr->sin.sin_port = htons(port);
                    374:                        memcpy(&addr->sin.sin_addr, host->h_addr, sizeof addr->sin.sin_addr);
1.14      misho     375:                        return sizeof addr->sin;
1.1       misho     376:                case AF_INET6:
1.13      misho     377: #ifndef __linux__
1.1       misho     378:                        addr->sin6.sin6_len = sizeof(struct sockaddr_in6);
1.13      misho     379: #endif
1.1       misho     380:                        addr->sin6.sin6_family = AF_INET6;
                    381:                        addr->sin6.sin6_port = htons(port);
                    382:                        memcpy(&addr->sin6.sin6_addr, host->h_addr, sizeof addr->sin6.sin6_addr);
1.14      misho     383:                        return sizeof addr->sin6;
1.1       misho     384:                case AF_LOCAL:
1.13      misho     385: #ifndef __linux__
1.1       misho     386:                        addr->sun.sun_len = sizeof(struct sockaddr_un);
1.13      misho     387: #endif
1.1       misho     388:                        addr->sun.sun_family = AF_LOCAL;
                    389:                        memset(addr->sun.sun_path, 0, sizeof addr->sun.sun_path);
                    390:                        snprintf(addr->sun.sun_path, sizeof addr->sun.sun_path, "%s-%hu", psHost, port);
1.14      misho     391:                        return sizeof addr->sun;
1.1       misho     392:                default:
                    393:                        elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d", addr->sa.sa_family);
                    394:                        break;
                    395:        }
                    396: 
1.14      misho     397:        return 0;
1.15      misho     398: }
                    399: 
                    400: /*
                    401:  * e_addrlen() - Get address length from network structure
                    402:  *
                    403:  * @addr = address
                    404:  * return: 0 is error or >0 length of network structure
                    405:  */
                    406: socklen_t
                    407: e_addrlen(const sockaddr_t *addr)
                    408: {
                    409:        if (!addr)
                    410:                return 0;
                    411: 
                    412:        switch (addr->sa.sa_family) {
                    413:                case AF_INET:
                    414:                        return sizeof addr->sin;
                    415:                case AF_INET6:
                    416:                        return sizeof addr->sin6;
                    417:                case AF_LOCAL:
                    418:                        return sizeof addr->sun;
                    419: #ifndef __linux__
                    420:                case AF_LINK:
                    421:                        return sizeof addr->sdl;
                    422: #endif
                    423:        }
                    424: 
1.16      misho     425:        return E_SOCKADDR_MAX;
1.1       misho     426: }
                    427: 
                    428: /*
                    429:  * e_addrcmp() - Compare network addresses
                    430:  *
                    431:  * @a = 1st address
                    432:  * @b = 2nd address
                    433:  * @p = compare and ports, if family is AF_INET or AF_INET6
                    434:  * return: 0 is equal or !=0 is different
                    435:  */
                    436: int
                    437: e_addrcmp(sockaddr_t * __restrict a, sockaddr_t * __restrict b, int p)
                    438: {
                    439:        if (a && b && a->sa.sa_family == b->sa.sa_family)
                    440:                switch (a->sa.sa_family) {
                    441:                        case AF_LOCAL:
                    442:                                return strcmp(a->sun.sun_path, b->sun.sun_path);
                    443:                        case AF_INET:
                    444:                                if (p && (a->sin.sin_port - b->sin.sin_port))
                    445:                                        return (int) !!(a->sin.sin_port - b->sin.sin_port);
                    446:                                else
                    447:                                        return memcmp(&a->sin.sin_addr, &b->sin.sin_addr, 
                    448:                                                        sizeof a->sin.sin_addr);
                    449:                        case AF_INET6:
                    450:                                if (p && (a->sin6.sin6_port - b->sin6.sin6_port))
                    451:                                        return (int) !!(a->sin6.sin6_port - b->sin6.sin6_port);
                    452:                                else
                    453:                                        return memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr, 
                    454:                                                        sizeof a->sin6.sin6_addr);
1.13      misho     455: #ifndef __linux__
1.1       misho     456:                        case AF_LINK:
                    457:                                return memcmp(&a->sdl.sdl_data, &b->sdl.sdl_data, 
                    458:                                                sizeof a->sdl.sdl_data);
1.13      misho     459: #endif
1.11      misho     460:                        case AF_UNSPEC:
                    461:                                return memcmp(a, b, sizeof(sockaddr_t));
1.1       misho     462:                }
                    463: 
                    464:        return (int) !!(a - b);
                    465: }
                    466: 
                    467: /*
                    468:  * e_usleep() - usleep() replacement for ELWIX
                    469:  *
                    470:  * @usec = microseconds for sleep
                    471:  * return: -1 interrupted by signal or 0 ok
                    472:  */
1.2       misho     473: int
1.1       misho     474: e_usleep(u_int usec)
                    475: {
                    476:        struct timeval tv = { (time_t) (usec / 1000000), (long) (usec % 1000000) };
                    477: 
                    478:        return select(0, NULL, NULL, NULL, &tv);
                    479: }
1.3       misho     480: 
                    481: /*
                    482:  * e_innet() - Test address match in network
                    483:  *
                    484:  * @net = network
                    485:  * @addr = address
                    486:  * return: -1 error, 0 match or 1 not match
                    487:  */
                    488: int
                    489: e_innet(netaddr_t * __restrict net, inaddr_t * __restrict addr)
                    490: {
                    491:        register int i;
                    492:        int ret = 0;
                    493: 
                    494:        if (!net || !addr)
                    495:                return -1;
                    496: 
                    497:        switch (net->addr.sa.sa_family) {
                    498:                case AF_INET:
                    499:                        for (i = 0; i < sizeof(struct in_addr); i++) {
                    500:                                ret = ((caddr_t) &net->addr.sin.sin_addr.s_addr)[i] & 
1.19      misho     501:                                        net->mask.in4.s4_addr[i];
                    502:                                ret -= addr->in4.s4_addr[i] & net->mask.in4.s4_addr[i];
1.3       misho     503:                                if (ret)
                    504:                                        break;
                    505:                        }
                    506:                        break;
                    507:                case AF_INET6:
                    508:                        for (i = 0; i < sizeof(struct in6_addr); i++) {
                    509:                                ret = net->addr.sin6.sin6_addr.s6_addr[i] & 
                    510:                                        net->mask.in6.s6_addr[i];
                    511:                                ret -= addr->in6.s6_addr[i] & net->mask.in6.s6_addr[i];
                    512:                                if (ret)
                    513:                                        break;
                    514:                        }
                    515:                        break;
                    516:                default:
                    517:                        return -1;
                    518:        }
                    519: 
                    520:        return !!ret;
                    521: }
1.4       misho     522: 
                    523: /*
                    524:  * e_getnet() - Get network from string
                    525:  *
                    526:  * @net = Network string (format: <net[/cidr]>)
                    527:  * return: NULL error or !=NULL network should be e_free()
                    528:  */
                    529: netaddr_t *
                    530: e_getnet(const char *net)
                    531: {
                    532:        netaddr_t *n;
                    533:        char *str, *wrk;
                    534:        struct hostent *host;
                    535: 
                    536:        n = e_malloc(sizeof(netaddr_t));
                    537:        if (!n) {
                    538:                LOGERR;
                    539:                return NULL;
                    540:        } else
                    541:                memset(n, 0, sizeof(netaddr_t));
                    542:        str = e_strdup(net);
                    543:        if (!str) {
                    544:                LOGERR;
                    545:                e_free(n);
                    546:                return NULL;
                    547:        }
                    548:        wrk = strchr(str, '/');
                    549:        if (wrk)
                    550:                *wrk++ = 0;
                    551: 
                    552:        host = gethostbyname2(str, strchr(str, ':') ? AF_INET6 : AF_INET);
                    553:        if (!host) {
                    554:                elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
                    555:                e_free(str);
                    556:                e_free(n);
                    557:                return NULL;
                    558:        }
                    559:        switch (host->h_addrtype) {
                    560:                case AF_INET:
1.13      misho     561: #ifndef __linux__
1.4       misho     562:                        n->addr.sin.sin_len = sizeof(struct sockaddr_in);
1.13      misho     563: #endif
1.4       misho     564:                        n->addr.sin.sin_family = host->h_addrtype;
                    565:                        memcpy(&n->addr.sin.sin_addr, host->h_addr, sizeof n->addr.sin.sin_addr);
1.18      misho     566:                        if (wrk && strtol(wrk, NULL, 10) != 32)
1.4       misho     567:                                n->mask.in.s_addr = E_CIDRMASK(strtol(wrk, NULL, 10));
                    568:                        else
                    569:                                n->mask.in.s_addr = 0xFFFFFFFF;
                    570:                        break;
                    571:                case AF_INET6:
1.13      misho     572: #ifndef __linux__
1.4       misho     573:                        n->addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
1.13      misho     574: #endif
1.4       misho     575:                        n->addr.sin6.sin6_family = host->h_addrtype;
                    576:                        memcpy(&n->addr.sin6.sin6_addr, host->h_addr, sizeof n->addr.sin6.sin6_addr);
                    577:                        /* TODO: should support ipv6 mask */
                    578:                        break;
                    579:                default:
                    580:                        elwix_SetErr(EINVAL, "Unsupported family #%d", host->h_addrtype);
                    581:                        e_free(str);
                    582:                        e_free(n);
                    583:                        return NULL;
                    584:        }
                    585: 
                    586:        e_free(str);
                    587:        return n;
                    588: }
1.7       misho     589: 
                    590: /*
                    591:  * e_ether_addr() - Get or set ethernet address from interface name
                    592:  *
                    593:  * @ifname = interface name
1.13      misho     594:  * @addr = if addr is !=NULL then set new ethernet address
                    595:  * return: NULL error or !=NULL get current ethernet address should be e_free()
1.7       misho     596:  */
                    597: ether_addr_t *
                    598: e_ether_addr(const char *ifname, ether_addr_t * __restrict addr)
                    599: {
                    600:        ether_addr_t *a = NULL;
                    601:        struct ifaddrs *p, *ifa = NULL;
1.13      misho     602:        struct ifreq req;
                    603:        int s;
                    604:        sockaddr_t sa = E_SOCKADDR_INIT;
1.7       misho     605: 
1.13      misho     606:        memset(&req, 0, sizeof req);
1.7       misho     607:        if (!ifname)
                    608:                return NULL;
                    609: 
                    610:        getifaddrs(&ifa);
1.13      misho     611:        for (p = ifa; p && p->ifa_name; p = p->ifa_next) {
                    612: #ifndef __linux__
1.7       misho     613:                if (p->ifa_name && !strcmp(p->ifa_name, ifname) && p->ifa_addr && 
                    614:                                p->ifa_addr->sa_family == AF_LINK) {
1.13      misho     615:                        a = e_malloc(sizeof(ether_addr_t));
                    616:                        if (a)
                    617:                                memcpy(a, LLADDR((struct sockaddr_dl*) p->ifa_addr), 
                    618:                                                sizeof(ether_addr_t));
                    619: 
                    620:                        /* should set mac address */
                    621:                        if (addr && (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) > 0) {
                    622:                                strlcpy(req.ifr_name, ifname, sizeof req.ifr_name);
                    623:                                sa.sa.sa_family = AF_LINK;
                    624:                                sa.sa.sa_len = sizeof(ether_addr_t);
                    625:                                memcpy(sa.sa.sa_data, addr, sizeof(ether_addr_t));
                    626:                                req.ifr_ifru.ifru_addr = sa.sa;
                    627:                                ioctl(s, SIOCSIFLLADDR, &req);
                    628:                                close(s);
                    629:                        }
1.7       misho     630:                        break;
                    631:                }
1.13      misho     632: #else
                    633:                if (p->ifa_name && !strcmp(p->ifa_name, ifname)) {
                    634:                        s = socket(AF_INET, SOCK_DGRAM, 0);
                    635:                        if (s == -1)
                    636:                                break;
                    637:                        strlcpy(req.ifr_name, ifname, sizeof req.ifr_name);
                    638:                        if (!ioctl(s, SIOCGIFHWADDR, &req)) {
                    639:                                a = e_malloc(sizeof(ether_addr_t));
                    640:                                if (a)
                    641:                                        memcpy(a, req.ifr_addr.sa_data, sizeof(ether_addr_t));
                    642: 
                    643:                                /* should set mac address */
                    644:                                if (addr) {
                    645:                                        memset(&req, 0, sizeof req);
                    646:                                        strlcpy(req.ifr_name, ifname, sizeof req.ifr_name);
                    647:                                        sa.sa.sa_family = ARPHRD_ETHER;
                    648:                                        memcpy(sa.sa.sa_data, addr, sizeof(ether_addr_t));
                    649:                                        req.ifr_hwaddr = sa.sa;
                    650:                                        ioctl(s, SIOCSIFHWADDR, &req);
                    651:                                }
                    652:                        }
                    653:                        close(s);
                    654:                        break;
                    655:                }
                    656: #endif
                    657:        }
1.7       misho     658:        freeifaddrs(ifa);
                    659: 
                    660:        return a;
                    661: }
1.11      misho     662: 
                    663: /*
                    664:  * e_get1stiface() - Get first interface of host
                    665:  *
                    666:  * @szIface = interface string buffer
                    667:  * @iflen = size of interface buffer
                    668:  * return: -1 error or 0 ok
                    669:  */
                    670: int
                    671: e_get1stiface(char *szIface, int iflen)
                    672: {
                    673:        struct ifaddrs *ifa;
                    674: 
                    675:        if (!szIface || !iflen)
                    676:                return -1;
                    677: 
                    678:        getifaddrs(&ifa);
                    679:        strlcpy(szIface, ifa->ifa_name, iflen);
                    680:        freeifaddrs(ifa);
                    681:        return 0;
                    682: }
                    683: 
1.13      misho     684: #ifndef __linux__
1.11      misho     685: /*
                    686:  * e_getifacebyname() - Get interface and make network structure
                    687:  *
                    688:  * @psIface = Interface, if =NULL first interface
                    689:  * @addr = Network address structure
                    690:  * return: NULL error or !=NULL network structure
                    691:  */
                    692: sockaddr_t *
                    693: e_getifacebyname(const char *psIface, sockaddr_t * __restrict addr)
                    694: {
                    695:        char szIface[64] = { [0 ... 63] = 0 };
                    696:        struct ifaddrs *p, *ifa = NULL;
                    697: 
                    698:        if (!addr)
                    699:                return NULL;
                    700: 
                    701:        memset(addr, 0, sizeof(sockaddr_t));
                    702:        getifaddrs(&ifa);
                    703:        strlcpy(szIface, psIface ? psIface : ifa->ifa_name, sizeof szIface);
1.13      misho     704:        for (p = ifa; p && p->ifa_name; p = p->ifa_next)
1.11      misho     705:                if (p->ifa_name && !strcmp(p->ifa_name, szIface) && p->ifa_addr && 
                    706:                                p->ifa_addr->sa_family == AF_LINK) {
                    707:                        memcpy(&addr->sdl, p->ifa_addr, sizeof(struct sockaddr_dl));
                    708:                        break;
                    709:                }
                    710:        freeifaddrs(ifa);
                    711: 
                    712:        return addr;
                    713: }
                    714: 
                    715: /*
                    716:  * e_getlinkbyname() - Get host ethernet address and make network structure
                    717:  *
                    718:  * @psHost = Host ethernet address
                    719:  * @addr = Network address structure
                    720:  * return: NULL error or !=NULL network structure
                    721:  */
                    722: sockaddr_t *
                    723: e_getlinkbyname(const char *psHost, sockaddr_t * __restrict addr)
                    724: {
                    725:        ait_val_t v;
                    726:        sockaddr_t *a = addr;
                    727: 
                    728:        if (!psHost || !addr)
                    729:                return NULL;
                    730:        else
                    731:                memset(addr, 0, sizeof(sockaddr_t));
                    732: 
                    733:        AIT_INIT_VAL2(&v, string);
                    734:        if (!strchr(psHost, '.'))
                    735:                AIT_SET_STR(&v, ":");
                    736:        AIT_SET_STRCAT(&v, psHost);
                    737: 
                    738:        addr->sdl.sdl_len = sizeof(struct sockaddr_dl);
                    739:        if (e_link_addr(AIT_GET_STR(&v), &addr->sdl))
                    740:                a = NULL;
                    741: 
                    742:        AIT_FREE_VAL(&v);
                    743:        return a;
                    744: }
                    745: 
                    746: /*
                    747:  * e_getlinkbyether() - Get ethernet address and make network structure
                    748:  *
                    749:  * @mac = Ethernet address
                    750:  * @idx = Interface index
                    751:  * @type = Interface type
                    752:  * @iface = Interface name
                    753:  * @addr = Network address structure
                    754:  * return: NULL error or !=NULL network structure
                    755:  */
                    756: sockaddr_t *
                    757: e_getlinkbyether(const ether_addr_t * __restrict mac, u_short idx, u_char type, 
                    758:                const char *iface, sockaddr_t * __restrict addr)
                    759: {
                    760:        sockaddr_t *a = addr;
                    761: 
                    762:        if (!addr)
                    763:                return NULL;
                    764:        else
                    765:                memset(addr, 0, sizeof(sockaddr_t));
                    766: 
                    767:        addr->sdl.sdl_len = sizeof(struct sockaddr_dl);
                    768:        addr->sdl.sdl_family = AF_LINK;
                    769:        addr->sdl.sdl_index = idx;
                    770:        addr->sdl.sdl_type = type;
                    771:        if (iface && *iface) {
                    772:                addr->sdl.sdl_nlen = strlen(iface);
                    773:                memcpy(addr->sdl.sdl_data, iface, addr->sdl.sdl_nlen);
                    774:        }
                    775:        addr->sdl.sdl_alen = sizeof(ether_addr_t);
                    776:        memcpy(LLADDR(&addr->sdl), mac, addr->sdl.sdl_alen);
                    777: 
                    778:        return a;
                    779: }
1.13      misho     780: #endif
1.21    ! misho     781: 
        !           782: /*
        !           783:  * e_network() - Get network from address string
        !           784:  *
        !           785:  * @csAddr = Address string with CIDR mask /xx
        !           786:  * @net = Network information structure
        !           787:  * return: -1 error, 1 nothing for return or 0 ok
        !           788:  */
        !           789: int
        !           790: e_network(const char *csAddr, netaddr_t * __restrict net)
        !           791: {
        !           792:        int ret = 0;
        !           793:        u_char mask = 0;
        !           794:        inaddr_t a;
        !           795:        char *pos, szAddr[STRSIZ];
        !           796:        register int i;
        !           797: 
        !           798:        if (!csAddr || !net)
        !           799:                return -1;
        !           800:        else
        !           801:                strlcpy(szAddr, csAddr, sizeof szAddr);
        !           802: 
        !           803:        memset(net, 0, sizeof(netaddr_t));
        !           804: 
        !           805:        pos = strrchr(szAddr, '/');
        !           806:        if (pos) {
        !           807:                *pos++ = 0;
        !           808:                mask = (u_char) strtol(pos, NULL, 10);
        !           809:        } else
        !           810:                return 1;
        !           811: 
        !           812:        if (strchr(szAddr, ':')) {
        !           813:                if (mask > 128)
        !           814:                        return -1;
        !           815:                else {
        !           816:                        for (i = 0; i < 4 && (mask / 32); i++, mask -= 32)
        !           817:                                net->mask.in6.__u6_addr.__u6_addr32[i] = 0xFFFFFFFF;
        !           818:                        if (mask)
        !           819:                                net->mask.in6.__u6_addr.__u6_addr32[i] = E_CIDRMASK(mask % 32);
        !           820:                }
        !           821: 
        !           822:                inet_pton(AF_INET6, szAddr, &a.in6);
        !           823: 
        !           824: #ifndef __linux__
        !           825:                net->addr.sin6.sin6_len = sizeof net->addr.sin6;
        !           826: #endif
        !           827:                for (i = 0; i < 4; i++)
        !           828:                        net->addr.sin6.sin6_addr.__u6_addr.__u6_addr32[i] = 
        !           829:                                a.in6.__u6_addr.__u6_addr32[i] & net->mask.in6.__u6_addr.__u6_addr32[i];
        !           830:        } else {
        !           831:                if (mask > 32)
        !           832:                        return -1;
        !           833:                else {
        !           834:                        if (mask == 32)
        !           835:                                net->mask.in.s_addr = 0xFFFFFFFF;
        !           836:                        else
        !           837:                                net->mask.in.s_addr = E_CIDRMASK(mask);
        !           838:                }
        !           839: 
        !           840:                inet_pton(AF_INET, szAddr, &a.in4);
        !           841: 
        !           842: #ifndef __linux__
        !           843:                net->addr.sin.sin_len = sizeof net->addr.sin;
        !           844: #endif
        !           845:                net->addr.sin.sin_addr.s_addr = a.in.s_addr & net->mask.in.s_addr;
        !           846:        }
        !           847: 
        !           848:        return ret;
        !           849: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>