Roy's Blog

A Hacker's musings on Code | Tech | Life

Welcome to 2018 :)
dhcpcd-7.0.0 has been released!

Here's the list of changes from rc4:

  • dhcp: when unicasting on L3, unicast on L2 as well
  • dhcp: when rebooting, don't set cidaddr
  • dhcp6: don't listen on IPv6 addresses when not using DHCPv6
  • dhcp: only set probe state when probing (fixes REBOOT reason)
  • linux: use IFA_F_NOPREFIXROUTE for IPv4 addresses
  • ipv6: disable kernel RA if interface is active
  • hooks: set protocol to link for link layer events

ftp://roy.marples.name/pub/dhcpcd/dhcpcd-7.0.0.tar.xz
ftp://roy.marples.name/pub/dhcpcd/dhcpcd-7.0.0.tar.xz.distinfo.asc
https://roy.marples.name/downloads/dhcpcd/dhcpcd-7.0.0.tar.xz
https://roy.marples.name/downloads/dhcpcd/dhcpcd-7.0.0.tar.xz.distinfo.asc

Continue reading...

Here's the changelog:

  • dhcp: fixed classless static routes
  • prefix delegation: build routes after assigning addresses
  • dhcp: on lease expiration, discover only when carrier
  • ip6: fix potential segfault when lifetime overflows
  • bsd: compile on recent OpenBSD platforms
  • dhcp: fix reporting of DNS encoded SIP servers
  • dhcp6: fix unicast in non master mode

All the critical issues people have highighted have now been resolved, so hopefully this is the last rc before release :)

Continue reading...

So dhcpcd has supported a shared IP address for a long time. It did this by removing the address from the non preferrred interface and then adding it to the preferred interface.
Easy!

But this came with some issues:

  • There is a window where the IP address doesn't exist, and the kernel may wipe out the subnet route at that point also.
  • DHCP renews didn't come through to the right interface.
  • Some kernels didn't like the address moving interfaces.

Still, to the best of my knowledge, no other product has this feature and for the most part, it did work well allowing almost seamless switching of wired -> wireless and back again with both using the same IP address. But that wasn't good enough - I was challenged to do better!

So I took up the bat and cooked up this changeset to change the behaviour to this:

  • Each applicable interface will have the shared ip address.
  • Whenever the address is added, the most preferred address will be ARP announced.

And lo - IT WORKS!!! The changeover when plugging/removing the wired interface is 100% seamless for me. ssh, ping, etc get zero interuption. Of course, YMMV ;)
But there are some costs:

  • Thanks to ARP, only the primary interface will receive DHCP unicast messages for other interfaces.
    As such we need to re-direct them to the correct interface by examining xid and chaddr.
    This means we have to relax the BPF filters to allow more through.
  • Kernels supporting RFC5227 will double ARP announce the address.
  • NetBSD-8 kernels needed some love to get it to work and there's still an issue with it not working when an address is deleted from the interface.

Only the last bullet is really important, which is mainly why the changeset hasn't hit the master branch yet. But that should be fixed soon. The other points can be fixed as and when.

Continue reading...

It's been a while in the making, but dhcpcd-7.0.0-beta1 is finally here! I have been using this a lot on all supported platforms bar Solaris and it's been very trouble free, so hopefully not many changes (if any? famous last words!) before a RC and final release.

Summary of changes since dhcpcd-6.11.5:

  • source file locations reworked: dhcpcd source is in src dhcpcd hooks are in hooks compat is in compat
  • README split into README.md and BUILDING.md
  • internal routing is now protocol agnostic
  • avoid using __packed and use compile time asserts instead
  • addresses some alignment issues
  • disable some ARP code on kernels which support RFC5227
  • BSD IPv6 kernel settings are now updated to reflect dhcpcd config
  • custom logger has been removed, syslog handles everything as such, the --logfile option has been removed as well. If you need better/earlier logging, get a better syslogger!
  • distinfo and signed distinfo files are now available alongside release taraballs from this point onwards
  • default DBDIR has changed from /var/db to /var/db/dhcpcd
  • /etc/dhcpcd.duid moves to DBDIR/duid
  • /etc/dhcpcd.secret moves to DBDIR/secret
  • lease file names have dhcpcd removed from them as they are now inside a directory of the same name
  • fixed issues with reject routes not working on some platforms
  • improved nl80211 support on Linux for working out the SSID
  • no longer request NTP by default in dhcpcd.conf
  • fix detecting IPv6 DAD on OpenBSD
  • remove custom Solaris DLPI filtering in favour of BPF (note there seems to be a kernel issue where the DHCP fd receives ARP's as well, the only side effect is a noisy syslog)
  • BPF filtering vastly improved so dhcpcd only wake up on ARP or DHCP packets destined for it
  • support for MUD URL (draft-ietf-opsawg-mud-05)
  • if the kernel isn't doing DAD, don't insist on waiting for it to actually do it
  • fix a potential crash where the DHCP or ARP states could be freed before the packet processing loop naturally breaks
  • removed gateway and nogateway options (these can be controlled by the nooption directive which works for more than just gateways)
  • removed ipv6ra_own and ipv6ra_own_default options (these can be controled by the ipv6rs/noipv6rs directive)
  • fix a memory leak on systems where posix_spawnattr_init allocates memory by calling posix_spawnattr_destroy afterwards
  • fix a crash receiving SIGUSR1

I've not done everything I've wanted to, but I feel that many issues have now been addressed and on the whole dhcpcd is in a very good state right now.

Let me know of any issues you find!

Continue reading...

I've been using Fossil for quite a while now as my SCM. I like Fossil. But Fossil is not Git, and most people seem to like Git. It could be better to say that most people like GitHub because it's the first hosted SCM that's free for open source with good social interaction I'm aware of. And GitHub is huge. Some might say that if you're not on GitHub, you don't exist as a project. Well this obviously isn't true, but you get the idea. You can get free Fossil hosting at Chisel, which is nice, but it's also not GitHub. Plus I like to be 100% self hosted.

So, to get myself on GitHub (as a mirror only), there needs to be a bridge between Fossil and Git. Fossil documentation implies this is quite easy. Sadly, this isn't the case as the <=Fossil-1.37 releases (note there is no guaranntee that future versions of follow will not have these flaws - my branch may not be comitted to trunk) have the following flaws:

  • Branch and Tag name mangling (dhcpcd-6 becomes dhcpcd_6)
  • Silent master branch renaming into trunk on inport, but not on export
  • No tag comments (Fossil lacks the feature) which means syncing tags back and forth results in tag conflict due to signature change

I submitted some initial patches the the Fossil mailing list and I now have a Fossil commit bit! You can find my branch here to fix the Fossil Git bridge.

But that's not the end of the story. A bridge has two ends. With my initial setup, the Git end was bare bones repository which I pushed to GitHub. This is no longer the case - I now need a staging repository to pull both ends. And this requires a script because Git needs a little more hand-holding to completely track a remote. The below script is tailored for my needs, yours may differ. It also reflects the above initial design and the subsequent change - as such it it may need editing if you need to create a git clone from fossil. This comes with no support, just as an idea of how you might implement such a bridge.

#!/bin/sh

fossildir=/var/fossil
# Cannot be a bare directory for git as we cannot write to the host directly.
# So we have a staging directory instead.
# This requires a bit of hand-holding to track all the branches.
gitdir=/var/git-staging

marksdir=/var/scm-marks

# Respect default naming at either end
fossil_export_opts="--rename-trunk master"
fossil_import_opts="--rename-master trunk"

# Only used when creating a git bare bones repo from Fossil.
export_fossil_to_git_new()
{

        rm -f "$fossilmarks" "$gitmarks"
        git init
        fossil export --git \
                --export-marks "$fossilmarks" \
                $fossil_export_opts "$fossildir/$fossilrepo" | \
                git fast-import \
                --export-marks="$gitmarks"
}

export_fossil_to_git()
{

        fossil export --git \
                --import-marks "$fossilmarks" --export-marks "$fossilmarks" \
                $fossil_export_opts "$fossildir/$fossilrepo" | \
                git fast-import \
                --import-marks="$gitmarks" --export-marks="$gitmarks"
}

export_git_to_fossil()
{

        git fast-export --all \
                --import-marks="$gitmarks" --export-marks="$gitmarks" | \
                fossil import --git --incremental \
                --import-marks "$fossilmarks" --export-marks "$fossilmarks" \
                $fossil_import_opts "$fossildir/$fossilrepo"
}

pull_git()
{
        local remote

        git fetch --all
        # Track all remote branches
        git branch -r | grep -v '\->' | while read remote; do
                if [ -z "$(git branch --list "${remote#origin/}")" ]; then
                        git branch --track "${remote#origin/}" "$remote"
                fi
        done
        git branch --list | sed -e 's/^\* //' | while read branch; do
                git checkout "$branch"
                git merge --ff-only
        done
}

push_git()
{

        git push --all
        git push --tags
        # Reset the current branch checkout.
        # If we don't, the next run will complain about unstashed changes.
        # This maybe a bug in git, but maybe not because the live checkout
        # *is* behind at this point as we just fast-imported.
        git reset --hard
}

echo "Syncing git and fossil."
for repo in "$fossildir"/*.fossil; do
        fossilrepo=${repo#${fossildir}/*}
        repo=${fossilrepo%.fossil}
        gitrepo="$repo"
        fossilmarks="$marksdir/$repo.fossil.marks"
        gitmarks="$marksdir/$repo.git.marks"

        # We just sync old fossil repos to new phab clones
        if [ -d "$gitdir/$gitrepo" ]; then
                cd "$gitdir/$gitrepo"
                pull_git # staging only
                export_git_to_fossil
                export_fossil_to_git
                push_git # staging only
# Enable the below if pusing to a bare git repo from fossil
#       else
#               export_fossil_to_git_new
        fi
done

Direct download to script

Continue reading...