Roy's Blog

A Hacker's musings on Code | Tech | Life

With the following changes:

  • NetBSD: Can be build without ARP support but listen to kernel DaD
  • ND6: Removed NA support from SMALL builds
  • ND6: Remove and warn about NA issues on OS's other than NetBSD and Linux
  • script: /tmp files are now cleaned up for systems without open_memstream(3)
  • configure: open_memstream(3) detected on recent glibc
  • DHCP: Avoid duplicate read of UDP socket when BPF is also open
  • IP: Avoid adding address if already exists on OS other than Linux
  • IP6: Avoid adding address is already exists on Solaris
  • route: Fixed a NULL de-reference error on statically configured routes
  • DHCP6: Move to REQUEST when any IA has error no-binding in RENEW/REBIND
  • DragonFlyBSD: Now compiles and works for
  • IP: Accept packets with IP header options

I don't anticipate any more releases for a while as this is looking really good now!

Continue reading...

Just three changes of note

  • Compile fixes for various build options on various platforms
  • IPv4LL is fixed on NetBSD-8
  • script buffers are freed on forking

Continue reading...

Huge update! The big points are:

  • ARP now supports many requests
  • Routing tables now use Red-Black Trees
  • Script variables are no longer allocated manually

dhcpcd-7 branch has now entered maintainance only mode, which means it only gets security updates. Minor changes from dhcpcd-7.2.3 include:

  • DHCP addresses are added with vltime of the lease time and pltime of the rebind time (Linux only)

Continue reading...

open_memstream is one of the more important functions added to POSIX libc of late. It's so important because it makes the generation of strings really easy - you no longer need to care about allocating the right amount of memory as the library will do it for you. Now, there's many functions that already help with this, such as asprintf but that's not standard and if you want to create many strings in one area you still need to care about the size of the area. You want to create an area if you have many strings, because it's more efficient for malloc and if you keep the area around and re-use it then it avoids memory fragmentation.

Now, to be clear, you have been able to do this since forever using fopen, writing to the file and then allocating your area based on the final file size. Still, it requires some memory management still but more importantly it writes to a file. Writing to a file is slow and reduces the life span of the disk you're writing to. It's only been fairly recently that tmpfs was a thing, but even today not all OS's have /tmp mounted as tmpfs. Requiring this isn't exactly ideal for a generic program to do - the setup and install should be easy. Because of all these reasons, most programs worked the string length needed and either allocated an area or string and then finally write the string. However, while saving the disk, it's also a lot more error prone because you need to work out the length of everything and that's not always trivial, especially for things like a DHCP client which is always building strings based on the information given by the DHCP server.

Here's an example of open_memstream in action:

 * Example program which manages an area of environment strings
 * to send to child programs.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static const char *foo = "foo";
static const char *bar = "bar";

int main(void)
        char *argv[] = { "/usr/bin/env", NULL };
        char *buf, *ep, *p, **env, **envp;
        size_t buflen, nenv, i;
        FILE *fp = open_memstream(&buf, &buflen);

        fprintf(fp, "FOO=%s", foo);
        fputc('\0', fp);
        fprintf(fp, "BAR=%s", bar);
        fputc('\0', fp);

        /* We could keep fp around as our area and just rewind it. */

        /* execve relies on a trailing NULL */
        nenv = 1;
        for (p = buf, ep = p + buflen; p < ep; p++) {
                if (*p == '\0')

        /* reallocarray(3) should be standard really */
        envp = env = malloc(nenv * sizeof(char *));
        *envp++ = buf;
        for (p = buf, ep--; p < ep; p++) {
                if (*p == '\0')
                        *envp++ = p + 1;
        *envp = NULL;

        execve(argv[0], argv, env);

As you can see, we only manage the environment array handed to to execve - open_memstream is managing our string area and fprintf is working out the length each string needs to be for us. This vastly reduces the complexity and increases the security and reliabilty of creating large environment strings, which most DHCP clients do. We could also write a helper function to write the string AND the trailing NULL terminator for the string to be more efficient. You'll get to see this in dhcpcd-8 which should be released later this year.

Continue reading...

Minor update with the following changes:

  • More strict POSIX shell support
  • Interfaces have an implicit metric of 0 unless specified
  • Inline comments are stripped from nameserver and domain entries

The last upate was in 2016, so this is proving to be very stable :)

Continue reading...