1

私は現在IPv6クラスに取り組んでおり、inet_ptonを使用して、文字列からIPの実際のバイナリ表現を取得します。

    AdressV6::AdressV6(const String & _ip)
    {
        int result = inet_pton(AF_INET6, _ip.c_str(), &(m_nativeAdress));

        if(result <= 0)
            //throw...

        //How can I retrieve the sope ID from that?
    }

それを行う一般的な方法はありますか?文字列を手動で解析して、防弾に聞こえない「%」を探しますか:(

ありがとうございました!

今のところ手動解析を試しましたが、うまくいくようです。それでも、もっと良い方法があれば教えてください:

        //retrieve scope ID
        uint32 scopeId = 0;
        size_t pos = _ip.find("%");
        if(pos != String::npos)
        {
            String theId = _ip.substr(pos+1);
            scopeId = atoi(theId.c_str());
        }
        m_scopeId = scopeId;
4

3 に答える 3

5

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()

于 2012-12-11T18:55:31.910 に答える
1

inet_pton()スコープIDはサポートしていません。他のプラットフォームについてはわかりませんが、WindowsRtlIpv6StringToAddressEx()では代わりに使用できます。

于 2012-04-28T00:51:01.393 に答える
0

inet_pton()スコープ識別子を半サポートします。スコープは、アドレスを1つで解析するときにエラーを発生させないということです。主な制限は、呼び出しのパラメーターがstruct in6_addrスコープIDのフィールドを含まないaであるということです。そのためには、上部構造struct sockaddr_in6が必要です。

簡単な方法は、便宜上、パラメータを使用しgetnameinfo()てラップすることです。例えば、getaddrinfo()struct sockaddr

socklen_t
sockaddr_len (
        const struct sockaddr*  sa
        )
{
        socklen_t sa_len;
        switch (sa->sa_family) {
        case AF_INET:   sa_len = sizeof(struct sockaddr_in); break;
        case AF_INET6:  sa_len = sizeof(struct sockaddr_in6); break;
        default:        sa_len = 0; break;
        }
        return sa_len;
}

int
sockaddr_ntop (
        const struct sockaddr* restrict sa,
        char*                  restrict host,
        size_t                          hostlen
        )
{
        return getnameinfo (sa, sockaddr_len (sa),
                            host, hostlen,
                            NULL, 0,
                            NI_NUMERICHOST);
}

int
sockaddr_pton (
        const char*      restrict src,
        struct sockaddr* restrict dst           /* will error on wrong size */
        )
{
        struct addrinfo hints = {
                .ai_family      = AF_UNSPEC,
                .ai_socktype    = SOCK_STREAM,          /* not really */
                .ai_protocol    = IPPROTO_TCP,          /* not really */
                .ai_flags       = AI_NUMERICHOST
        }, *result = NULL;
        const int status = getaddrinfo (src, NULL, &hints, &result);
        if (0 == status) {
                memcpy (dst, result->ai_addr, result->ai_addrlen);
                freeaddrinfo (result);
                return 1;
        }
        return 0;
}

元の前提に答えるために、与えられたstruct sockaddr場合、追加のAPIが保証される場合があります。例:

uint32_t
sockaddr_scope_id (
        const struct sockaddr*  sa
        )
{
        uint32_t scope_id;
        if (AF_INET6 == sa->sa_family) {
                struct sockaddr_in6 s6;
                memcpy (&s6, sa, sizeof(s6));
                scope_id = s6.sin6_scope_id;
        } else
                scope_id = 0;
        return scope_id;
}
于 2012-12-11T20:07:58.637 に答える