npd6 – Software now available

As per previous posts and discussions, my project to develop npd6 (Neighbor Proxy Daemon 6) is now advancing very rapidly.

If you have a Linux gateway router terminating your ISP feed supporting IPv6, this may be just what you need. To summarise the problem it solves: your ISP has given you an /64 (or some other size) IPv6 prefix, with the last 64 bits (or whatever) entirely for your own use on a private-side of the network. The IPv6 addresses in use by your own devices may well not even be known to you – it’s possible that you use DHCP6 to statically pre-allocate them (yuck!) or more likely you are using radvd on the gateway to advertise the ISP-supplied IPv6 prefix and let the devices themselves choose what they wish to tag on to that. It may be vaguely predictable (based upon the device’s Ethernet MAC address) or totally unpredictable (as per the Windows 7 box I looked at the other day!)

For these devices to be able to reach the outside IPv6 world, there is a good chance that your ISP will use the ICMP6 Neighbor Solicitation mechanism – and your gateway needs to play along. Other articles on this site go into painful details about this mechanism, so let’s sum it up as: in a very vaguely similar way to IPv4 ARPs, a device may receive an IPv6 Neighbor Solicitation for a specific global address and, if it knows how to reach it, respond with a Neighbor Advertisement. So for example, your ISP has given you the global prefix:


and your home devices thus all end up with addresses using this prefix plus a variable suffix, of the form:


So the Windows workstation which has chosen the 128-bit global address AAAA:AAAA:AAAA:AAAA:BBBB:BBBB:BBBB:BBBB tries to connect to Out goes the connection, and when the response comes back, the ISP’s router says to your gateway: “Neighbor Solicitation: Do you know how to reach AAAA:AAAA:AAAA:AAAA:BBBB:BBBB:BBBB:BBBB?”

And you want to say back “Neighbor Advertisement: Sure, AAAA:AAAA:AAAA:AAAA:BBBB:BBBB:BBBB:BBBB is known to me – send me his traffic.”

And to do this today you need to statically pre-configure that full address into the Linux system. And if it changes, you need to change it. And if a new one appears, you need to ad it. And so on. Oh, and to add insult to injury, you cannot even display a list of which ones you have already configured in the system!!

And thus I offer npd6 as a solution: it runs on the gateway, and requires little configuration. You tell it your prefix and which is the ISP’s interface. There are a few optional knobs and levers. Then it runs and automatically responds to any Neighbor Solicitation received from the ISP for a device with your prefix.


The code today is working well. It is easy to build on any typical Linux system. Soon I will package it and offer .debs, RPMs etc. It is highly efficient and low-impact in terms of CPU an so on.  Also, extensive debug options are built in, to assist if any problems occur.

To get it, please visit the GoogleCode hosting site at: and specifically the code at: (Subversion) or a tarball at

If you want to try it out, please do download and build it. If you need help, please ask! Feel free to raise issues via:

Good luck!

27 comments to npd6 – Software now available

  • Tom

    Thank you for this. I hope it will solve some of the problems I’ve been having. Having a problem with uplinks randomly dropping ipv6 traffic due to solicitation issues. (Among other issues)

    I noticed the latest version is 0.4.2 – can this be considered stable yet?

    • Hi – Fab to hear from you… Apart from my captive test user (sits at the desk opposite!) you’re the first person “in the wild” to say it works for you!! Is 0.4.2 stable? Yes, until I find that there’s a bug and 0.4.3 appears… 😉 Seriously: it seems stable within the limits of my testing – which can be read both ways. In my environment it’s highly stable and works great. But from development experience in general, and definitely with my recent lessons in IPv6 (it’s new to everyone) I am sure there will be situations and environments where bugs appear. And when they do, the sooner folks report them they can be fixed. But as far as it goes now: I think it’s usable. Modestly aside, it’s fairly tightly coded (so uses negligible resource in terms of CPU/memory) and is also readable/maintainable – there’s nothing too obtuse in it for anyone who likes reading code! Also moderately commented.

      I expect “issues” to crop up re RFC compliance… One always tries to achieve the balancing act between RFC-Compliant and actually working – but with the ambiguous state of some areas of IPv6 RFCs, I expect there’s room to argue over compliance. I’ve tended towards the “make it work with a real ISP” approach and can review against RFCs more fully in due course…!

      Do let me know of any issues – email or, better, raise a bug directly on the code site.


  • Tom

    Set this up on one of my Centos 5.6 boxes for testing and it seems to be working beautifully. The IPv6 drop outs went away.

    • PS Sorry your comments took a while to appear… The spam filter was suspicious – had them quarantined… I suspect conspiracy: first user feedback saying “Yes – works for me!” and it gets blocked. 😉

  • old_guy

    Thanks for the software , that’s the program I am looking for ,
    However, it seems not work on my box , I got a “Invalid argument” socket error at run time , is there anything wrong ?
    [Nov 06 00:03:20] processNS: NS target addr: 200x:x030:x003:xxxx:020f:66ff:fe19:a516
    [Nov 06 00:03:20] processNS: Local prefix: 200x:x030:x003:xxxx:0000:0000:0000:0000
    [Nov 06 00:03:20] processNS: Neither white nor black listing in operation.
    [Nov 06 00:03:20] addr6match: Called to match up to 64 bits.
    [Nov 06 00:03:20] addr6match: Target and prefix matched up to bit position 64
    [Nov 06 00:03:20] processNS: Target:prefix – Build NA response.
    [Nov 06 00:03:20] processNS: Store target to list.
    [Nov 06 00:03:20] storeTarget: New entry – recording.
    [Nov 06 00:03:20] processNS: Outbound message built
    [Nov 06 00:03:20] processNS: sendmsg returned with error 22 = Invalid argument
    ——–> got an error message from the log file .

  • old_guy

    Thanks for the quick reply .
    I has added more info on bug report#27 .
    ( However , I may have already enabled the –debug2 flag on my previous log )

    • So bug 27 now has a lot of detail in it!! I think the issue is resolved now – it related to a rather interesting scenario where other IPv6 devices are performing “Duplicate Address Dectection”, by means of using Neighbor Solicitation messages – which is a legitimate activity. npd6 now correctly detects this and, essentially, ignores it rather than erroring as it was doing previously (although previously it did not fail – it just barfed an error report and carried on)

  • Piyush Agarwal

    Sorry for a rather off-topic question.

    Are there any recommendations you would have for stateful DHCPv6 address assignment? I want control over ipv6 address assignment hence don’t want to use SLAAC.

    I am trying to get ISC DHCPv6 client (ubuntu lucid) to accept a DHCPv6 server assigned IP address. While the client sees the DHCPv6 reply packet with the ipv6 address, the address does NOT get configured on the interface — i.e., “ip -6 addr show” does not show the address configured. I am clueless.

    • Off hand no… sorry. But I may yet poke around in that area and see what I can see. Personally I’m sorely tempted to go down the “static-ish via DHCP” route (as so often done in IPv4) path for the home network. I think the one area I nee to investigate better it just how many client devices are likely (today and into the future) to support DHCPv6 “out of the box” without the need (if even possible!) to add a client.

      So you’ve piqued my interest into doing a quick lab test with the Ubuntu tools to see what they do (or don’t do…) look back here for an update maybe soon!

    • Well, any luck? I just ran some lab tests between a Ubuntu server running the dibbler ipv6 dhcp6d, and a client with the default isc dhclient. All worked pretty much out of the box. I’d suggest:
      – What server are you using?
      – Then check the myriad options which it may be supplying back to the client. In dibbler, for example, they are all enabled by default. Turn’em off and try again!
      – Run dhclient with the -v option and see what it sees.
      – Maybe also run a pcap on the network to see what exactly the server is handing back.
      – On the client, check the lease file(s) in /var/lib/dhcp. If dhclient is accepting an offer, but it then fails to actually drop it onto the i/f, you should get something there.

      Some pointers… Tell us what you find!

    • Tom

      I feel your pain. IPv6 designers put 0 thought into how people actually use the networks and internet. What a nightmare.

      I just gave up on ipv6 for a couple years. Coming back to now that Ip addresses are getting more expensive. But I’m still so annoyed at how radically different it is. What administrator in the world would want devices on the network to decide what their ip address would be? I smell a conspiracy.

  • Kert


    I just discoverd npd6, I believe it is what I have been looking for!

    Just a few questions.

    Is is possible to have both a black list and a white list?

    Is it possible to (for lack of a better term) wildcard list entries?

    For example, I want to do the following:

    blackList = fe80::/16

    whiteList = 2001:0123:4567:89aa:021d:5500::/88
    whiteList = 2001:0123:4567:89aa:0244:6600::/88


    • Hi!! Will reply later in the day – tight for time this morning….!!


    • Hi again…. Sunday evening so time to catch up with stuff.

      Glad to hear that npd6 seems to be useful for you. It was one of those utils that I simply could NOT believe did not already exist when I needed it. But after copious searching found nothing and hence wrote it myself…!

      OK, to your queries: black AND white list…? A kinda grey list? 🙂

      As it stands now, they are mutually exclusive. i.e. if you have “whites” defined, then ONLY those are used, and by definition everything else is blacklisted. And vice versa: if “blacks” are defined, then only they are blocked and ANYTHING else is answered.

      Your question raises a scenario I had not considered. I had made the assumption (the downfall of many a coder…) that black/whitelist entries would, both, be more specific addresses within the prefix already defined.

      So as per the config file example, the prefix there is:

      and there are then example white/blacklists (again, mutually exclusive so one or the other):

      //listtype = black
      //addrlist = 2a01:0123:4567:89aa:aaaa:bbbb:cccc:dddd
      //addrlist = 2a01:123:4567:89aa:dead:beef:dead:beef

      Both matching the prefix, and more besides.

      Also, as it says, the list entries must be full 128 bit addresses. So the example you give for the blackList of fe80::/16 would give an error. Remember though that in your example, if the prefix is a shorter-version of those whitelist entries, then by definition anything else (including that fe80::/16) would anyway not get matched. The idea is that ANYTHING needs to FIRST match the prefix and only THEN gets the possibility of hitting white or black-list.

      Anyway, that covers how it is today – I hope it’s clearer now. Of course I’m wildly open to suggestion to enhance it to offer more functionality. What I’d ask you to do is give me a scenario where what you describe is required. I can’t think of a practical one… but that’s probably just my limited view of what *I* need! Give me a reason, and I’ll certainly consider adding/adapting it. In fact I’d be delighted to do so. Based on what you have told me, I do not think you need both black and white listing together. But you may have a case for having the list entries being <128 bits!

      So. Fire away. 🙂

  • Kert

    Thanks for the clarification on white vs black lists.

    As far as my needs go, they are probably very specific to my application and may not
    be general enough to be incorporated into npd6. With that in mind, here is what I

    Instead of just one gateway, I may have two (and possibly up to ten).
    (in your diagram, replace the direct connection to your ISP with a
    switch and hang these gateway machines on it).

    Each shares the common /64 prefix.
    Each gateaway has a unique host portion of the address (lower 64).
    Each is a gateway for several nodes (possibly hundreds).
    I have complete control over the assignment of the host portion of the subtended nodes.

    The lower 64-bits of the address for each of subtended nodes conforms to the EUI-64 standard.
    As per EUI-64, the top 24 bits define the OUI for the remaining lower 40 bits.

    In my configuration, the top 24 bits (OUI) (of the lower 64) will be unique for
    each the “subnets” for the gateway machines. ie: each of the subtended nodes
    for each gateway share the same OUI.

    So one gateway will have a whitelist of:


    and another may have:


    and so on…

    This allows each gateway machine to selectively accept NS messages for the nodes
    that it is responsible for.

    Again, this is probably very specific to my application…

    • Thankfully Kert emailed me to nudge me – I had managed to totally lose sight of this. He has sent a very interesting looking change, and will examine it and it’ll likely be in npd6 any day now!!!!


  • John

    Currently, I’m running two different copies of npd6, each with their own config file. For what I’m doing, the only difference between the config’s is the interface and the blacklist/whitelist.

    Perhaps just running multiple copies, is enough to get the job done. However I do concur that a blacklist/whitelist of a subnet would be great.


    Currently, I have some 300+ addrlist’s in my config files.

    • So two issues actually arise from your comment (for which thanks!):

      – expression matching on the black/white-lists: Kert, elsewhere on this comment list, and also by emails, has whistled something up which does just that (not tried it myself yet… but I’m hopeful!) So we may have something there real soon now. Keep looking for a new release soon!

      – multiple interfaces. npd6 to date has always assumed a single interface. It grew out of the simple environment of ISP/Public one side, Private the other, and we thus want to sit on the ISP interface. But I guess there is indeed no reason why one may not have > 1 interface which require the functionality.

      I’d be interested to hear if others think this would be useful and thus worth incorporating. Anyone else? Running 2 copies of npd6 is not a huge overhead in terms on CPU/memory – it’s nice and light. But if it was a common requirement I can see that it would be cool to incorporate multiple interfaces into the config itself.

      Indeed the obvious solution to this would maybe be to actually spawn of N daemon processes, one per interface, based upon the config file.

      Anyway: the 300+ addresses you currently have – we should have something for that real soon now, thanks to the contribution I received (embarrassingly in March, but managed to not see until today….)

      And I’ll think on the multiple-interface scenario some more.



    • On npd6 site we’ve now got 2 bugs for these issues: 36 & 37.

  • John

    On Building an IPv6 Router.

    Take a look at Vladimir Ivashchenko’s “parprouted” project. This is really what we want, only in IPv6 land.

    parprouted is the IPv4 equivalent of what Sean (sgoarke) said above. It spawns multiple threads. It listens for ARPs on one interface, and (re-)broadcast’s the ARP on the other interface. If there is a response from the second ARP, it creates a point-to-point route across the two interfaces.

    I can in in-vision an IPv6 version of parprouted. Change ARP for NDP and it seems easy.

    My only problem is that I don’t really understand IPv6. Is there some part of the protocol where there is some “active” way of monitoring neighbor reach-ability? ARP just depends upon “timeouts” and is not active, whereas IPv6 seems active, sending packets occasionally to verify reach-ability. Do we need some way of keeping track of these “active” connections?

    Thoughts? or am I completely washed up?

    – john

    • Sean Groarke

      Hi John.

      No, all your thoughts seem entirely valid to me. For those who have not had the joy of learning it before, let me introduce the Perl-originated acronym: TIMTOWTDI (“tim-toady” – There Is More Than One Way To Do It) which I think definitely fits here!

      In general, network devices at the “lower end” of the stack often face an architectural choice of being Layer-2 (and somewhat or completely “transparent”) or Layer-3 (and more “visible” and clearly doing stuff…) Sorry to show my age and use such terms. I suppose the trendy young things these days would rather refer to Link Layer versus Internet Layer. But you get my point: active or passive?

      And when it came to npd6 I toyed with this very question (and still am!) The box on which npd6 runs is pretty clearly a router, in network terms. And if we (and I do wish I would stop doing this, but I can’t…) use IPv4 as a crude analogy to IPv6 Neighbor Discovery then ARP and so forth clearly stop at the interface, and do not transparently cross the box .

      Yet I agree that an approach npd6 could have taken (RFC compliance be damned) is to treat the “inside” network as a Layer-2 extension of the ISP connection and simply pass in anything from the ISP, and then pass back similarly. So Neigh-Sol comes in from ISP, and we flood it out to the local net and, if/when we see a reply, pass that back.

      I decided not to go down that path as, while at first looking “easy”, it’s actually not as easy when fitted into the bigger picture. Quite apart from grossly breaking RFC models (OK, I do care about RFCs really… just in case my employer reads this) we then have problems like fitting in to IPv4-IPv6 gateways, VPN tunneling, and so on… And indeed in light of the discussion about supporting multiple interfaces, we would have to decide what we do there. Also, npd6 would still anyway have to dick around with the appropriate Link-Local addressing for this communication.

      Architecturally I like the simple concept of “ISP IPv6 NDP stops at the edge of my network, and I decide what happens inside the network.”

      To round off: what I did consider (and conceivably this could still happen) is to have two modes of operation for npd6. The present one, based on pre-configured prefix (with the added refinements of black-white listing) and a “discovery mode” where npd6 “discovers” what globals exist on the private net, and then only answers Negh-Sol for global addresses which are *known* to exist and be active, rather than just matching the prefix.

      This wouldn’t be a huge stretch to do. When I added the white-black listing, I added a bunch of code to handle storage/addition/deletion/searching of addresses in a highly scalable and efficient manner (god bless 30 year old tree handling algorithms… good algorithms never go out of fashion!) I added the infrastructure which such a feature would use.

      Anyway, I’ve rather rambled around, but your comment triggered these thoughts… and I find one of the uses of this little blog is to act as a public note-pad for myself!

      Bye for now.

  • Hi, sgroarke, well done. But npd6 doesn’t work on my OpenWrt router properly 🙁 , I can’t confirm whether is a config problem or network specificity or a bug.

    The debug information as follow:

    dispatcher: get_rx() gave msg with len = 86
    processNS: Confirmed packet as icmp6 Neighbor Solicitation.
    processNS: src addr = 2400:dd05:xxxx:100::1
    processNS: dst addr = ff02::1:ffaa:ef33
    processNS: Multicast NS
    processNS: NS target addr: 2400:dd05:xxxx:0100:5cd6:af76:58aa:ef33
    processNS: Local prefix: 2400:dd05:xxxx:0100:0000:0000:0000:0000
    processNS: Neither white nor black listing in operation.
    addr6match: Called to match up to 64 bits.
    addr6match: Target and prefix matched up to bit position 64
    processNS: Target:prefix – Build NA response.
    processNS: Store target to list.
    storeTarget: Entry already recorded. Ignoring.
    processNS: Outbound message built
    processNS: sendmsg completed OK
    dispatcher: get_rx() gave msg with len = 86
    processNS: Confirmed packet as icmp6 Neighbor Solicitation.
    processNS: src addr = fe80::3ee5:a6ff:xxxx:42f1
    processNS: dst addr = fe80::72f3:95ff:xxxx:4ed9
    processNS: Unicast NS
    processNS: NS target addr: fe80:0000:0000:0000:72f3:95ff:fe0b:4ed9
    processNS: Local prefix: 2400:dd05:xxxx:0100:0000:0000:0000:0000
    processNS: tgt==dst – Ignore.

    Here ‘fe80::3ee5:a6ff:xxxx:42f1’ is my ISP’s gateway,not is normally ‘2400:dd05:xxxx:100::1’, I doubt is the issue.
    ‘2400:dd05:xxxx:0100:5cd6:af76:58aa:ef33’ is IPv6 address of my router wan interface, ‘fe80::72f3:95ff:xxxx:4ed9’ is local address of my router wan interface.

    So far I can only add my laptop and cell phone’s address to router wan interface manually 🙁

  • Sorry for the slip in my original comment, ‘2400:dd05:xxxx:0100:5cd6:af76:58aa:ef33’ is the IPv6 address of my laptop, not
    router wan interface.

  • […] solved this thanks to a wonderful little daemon process called 'npd6'. See the project here: Thanks to Sean for this wonderful little app. […]