Privacy Extensions for Stateless Address Autoconfiguration in IPv6

Jump to: navigation, search

Table of Contents >> IPv6 Programmer's Reference


Autoconfiguration of IPv6 addresses typically involves concatenating a prefix with an interface identifier. The prefix will be FE80::/10 for an autoconfigured link-local address or a global prefix provided by an IPv6 router. The interface identifier is usually derived from a link layer identifier (e.g. MAC address) that is globally unique and particular to that interface. There is a concern that the source address stored in outbound IPv6 packets contains consistent information that can be used to identify and track you.

RFC 4941 describes a method for enhancing node privacy by using randomly generated, temporary, global scope IPv6 addresses that are regularly discarded and replaced with different addresses. Like public autoconfigured addresses, temporary address are autoconfigured from the global prefix information provided by a router on the same subnet. However, where public addresses use a fixed interface identifier, temporary addresses use a separate interface identifier that is randomly generated and constantly changing.

Each temporary address undergoes a typical lifecycle: generation, duplicate address detection phase, preferred phase, deprecated but still valid phase, then invalid. If a temporary address fails duplcate address detection, it is discarded and the cycle starts again. Typically, there is only one preferred temporary address per interface. When it comes time to generate a new temporary address, the old address becomes deprecated and the new address becomes the preferred address. When an address becomes invalid, it is removed from the interface and can no longer be used.

Deprecated addresses are still valid and usable, but new outbound packets will always use the preferred address, if there is one. There may be many deprecated temporary addresses configured for an interface. The default valid lifetime for a temporary address is 7 days, but a new one is generated every day, so there may be 6 deprecated addresses.

There is a fixed but configurable limit on the number of valid temporary autoconfigured addresses an interface may have. Some factors may cause you to unexpectedly exhaust your supply of temporary addresses, which means your public address may become the only preferred global address available.

  • Mobile IPv6. Whenever a change of subnet occurs, a new random interface identifier and temporary address are immediately generated and the current preferred temporary address is deprecated. The deprecated addresses remain valid for the designated lifetime.
  • Routers advertising multiple global prefixes will cause the creation of multiple sets of preferred addresses and deprecated addresses.
  • TM_6_MAX_TEMP_IPS_PER_IF is the macro that limits the number of temporary autoconfigured addresses per interface. It is 8 by default. Redefine it in trsystem.h if you think you will need more.
  • Providing a callback function when you open the interface allows you to monitor all IPv6 addresses as they go through their lifecycle. You can use tfNgUnConfigInterface() to remove deprecated temporary addresses that you no longer need.

The use of temporary addresses is disabled by default. You must enable the feature on each interface for which you want support. Alternatively, you could set a system-wide default that is inherited by all interfaces.

If enabled for an interface, temporary addresses will not replace the public address for the interface. Temporary addresses exist in addition to the standard public addresses that would normally be configured for the interface.

Treck has three levels of support for this privacy feature:

Code Configuration Macros

This feature (Privacy Extensions for Stateless Address Autoconfiguration in IPv6) is disabled by default and the supporting code is absent. To enable this feature, you must uncomment the following Compile Time Macros in trsystem.h.

  • TM_USE_IPV6
    Enable IPv6.
  • TM_6_USE_TEMPADDR
    Enable Privacy Extensions for Stateless Address Autoconfiguration in IPv6. Macros TM_6_USE_DAD and TM_6_USE_PREFIX_DISCOVERY are required by this feature and will automatically be defined.

In the case where Treck must select an appropriate source address for an outbound packet, a public IPv6 address will typically be preferred to a temporary address. The user can reverse this preference (as discussed in RFC 3484, section 5) by uncommenting the following macro in trsystem.h. This macro does not require TM_6_USE_TEMPADDR, as the user can manually configure a temporary address by using the TM_6_DEV_IP_TEMPORARY IPv6 flag when calling tfNgOpenInterface() or tfNgConfigInterface().

  • TM_6_PREFER_TEMPADDR
    Use temporary addresses by default, even when a public address is available. Default: prefer public addresses.

Treck limits the number of addresses on an interface that can be used for autoconfigured temporary addresses. The following macro defines this limit and is set to 8 by default.


Warning Warning: If a temporary address cannot be generated because of space limitations, the node's public address may be selected as the only non-deprecated alternative. Ensure that macro TM_6_MAX_TEMP_IPS_PER_IF provides sufficient space for holding deprecated temporary addresses.

Use the following formula to calculate how many temporary addresses you will need for an interface:

T = G * (V / min(P, M))

where,
  T is the number of temporary addresses,
  V is the valid lifetime for a temporary address,
  P is the preferred lifetime for a temporary address,
  M is the worst case minimum time before switching subnets (for Mobile IPv6 only),
  G is the worst case maximum number of autoconfiguration prefixes per interface.

Inserting the default values: T = 1 * (7 days / 1 day) = 7 temporary addresses per interface.

You can manually dispose of temporary addresses you no longer need to free up space for new addresses. This is discussed in the section below, Using Prefix Filters.

Performance Tuning Macros

The following macros can be defined in trsystem.h to change the default behavior. Most of these values can be overriden at runtime, as discussed in subsequent sections. Default values are derived from RFC 4941.

  • TM_6_TEMP_VALID_LIFETIME
    The time (seconds) until a temporary address becomes invalid and is removed from the interface. Default: 7 days.
  • TM_6_TEMP_PREFER_LIFETIME
    The time (seconds) until a temporary address becomes deprecated and a new one is generated. Default: 1 day.
  • TM_6_TEMP_MAX_DESYNC_FACTOR
    Maximum desynchronizing factor (seconds). The desynchronizing factor is a randomly chosen value subtracted from the preferred lifetime to help reduce network congestion caused by simultaneous autoconfiguration of multiple interfaces. Default: 10 minutes.
  • TM_6_TEMP_REGEN_ADVANCE
    Time (seconds) to start address regeneration in advance of a temporary address becoming deprecated. Advance autoconfiguration is necessary to prevent a condition where there are no preferred temporary addresses available. Default: 5 seconds.
  • TM_6_TEMP_REGEN_MAX_RETRY
    Maximum attempts to generate a valid address. This is a limit on the number of consecutive Duplicate Address Detection failures. If this limit is reached, temporary address generation will be disabled for the interface. Default: 3 attempts.

The following values are not part of the specification. The macros are defined for internal purposes. You should never need to change them.

  • TM_6_TEMP_MAX_POLL_SEC
    Maximum polling interval (seconds) for checking the age of temporary addresses. This is used to avoid 32-bit overflow when converting the timer interval from seconds to milliseconds. There should be no need to change this value. Default: 7 days.
  • TM_6_TEMP_MIN_IFID_RETRY
    Minimum number of attempts to try to generate a unique random temporary interface identifier. There should be no need to change this value. Default: 10.

Treck Initialization Options

Some of the Compile Time Macros shown above can be changed at runtime, if necessary. The options listed below can be set by calling tfInitTreckOptions() or tfSetTreckOptions(). The new settings will be inherited by all devices at the time you call tfAddInterface().

Option Name Description
TM_6_OPTION_USE_TEMPADDR Set the default level of support for RFC 4941, Privacy Extensions for Stateless Address Autoconfiguration in IPv6. The value you set will be inherited by all subsequently created interfaces when you call tfAddInterface(). Refer to the Main Article for details on this feature. Acceptable values for this option are:
  • TM_6_OPTION_TEMPADDR_DISABLE (0) - By default, temporary addresses will not be generated for newly created interfaces.
  • TM_6_OPTION_TEMPADDR_ENABLE (1) - By default, temporary addresses will be generated for newly created interfaces but public addresses will be used in preference to temporary addresses.
  • TM_6_OPTION_TEMPADDR_PREFER (2) - By default, temporary addresses will be generated for newly created interfaces and temporary addresses will be used in preference to public addresses.

Associated compile-time macros: TM_6_USE_TEMPADDR and TM_6_PREFER_TEMPADDR
Default: TM_6_OPTION_TEMPADDR_DISABLE

TM_6_OPTION_TEMP_VALID_LFT Time from creation (seconds) that an autoconfigured temporary address remains valid. An address is removed from the interface when it becomes invalid. If you increase this number you should increase TM_6_MAX_TEMP_IPS_PER_IF.

Associated compile-time macro: TM_6_TEMP_VALID_LIFETIME
Default: 7 days

TM_6_OPTION_TEMP_PREFER_LFT Time from creation (seconds) that an autoconfigured temporary address remains preferred. This determines the rate at which preferred addresses become deprecated and new addresses are created. If you decrease this number you should increase TM_6_MAX_TEMP_IPS_PER_IF.

Associated compile-time macro: TM_6_TEMP_PREFER_LIFETIME
Default: 1 day

TM_6_OPTION_TEMP_MAX_DESYNC Maximum desynchronizing factor (seconds) for autoconfiguring temporary addresses. The desynchronizing factor is a randomly chosen value subtracted from the preferred lifetime to help reduce network congestion caused by simultaneous autoconfiguration of multiple interfaces.

Associated compile-time macro: TM_6_TEMP_MAX_DESYNC_FACTOR
Default: 10 minutes

TM_6_OPTION_TEMP_MAX_RETRY Maximum attempts to generate and autoconfigure a valid temporary address. This is a limit on the number of consecutive Duplicate Address Detection failures. If this limit is reached, temporary address generation will be disabled for the interface.

Associated compile-time macro: TM_6_TEMP_REGEN_MAX_RETRY
Default: 3 attempts


Interface Options

You can change option values for individual interfaces by calling tfInterfaceSetOptions() with the options listed below. The values should be changed prior to opening the interface with tfNgOpenInterface() or tfNgConfigInterface().

Option Name Description
TM_6_DEV_OPTIONS_USE_TEMPADDR Set the level of support for RFC 4941, Privacy Extensions for Stateless Address Autoconfiguration in IPv6. Acceptable values for this option are:
  • TM_6_OPTION_TEMPADDR_DISABLE (0) - Temporary addresses will not be generated for this interface.
  • TM_6_OPTION_TEMPADDR_ENABLE (1) - Temporary addresses will be generated but public addresses will be used in preference to temporary addresses.
  • TM_6_OPTION_TEMPADDR_PREFER (2) - Temporary addresses will be generated and will be used in preference to public addresses.

Associated Treck option: TM_6_OPTION_USE_TEMPADDR
Data Type: int
Default: TM_6_OPTION_TEMPADDR_DISABLE unless changed via tfInitTreckOptions() or tfSetTreckOptions()

TM_6_DEV_OPTIONS_TEMP_VALID_LFT Time from creation (seconds) that an autoconfigured temporary address remains valid. An address is removed from the interface when it becomes invalid. If you increase this number you should increase TM_6_MAX_TEMP_IPS_PER_IF.

Associated Treck option: TM_6_OPTION_TEMP_VALID_LFT
Data Type: ttUser32Bit
Default: 7 days unless changed via tfInitTreckOptions() or tfSetTreckOptions()

TM_6_DEV_OPTIONS_TEMP_PREFER_LFT Time from creation (seconds) that an autoconfigured temporary address remains preferred. This determines the rate at which preferred addresses become deprecated and new addresses are created. If you decrease this number you should increase TM_6_MAX_TEMP_IPS_PER_IF.

Associated Treck option: TM_6_OPTION_TEMP_PREFER_LFT
Data Type: ttUser32Bit
Default: 1 day unless changed via tfInitTreckOptions() or tfSetTreckOptions()

TM_6_DEV_OPTIONS_TEMP_MAX_DESYNC Maximum desynchronizing factor (seconds) for autoconfiguring temporary addresses. The desynchronizing factor is a randomly chosen value subtracted from the preferred lifetime to help reduce network congestion caused by simultaneous autoconfiguration of multiple interfaces.

Associated Treck option: TM_6_OPTION_TEMP_MAX_DESYNC
Data Type: ttUser32Bit
Default: 10 minutes unless changed via tfInitTreckOptions() or tfSetTreckOptions()

TM_6_DEV_OPTIONS_TEMP_MAX_RETRY Maximum attempts to generate and autoconfigure a valid temporary address. This is a limit on the number of consecutive Duplicate Address Detection failures. If this limit is reached, temporary address generation will be disabled for the interface.

Associated Treck option: TM_6_OPTION_TEMP_MAX_RETRY
Data Type: int
Default: 3 attempts unless changed via tfInitTreckOptions() or tfSetTreckOptions()

TM_6_DEV_OPTIONS_TEMP_SET_FILT Set or update a prefix filter. You can enable or disable temporary address autoconfiguration on an interface for one or more specific prefixes.

Data Type: tt6TempPrefixFilter
Default: temporary address autoconfiguration is not disabled for any specific prefixes

TM_6_DEV_OPTIONS_TEMP_RESET_FILT Purge the list of prefix filters. The option value is not used.


Temporary Address Discovery and Management

You may find it necessary to learn what temporary addresses have been autoconfigured and when those addresses become deprecated or invalid. Knowing your temporary addresses allows you to:

  • Bind a socket to a temporary address to make sure that Treck uses that address in outbound packets,
  • Use tfSendToFrom() or tfSendToFromInterface() to specify a temporary address as the from address,
  • Unconfigure the address from the interface when it becomes deprecated and you no longer need it.

To discover what addresses are being configured and when those addresses cease to be preferred or valid, you must provide a pointer to your notifcation function when you open the interface with tfNgOpenInterface() or tfNgConfigInterface(). For example,

void createMyInterface(void)
{
    ttUserLinkLayer         linkLayerHandle;
    ttUserInterface         myInterfaceHandle;
    struct sockaddr_storage zeroAddr;
    int                     optVal;
    int                     errorCode;
 
    linkLayerHandle = tfUseEthernet();
    myInterfaceHandle = tfAddInterface( ... );
 
/* Enable autoconfigured temporary addresses */
    optVal = TM_6_OPTION_TEMPADDR_ENABLE;
    errorCode = tfInterfaceSetOptions(
                        myInterfaceHandle,
                        TM_6_DEV_OPTIONS_USE_TEMPADDR,
                        &optVal,
                        sizeof(optVal) );
    assert(errorCode == TM_ENOERROR);
 
/* Open the interface with no manually configured addresses */
    memset(&zeroAddr, 0, sizeof(zeroAddr));
    zeroAddr.ss_len = sizeof(zeroAddr);
    zeroAddr.ss_family = AF_INET6;
    errorCode = tfNgOpenInterface(
                        myInterfaceHandle,
                        &zeroAddr,
                        64,
                        TM_DEV_MCAST_ENB,
                        0,
                        1,
                        myAddrNotifyFunc );
    assert(errorCode == TM_ENOERROR);
}

This sample will create an interface, begin autoconfiguration of a link-local address and attempt to communicate with a router to learn what the global IPv6 prefix is for the subnet. When the router responds with a prefix, Treck begins autoconfiguration of both a public and temporary IPv6 addresses with the given prefix.

Whenever any IPv6 address successfully passes autoconfiguration, your function, myAddrNotifyFunc(), will be called with the TM_6_DEV_ADDR_CONFIG_COMPLETE event identifier and a pointer to temporary storage containing the address. For example,

struct sockaddr_storage linkLocalAddr;
struct sockaddr_storage publicAddr;
struct sockaddr_storage temporaryAddr;
 
void myAddrNotifyFunc(
    ttUserInterface         interfaceHandle,
    unsigned int            mHomeIndex,
    ttSockAddrStoragePtr    sockAddrPtr,
    int                     eventId )
{
    switch (eventId)
    {
    case TM_6_DEV_ADDR_CONFIG_COMPLETE:
        if (IN6_IS_ADDR_LINKLOCAL(&sockAddrPtr->addr.ipv6.sin6_addr))
        {
            memcpy(&linkLocalAddr, sockAddrPtr, sizeof(linkLocalAddr));
        }
        else if (isPublicAddr(interfaceHandle, sockAddrPtr))
        {
            memcpy(&publicAddr, sockAddrPtr, sizeof(publicAddr));
        }
        else
        {
            memcpy(&temporaryAddr, sockAddrPtr, sizeof(temporaryAddr));
        }
        break;
    case TM_6_DEV_ADDR_INVALIDATED:
        if (memcmp(&temporaryAddr, sockAddrPtr, sizeof(temporaryAddr)) == 0)
        {
/* Cannot use the temporary address any more */
            memset(&temporaryAddr, 0, sizeof(temporaryAddr));
        }
        break;
    default:
        ;
    }
}

This is a simplistic example. It only keeps track of the current preferred temporary address. After awhile (1 day by default), a new temporary address with the same prefix will begin autoconfiguration and the current temporary address will become deprecated. The following example shows how you can differentiate between public and temporary addresses by using the EUI-64 for the interface, upon which the public address is derived.

int isPublicAddr(
    ttUserInterface         interfaceHandle,
    ttSockAddrStoragePtr    sockAddrPtr)
{
    ttUser8Bit      interfaceId[8];
    int             errorCode;
 
/* Convert the interface's EUI-64 to an interface identifier */
    errorCode = tf6Eui64GetInterfaceId(interfaceHandle, interfaceId);
    assert(errorCode == TM_ENOERROR);
    interfaceId[0] ^= 2;
 
/* A public autoconfigured address = (public prefix) + (interface id) */
    errorCode = memcmp(&sockAddrPtr->addr.ipv6.sin6_addr.s6_addr[8],
                                                interfaceId, 8);
    return(!IN6_IS_ADDR_LINKLOCAL(&sockAddrPtr->addr.ipv6.sin6_addr)
                                                && (errorCode == 0));
}

You may also want to keep track of deprecated temporary addresses so you can dispose of them by calling tfNgUnConfigInterface() when you no longer have any sockets that are using the address.

Using Prefix Filters

You can selectively enable or disable the use of temporary addresses on an interface for specific prefixes of your choice. For example, you may wish to generate temporary addresses for all prefixes except unique global unicast addresses (i.e. FC00::/7). Or, you may wish to disable temporary addresses for all prefixes except those that begin with 2001::/16 or 2002::/16.

Use the tt6TempPrefixFilter structure to convey each of your filters to Treck. Set the address in tpf6Prefix, the prefix length in tpf6PrefixLen and a boolean in tpf6Configure (zero = NO, non-zero = YES) to indicate whether you do or do not want to configure temporary addresses for the prefix.

typedef struct ts6TempPrefixFilter
{
    struct in6_addr tpf6Prefix;
    int             tpf6PrefixLen;
    int             tpf6Configure;
} tt6TempPrefixFilter;

Pass a pointer to your filter structure variable when calling tfInterfaceSetOptions() with option TM_6_DEV_OPTIONS_TEMP_SET_FILT. For example,

void setMyPrefixFilters(ttUserInterface interfaceHandle)
{
    tt6TempPrefixFilter     prefixFilter;
    int                     errorCode;
 
/* Disallow temporary address configuration for FC00::/7 */
    inet_pton(AF_INET6, "FC00::", &prefixFilter.tpf6Prefix);
    prefixFilter.tpf6PrefixLen = 7;
    prefixFilter.tpf6Configure = 0;
    errorCode = tfInterfaceSetOptions(
                        interfaceHandle,
                        TM_6_DEV_OPTIONS_TEMP_SET_FILT,
                        &prefixFilter,
                        sizeof(prefixFilter) );
    assert(errorCode == TM_ENOERROR);
}

You can nest prefix filters, as shown in the following example. The order that you provide your filters is not important. Longer prefixes take precedence over shorter ones.

void setMyPrefixFilters(ttUserInterface interfaceHandle)
{
    tt6TempPrefixFilter     prefixFilter;
    int                     errorCode;
 
/* Disallow temporary address configuration for all prefixes (::/0) */
    inet_pton(AF_INET6, "::", &prefixFilter.tpf6Prefix);
    prefixFilter.tpf6PrefixLen = 0;
    prefixFilter.tpf6Configure = 0;
    errorCode = tfInterfaceSetOptions(
                        interfaceHandle,
                        TM_6_DEV_OPTIONS_TEMP_SET_FILT,
                        &prefixFilter,
                        sizeof(prefixFilter) );
    assert(errorCode == TM_ENOERROR);
 
/* Allow temporary address configuration for 2001::/16 */
    inet_pton(AF_INET6, "2001::", &prefixFilter.tpf6Prefix);
    prefixFilter.tpf6PrefixLen = 16;
    prefixFilter.tpf6Configure = 1;
    errorCode = tfInterfaceSetOptions(
                        interfaceHandle,
                        TM_6_DEV_OPTIONS_TEMP_SET_FILT,
                        &prefixFilter,
                        sizeof(prefixFilter) );
    assert(errorCode == TM_ENOERROR);
}

You can remove all your prefix filters by calling tfInterfaceSetOptions() with option TM_6_DEV_OPTIONS_TEMP_RESET_FILT. The option takes no parameters. For example,

void resetMyPrefixFilters(ttUserInterface interfaceHandle)
{
    int     dummyParam;
    int     errorCode;
 
/* Remove all prefix filters */
    errorCode = tfInterfaceSetOptions(
                        interfaceHandle,
                        TM_6_DEV_OPTIONS_TEMP_RESET_FILT,
                        &dummyParam,
                        sizeof(dummyParam) );
    assert(errorCode == TM_ENOERROR);
}

Function Calls


Table of Contents >> IPv6 Programmer's Reference