Hello again,

I think this is a regression, since now it will refuse all IPv4
connections. I filed a new PR on github [0].

[0] https://github.com/apache/apr/pull/44

Best,
Lubos Uhliarik

On Fri, Jun 23, 2023 at 1:04 PM Lubos Uhliarik <luhli...@redhat.com> wrote:

> Hello all,
>
> I have recently created PR [0], which has been merged and I backported
> this patch to our latest apr-util version in Fedora.
>
> Now I have been trying to come up with some test. I created simple C file
> where I'm trying to query memcached:
>
> int main(int argc, char **argv)
> {
>     apr_pool_t *pglobal;
>     apr_status_t rv;
>     char *mcversion;
>     char *errstr = malloc(1024);
>
>     apr_app_initialize(NULL, NULL, NULL);
>
>     if (apr_pool_create(&pglobal, NULL)){
>         fprintf(stderr, "could not create global pool");
>         return 1;
>     }
>
>     if (argc != 3){
>         fprintf(stderr, "Usage: ./connconnectipv6 HOST PORT\n");
>         return 2;
>     }
>
>     apr_memcache_server_t *ms;
>
>     rv = apr_memcache_server_create(pglobal, argv[1], atoi(argv[2]), 0, 2,
> 2, 60, &ms);
>     if (rv != APR_SUCCESS){.
>         fprintf(stderr, "Errno: %d - %s\n", errno, apr_strerror(errno,
> errstr, 1024));
>         return 3;
>     }
>
>     rv = apr_memcache_version(ms, pglobal, &mcversion);
>     if (rv != APR_SUCCESS){.
>        fprintf(stderr, "Errno: %d - %s\n", errno, apr_strerror(errno,
> errstr, 1024));
>        return 5;
>     }
>
>     fprintf(stdout, "memcached version: %s\n", mcversion);
>
>     apr_pool_destroy(pglobal);
>     free(errstr);
>
>     return 0;
> }
>
>
>
> In old apr-util version without patch[0] , I'm getting output as expected:
>
> # ./memcachecon 127.0.0.1 11211
> memcached version: 1.6.21
> # echo $?
> 0
> # ./memcachecon ::1 11211
> Errno: 0 - Success
> # echo $?
> 5
>
> But with new apr-util containing patch[0], I'm getting weird behavior:
>
> # ./memcachecon 127.0.0.1 11211
> Errno: 22 - Invalid argument
> # echo $?
> 5
> # ./memcachecon ::1 11211
> memcached version: 1.6.21
> # echo $?
> 0
>
> I don't know why, but somehow I'm getting errcode 22 in mc_conn_construct
> function allegedly returned by conn_connect, but when I debug it in gdb it
> shows me that conn_connect returns 0. Also it looks like
> apr_socketaddr_info_get finished successfully. I'm really puzzled here. Do
> you have any idea, what am I doing wrong?
>
> Also adding output from gdb:
>
> (gdb) run 127.0.0.1 11211
> Starting program: /tmp/tmp.ntb0HNhuvT/memcachecon 127.0.0.1 11211
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib64/libthread_db.so.1".
>
> Breakpoint 2, apr_sockaddr_info_get (sa=sa@entry=0x7fffffffd9f0,
> hostname=0x40b490 "127.0.0.1", family=0, port=11211, flags=flags@entry=0,
> p=0x40d3f8) at network_io/unix/sockaddr.c:639
> 639 {
> (gdb) list
> 634
> 635 APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa,
> 636                                                const char *hostname,
> 637                                                apr_int32_t family,
> apr_port_t port,
> 638                                                apr_int32_t flags,
> apr_pool_t *p)
> 639 {
> 640    apr_int32_t masked;
> 641    *sa = NULL;
> 642
> 643    if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) {
> (gdb)
> 644        if (!hostname ||
> 645            family != APR_UNSPEC ||
> 646            masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) {
> 647            return APR_EINVAL;
> 648        }
> 649 #if !APR_HAVE_IPV6
> 650        if (flags & APR_IPV6_ADDR_OK) {
> 651            return APR_ENOTIMPL;
> 652        }
> 653 #endif
> (gdb)
> 654    }
> 655    if (family == APR_UNSPEC && hostname && *hostname == '/') {
> 656        family = APR_UNIX;
> 657    }
> 658    if (family == APR_UNIX) {
> 659 #if APR_HAVE_SOCKADDR_UN
> 660        if (hostname && *hostname == '/') {
> 661            *sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
> 662            (*sa)->pool = p;
> 663            apr_cpystrn((*sa)->sa.unx.sun_path, hostname,
> (gdb)
> 664                        sizeof((*sa)->sa.unx.sun_path));
> 665            (*sa)->hostname = apr_pstrdup(p, hostname);
> 666            (*sa)->family = APR_UNIX;
> 667            (*sa)->sa.unx.sun_family = APR_UNIX;
> 668            (*sa)->salen = sizeof(struct sockaddr_un);
> 669            (*sa)->addr_str_len = sizeof((*sa)->sa.unx.sun_path);
> 670            (*sa)->ipaddr_ptr = &((*sa)->sa.unx.sun_path);
> 671            (*sa)->ipaddr_len = (*sa)->addr_str_len;
> 672
> 673            return APR_SUCCESS;
> (gdb)
> 674        }
> 675        else
> 676 #endif
> 677        {
> 678            *sa = NULL;
> 679            return APR_ENOTIMPL;
> 680        }
> 681    }
> 682 #if !APR_HAVE_IPV6
> 683    /* What may happen is that APR is not IPv6-enabled, but we're still
> (gdb)
> 684     * going to call getaddrinfo(), so we have to tell the OS we only
> 685     * want IPv4 addresses back since we won't know what to do with
> 686     * IPv6 addresses.
> 687     */
> 688    if (family == APR_UNSPEC) {
> 689        family = APR_INET;
> 690    }
> 691 #endif
> 692
> 693    return find_addresses(sa, hostname, family, port, flags, p);
> (gdb)
> 694 }
> 695
> 696 APR_DECLARE(apr_status_t) apr_sockaddr_info_copy(apr_sockaddr_t **dst,
> 697                                                 const apr_sockaddr_t
> *src,
> 698                                                 apr_pool_t *p)
> 699 {
> 700    apr_sockaddr_t *d;
> 701    const apr_sockaddr_t *s;
> 702
> 703    for (*dst = d = NULL, s = src; s; s = s->next) {
> (gdb)
> 704        if (!d) {
> 705            *dst = d = apr_pmemdup(p, s, sizeof *s);
> 706        }
> 707        else {
> 708            d = d->next = apr_pmemdup(p, s, sizeof *s);
> 709        }
> 710        if (s->hostname) {
> 711            if (s == src || s->hostname != src->hostname) {
> 712                d->hostname = apr_pstrdup(p, s->hostname);
> 713            }
> (gdb) n
> 641    *sa = NULL;
> (gdb)
> 643    if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) {
> (gdb)
> 655    if (family == APR_UNSPEC && hostname && *hostname == '/') {
> (gdb)
> 693    return find_addresses(sa, hostname, family, port, flags, p);
> (gdb)
> call_resolver.constprop.0 (sa=sa@entry=0x7fffffffd9f0, hostname=0x40b490
> "127.0.0.1", family=0, port=11211, p=0x40d3f8, flags=<optimized out>) at
> network_io/unix/sockaddr.c:337
> 337 static apr_status_t call_resolver(apr_sockaddr_t **sa,
> (gdb)
> 347    memset(&hints, 0, sizeof(hints));
> (gdb)
> 337 static apr_status_t call_resolver(apr_sockaddr_t **sa,
> (gdb)
> 347    memset(&hints, 0, sizeof(hints));
> (gdb)
> 337 static apr_status_t call_resolver(apr_sockaddr_t **sa,
> (gdb)
> 347    memset(&hints, 0, sizeof(hints));
> (gdb)
> 348    hints.ai_family = family;
> (gdb)
> 349    hints.ai_socktype = SOCK_STREAM;
> (gdb)
> 347    memset(&hints, 0, sizeof(hints));
> (gdb)
> 351    if (family == APR_UNSPEC) {
> (gdb)
> 355        hints.ai_flags = AI_ADDRCONFIG;
> (gdb)
> 368    if(hostname == NULL) {
> (gdb)
> 397    error = getaddrinfo(hostname, servname, &hints, &ai_list);
> (gdb)
> 345    char *servname = NULL;
> (gdb)
> 397    error = getaddrinfo(hostname, servname, &hints, &ai_list);
> (gdb)
> 416                                   || error == EAI_ADDRFAMILY
> (gdb)
> 414    if ((family == APR_UNSPEC) && (error == EAI_BADFLAGS
> (gdb)
> 423    if (error) {
> (gdb)
> 446    ai = ai_list;
> (gdb)
> 447    while (ai) { /* while more addresses to report */
> (gdb)
> 445    prev_sa = NULL;
> (gdb)
> 454        if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
> (gdb)
> 462        new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
> (gdb)
> 464        new_sa->pool = p;
> (gdb)
> 465        memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen);
> (gdb)
> 466        apr_sockaddr_vars_set(new_sa, ai->ai_family, port);
> (gdb)
> 468        if (!prev_sa) { /* first element in new list */
> (gdb)
> 469            if (hostname) {
> (gdb)
> 470                new_sa->hostname = apr_pstrdup(p, hostname);
> (gdb)
> 472            *sa = new_sa;
> (gdb)
> 480        ai = ai->ai_next;
> (gdb)
> 447    while (ai) { /* while more addresses to report */
> (gdb)
> 482    freeaddrinfo(ai_list);
> (gdb)
> 484    if (prev_sa == NULL) {
> (gdb)
> 493 }
> (gdb)
> conn_connect (conn=0x40d470) at memcache/apr_memcache.c:299
> 299    if (rv != APR_SUCCESS) {
> (gdb) p rv
> $1 = 0
> (gdb) l
> 294 #else
> 295    apr_int32_t family = APR_UNSPEC;
> 296 #endif
> 297
> 298    rv = apr_sockaddr_info_get(&sa, conn->ms->host, family,
> conn->ms->port, 0, conn->p);
> 299    if (rv != APR_SUCCESS) {
> 300        return rv;
> 301    }
> 302
> 303    rv = apr_socket_timeout_set(conn->sock, 1 * APR_USEC_PER_SEC);
> (gdb)
> 304    if (rv != APR_SUCCESS) {
> 305        return rv;
> 306    }
> 307
> 308    rv = apr_socket_connect(conn->sock, sa);
> 309    if (rv != APR_SUCCESS) {
> 310        return rv;
> 311    }
> 312
> 313    rv = apr_socket_timeout_set(conn->sock, -1);
> (gdb)
> 314    if (rv != APR_SUCCESS) {
> 315        return rv;
> 316    }
> 317
> 318    return rv;
> 319 }
> 320
> 321
> 322 static apr_status_t
> 323 mc_conn_construct(void **conn_, void *params, apr_pool_t *pool)
> (gdb) bt
> #0  conn_connect (conn=0x40d470) at memcache/apr_memcache.c:299
> #1  mc_conn_construct (conn_=0x40b638, params=0x40b460, pool=<optimized
> out>) at memcache/apr_memcache.c:363
> #2  0x00007ffff7cff75d in create_resource (ret_res=<synthetic pointer>,
> reslist=0x40b4f0) at misc/apr_reslist.c:123
> #3  apr_reslist_acquire (reslist=0x40b4f0, 
> resource=resource@entry=0x7fffffffda78)
> at misc/apr_reslist.c:395
> #4  0x00007ffff7d060fc in ms_find_conn (ms=<optimized out>, ms=<optimized
> out>, conn=0x7fffffffda78) at memcache/apr_memcache.c:232
> #5  apr_memcache_version (ms=0x40b460, p=0x4093d8, baton=0x7fffffffdb08)
> at memcache/apr_memcache.c:1063
> #6  0x000000000040129e in main (argc=3, argv=0x7fffffffdc38) at
> /mnt/tests/CoreOS/apr-util/memcache/bz2063562-memcache-conn-connect-allow-ipv6/connconnectipv6.c:39
> (gdb) n
> mc_conn_construct (conn_=0x40b638, params=0x40b460, pool=<optimized out>)
> at memcache/apr_memcache.c:363
> 363    rv = conn_connect(conn);
> (gdb) p rv
> $2 = <optimized out>
> (gdb) list
> 358
> 359    conn->buffer = apr_palloc(conn->p, BUFFER_SIZE + 1);
> 360    conn->blen = 0;
> 361    conn->ms = ms;
> 362
> 363    rv = conn_connect(conn);
> 364    if (rv != APR_SUCCESS) {
> 365        apr_pool_destroy(np);
> 366    }
> 367    else {
> (gdb)
> 368        *conn_ = conn;
> 369    }
> 370
> 371    return rv;
> 372 }
> 373
> 374 #if APR_HAS_THREADS
> 375 static apr_status_t
> 376 mc_conn_destruct(void *conn_, void *params, apr_pool_t *pool)
> 377 {
> (gdb) n
> 365        apr_pool_destroy(np);
> (gdb) p rv
> $3 = 22
> (gdb)
>
> [0]
> https://github.com/apache/apr-util/commit/fb3feebd617f6aa904d9132618649f24821bd67f
>
> Best,
> Lubos Uhliarik
>


-- 

Luboš Uhliarik

Senior Software Engineer | Infrastructure Services

luhli...@redhat.com

BRQ-TPBC

*irc (luhliari at): #brno, #infrastructure-services, #core-services*
<https://www.redhat.com/>

Reply via email to