udhcpc6 kernel listen mode is broken

Danomi Manchego danomimanchego123 at gmail.com
Wed May 11 01:34:18 UTC 2022


Hello,

On April 1, I sent "udhcpc6 renew message copy/paste error" email
about udhcpc6 sends the wrong message ID for Renew message due to
copy/paste error from IPv4 dhcpc.c.  (Was DHCPREQUEST, should be
D6_MSG_RENEW.)  After fixing that, I found that the Renew is sent
correctly, and the DHCPv6 server replies, but udhcpc6 fails to get the
reply.  Because there is no reply, the lease does not get extended by
Renew.  I found that the issue is that the udhcp_listen_socket() in
socket.c (used for kernel listen mode in d6_dhcpc.c) is somewhat
hard-coded for IPv4.  I was able to get kernel listen mode to work by
adding a new function like this to socket.c and using it in d6_dhcp.c.
My udhcp6_listen_socket() differs from udhcp_listen_socket() as
follows:

* Use PF_INET6 instead of PF_INET.

* Set IPPROTO_IPV6 / IPV6_V6ONLY socket option rather than broadcast option.

* Use `struct sockaddr_in6` instead of `struct sockaddr_in`.

* Use AF_INET6 instead of AF_INET.

(Maybe SOCK_CLOEXEC should also be set in *both* functions when
calling xsocket since udhcpc/udhcpc6 invoke external udhcpc.script,
but I did not try it.)

My function is pasted below.

int FAST_FUNC udhcp6_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
{
    int fd;
    struct sockaddr_in6 addr;
    char *colon;

    log2("opening listen socket on *:%d %s", port, inf);
    fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);

    setsockopt_reuseaddr(fd);

    if (setsockopt_1(fd, IPPROTO_IPV6, IPV6_V6ONLY) < 0)
        bb_simple_perror_msg_and_die("IPPROTO_IPV6");

    /* SO_BINDTODEVICE doesn't work on ethernet aliases (ethN:M) */
    colon = strrchr(inf, ':');
    if (colon)
        *colon = '\0';

    if (setsockopt_bindtodevice(fd, inf))
        xfunc_die(); /* warning is already printed */

    if (colon)
        *colon = ':';

    memset(&addr, 0, sizeof(addr));
    addr.sin6_family = AF_INET6;
    addr.sin6_port = htons(port);
    /* addr.sin_addr.s_addr = ip; - all-zeros is INADDR_ANY */
    xbind(fd, (struct sockaddr *)&addr, sizeof(addr));

    return fd;
}

Regards,
Danomi -


More information about the busybox mailing list