08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0440;
+ LastUpgradeCheck = 0700;
};
buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "Libinfo" */;
compatibilityVersion = "Xcode 3.2";
isa = XCBuildConfiguration;
baseConfigurationReference = 3F397F7D185BD67F00987BCC /* Libinfo.xcconfig */;
buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
PRODUCT_NAME = info;
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
VERSION_INFO_EXPORT_DECL = static;
VERSION_INFO_PREFIX = __;
};
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
+ OTHER_CFLAGS = "";
VERSIONING_SYSTEM = "apple-generic";
WARNING_LDFLAGS = "-Wall";
};
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
+ SUPPORTED_PLATFORMS = iphonesimulator;
};
name = Release;
};
+ 90E08A3C1BB364CA0093311B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ BUILD_VARIANTS = (
+ normal,
+ profile,
+ debug,
+ );
+ CODE_SIGN_IDENTITY = "-";
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_CURRENT_VERSION = "$(CURRENT_PROJECT_VERSION)";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ OTHER_CFLAGS = "-DDEBUG=1";
+ VERSIONING_SYSTEM = "apple-generic";
+ WARNING_LDFLAGS = "-Wall";
+ };
+ name = Debug;
+ };
+ 90E08A3D1BB364CA0093311B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3F397F7D185BD67F00987BCC /* Libinfo.xcconfig */;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ PRODUCT_NAME = info;
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ VERSION_INFO_EXPORT_DECL = static;
+ VERSION_INFO_PREFIX = __;
+ };
+ name = Debug;
+ };
+ 90E08A3E1BB364CA0093311B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SUPPORTED_PLATFORMS = iphonesimulator;
+ };
+ name = Debug;
+ };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
isa = XCConfigurationList;
buildConfigurations = (
1DEB914C08733D8E0010E9CD /* Release */,
+ 90E08A3D1BB364CA0093311B /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
isa = XCConfigurationList;
buildConfigurations = (
1DEB915008733D8E0010E9CD /* Release */,
+ 90E08A3C1BB364CA0093311B /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
isa = XCConfigurationList;
buildConfigurations = (
3F397F80185BD71500987BCC /* Release */,
+ 90E08A3E1BB364CA0093311B /* Debug */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
.Dv AI_NUMERICHOST ,
.Dv AI_NUMERICSERV ,
.Dv AI_PASSIVE ,
+.Dv AI_V4MAPPED ,
+.Dv AI_V4MAPPED_CFG ,
and
-.Dv AI_V4MAPPED .
+.Dv AI_DEFAULT .
.Bl -tag -width "AI_CANONNAMEXX"
.It Dv AI_ADDRCONFIG
If the
flag is specified along with an
.Fa ai_family
of
-.Dv AF_INET6 ,
+.Dv PF_INET6 ,
then
.Fn getaddrinfo
shall return IPv4-mapped IPv6 addresses
flag shall be ignored unless
.Fa ai_family
equals
-.Dv AF_INET6 .
+.Dv PF_INET6 .
+.It Dv AI_V4MAPPED_CFG
+The
+.Dv AI_V4MAPPED_CFG
+flag behaves exactly like the
+.Dv AI_V4MAPPED
+flag if the kernel supports IPv4-mapped IPv6 addresses. Otherwise it is ignored.
+.It Dv AI_DEFAULT
+.Dv AI_DEFAULT
+is defined as (
+.Dv AI_V4MAPPED_CFG
+|
+.Dv AI_ADDRCONFIG
+).
.El
.El
.Pp
This implementation of
.Fn getaddrinfo
allows numeric IPv6 address notation with scope identifier,
-as documented in chapter 11 of draft-ietf-ipv6-scoping-arch-02.txt.
+as documented in section 11 of RFC 4007.
By appending the percent character and scope identifier to addresses,
one can fill the
.Li sin6_scope_id
.Li addrinfo
structure created by a call to
.Fn getaddrinfo .
+.Pp
+The current implementation supports synthesis of NAT64 mapped IPv6 addresses.
+If
+.Fa hostname
+is a numeric string defining an IPv4 address (for example,
+.Dq Li 192.0.2.1
+) and
+.Fa ai_family
+is set to
+.Dv PF_UNSPEC
+or
+.Dv PF_INET6,
+.Fn getaddrinfo
+will synthesize the appropriate IPv6 address(es) (for example,
+.Dq Li 64:ff9b::192.0.2.1
+) if the current interface supports IPv6, NAT64 and DNS64
+and does not support IPv4. If the
+.Dv AI_ADDRCONFIG
+flag is set, the IPv4 address will be suppressed on those interfaces.
+On non-qualifying interfaces,
+.Fn getaddrinfo
+is guaranteed to return immediately without attempting any resolution, and will
+return the IPv4 address if
+.Fa ai_family
+is
+.Dv PF_UNSPEC
+or
+.Dv PF_INET.
+NAT64 address synthesis can be disabled by setting the
+.Dv AI_NUMERICHOST
+flag. To best support NAT64 networks, it is recommended to resolve all
+IP address literals with
+.Fa ai_family
+set to
+.Dv PF_UNSPEC
+and
+.Fa ai_flags
+set to
+.Dv AI_DEFAULT.
.Sh RETURN VALUES
.Fn getaddrinfo
returns zero on success or one of the error codes listed in
via a stream socket.
It loops through all the addresses available, regardless of address family.
If the destination resolves to an IPv4 address, it will use an
-.Dv AF_INET
+.Dv PF_INET
socket.
Similarly, if it resolves to IPv6, an
-.Dv AF_INET6
+.Dv PF_INET6
socket is used.
Observe that there is no hardcoded reference to a particular address family.
The code works even if
.%A E. Nordmark
.%A B. Zill
.%T "IPv6 Scoped Address Architecture"
-.%R internet draft
-.%N draft-ietf-ipv6-scoping-arch-02.txt
-.%O work in progress material
+.%R RFC 4007
+.%D March 2005
.Re
.Rs
.%A Craig Metz
#include <net/if.h>
#include <netinet/in.h>
#include <network/sa_compare.h>
+#include <network/nat64.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <net/if.h>
return result;
}
+static si_list_t *
+_gai_nat64_synthesis(si_mod_t *si, const char *node, const char *serv, int numericserv,
+ uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface)
+{
+ if (NULL == node)
+ {
+ return NULL;
+ }
+
+ /* validate AI_NUMERICHOST */
+ if ((flags & AI_NUMERICHOST) != 0)
+ {
+ return NULL;
+ }
+
+ /* validate family */
+ if ((AF_UNSPEC != family) && (AF_INET6 != family))
+ {
+ return NULL;
+ }
+
+ /* validate that node is an IPv4 address */
+ struct in_addr a4;
+ if (1 != inet_pton(AF_INET, node, &a4))
+ {
+ return NULL;
+ }
+
+ /* validate that there is at least an IPv6 address configured */
+ uint32_t num_inet6 = 0;
+ if ((si_inet_config(NULL, &num_inet6) < 0) || (0 == num_inet6))
+ {
+ return NULL;
+ }
+
+ /* validate interface name and convert to index */
+ uint32_t ifindex = 0;
+ if (NULL != interface)
+ {
+ ifindex = if_nametoindex(interface);
+ if (0 == ifindex)
+ {
+ return NULL;
+ }
+ }
+
+ /* validate serv and convert to port */
+ uint16_t port = 0;
+ if (0 == numericserv)
+ {
+ if (_gai_serv_to_port(serv, proto, &port) != 0)
+ {
+ return NULL;
+ }
+ else
+ {
+ flags |= AI_NUMERICSERV;
+ }
+ }
+
+ /* query NAT64 prefixes */
+ nw_nat64_prefix_t *prefixes = NULL;
+ const int32_t num_prefixes = nw_nat64_copy_prefixes(&ifindex, &prefixes);
+ if ((num_prefixes <= 0) || (NULL == prefixes))
+ {
+ return NULL;
+ }
+
+ /* add every address to results */
+ si_list_t *out_list = NULL;
+ for (int32_t i = 0; i < num_prefixes; i++)
+ {
+ struct in6_addr a6;
+ if (!nw_nat64_synthesize_v6(&prefixes[i], &a4, &a6))
+ {
+ continue;
+ }
+ si_list_t *temp_list = si_addrinfo_list(si, flags, socktype, proto, NULL, &a6, port, (int)ifindex, NULL, NULL);
+ if (NULL == temp_list)
+ {
+ continue;
+ }
+ if (NULL != out_list)
+ {
+ out_list = si_list_concat(out_list, temp_list);
+ si_list_release(temp_list);
+ }
+ else
+ {
+ out_list = temp_list;
+ }
+ }
+
+ free(prefixes);
+
+ /* return to standard code path if no NAT64 addresses could be synthesized */
+ if (NULL == out_list)
+ {
+ return NULL;
+ }
+
+ /* add IPv4 addresses and IPv4-mapped IPv6 addresses if appropriate */
+ if (((AF_UNSPEC == family) && ((flags & AI_ADDRCONFIG) == 0)) ||
+ ((AF_INET6 == family) && ((flags & AI_ALL) != 0) && ((flags & AI_V4MAPPED) != 0)))
+ {
+ si_list_t *list4 = si_addrinfo_list(si, flags, socktype, proto, &a4, NULL, port, (int)ifindex, NULL, NULL);
+ if (NULL != list4)
+ {
+ out_list = si_list_concat(out_list, list4);
+ si_list_release(list4);
+ }
+ }
+
+ return _gai_sort_list(out_list, flags);
+}
+
si_list_t *
si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, uint32_t socktype, uint32_t proto, uint32_t flags, const char *interface, uint32_t *err)
{
return NULL;
}
+ /* replace AI_V4MAPPED_CFG with AI_V4MAPPED */
+ if ((flags & AI_V4MAPPED_CFG) != 0)
+ {
+ flags = (flags & ~AI_V4MAPPED_CFG) | AI_V4MAPPED;
+ }
+
/* check AI_V4MAPPED and AI_ALL */
if (family != AF_INET6)
{
}
}
+ /* NAT64 IPv6 address synthesis support */
+ si_list_t *nat64_list = _gai_nat64_synthesis(si, node, serv, numericserv, family, socktype, proto, flags, interface);
+ if (NULL != nat64_list)
+ {
+ return nat64_list;
+ }
+
numerichost = _gai_numerichost(node, &family, flags, &a4, &a6, &scope);
if ((numerichost == -1) || ((flags & AI_NUMERICHOST) && (numerichost == 0)))
{