tasklwIP - A Lightweight TCP/IP stack - Tasks: task #15393, Support scoped literal IPv6...

 
 

You are not allowed to post comments on this tracker with your current authentication level.

task #15393: Support scoped literal IPv6 addresses in getaddrinfo

Submitter:  Ashley Duncan <ashesman>
Submitted:  Thu 19 Sep 2019 04:20:16 AM UTC
   
 
Category:  socket/netconn Should Start On:  Thu 19 Sep 2019 12:00:00 AM UTC
Should be Finished on:  Thu 19 Sep 2019 12:00:00 AM UTC Priority:  5 - Normal
Status:  Done Privacy:  Public
Assigned to:  goldsimon Percent Complete:  100%
Open/Closed:  Closed Planned Release:  2.2.0
Effort:  0.00

Wed 11 Dec 2019 08:14:12 PM UTC, comment #5: 

Fixed in ip6addr_aton.
And while at it, I've added those missing IN6_IS_ADDR_* macros.

Simon Goldschmidt <goldsimon>
Group administrator
Thu 19 Sep 2019 10:49:45 PM UTC, comment #4: 

Yes, correct.  getaddrinfo works as expected under linux.  For example:

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char **argv)
{
    struct addrinfo hints = {0};
    struct addrinfo * res = NULL;
    if (getaddrinfo("fe80::8831:ba34:ba2e:667f%wlp5s0", "1234", &hints, &res) == 0)
    {
        struct addrinfo * info = res;
        while (info)
        {
            if (info->ai_family == AF_INET6)
            {
                struct sockaddr_in6 pI6 = (struct sockaddr_in6 )info->ai_addr;
if (IN6_IS_ADDR_LINKLOCAL(&(pI6->sin6_addr)))
{
                    char buf[64];
printf("IP6 Addr: %s%%%d\n", inet_ntop(AF_INET6, &pI6->sin6_addr, buf, sizeof(buf)), pI6->sin6_scope_id);
}
            }
            info = info->ai_next;
        }
    }
    freeaddrinfo(res);
    return 0;
}

Gives the following result for "fe80::8831:ba34:ba2e:667f%wlp5s0" :

IP6 Addr: fe80::8831:ba34:ba2e:667f%3
IP6 Addr: fe80::8831:ba34:ba2e:667f%3
IP6 Addr: fe80::8831:ba34:ba2e:667f%3

Or for "fe80::a8e0:d579:be00:72ab%enp4s0" :
IP6 Addr: fe80::a8e0:d579:be00:72ab%2
IP6 Addr: fe80::a8e0:d579:be00:72ab%2
IP6 Addr: fe80::a8e0:d579:be00:72ab%2

Ashley Duncan <ashesman>
Thu 19 Sep 2019 05:44:35 AM UTC, comment #3: 

Ok, so it's getaddrinfo("FE80::2B0:52FF:FEFF:FF05%pl1" , ...) that doesn't work as expected...

Simon Goldschmidt <goldsimon>
Group administrator
Thu 19 Sep 2019 05:41:35 AM UTC, comment #2: 

Thanks for your reply.

The code used by mbedtls is below.  I know the interface name is correct as I made the interface myself and it returns the correct index when queried by name.  It gets as deep down as ip6addr_aton with the scoped address which returns a correctly decoded IPV6 address but the zone is always set to 0 by line 187 of ip6_addr.c.  There is no test in this function for the existence of a % in the address. 

I can bind to a link local address on my interface using the socket bind function as expected but need to call an lwip function to get the interface id which is not available through a portable API.

I pass "FE80::2B0:52FF:FEFF:FF05%pl1" as bind_ip and it always results in a zone (scope_id) of 0.  It should set the correct zone I think if there was only one interface present (there is a test for this somewhere down the stack).  But I have two interfaces.

int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto )
{
    int ret;
    struct addrinfo hints, *addr_list, *cur;

    if ( ( ret = net_prepare() ) != 0 ) {
        return ( ret );
    }

    /* Bind to IPv6 and/or IPv4, but only in the desired protocol */
    memset( &hints, 0, sizeof( hints ) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
    hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;

    if ( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) {
        return ( MBEDTLS_ERR_NET_UNKNOWN_HOST );
    }

    /* Try the sockaddrs until a binding succeeds */
    ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
    for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
        int fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
        if ( fd < 0 ) {
            ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
            continue;
        }

        /*SO_REUSEADDR option dafault is disable in source code(lwip)*/
#if SO_REUSE
        int n = 1;
        if ( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
                         (const char *) &n, sizeof( n ) ) != 0 ) {
            close( fd );
            ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
            continue;
        }
#endif
        /*bind interface default don't process the addr is 0xffffffff for TCP Protocol*/
        struct sockaddr_in *serv_addr = NULL;
        serv_addr = (struct sockaddr_in *)cur->ai_addr;
        serv_addr->sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
        if ( bind( fd, (struct sockaddr *)serv_addr, cur->ai_addrlen ) != 0 ) {
            close( fd );
            ret = MBEDTLS_ERR_NET_BIND_FAILED;
            continue;
        }
...


I use this function I wrote instead to bind to the link local address on my interface which works perfectly:

#include "lwip/netifapi.h"
int mbedtls_net_bind_ip6_interface(mbedtls_net_context ctx, const char bind_ip, const char * interface, unsigned port, int proto )
{
    int ret;
    struct sockaddr_in6 sa6;
    if ( ( ret = net_prepare() ) != 0 ) {
        return ( ret );
    }
    inet_pton(AF_INET6, bind_ip, &(sa6.sin6_addr));
    sa6.sin6_port = htons(port);
    sa6.sin6_len = sizeof(sa6);
    sa6.sin6_flowinfo = 0;
    sa6.sin6_family = AF_INET6;
    u8_t idx = 0;
    netifapi_netif_name_to_index(interface, &idx);
    sa6.sin6_scope_id = idx;
   
    int fd = socket( sa6.sin6_family, proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP);
    if ( fd < 0 ) {
        return MBEDTLS_ERR_NET_SOCKET_FAILED;
    }

    /*SO_REUSEADDR option dafault is disable in source code(lwip)*/
#if SO_REUSE
    int n = 1;
    if ( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof( n ) ) != 0 ) {
        close( fd );
        return MBEDTLS_ERR_NET_SOCKET_FAILED;
    }
#endif
    if ( bind( fd, (struct sockaddr *)&sa6, sizeof(sa6) ) != 0 ) {
        close( fd );
        return MBEDTLS_ERR_NET_BIND_FAILED;
    }

...

Ashley Duncan <ashesman>
Thu 19 Sep 2019 04:39:33 AM UTC, comment #1: 

I thought that should work. Could you help us by telling us which lwIP function mbedTLS calls to bind and with which parameters? Maybe you just got the netif name wrong?

Simon Goldschmidt <goldsimon>
Group administrator
Thu 19 Sep 2019 04:20:16 AM UTC, original submission:  

It would be great if you could bind to a linklocal ip address used a scoped literal type address through the APIs that just take a URI string.  E.g. fe80::1ff:fe23:4567:890a%en1 or fe80::1ff:fe23:4567:890a%2.

mbedtls net abstraction layer only offers a bind that takes a char *.  Passing a scoped link local IP address in causes the socket to be incorrectly bound to zone 0 and hence cannot accept incoming packets.

Currently I cannot see a way to do this in a portable manner using the existing APIs.

Of course, you can achieve this functionality through lower layer calls...

Please excuse if I have missed something...

Ashley Duncan <ashesman>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by goldsimon (Posted a comment)
  • -email is unavailable- added by ashesman (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

     

    Follow 5 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2019-12-11 goldsimon StatusNone Done
        Percent Complete0% 100%
        Assigned toNone goldsimon
        Open/ClosedOpen Closed
        Planned ReleaseNone 2.2.0

    Back to the top

    Powered by Savane 3.13-d3ae.
    Corresponding source code