SLAAC and Stateless DHCPv6 on Juniper SRX routers

If you have struggled to find the easiest guide to getting IPv6 onto an SRX router, giving out Routing Announcements (RAs) to clients to tell them what the subnet is and using DHCPv6 to only tell them about DNS servers, you’ve come to the right place.
You have the option of using DHCPv6 in Stateful mode, assigning IP addresses and other attributes, but that removes the SLAAC functionality and instead makes your poor little router into a DHCP database, just like it was in IPv4. There really isn’t any need to do it that way. So let’s instead build it so the clients ask the router simply where the DNS servers are and otherwise just look after themselves. We call this a “Stateless” configuration.
The trick is to ensure that the RAs go out with the DHCP “O” flag set. This tells clients that they should work out their own IP addresses using SLAAC (by far the best way to do it and the way IPv6 was designed) but that they should poll DHCP using a “DHCPINFORM” message to get the DNS resolvers or any other related info.
Let’s start with configuring a local IPv6 address and then turn-on RA with that flag set:

interfaces {
    fe-0/0/0  {
       unit 0 {
         family inet6 {
            address 2a01:a000:110::1/64;
         }
       }
    }
protocols {
     router-advertisement {
         interface fe-0/0/0.0 {
             prefix 2a01:a000:110::/64;
            other-stateful-configuration;
         }
    }

Now we’ve done that, the only thing left to do is to build a DHCPv6 config. We’ll create a DHCP pool called “mypool” but we won’t give it any IP addresses as clients will already have an address from SLAAC. Instead we will just load it with the attributes we want clients to know about.
We’ll create an optional token as a security measure so that any DHCP reset messages heard by the client will be compared to this token and ignored if they don’t match. Then we’ll put a group together called “mygroup” containing all participating interfaces, which in this case is just fe-0/0/0.
Notice the inclusion of the “process-inform” override. Without this, DHCP will ignore requests from clients that already have an address, assuming they have been speaking to another DHCP server. With this turned on, it will instead listen to and respond to DHCPINFORM requests and respond with the dhcp attributes set in the pool that matches the subnet the client resides in.

system {
    services {
        dhcp-local-server {
              dhcpv6 {
                  reconfigure {
                      token 8ysIU9E32k8r;
                  }
                  group mygroup {
                     overrides {
                         interface-client-limit 200;
                           process-inform {
                              pool mypool;
                           }
                         }
                      interface fe-0/0/0.0;
}}}}
access {
   address-assignment {
      pool mypool {
         family inet6 {
             prefix 2a01:a000:110::/64;
             dhcp-attributes {
                   maximum-lease-time 120;
                   grace-period 3600;
                   dns-server {
                      2620:0:ccc::2;
                      2620:0:ccd::2;
}}}}}

That should pretty much do it for you. Don’t forget to do an ipconfig /release6 followed by ipconfig /renew6 on any Windows clients.
Clients that already have DHCPv4 DNS resolvers in their config won’t necessarily show they have picked up the IPv6 DNS resolvers. The only way to be sure is to turn-off IPv4 on the client and see if you can ping a site that isn’t in the local DNS cache. On the router, you can useĀ “show dhcpv6 server statistics” to ensure you have more INFORMATION_REQUEST packets than you have drops.