IP(4)

名称
ip - インターネットプロトコル

書式
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> int socket(AF_INET, SOCK_RAW, proto)

説明
IP は、インターネットプロトコルファミリが用いるトランスポート層の プロトコルです。 IP に基づいた、より高位のプロトコル (例えば、 TCP や UDP ) を用いているときには、 IP レベルでオプションを設定できます。 また、新しいプロトコルや特別な用途のアプリケーションを 開発しているときには、 “raw ソケット” を通してアクセスすることもできます。

IP レベル の setsockopt(2) ならびに getsockopt(2) オプションがいくつかあります。 IP_OPTIONS は、送信される各パケットの IP ヘッダ中に埋め込まれる IP オプションを提供したり、受信されるパケットの ヘッダ部のオプションを検査したりするために 使われます。 IP オプションは、インターネットファミリの全てのソケットタイプで 使うことができます。 送信される IP オプションのフォーマットは、 IP プロトコルの仕様 (RFC-791) で決められています。ただし、1 つ例外が あります。 指定経路制御オプション用のアドレスリストには、ゲートウェイ リストの先頭に、最初にパケットが通過するゲートウェイが含まれて いることが必要です。 最初にパケットが通過するゲートウェイのアドレスはオプションリストから 取り出され、使用される前に適切な大きさに直されます。 以前に指定されたオプションを無効にするには、長さ 0 のバッファを使用して ください。

    setsockopt(s, IPPROTO_IP, IP_OPTIONS, NULL, 0);

IP_TOS および IP_TTL は、 SOCK_STREAM および SOCK_DGRAM で用いられる IP ヘッダ内の、 サービスタイプ (type-of-service) フィールドと生存時間 (time-to-live) フィールドを設定するために使用されます。 例えば、以下のようにします。

    int tos = IPTOS_LOWDELAY;       /* <netinet/in.h> 参照 */
    setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
    int ttl = 60;                   /* 最大値は 255 */
    setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));

もし、 IP_RECVDSTADDR オプションが SOCK_DGRAM ソケットで有効になっていた場合、 recvmsg(2) システムコールは、 UDP ダイアグラム用の送り先の IP アドレスを返します。 msghdr 構造体の msg_control フィールドは IP アドレスの後に続いた cmsghdr 構造体の入ったバッファへの ポインタになっています。 cmsghdr フィールドは以下のような値を持ちます。

    cmsg_len = sizeof(struct in_addr)
    cmsg_level = IPPROTO_IP
    cmsg_type = IP_RECVDSTADDR

IP_PORTRANGE は、ポート番号の範囲を設定するために使されます。 この範囲のローカルポート番号のうちのひとつが、 ポート番号を指定しなかった (0 が指定された) ソケット用に選択されます。 これは、以下のような値を取り得ます。

IP_PORTRANGE_DEFAULT
    デフォルトの範囲のポート番号値を使います。通常は IPPORT_RESERVED から IPPORT_USERRESERVED です。 この値は、sysctl の設定、 net.inet.ip.portrange.first および net.inet.ip.portrange.last を通して調整できます。

IP_PORTRANGE_HIGH
    は、大きな値の範囲のポート番号を使います。通常は IPPORT_HIFIRSTAUTO および IPPORT_HILASTAUTO です。 この値は、sysctlの設定、 net.inet.ip.portrange.hifirst および net.inet.ip.portrange.hilast を通して調整できます。

IP_PORTRANGE_LOW
    は、小さな値の範囲のポート番号を使います。通常は、 UNIX システム上で特権を持ったプロセスに使用が限定されています。 この値の範囲は、通常 IPPORT_RESERVED から 1 までで、降順に並んでいます。この値の範囲は sysctl では設定できません。

  マルチキャストオプション

IP のマルチキャストは SOCK_DGRAM および SOCK_RAW 型の AF_INET ソケットで、インタフェースドライバがマルチキャスト に対応しているネットワークのみで行えます。

IP_MULTICAST_TTL オプションは、送信されるマルチキャストデータグラムの 生存時間 (TTL) 値を変更します。この値を変更することで マルチキャストの範囲を制御できます。

    u_char ttl;	/*  0 から 255 の範囲。 デフォルト値は 1 */
    setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));

TTL 値が 1 のデータグラムは、ローカルネットワークを超えて 転送されることはありません。 TTL 値が 0 のデータグラムはどのネットワークにも送信されませんが、 データグラムを送ったホストが送り先のグループに属しており、 送信を行うソケットがマルチキャストループパックを無効にしていなければ (下記参照)、ローカルネットワークには送信されるかもしれません。 TTL 値が 1 より大きいデータグラムは、ローカルネットワークに マルチキャストルータが接続されていれば、他のネットワークに転送されます。

複数のインタフェースを持ったホストには、各マルチキャスト 送信は、最初のネットワークインタフェースから行われます。 IP_MULTICAST_IF オプションを使うと、指定されたソケットからの次の送信のために デフォルト値を書きかえることができます。

    struct in_addr addr;
    setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));

ここで、"addr" は、ローカルホストの使用したいインタフェースの IP アドレスです。または、 INADDR_ANY を指定して、デフォルトのインタフェースを示すようにもできます。 インタフェースのローカル IP アドレスおよびマルチキャスト能力の 有無は、 SIOCGIFCONF および SIOCGIFFLAGS ioctl システムコールで得ることができます。 普通のアプリケーションではこのオプションを使う必要は ないはずです。

もし、マルチキャストデータグラムが送り元のホスト自身が 属しているグループ (送り先のインタフェース上にある) に送信されるのであれば、デフォルトではローカルへの配送用に、 そのダイアグラムのコピーが IP 層によってループバック されます。 IP_MULTICAST_LOOP オプションは、送信ホストに今後のデータグラムをループバック するのかどうかを制御する権限を明示的に与えます。

    u_char loop;	/* 0 = 無効, 1 = 有効 (デフォルト) */
    setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));

このオプションは、自身が送信したパケットを受け取る際のオーバヘッドを 軽減することで、1 つのホストに 1 つしか実体を持たないアプリケーション (例えば、ルータデーモン) のパフォーマンスを向上させます。 このオプションは、1 つのホスト上で複数の実体を持ち得るアプリケーション (例えば、会議プログラム) や、 送信元のホストが送信先のグループに属さないアプリケーション (例えば、 時刻問い合わせプログラム) では使われません。

TTL の初期値を 1 より大きくして送信されたマルチキャストデータグラムは、 送信元のインタフェースとは別のインタフェース上のホストから送信元 のホストに配送されるかもしれません。 ただし、送信元ではない方のインタフェース上で、 このホストが宛先のグループに属している場合です。 ループバックコントロールオプションは、このような配送に対しては 何の効力も持ちません。

あるマルチキャストグループから送信されたデータグラムを受け取るには、 ホストがそのマルチキャストグループに属していることが必要です。 あるマルチキャストグループに加わるには、 IP_ADD_MEMBERSHIP オプションを使用します。

    struct ip_mreq mreq;
    setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

ここでは、 mreq は以下のような構造体です。

    struct ip_mreq {
        struct in_addr imr_multiaddr; /* グループの IP マルチキャストアドレス */
        struct in_addr imr_interface; /* インタフェースのローカル IP アドレス */
    }

デフォルトのマルチキャストインタフェースを選択するには、 imr_interface は INADDR_ANY にします。 また、ホストがマルチホームに設定されていれば、 特定のマルチキャスト可能なインタフェースの IP アドレスに指定することが必要です。 メンバシップは、1 つのインタフェースに結びついています。 そのため、マルチホームホスト上で動作しているプログラムは、 1 つ以上のインタフェース上で同一のグループに入る必要がある かもしれません。 1 つのソケットに最大 IP_MAX_MEMBERSHIPS (現在では 20) 個のメンバシップを設定できます。

メンバから抜けるには、以下の関数を使います。

    struct ip_mreq mreq;
    setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));

ここで、 mreq はメンバに加わるときに使ったのと同じ値が入ります。ソケットを閉じたり プロセスが終了したりした場合はメンバから抜けます。

  raw IP ソケット

raw IP ソケットは、コネクションを持たないソケットで、 通常は sendto(2) や recvfrom(2) コールと一緒に使われます。 ただし、 connect(2) コールは、 これから流れてくるパケットの送り先を定めるためにも使われます。 (この場合には、 read(2) もしくは recv(2) 、および write(2) もしくは send(2) システムコールが使われるでしょう。)

proto が 0 の場合には、パケットの送信にはデフォルトの プロトコルである IPPROTO_RAW が使われ、このプロトコルに向かって送られてきたパケットだけが 受信されます。 proto が 0 でない場合、そのプロトコルの番号が送信パケット上で使われ、 また、入力パケットをフィルタリングするために使われます。

送信パケットには、自動的に IP ヘッダ (これは、送り先アドレスおよびソケットが 作成されたときのプロトコル番号にもどづいています) が与えられます。ただし、 IP_HDRINCL オプションが設定されているときは IP ヘッダは与えられません。 受信パケットは、完全な形の IP ヘッダおよびオプションと一緒に受け取られます。

IP_HDRINCL は、データと一緒に完全な IP ヘッダが含まれていることを 示し、 SOCK_RAW 型でしか使われません。

    #include <netinet/in_systm.h>
    #include <netinet/ip.h>
    int hincl = 1;                  /* 1: オン , 0: オフ */
    setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl));

以前の BSD リリースとは違って、このプログラムでは、すべての IP ヘッダ のフィールドを設定することが必要です。これには次のフィールド も含みます。

    ip->ip_v = IPVERSION;
    ip->ip_hl = hlen >> 2;
    ip->ip_id = 0;  /* 0 ということは、カーネルが適切な値を
                       設定してくれるということです。 */
    ip->ip_off = offset;

ヘッダの送り元のアドレスが INADDR_ANY に設定されていたら、 カーネルが適切なアドレスを選択します。

診断
ソケット操作が次のようなエラーのいずれかを返して失敗することが あります。

[EISCONN]
    すでに接続が確立されたソケットに接続を試みようとしたときや、 送り先アドレスを指定してデータグラムを送信しようとしたときに 送り先のソケットがすでに接続されているときに生じます。

[ENOTCONN]
    データグラムを送信しようとしたときに、送り先アドレスが 指定されておらず、ソケットがまだ接続されていないときに生じます。

[ENOBUFS]
    内部のデータ構造でシステムがメモリを使い果たしたときに 生じます。

[EADDRNOTAVAIL]
    ネットワークアドレスを用いてソケットを作成しようとしたが、 そのためのネットワークインタフェースが存在しないときに 生じます。

[EACESS]
    特権のないプロセスによって raw IP ソケットを作成しようと したときに生じます。

次のような、 IP に特有のエラーが IP のオプションを設定したり取得したりする際に生じることがあります。

[EINVAL]
    ソケットのオプション名に不明なものが与えられました。

[EINVAL]
    IP のオプションフィールドが適切な形になっていませんでした。 すなわち、オプションフィールドが最小値より短かったり、 与えられたオプションバッファよりも長かったりしたということです。

関連項目
getsockopt(2), recv(2), send(2), icmp(4), inet(4), intro(4)

歴史
ip プロトコルは、 4.2BSD から登場しました。