Skip to content
  • Jiri Bohac's avatar
    IPv6: fix DESYNC_FACTOR · 76506a98
    Jiri Bohac authored
    The IPv6 temporary address generation uses a variable called DESYNC_FACTOR
    to prevent hosts updating the addresses at the same time. Quoting RFC 4941:
    
       ... The value DESYNC_FACTOR is a random value (different for each
       client) that ensures that clients don't synchronize with each other and
       generate new addresses at exactly the same time ...
    
    DESYNC_FACTOR is defined as:
    
       DESYNC_FACTOR -- A random value within the range 0 - MAX_DESYNC_FACTOR.
       It is computed once at system start (rather than each time it is used)
       and must never be greater than (TEMP_VALID_LIFETIME - REGEN_ADVANCE).
    
    First, I believe the RFC has a typo in it and meant to say: "and must
    never be greater than (TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE)"
    
    The reason is that at various places in the RFC, DESYNC_FACTOR is used in
    a calculation like (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR) or
    (TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE - DESYNC_FACTOR). It needs to be
    smaller than (TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE) for the result of
    these calculations to be larger than zero. It's never used in a
    calculation together with TEMP_VALID_LIFETIME.
    
    I already submitted an errata to the rfc-editor:
    https://www.rfc-editor.org/errata_search.php?rfc=4941
    
    
    
    The Linux implementation of DESYNC_FACTOR is very wrong:
    max_desync_factor is used in places DESYNC_FACTOR should be used.
    max_desync_factor is initialized to the RFC-recommended value for
    MAX_DESYNC_FACTOR (600) but the whole point is to get a _random_ value.
    
    And nothing ensures that the value used is not greater than
    (TEMP_PREFERRED_LIFETIME - REGEN_ADVANCE), which leads to underflows.  The
    effect can easily be observed when setting the temp_prefered_lft sysctl
    e.g. to 60. The preferred lifetime of the temporary addresses will be
    bogus.
    
    TEMP_PREFERRED_LIFETIME and REGEN_ADVANCE are not constants and can be
    influenced by these three sysctls: regen_max_retry, dad_transmits and
    temp_prefered_lft. Thus, the upper bound for desync_factor needs to be
    re-calculated each time a new address is generated and if desync_factor is
    larger than the new upper bound, a new random value needs to be
    re-generated.
    
    And since we already have max_desync_factor configurable per interface, we
    also need to calculate and store desync_factor per interface.
    
    Signed-off-by: default avatarJiri Bohac <jbohac@suse.cz>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    76506a98