2012-04-26 8 views
1

を取得するために、私は現在、IPv6のクラスに取り組んでおり、すなわち文字列からIPの実際のバイナリ表現を取得するためにはinet_pton使用しています:BSDソケットIP6はinet_ptonとどのようにスコープID

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; 
+0

、それはスコープIDが数値であることを前提としてい。 %1または%2は有効なスコープIDですが、その意味は実装によって異なります。スコープIDには、%dc0、%eth0、%en0などのインタフェース名を使用することもできます。正しいスコープIDを取得する方法については、インターフェイス名であっても、返信を参照してください。 – Mecki

答えて

1

inet_pton()私は他のプラットフォームについては知りませんが、Windows上で、あなたが代わりにRtlIpv6StringToAddressEx()を使用することができますBSDおよびBSDベースのシステムで

+0

ty、私は窓にいない。手動解析は、特定のipv6表記法を使用する必要があるにもかかわらず、現在は機能しているようです。 – moka

3

スコープIDをサポートしていません。 (これにはMacOS X例えば、スコープIDは、第2の16ビットワードとしてリンクローカルアドレスのアドレス自体に埋め込まれる。 FreeBSD Handbookを参照し、「8.1.1.3スコープインデックス」(引用符は不要)を検索してください。

は、したがって、これらのプラットフォームでは、次のようにinet_pton()は、文字列を変換し、そのINTF1は、スコープID 1を持っており、INTF2は、スコープID 2を持っていると仮定すると:

"fe80::1234%intf1" -> fe80:1::1234 
"fe80::1234%intf2" -> fe80:2::1234 
"fe80::1234"  -> fe80::1234 

最後のアドレスは、単に、スコープ外であるため、実際に使用することはできませんデータを送信する。

これは標準ではありません。 inet_pton()は、LinuxまたはWindowsベースのシステムではそのように動作しません。しかし、私はLinuxとWindowsベースのシステムでも、inet_pton()は最後にスコープIDを許可していると考えていますが、単に無視するだけです。

リンクローカルでないアドレスの場合、このトリックは機能しませんが、これらのアドレスは通常スコープではありません。スコープを設定できますが、通常はすべてのインターフェイスにインターフェイス識別子に基づいた独自のインターフェイスのIPv6アドレスがあります(DHCPv6を使用している場合でも、DHCPサーバーによってDHCPアドレスが割り当てられ、自動生成されますこの自動生成が禁止されていない限り、IPv6インタフェースアドレス)。

構造体にはスコープIDのフィールドがありますが、このフィールド(RFC 2553 - Section 3.3)を定義するRFCでは、このフィールドの解釈方法についてはあまり詳しく説明していません。それだけの言葉:

を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()を使用してください。

+0

組み込みスコープIDについて:これらは内部表現であり、BSD/Darwinのカーネルの外側には表示されません。むしろ、いくつかのAPIが公開されており、最終的に修正される予定です。 ioctlsとsysctlsは、スコープIDが組み込まれたアドレスを保持する唯一の一般的な方法です。さもなければ、ユーザランド関数とコードは可能な限りsockaddr_in6の正しい使い方で動作するはずです。 –

+0

@NicholasWilsonカーネルの外では見えないようにすることはできますが、当面は目に見えます。 OS Xでは、たとえリンクローカルIPv6アドレスしか持たないのであれば、OS XでもUIにもスコープIDが組み込まれたそれらのアドレスが表示されます(たとえば、ネットワーク環境設定でもそうです)。したがって、それらのアドレスについて何も知らないユーザーは、間違ってそこからコピー&ペーストする可能性があります。その結果、IPv6アドレス文字列を処理するはずのすべての機能が、OS Xで組み込みスコープを正しく処理します。 – Mecki

+0

おそらくgetifaddrsを呼び出しているだけです。これはまだ埋め込みスコープIDを公開している数少ないlibc関数の1つです(ダーウィンでioctlで実装されているか、またはそれがコピーされたアドレスを再フォーマットしないという事実です)実際にはバグです)。さらに悪いことに、いくつかの壊れたシステムでは、getaddrinfoはスコープid(bad bad bug)を追加せずにアドレスを出力し、SunOSはエイリアスインターフェイスのスコープIDと混在します。 –

0

inet_pton()セミサポート型スコープ識別子の場合、スコープは1でアドレスを解析するときにエラーを発生させないことです。主な制限は、コールのパラメータがstruct in6_addrでスコープ識別子のフィールドが含まれていないことです。スーパー構造struct sockaddr_in6が必要です。

簡単な方法は、便宜上、を、便宜上、のパラメータで囲むことです。例えば、

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; 
} 
関連する問題