BSDおよびBSDベースのシステム(たとえばMacOS Xを含む)では、スコープIDは、2番目の16ビットワードとしてリンクローカルアドレスのアドレス自体に埋め込まれます。FreeBSDハンドブックを参照し、「8.1.1.3スコープインデックス」(引用符なし)を検索してください。
したがって、intf1のスコープIDが1で、intf2のスコープIDが2であるinet_pton()
とすると、これらのプラットフォームでは次のように文字列が変換されます。
"fe80::1234%intf1" -> fe80:1::1234
"fe80::1234%intf2" -> fe80:2::1234
"fe80::1234" -> fe80::1234
最後のアドレスは単にスコープが設定されていないため、データの送信に実際に使用することはできません。
これは非標準であることに注意してください。inet_pton()
LinuxまたはWindowsベースのシステムではそのようには機能しません。ただし、LinuxおよびWindowsベースのシステムでも、最後にスコープIDを許可していると思いますinet_pton()
が、それは単に無視されます。
もちろん、非リンクローカルアドレスの場合、このトリックは機能しませんが、これらのアドレスは通常スコープされていません。スコープを設定できますが、通常、すべてのインターフェイスには、そのインターフェイス識別子に基づいた独自の一意のインターフェイスIPv6アドレスがあります(DHCPv6を使用している場合でも、DHCPサーバーによって割り当てられたDHCPアドレスと、自動生成されたものがあります)。この自動生成が禁止されていない限り、IPv6インターフェイスアドレス)。
struct sockaddr_in6
構造にはスコープIDのフィールドがありますが、このフィールドを定義するRFC(RFC 2553-セクション3.3)は、このフィールドがどのように解釈されるかについてはあまり詳しく説明していません。それは言うだけです:
sin6_scope_idのインターフェイスまたはインターフェイスのセットへのマッピングは、サイト識別子に関する実装と将来の仕様に任されています。
したがって、このフィールドは完全に実装固有です。
このフィールドに正しく入力する必要があり、コードを可能な限りクロスプラットフォームにする必要がある場合は、次を使用する必要がありますgetaddrinfo()
。
struct addrinfo hints;
struct addrinfo * result;
memset(&hints, 0, sizeof(hints));
// AI_NUMERICHOST prevents usage of DNS servers,
// it tells getaddrinfo that the input string is a numeric IP address.
hints.flags = AI_NUMERICHOST;
if (getaddrinfo("fe80::1234%intf1", NULL, &hints, &result) == 0) {
// result->ai_addr claims to be a pointer to struct sockaddr,
// in fact it will be a pointer to a struct sockaddr_in6 in our case.
struct sockaddr_in6 * so = (struct sockaddr_in6 *)result->ai_addr;
// It will be prefilled like this:
//
// so->sin6_family ==> AF_INET6;
// so->sin6_port ==> 0
// so->sin6_flowinfo ==> 0
// so->sin6_addr ==> fe80::1234
// so->sin6_scope_id ==> "intf1" as scope ID
// Do something with that sockaddr,
// e.g. set a port number and connect a socket to that address.
freeaddrinfo(result);
}
追加のヒント:返さgetaddrinfo()
れたサーバーソケット(ローカルでバインドしてから呼び出すソケット)を使用するaccept()
場合は、パッシブフラグも設定する必要があります。
hints.flags = AI_NUMERICHOST | AI_PASSIVE;
ほとんどの場合、それが役割を果たすというわけではありませんが、それが正しい使用方法ですgetaddrinfo()
。