RFC 5014
IPv6 Socket API for Source Address Selection
IPv6 Socket API for Source Address Selection ๐
Okay bestie, this is the RFC title and the whole gang behind it ๐
- Network Working Group: the group that produces these documents
- Request for Comments: 5014
- Authors: E. Nordmark (Sun Microsystems, Inc.), S. Chakrabarti (Azaire Networks), and J. Laganier (DoCoMo Euro-Labs)
- Category: Informational ๐ง
- Date: September 2007
- Obsoletes / Updates: the title block doesn't list anything it obsoletes or updates ๐ธ
Status of This Memo
This memo gives information to the Internet community. It is not an Internet standard of any kind, and it's free to distribute with no limits ๐ฆ
Abstract
Okay so, RFC 3484 is the IPv6 default address selection document, and it says that apps should be able to flip some of the address selection rules using some API. Problem is, there's no such socket API in the basic one (RFC 3493) or the advanced one (RFC 3542). ๐ญ This doc fills that gap, partially ๐
It specifies new socket-level options for source address selection, plus flags for getaddrinfo() so you can pick addresses by source address preference. These options tweak the default source address selection algorithm. The API is especially useful for IPv6 apps that want to choose between temporary and public addresses, and for Mobile IPv6 aware apps that want to use the care-of address for communication. It also has options and flags for picking a Cryptographically Generated Address (CGA) or a non-CGA source address ๐ฅ
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2
2. Definition Of Terms . . . . . . . . . . . . . . . . . . . . . 5
3. Usage Scenario . . . . . . . . . . . . . . . . . . . . . . . . 6
4. Design Alternatives . . . . . . . . . . . . . . . . . . . . . 6
5. Address Preference Flags . . . . . . . . . . . . . . . . . . . 7
6. Additions to the Socket Interface . . . . . . . . . . . . . . 9
7. Additions to the Protocol-Independent Nodename Translation . . 10
8. Application Requirements . . . . . . . . . . . . . . . . . . . 11
9. Usage Example . . . . . . . . . . . . . . . . . . . . . . . . 13
10. Implementation Notes . . . . . . . . . . . . . . . . . . . . . 13
11. Mapping to Default Address Selection Rules . . . . . . . . . . 14
12. IPv4-Mapped IPv6 Addresses . . . . . . . . . . . . . . . . . . 16
13. Validating Source Address Preferences . . . . . . . . . . . . 16
14. Summary of New Definitions . . . . . . . . . . . . . . . . . . 19
15. Security Considerations . . . . . . . . . . . . . . . . . . . 19
16. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 19
17. References . . . . . . . . . . . . . . . . . . . . . . . . . . 20
17.1. Normative References . . . . . . . . . . . . . . . . . . 20
17.2. Informative References . . . . . . . . . . . . . . . . . 20
Appendix A. Per-Packet Address Selection Preference . . . . . . . 21
Appendix B. Intellectual Property Statement . . . . . . . . . . . 22
1. Introduction โจ
Okay so the default address selection rules live in [RFC3484], and those rules are for IPv6 [RFC2460]. This doc adds socket API extensions that let apps override the default source address pick. That means it indirectly changes destination address selection through getaddrinfo() too ๐ Privacy stuff in [RFC3041] gave us "public" and "temporary" addresses. IPv6 Mobility in [RFC3775] brought in "home address" and "care-of address" for mobile systems ๐ฆ
Here's the vibe of the default rules in [RFC3484]: a public address beats a temporary one, a mobile IPv6 home address beats a care-of address, and a larger scope address beats a smaller scope one. Default rules are great, but an app might still want to flip certain rules for efficiency or its own reasons ๐
Right now, IPv6 socket API extensions let you pick a specific source address with a plain bind() call or the IPV6_PKTINFO socket option [RFC3542]. But here's the catch ๐ If you use bind() or IPV6_PKTINFO, the app itself has to make sure the source address fits the destination address, like matching the interface used to send packets. It also has to check the source address scope against the destination, and so on. That's a LOT of work, because the app basically has to reimplement all the default rules just to change its preference on one of them ๐
This mechanism lets the app describe the source addresses it prefers, and the system still runs the rest of the address selection rules for it ๐ซถ For example, say an app prefers a care-of address over a home address as its source. If the host has two care-of addresses, one public and one temporary, the host picks the public care-of address, because the default rule prefers public over temporary ๐
A socket option is a good fit for this, since it lets an app set address selection preferences per socket. It can also turn those preferences on and off for non-connected (UDP) sockets ๐ The socket option uses a set of flags for the preferences. Since the API shouldn't assume how [RFC3484] address selection is implemented in the network layer or in getaddrinfo(), matching flags are also defined for getaddrinfo(), because it depends on the source address selection ๐ง
So this doc introduces several flags for address selection preferences that change the default selection [RFC3484] for a bunch of rules. It looks at which default rules are actually useful to change, and it only provides API for the rules that certain classes of apps might really use. It also considers CGA [RFC3972] and non-CGA source addresses when CGA addresses are available on the system. More source flags may be added in the future if needed ๐ฅ
The approach here lets apps specify preferences for address selection, not hard requirements. For example, an app can set a flag to prefer a temporary source address, but if the node has no temporary source addresses, a public address gets chosen instead ๐
Hard requirements would be a problem for a few reasons, and the big one is that in most cases the app still wants to communicate even when an address with the 'optimal' attributes isn't available ๐ญ Take an app doing very short UDP transactions, like DNS queries. It might want a care-of address when it's running on a mobile host that's away from home, since that often gives a short roundtrip time. But if the same app runs on a mobile host at home, or on a host that doesn't do Mobile IPv6, it makes no sense for the app to fail just because no care-of address exists. Also, with UDP sockets and the sendto() or sendmsg() primitives, hard requirements would cause trouble, because the set of available IP addresses could change between the getaddrinfo() call and the sendto() or sendmsg() call. That would add brand new failure modes ๐
A few apps really do have hard requirements on the attributes of the IP addresses they use. For those, this doc defines a verification function, so they can fail properly when their address selection requirements aren't met ๐ง
Here's the structure: each modifiable rule gets two flags. An app can say it prefers addresses selected by that rule, or it can say the opposite (the address selected by the rule gets reverted), or it can set neither flag and leave it to the system default (Section 4). This lets different implementations have different system defaults, and it works with getaddrinfo() as well as setsockopt(). (For setsockopt, a different approach could have been chosen, but that would still require the same approach for getaddrinfo.) ๐ธ
Note that this doc doesn't directly change the destination address selection rules in [RFC3484]. The authors checked which destination address rules apps might alter. Rule number 4(prefer home address), 8(prefer smaller scope), 7(prefer native interfaces) of the default address selection document [RFC3484] were considered for destination address alteration. But as of this writing, apps didn't have enough practical use for changing destination address selection rules directly using setsockopt() with a preferred destination type of address flag. This doc doesn't rule out adding flags for preferred destination address selection later ๐ Still, the [RFC3484] destination address selection rules depend on source address selection. So when you change the default source address selection using the methods in this doc, you indirectly influence the destination address choice too. That's why this doc explains how getaddrinfo() can pick the destination address while taking the preferred source addresses into account (Section 11) ๐
This doc only extends the Basic IPv6 socket API from [RFC3493]. The idea is that it works as a model for expressing preferences about attributes of IP addresses. That same model should also be expressible in other networking APIs, like those in middleware systems and the Java environment. A similar model also applies to other socket families ๐ฆ
2. Definition Of Terms โจ
Okay so, bestie, let's get the vocab down first ๐ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. Nothing fancy, just the standard BCP 14 vibe ๐
Address preference flag: A flag expressing a preference for a particular type of address (e.g., temporary, public). ๐
Opposite flags: Each flag expressing an address preference has an "opposite flag" expressing the opposite preference: ๐
- Home address preference flag is the opposite of the care-of address preference flag. ๐
- Temporary address preference flag is the opposite of the public address preference flag. โณ
- CGA address preference flag is the opposite of the non-CGA address preference flag. ๐
Contradictory flags: Any combination of flags including both a flag expressing a given address preference and a flag expressing the opposite preference constitutes contradictory flags. ๐ Such flags are contradictory by definition of their usefulness with respect to source address selection. For example, consider a set of flags, including both the home address preference flag and the care-of address preference flag. When considering source address selection, the selected address can be a home address, or a care-of address, but it cannot be both at the same time. Hence, to prefer an address that is both a home address and a care-of address is contradictory. ๐ Literally can't be both, so it's a no-go.
3. Usage Scenario ๐ธ
Okay so the examples here are limited to applications supporting Mobile IPv6, IPv6 Privacy Extensions, and Cryptographically Generated Addresses. ๐ฆ Address selection document [RFC3484] recommends that home addresses should be preferred over care-of address when both are configured. However, a mobile node may want to prefer a care-of address as the source address for a DNS query in the foreign network, as it normally means a shorter and local return path compared to the route via the mobile node's home-agent when the query contains a home address as the source address. โ๏ธ Lowkey makes sense, right?
Another example is the IKE application, which requires a care-of address as its source address for the initial security association pair with a Home Agent [RFC3775] while the mobile node boots up at the foreign network and wants to do the key exchange before a successful home-registration. ๐ Also, a Mobile IPv6 aware application may want to toggle between the home address and care-of address, depending on its location and state of the application. ๐ It may also want to open different sockets and use the home address as the source address for one socket and a care-of address for the others. ๐ง
In a non-mobile environment, an application may similarly prefer to use a temporary address as the source address for certain cases. ๐ซถ By default, the source address selection rule selects "public" address when both are available. For example, an application supporting Web browser and mail-server may want to use a "temporary" address for the former and a "public" address for the mail-server, as a mail-server may require a reverse path for DNS records for anti-spam rules. ๐ฌ It's giving very strategic energy ngl.
Similarly, a node may be configured to use Cryptographically Generated Addresses [RFC3972] by default, as in Secure Neighbor Discovery [RFC3971], but an application may prefer not to use it; for instance, fping [FPING], a debugging tool that tests basic reachability of multiple destinations by sending packets in parallel. ๐ These packets may end up initiating neighbor discovery signaling that uses SEND if used with a CGA source address. SEND performs some cryptographic operations to prove ownership of the said CGA address. If the application does not require this feature, it would like to use a non-CGA address to avoid potentially expensive computations performed by SEND. ๐งฎ On the other hand, when a node is not configured for CGA as default, an application may prefer using CGA by setting the corresponding preference. ๐ Iykyk.
4. Design Alternatives ๐
Some suggested to have per-application flags instead of per-socket and per-packet flags. ๐ค However, this design stays with per-socket and per-packet flags for the following reasons:
- While some systems have per-environment/application flags (such as environment variables in Unix systems) this might not be available in all systems that implement the socket API. ๐ง
- When an application links with some standard library, that library might use the socket API while the application is unaware of that fact. Mechanisms that would provide per-application flags may affect not only the application itself but also the libraries, hence, creating risks of unintended consequences. ๐ญ
Instead of the pair of 'flag' and 'opposite flag' for each rule that can be modified, the socket option could have been defined to use a single 'flag' value for each rule. โจ This would still have allowed different implementations to have different default settings as long as the applications were coded to first retrieve the default setting (using getsockopt()), and then clear or set the 'flag' according to their preferences, and finally set the new value with setsockopt(). ๐
But such an approach would not be possible for getaddrinfo() because all the preferences would need to be expressible in the parameters that are passed with a single getaddrinfo() call. Hence, for consistency, the 'flag' and 'opposite flag' approach is used for both getaddrinfo() and setsockopt(). ๐ซถ
Thus, in this API document, an application has three choices on source address selection:
a) The application wants to use an address with flag X: Set flag
X; unset opposite/contradictory flags of X if they are set before.
b) The application wants to use an address with 'opposite' or
contradictory flag of X: Set opposite or contradictory flag of X;
unset flag X, if already set.
c) The application does not care about the presence of flag X and
would like to use default: No need to set any address preference
flags through setsockopt() or getaddrinfo(); unset any address
preference flags if they are set before by the same socket.
5. Address Preference Flags ๐ฆ
Okay, these flags are defined to alter or set the default rule of source address selection rules discussed in default address selection specification [RFC3484]. ๐
IPV6_PREFER_SRC_HOME /* Prefer Home address as source */
IPV6_PREFER_SRC_COA /* Prefer Care-of address as source */
IPV6_PREFER_SRC_TMP /* Prefer Temporary address as source */
IPV6_PREFER_SRC_PUBLIC /* Prefer Public address as source */
IPV6_PREFER_SRC_CGA /* Prefer CGA address as source */
IPV6_PREFER_SRC_NONCGA /* Prefer a non-CGA address as source */
These flags can be combined together in a flag-set to express more complex address preferences. ๐งฉ However, such combinations can result in a contradictory flag-set, for example:
IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_TMP
IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_COA
IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_COA | IPV6_PREFER_SRC_TMP
IPV6_PREFER_SRC_CGA | IPV6_PREFER_SRC_NONCGA
Etc.
Examples of valid combinations of address selection flags are given below: ๐
IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_PUBLIC
IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_CGA
IPV6_PREFER_SRC_COA | IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_CGA
IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA
If a flag-set includes a combination of 'X' and 'Y', and if 'Y' is not applicable or available in the system, then the selected address has attribute 'X' and system default for the attribute 'Y'. For example, on a system that has only public addresses, the valid combination of flags:
IPV6_PREFER_SRC_TMP | IPV6_PREFER_SRC_HOME
would result in the selected address being a public home address, since no temporary addresses are available. ๐ก Main character energy for the home address, no cap.
6. Additions to the Socket Interface ๐
The IPv6 Basic Socket API [RFC3493] defines socket options for IPv6. To allow applications to influence address selection mechanisms, this document adds a new socket option at the IPPROTO_IPV6 level. ๐ง This socket option is called IPV6_ADDR_PREFERENCES. It can be used with setsockopt() and getsockopt() calls to set and get the address selection preferences affecting all packets sent via a given socket. The socket option value (optval) is a 32-bit unsigned integer argument. The argument consists of a number of flags where each flag indicates an address selection preference that modifies one of the rules in the default address selection specification. ๐ธ
The following flags are defined to alter or set the default rule of source address selection rules discussed in default address selection specification [RFC3484]. They are defined as a result of including the <netinet/in.h> header:
IPV6_PREFER_SRC_HOME /* Prefer Home address as source */
IPV6_PREFER_SRC_COA /* Prefer Care-of address as source */
IPV6_PREFER_SRC_TMP /* Prefer Temporary address as source */
IPV6_PREFER_SRC_PUBLIC /* Prefer Public address as source */
IPV6_PREFER_SRC_CGA /* Prefer CGA address as source */
IPV6_PREFER_SRC_NONCGA /* Prefer a non-CGA address as source */
NOTE: No source preference flag for the longest matching prefix is defined here because it is believed to be handled by the policy table defined in the default address selection specification. ๐
When the IPV6_ADDR_PREFERENCES is successfully set with setsockopt(), the option value given is used to specify the address preference for any connection initiation through the socket and all subsequent packets sent via that socket. If no option is set, the system selects a default value as per default address selection algorithm or by some other equivalent means. ๐ซถ
Setting contradictory flags at the same time results in the error EINVAL. ๐ Big no-no, bestie.
7. Additions to the Protocol-Independent Nodename Translation โจ
Okay so, Section 8 of the Default Address Selection [RFC3484] document lays out possible ways to implement getaddrinfo() [RFC3493] ๐ . One option is that getaddrinfo() collects the available source/destination pairs from the network layer, after they've been sorted there with full knowledge of source address selection. Another option is to call down to the network layer to grab the source address information, then sort the list inside getaddrinfo() itself ๐ง.
This means getaddrinfo() should be aware of the application's address selection preferences, since getaddrinfo() is independent of any socket the application might be using ๐ซถ.
So if an application changes the default address selection rules by using setsockopt() with the IPV6_ADDR_PREFERENCES option, the application should also use the matching address selection preference flags with its getaddrinfo() call ๐.
For that purpose, the addrinfo data structure defined in Basic IPV6 Socket API Extension [RFC3493] got a new extended "ai_eflags" flag-set field ๐ฆ. This gives the designers room to add more flags as needed without crowding the valuable bit space in the "ai_flags" flag-set field. The extended addrinfo data structure is defined when the <netdb.h> header is included:
struct addrinfo {
int ai_flags; /* input flags */
int ai_family; /* protocol family for socket */
int ai_socktype; /* socket type */
int ai_protocol; /* protocol for socket */
socklen_t ai_addrlen; /* length of socket address */
char *ai_canonname; /* canonical name for hostname */
struct sockaddr *ai_addr; /* socket address for socket */
struct addrinfo *ai_next; /* pointer to next in list */
int ai_eflags; /* Extended flags for special usage */
};
The new extended flags field goes at the bottom of the addrinfo structure, which keeps the new functionality binary compatible with older applications that use the existing addrinfo data structure ๐ธ.
A new flag, AI_EXTFLAGS, is defined for the "ai_flags" flag-set field. It tells the system to look for the "ai_eflags" extended flag-set field in the addrinfo structure. It is defined in the <netdb.h> header:
AI_EXTFLAGS /* extended flag-set present */
If the AI_EXTFLAGS flag is set in the "ai_flags" flag-set field of the addrinfo data structure, then the getaddrinfo() implementation MUST look for the "ai_eflags" values stored in the extended flag-set field "ai_eflags" of the addrinfo data structure. The flags stored in "ai_eflags" only mean something if AI_EXTFLAGS is set in "ai_flags" ๐ฅ. By default, AI_EXTFLAGS is not set in the "ai_flags" flag-set field. If AI_EXTFLAGS is set in "ai_flags", and the "ai_eflags" extended flag-set field is 0 (zero) or undefined, then AI_EXTFLAGS is ignored ๐.
The IPV6 source address preference values (IPV6_PREFER_SRC_*) that are defined for the IPV6_ADDR_PREFERENCES socket option are also defined as address selection preference flags for the "ai_eflags" extended flag-set field. That way getaddrinfo() can return matching destination addresses for the source address preferences the caller application expressed โจ.
So an application passes source address selection hints to getaddrinfo() by setting AI_EXTFLAGS in the "ai_flags" field, and the matching address selection preference flags (IPV6_PREFER_SRC_*) in the "ai_eflags" field ๐.
Right now AI_EXTFLAGS is only defined for the AF_INET6 socket protocol family. But its usage should be extendable to other socket protocol families, such as AF_INET, or wherever it makes sense ๐.
If contradictory flags, such as IPV6_PREFER_SRC_HOME and IPV6_PREFER_SRC_COA, are set in ai_eflags, then getaddrinfo() fails and returns the value EAI_BADEXTFLAGS, which is defined when the <netdb.h> header is included. This error value MUST be interpreted into a descriptive text string when it is passed to the gai_strerror() function [RFC3493] ๐ญ.
8. Application Requirements
An application should call getsockopt() before calling setsockopt() if it needs to be able to restore the socket to the system default preferences. Note that this is suggested for portability ๐งธ. An application that doesn't have this requirement can just use getaddrinfo() while specifying its preferences, followed by:
uint32_t flags = IPV6_PREFER_SRC_TMP;
if (setsockopt(s, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
(void *) &flags, sizeof (flags)) == -1) {
perror("setsockopt IPV6_ADDR_REFERENCES");
}
An application that does need to restore the default settings on the socket would do this instead ๐:
uint32_t save_flags, flags;
int optlen = sizeof (save_flags);
/* Save the existing IPv6_ADDR_PREFERENCE flags now */
if (getsockopt(s, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
(void *) &save_flags, &optlen) == -1 {
perror("getsockopt IPV6_ADDR_REFERENCES");
}
/* Set the new flags */
flags = IPV6_PREFER_SRC_TMP;
if (setsockopt(s, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
(void *) &flags, sizeof (flags)) == -1) {
perror("setsockopt IPV6_ADDR_REFERENCES");
}
/*
*
* Do some work with the socket here.
*
*/
/* Restore the flags */
if (setsockopt(s, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
(void *) &save_flags, sizeof (save_flags)) == -1) {
perror("setsockopt IPV6_ADDR_REFERENCES");
}
Applications should not set contradictory flags at the same time ๐ โโ๏ธ.
In order to let different implementations do different parts of address selection in getaddrinfo() and in the protocol stack, this specification requires that applications set the semantically equivalent flags when calling getaddrinfo() and setsockopt(). For example, if the application sets the IPV6_PREFER_SRC_COA flag, it MUST use the same for the "ai_eflag" field of the addrinfo data structure when calling getaddrinfo(). If applications are not setting the semantically equivalent flags, the behavior of the implementation is undefined ๐.
9. Usage Example
Here's an example of how this API gets used ๐:
struct addrinfo hints, *ai, *ai0;
uint32_t preferences;
preferences = IPV6_PREFER_SRC_TMP;
hints.ai_flags |= AI_EXTFLAGS;
hints.ai_eflags = preferences; /* Chosen address preference flag */
/* Fill in other hints fields */
getaddrinfo(....,&hints,. &ai0..);
/* Loop over all returned addresses and do connect */
for (ai = ai0; ai; ai = ai->ai_next) {
s = socket(ai->ai_family, ...);
setsockopt(s, IPV6_ADDR_PREFERENCES, (void *) &preferences,
sizeof (preferences));
if (connect(s, ai->ai_addr, ai->ai_addrlen) == -1){
close (s);
s = -1;
continue;
}
break;
}
freeaddrinfo(ai0);
10. Implementation Notes
- Within the same application, if a specific source address is set by either bind() or the
IPV6_PKTINFOsocket option, while at the same time an address selection preference is expressed with theIPV6_ADDR_PREFERENCESsocket option, then the source address setting carried by bind() orIPV6_PKTINFOtakes precedence over the address selection setting ๐. - setsockopt() and getaddrinfo() should silently ignore any address preference flags that are not supported in the system. For example, a host that does not implement Mobile IPv6 should not fail setsockopt() or getaddrinfo() that specify preferences for home or care-of addresses. The socket option calls should return error (-1) and set errno to EINVAL when contradictory flags values are passed to them ๐ง.
- If an implementation supports both stream and datagram sockets, it should implement the address preference mechanism API described in this document on both types of sockets ๐.
- An implementation supporting this API MUST implement both getaddrinfo() extension flags and socket option flags processing for portability of applications ๐ท.
- The following flags are set as default values on a system (which is consistent with [RFC3484] defaults) ๐ฆ:
IPV6_PREFER_SRC_HOME
IPV6_PREFER_SRC_PUBLIC
IPV6_PREFER_SRC_CGA
11. Mapping to Default Address Selection Rules โจ
okay so this API only adds the flags that applications would actually find useful for tweaking the default address selection rules ๐ so let's go through how each set of flags lines up with a rule number in the address selection doc [RFC3484] ๐ฆ
Source address selection rule #4 (prefer home address):
IPV6_PREFER_SRC_HOME (default)
IPV6_PREFER_SRC_COA
Source address selection rule #7 (prefer public address):
IPV6_PREFER_SRC_PUBLIC (default)
IPV6_PREFER_SRC_TMP
not this doc defining flags for source rule #2 (prefer appropriate scope for destination) or destination rule #8 (prefer smaller scope) ๐ the implementers felt there weren't any real apps that would want to undo IPv6's scoping rules, so they skipped it.
destination rules #4 (prefer home address) and #7 (prefer native transport) could be useful, BUT the big problem is the local system can't always tell whether a destination is a tunnel address for rule #7 ๐ฅบ it can if the destination is one of its own addresses, or if it can be recognized as a tunnel address by its syntax (like a 6-to-4 address). the flags for source rule #4 should also cover destination rule #4 anyway, so no separate flags for these destination rules. the decision was made and we're moving on ๐
also, btw, there's no destination rule that matches source rule #7 (prefer public addresses) in [RFC3484] ๐ค BUT this API has a way to make sure the source address preference from setsockopt() gets taken into account by getaddrinfo() too. it's giving main character energy โจ here's an example:
DA and DB are two global destination addresses, and the node has two global source addresses, SA and SB, on interface A and interface B. SA is a temporary address and SB is a public address. the app sets IPV6_PREFER_SRC_TMP in setsockopt(). the route to DA points to interface A, and the route to DB points to interface B. so when AI_EXTFLAGS is in ai_flags and IPV6_PREFER_SRC_TMP is in ai_eflags, getaddrinfo() returns DA before DB in the list of destination addresses, and SA gets used to talk to DA. and the same idea works in reverse: getaddrinfo() returns DB before DA when AI_EXTFLAGS and ai_eflags are set to IPV6_PREFER_SRC_PUBLIC. so the source address preference affects both destination address selection AND source address selection inside getaddrinfo() ๐ญ๐ฅ
here's a numerical example to make it click ๐ง
Imagine a host with two addresses:
1234::1:1 public
9876::1:2 temporary
and the destination has these two addresses:
1234::9:3
9876::9:4
by default, getaddrinfo() returns the destination addresses in this order:
1234::9:3
9876::9:4
because the public source is preferred, and 1234 matches more bits with the public source address ๐ but if ai_flags is set to AI_EXTFLAGS and ai_eflags to IPV6_PREFER_SRC_TMP, getaddrinfo returns them in the reverse order, since the temporary source address gets preferred ๐ธ
other source address rules (not mentioned here) were also judged not applicable to changing their defaults on a per-application basis, so they're not in this API ๐
12. IPv4-Mapped IPv6 Addresses ๐ฆ
IPv4-mapped IPv6 addresses for AF_INET6 sockets are supported in this API โจ but ngl the usefulness is limited sometimes, because the API attributes are IPv6-specific ๐ญ for example, IPv6 temporary addresses and cryptographically generated addresses have no IPv4 counterparts. so IPV6_PREFER_SRC_TMP and IPV6_PREFER_SRC_CGA aren't directly applicable to an IPv4-mapped IPv6 address.
BUT the IPv4-mapped support might be useful for mobile-IPv4 apps that shift their source address between the home address and the care-of address ๐งณ so IPV6_PREFER_SRC_COA and IPV6_PREFER_SRC_HOME ARE applicable to an IPv4-mapped IPv6 address.
it's not well understood yet whether this API has any value for IPv4 addresses or the AF_INET socket family ๐คทโโ๏ธ but a similar model still applies to the AF_INET socket family if corresponding address flags get defined.
13. Validating Source Address Preferences ๐ฅ
sometimes an app has a hard requirement to only use addresses with some particular attribute ๐ฅบ and if none of those addresses are available, the app should fail to communicate instead of quietly communicating using the 'wrong' address. the thing is, address selection preferences don't guarantee those requirements get met. so the app has to bind a socket to the source address that would be selected for a given destination (based on its preferences), and then explicitly check that the chosen address is actually okay using a validation function โ this is the flow:
- the app specifies one or more IPV6_PREFER_SRC_* flags and AI_EXTFLAGS in
ai_flagswithgetaddrinfo(). - the app specifies the same IPV6_PREFER_SRC_* flags with
setsockopt(). - the app calls the stack to select a source address for the destination it wants, following the address selection preferences it set up. this happens with a
connect()call, or abind2addrsel()call (more on that below). theconnect()function must not be used when the app uses connection-oriented communication (e.g., TCP) and wants to make sure that no single packet (e.g., a TCP SYN) gets sent before the app can verify its requirements were fulfilled. instead, the app must use the newly introducedbind2addrsel()call, which binds a socket to the source address that would be selected for a given destination, according to the app's preferences. for datagram-oriented communication (e.g., UDP),connect()can be used, since it makes the stack select a source address without sending any packets. - retrieve the selected source address using the
getsockname()API call. - verify with the validation function that the retrieved address is satisfactory (details below). if it isn't, abort the communication, e.g., by closing the socket.
binding the socket to the address that would be selected for a given destination, based on the app's preferences, is done with a brand new binding function ๐ง:
#include <netinet/in.h>
int bind2addrsel(int s, const struct sockaddr *dstaddr,
socklen_t dstaddrlen);
here, s is the socket the app has expressed source address selection preferences for, and dstaddr is a non-NULL pointer to a sockaddr_in6 structure set up like this:
- sin6_addr is a 128-bit IPv6 destination address that the local node wants to talk to;
- sin6_family MUST be set to AF_INET6;
- sin6_scope_id MUST be set if the address is link-local;
and dstaddrlen is the size of the sockaddr structure passed in ๐
bind2addrsel() returns the same values as bind(): 0 if it works, -1 otherwise, with the global variable errno set to show what went wrong. it fails for the same reasons bind() does ๐
the checks for temporary vs. public, home vs. care-of, and CGA vs. not are done by a new validation function ๐ซถ:
#include <netinet/in.h>
short inet6_is_srcaddr(struct sockaddr_in6 *srcaddr,
uint32_t flags);
here, flags contains the specified IPV6_PREFER_SRC_* source preference flags, and srcaddr is a non-NULL pointer to a sockaddr_in6 structure set up like this:
- sin6_addr is a 128-bit IPv6 address of the local node.
- sin6_family MUST be set to AF_INET6.
- sin6_scope_id MUST be set if the address is link-local.
inet6_is_srcaddr() can return three possible values (0, 1, -1) ๐:
- it returns true (1) when the IPv6 address matches a valid address on the node AND satisfies the given preference flags.
- if the IPv6 address doesn't correspond to any address on the node, OR the flags aren't one of the valid preference flags, it returns a failure (-1).
- if the input address doesn't match an address that satisfies the preference flags, it returns false (0).
this function can handle multiple valid preference flag combinations as its second parameter ๐ for example, IPV6_PREFER_SRC_COA | IPV6_PREFER_SRC_TMP, which means that all flags MUST be satisfied for the result to be true. contradictory flag values give a false return value ๐
it'll return true for IPV6_PREFER_SRC_HOME even if the host isn't implementing mobile IPv6, and also for a mobile node that's at home (aka it doesn't have any care-of address) ๐ก
14. Summary of New Definitions ๐
here's the list of constants, structures, and extern definitions talked about in this memo, sorted by header ๐
<netdb.h> AI_EXTFLAGS
<netdb.h> IPV6_PREFER_SRC_HOME
<netdb.h> IPV6_PREFER_SRC_COA
<netdb.h> IPV6_PREFER_SRC_TMP
<netdb.h> IPV6_PREFER_SRC_PUBLIC
<netdb.h> IPV6_PREFER_SRC_CGA
<netdb.h> IPV6_PREFER_SRC_NONCGA
<netdb.h> EAI_BADEXTFLAGS
<netdb.h> struct addrinfo{};
<netinet/in.h> IPV6_PREFER_SRC_HOME
<netinet/in.h> IPV6_PREFER_SRC_COA
<netinet/in.h> IPV6_PREFER_SRC_TMP
<netinet/in.h> IPV6_PREFER_SRC_PUBLIC
<netinet/in.h> IPV6_PREFER_SRC_CGA
<netinet/in.h> IPV6_PREFER_SRC_NONCGA
<netinet/in.h> short inet6_is_srcaddr(struct sockaddr_in6 *,
uint32_t);
<netinet/in.h> int bind2addrsel(int, const struct sockaddr *,
socklen_t);
15. Security Considerations ๐
โ ๏ธ this part is serious, bestie, so read it carefully ๐ซถ
this document follows the same security implications as the Basic IPv6 socket API [RFC3493] and the address selection rules [RFC3484] ๐ allowing apps to specify a preference for temporary addresses gives each app (and each socket) the ability to use the privacy benefits of temporary addresses ๐ but setting certain address preferences (e.g., not using a CGA address, or not using a temporary address) may need to be restricted to privileged processes, because of security implications ๐จ
16. Acknowledgments โจ
Okay bestie, the authors gotta shout out everyone who helped ๐ซถ. They say thanks to members of the Mobile-IP and IPV6 working groups for useful discussion on this topic. Richard Draves and Dave Thaler suggested that getaddrinfo also needs to be considered along with the new socket option ๐ . Gabriel Montenegro suggested that CGAs may also be considered in this document ๐ฅ.
Thanks also to Alain Durand, Renee Danson, Alper Yegin, Francis Dupont, Keiichi Shima, Michael Hunter, Sebastien Roy, Robert Elz, Pekka Savola, Itojun, Jim Bound, Jeff Boote, Steve Cipolli, Vlad Yasevich, Mika Liljeberg, Ted Hardie, Vidya Narayanan, and Lars Eggert for useful discussions and suggestions ๐.
Finally, thanks to Remi Denis-Courmont, Brian Haberman, Brian Haley, Bob Gilligan, Jack McCann, Jim Bound, Jinmei Tatuya, Suresh Krishnan, Hilarie Orman, Geoff Houston, Marcelo Bungulo, and Jari Arkko for reviewing this document and suggesting improvements ๐ธ๐ง.
17. References ๐
17.1. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC3484] Draves, R., "Default Address Selection for Internet
Protocol version 6 (IPv6)", RFC 3484, February 2003.
[RFC3493] Gilligan, R., Thomson, S., Bound, J., McCann, J., and W.
Stevens, "Basic Socket Interface Extensions for IPv6",
RFC 3493, February 2003.
17.2. Informative References
[FPING] "Fping - a program to ping hosts in parallel", Online web
site http://www.fping.com.
[RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6
(IPv6) Specification", RFC 2460, December 1998.
[RFC3041] Narten, T. and R. Draves, "Privacy Extensions for
Stateless Address Autoconfiguration in IPv6", RFC 3041,
January 2001.
[RFC3542] Stevens, W., Thomas, M., Nordmark, E., and T. Jinmei,
"Advanced Sockets Application Program Interface (API) for
IPv6", RFC 3542, May 2003.
[RFC3775] Johnson, D., Perkins, C., and J. Arkko, "Mobility Support
in IPv6", RFC 3775, June 2004.
[RFC3971] Arkko, J., Kempf, J., Zill, B., and P. Nikander, "SEcure
Neighbor Discovery (SEND)", RFC 3971, March 2005.
[RFC3972] Aura, T., "Cryptographically Generated Addresses (CGA)",
RFC 3972, March 2005.
Appendix A. Per-Packet Address Selection Preference ๐ฆ
Okay so this doc talks about setting source address selection preferences per socket, using the new IPV6_ADDR_PREFERENCES socket option with setsockopt(). What it does NOT encourage is setting the preference per packet, using ancillary data objects with sendmsg(), or setsockopt() with unconnected datagram sockets. Not me going "no" to per-packet, but it's giving "pick your battles" ๐.
Per-packet source address selection is expensive, bestie. The system has to figure out the source address the application asked for before sending each packet. Meanwhile, setting the preference on a connected socket makes the selection once, and then that source address gets used for every packet sent through that socket endpoint, as long as the socket option stays set. Way less work, very iconic ๐.
That said, this doc gives guidelines for implementations that want the option of transmit-side ancillary data support for changing the default source address selection. So if an application does choose per-packet selection, the implementation should process an ancillary data object at the IPPROTO_IPV6 level (cmsg_level), of type (cmsg_type) IPV6_ADDR_PREFERENCES. Its data (cmsg_data[]) is a 32-bit unsigned integer encoding the source address selection preference flags (e.g., IPV6_PREFER_SRC_COA | IPV6_PREFER_SRC_PUBLIC), done in a fashion similar to the advanced IPV6 Socket API [RFC3542]. This preference ancillary data object may be present along with other ancillary data objects ๐.
The implementation processing the ancillary data object is responsible for selecting the preferred source address that the object indicates. So an application can use sendmsg() to pass an address selection preference ancillary data object down to the IPv6 layer. Here's the example for setting address preferences with the ancillary data API:
void *extptr;
socklen_t extlen;
struct msghdr msg;
struct cmsghdr *cmsgptr;
int cmsglen;
struct sockaddr_in6 dest;
uint32_t flags;
extlen = sizeof(flags);
cmsglen = CMSG_SPACE(extlen);
cmsgptr = malloc(cmsglen);
cmsgptr->cmsg_len = CMSG_LEN(extlen);
cmsgptr->cmsg_level = IPPROTO_IPV6;
cmsgptr->cmsg_type = IPV6_ADDR_PREFERENCES;
extptr = CMSG_DATA(cmsgptr);
flags = IPV6_PREFER_SRC_COA;
memcpy(extptr, &flags, extlen);
msg.msg_control = cmsgptr;
msg.msg_controllen = cmsglen;
/* finish filling in msg{} */
msg.msg_name = dest;
sendmsg(s, &msg, 0);
So basically, when an IPV6_ADDR_PREFERENCES ancillary data object gets passed to sendmsg(), the value inside it is used to specify the address preference for the packet that sendmsg() is sending. Slay ๐
.
Appendix B. Intellectual Property Statement ๐ฎ
Quick heads up: this doc only defines a source preference flag for choosing a Cryptographically Generated Address (CGA) as the source address when that's applicable. CGAs are obtained using public keys and hashes to prove address ownership. Several IPR claims have been made about such methods, so keep that in mind ๐.
Authors' Addresses ๐๏ธ
Erik Nordmark
Sun Microsystems, Inc.
17 Network Circle
Menlo Park, CA 94025
USA
EMail: Erik.Nordmark@Sun.com
Samita Chakrabarti
Azaire Networks
3121 Jay Street, Suite 210
Santa Clara, CA 95054
USA
EMail: samitac2@gmail.com
Julien Laganier
DoCoMo Euro-Labs
Landsbergerstrasse 312
D-80687 Muenchen
Germany
EMail: julien.IETF@laposte.net
Full Copyright Statement โ๏ธ
Copyright (C) The IETF Trust (2007).
This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.
This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Intellectual Property ๐งพ
The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document, or the extent to which any license under such rights might or might not be available. It also doesn't represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79.
Copies of IPR disclosures made to the IETF Secretariat, any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.
The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org. ๐
๐ฆ where this page comes from
- ietf: rfc5014 2007-09
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms