魔術師見習いのノート

プロフィール

魔術師見習い
Author魔術師見習い-_-.
Twitter魔術師見習い

コンピュータ関係のメモを主に書きます.

MENU

コンピュータ・ネットワーク(4) -ネットワーク層-

投稿日:
編集日:
タグ:

目次

ネットワーク層は5階層TCP/IPモデルの下から3番目の層である。

アプリケーション層
トランスポート層
ネットワーク層
データリンク層
物理層
ネットワーク層は、データリンク層で物理的に接続されたネットワークを跨いだノード間の通信を可能にする。

サービス
    物理的なネットワークを跨いで全てのノード間の通信を可能にする。
  • 誤り検出
インタフェースデータ単位パケット
アドレス論理アドレス
代表的なプロトコル
  • IPv4
  • IPv6
  • ICMP

IPパケット

IPでは、IPパケットというデータ単位で通信を行う。IPパケットは次のようなデータ構造である。ここで、各セルは基本的に1ビットを表す。

012345678910111213141516171819202122232425262728293031
Version IHL TOS Total Length
identification VCF Fragment Offset
TTL Protocol Header Checksum
Source Address
Destination Address
Options
Data
Version
IPのバージョン。IPv4ならば4。
IHL: Internet Header Length
IPヘッダの長さ。
Type Of Service
パケットが転送される際に重視するサービスを指定するフィールド。
01234567
優先度 遅延度 転送量 信頼性 予備
予備のフィールドは、RFC3168ではECN(輻輳通知機能)のために定義される。
67
ECTCE
各ビットはそれぞれ次のような名前である。
  • ECT(Explicit Capable Transport)
  • CE(Congestion Experience)
そしてそれらの値は次のような意味を持つ。
00ECNを未サポート。
01送信ホストはECNをサポート。
10
11輻輳はルータにより経験。
Total Length
パケットの全長。1バイトが8ビットとした時のバイト数。
identification
断片化した時にその断片がどのパケットのものかを表す。
VCF: Various Control Flags
断片化の制御に用いるフィールド。
012
予備禁止継続
Fragment Offset
パケットを断片化した時に、パケット全体のどこの位置にあたるのかを示すフィールド。
TTL: Time To Live
ルーティング可能な回数。パケットを転送する度に1減らし、これが0になったらそのパケットを破棄する。
Protocol
トランスポート層やネットワーク層の他のプロトコルなどでIPパケットを使用する場合にその種類を示すフィールド。
プロトコル番号プロトコル名
1ICMP
2IGMP
4IP
6TCP
7CBT
8EGP
9IGP
17UDP
41IPv6
43IPv6-Route
44IPv6-Flag
45IDRP
46RSVP
47GRE
50ESP
51AH
55MOBILE
58IPv6-ICMP
59IPV6-NoNxt
60IPv6-Opts
88EIGRP
89OSPF
94IPIP
103PIM
112VRRP
113PGM
115L2TP
Header Checksum
IPヘッダの誤り検査のためのフィールド。ルーティングの度にTTLの値が変化するため、この値も変化する。なおIPではデータ内容のチェックは行われない。
Source Address
送信元IPアドレス。
Destination Address
宛先IPアドレス。
Options
セキュリティやルーティングなどの拡張情報。可変長のフィールドで、ないこと、すなわち5であることが多い。


IPアドレス

IPアドレスとは32ビットの論理アドレスのことである。データリンク層で使用されるMACアドレスが各ネットワークデバイスにそれぞれ割り当てられているのに対し、IPアドレスはソフトウェアによってMACアドレスに対応づけられる(厳密には1対1関係とはいえないがそれについては後述する)。それゆえノードに割り当てられるIPアドレスは、常に同じであるとは限らない。

MACアドレスが隣接するノード間の通信に使われるのに、IPアドレスは接続されたノード間の通信のために使用される。例えば、送信元IPアドレス"192.168.1.2"から宛先IPアドレス"64.4.11.37"への通信を行う場合、経路中のパケットやフレームで使用される各アドレス情報は、それぞれ図のようになる(実際にはプライベートアドレスと呼ばれる"192.168.1.2"からグローバルアドレス"64.4.11.37"には直接通信できない)。

このように送信元・宛先IPアドレスが常にエンドのものであるのに対し、送信元・宛先MACアドレスはフレームを送受信するノードのものが使用される。

ネットワークインタフェース

IPアドレスはMACアドレスに対応付けられると述べたが、厳密にはこれは正しくない。前述の通り、MACアドレスはネットワークデバイス毎に割り当てられている。しかしソフトウェアレベルでは、ネットワークデバイスを抽象化したネットワークインタフェースという単位で扱われ、IPアドレスはネットワークインタフェースに割り当てられる。そして、ネットワークインタフェースにはMACアドレスがないがIPアドレスを持つものや、1つのネットワークインタフェースで複数のIPアドレスを持つもの、いくつかのネットワークインタフェースで同じMACアドレスが使用されるようなものなど様々なタイプがある。例えばUNIX系OSでは、ローカルループバックと呼ばれる自分自身と通信するためのIPアドレスが割り当てられたネットワークインタフェースがある。これは実際のネットワークデバイスの有無に関係なく存在し、かつMACアドレスがない。

ネットワーククラス -RFC791-

RFC791では、IPアドレスは3つの要素から構成される。各フィールドは、クラスとネットワークアドレス、ホストアドレスに分けられる。

クラス
ネットワークの規模。
ネットワークアドレス
ネットワークの識別番号。
ホストアドレス
あるネットワーク内のノードの識別番号。
クラス 0123456789 10111213141516171819 20212223242526272829 3031
A 0
B 1 0
C 1 1 0
1 1 1 拡張アドレスモード
IPアドレスは1バイト(8ビット)毎に区切って表示される(例:172.16.1.1)。IPアドレスにはいくつかの特別な番号のものがある。

サブネット -RFC950-

RFC950では、RFC791で出てきたネットワークを更に小さいネットワーク(サブネット)に分割できる。サブネットを指定するには、ネットワークマスクと呼ばれる32ビットの値を使用する。例えばクラスBのネットワークは次のようにしてサブネットを指定する。

0123456789 10111213141516171819 20212223242526272829 3031
B 1 0 ネットワーク ホスト
1 0 ネットワーク サブネット ホスト
1111111111 1111111111 000000000000
ネットワークマスクは255.255.0.0のように記述したり、IPアドレスと一緒に172.16.1.1/16のようにして表す。

プライベートアドレス -RFC1918-

インターネットで使用されるIPアドレスをグローバルアドレスと呼ぶ。そして、これとは別に局所的なネットワークで使用されるアドレスがある。これをプライベートアドレスという。RFC1918ではプライベートアドレスの範囲を次のように定めた。

10.0.0.0〜10.255.255.25510.0.0.0/8
172.16.0.0〜172.31.255.255172.16.0.0/12
192.168.0.0〜192.168.255.255192.168.0.0/16
プライベートアドレスとグローバルアドレスは、直接通信することができない。そのため、プライベートアドレスのマシンからグローバルアドレスのマシンにアクセスする場合、グローバルなネットワークに接続するルータによってアドレス変換が行われる。これをNAT(Network Address Translation)という。

このようなRFCで定められたグローバルアドレス以外の特別なアドレスのことを予約アドレスという。

予約アドレス

2014/02時点の予約アドレスは次の通りである。

アドレスネットワーク名RFC
0.0.0.0/8現在のネットワークRFC1122
10.0.0.0/8PRIVATE-ADDRESS-ABLK-RFC1918-IANA-RESERVEDRFC1918
127.0.0.0/8SPECIAL-IPV4-LOOPBACK-IANA-RESERVEDRFC6598
169.254.0.0/16SHARED-ADDRESS-SPACE-RFCTBD-IANA-RESERVEDRFC3927
172.16.0.0/12PRIVATE-ADDRESS-ABLK-RFC1918-IANA-RESERVEDRFC1918
192.0.0.0/24SPECIAL-IPV4-REGISTRY-IANA-RESERVEDRFC5736
192.0.2.0/24IANA Special UseRFC5737
192.88.99.0/246TO4-RELAY-ANYCAST-IANA-RESERVEDRFC1198
192.168.0.0/16PRIVATE-ADDRESS-ABLK-RFC1918-IANA-RESERVEDRFC1918
198.18.0.0/15SPECIAL-IPV4-BENCHMARK-TESTING-IANA-RESERVEDRFC2544
198.51.100.0/24TEST-NET-1RFC5737
203.0.113.0/24TEST-NET-3RFC5737
224.0.0.0/4マルチキャスト(クラスD)RFC3171
240.0.0.0/4クラスERFC1112
255.255.255.255ブロードキャストRFC919,RFC922
RFCは廃止される場合がある。すなわち予約アドレスが常に同じとは限らないし、それを規定するRFCも同じであるとは限らない。例えばプライベートアドレスは初めRFC1597で規定されたが、今は廃止され、現在はRFC1918で規定されている。

UNIX系OSでは、いくつかの例外を除いてIPアドレスの情報をwhoisコマンドで調べることができる。例えば127.0.0.1のIPアドレスについて調べたい時、次のようにすれば良い。

user% whois 127.0.0.1

ドメイン

人間がIPアドレスを指定する際、多くの場合はIPアドレスを指定する代わりにドメイン名といわれるコンピュータ名を指定する。ドメイン名はICANN(Internet Corporation for AssignedNames andNumbers)と呼ばれる団体によって管理される。ドメイン名の情報は、アプリケーション層のWHOISプロトコルを使用して取得できる。UNIX系では、そのためのクライアントアプリとしてwhoisがある。

user% whois google.co.jp

ドメインは、アプリケーション層のDNSという仕組みによって成り立つ。ドメイン名はDNSサーバによって管理され、DNSクライアントでアクセスすることで、ドメイン名からIPアドレスへ変換することができる。

user% nslookup google.co.jp


ルーティング

ルーティングとは、パケットの経路制御のことである。ルーティングはルーティングテーブルに基づいてルート(経路)を探索する。ルーティングは次の2種類に分類できる。

静的ルーティング
手動でルーティングテーブルの中身を設定する方法。
動的ルーティング
アルゴリズムに基づいて自動でルーティングテーブルの中身を設定する方法。経路決定アルゴリズムには次の2種類がある。
  • 距離ベクトルアルゴリズム(DVA:Distance Vector Algorithm)
  • リンク状態アルゴリズム(LSA:Link State Algorithm)

ここでルーティングの仕組みを紹介する。次のような3つのネットワークインタフェースを持つノードがあるとする。

lo
127.0.0.1
eth0
192.168.1.2/24
eth1
173.194.117.183/16
この時、ルーティングテーブルは次のような情報を持つ。
ネットワーク/ノードゲートウェイインタフェース
デフォルト192.168.1.1eth0
192.168.1.0/24*eth0
173.194.0.0/16*eth1
127.0.0.1/8*lo
ゲートウェイとは、あるパケットを別のネットワークに転送してくれるためのノードのことである。ここで、*はゲートウェイが設定されていないこと、すなわちそのネットワークに属するノードであることを示す。同じネットワーク内のノードであれば、データリンク層で接続されているため、直接通信可能である。また、全てのルーティングテーブルには、デフォルトルートと呼ばれるものがある。もしルーティングテーブルに宛先のネットワークが載っていない場合、デフォルトルートを使用する。

次のようなネットワークで前述のノードが通信を行うとする。

この時、送信元IPアドレスから宛先IPアドレス(64.4.11.37)までの経路は次のようになる。
  1. 宛先のネットワークが不明のため、デフォルトルートを使用。eth0のネットワークインタフェースを使用し、192.168.1.1に送信。
  2. 203.216.243.243に送信。
  3. 64.4.11.37に送信。
送信元ノードは、経路途中にあるノードのルーティングテーブルの情報が分からなくても問題ない。また、各ネットワーク内のノード間はデータリンク層で接続されており、識別にはMACアドレスが使用されている。データリンク層の通信については本稿では詳しく言及しない。IPアドレスはARPによってMACアドレスに変換することができる。

ネットワークインタフェースの情報は、UNIX系OSではifconfig、Windowsではipconfigコマンドで、ルーティングテーブルの情報は、UNIX系OSもWindowsも、routeコマンドや、netstatコマンドの-rオプションで表示したり設定したりできる。また、パケットが辿った経路については、tracerouteコマンドで確認することができる。


関連コマンド

以下にネットワーク層に関するコマンドをいくつか紹介する。なおここで紹介するコマンドは、主にUNIX系OSを想定している。

whois
IPアドレスやドメインの情報をRFC3912のデータベースより検索するコマンド。ドメインとはIPアドレスに対応づけた名前のことで、"google.co.jp"や"yahoo.co.jp"などがそれに該当する。whoisの使い方は次の通りである。
user% whois 173.194.117.166
これによりネットワークの大きさや名前、それを管理する団体の情報などを取得できる。また、ドメインを指定することでそのドメインの管理者や有効期限などの情報を取得できる。
user% whois google.co.jp
nslookup
dig
ドメインとIPアドレスを変換するにはnslookupやdigコマンドがある。nslookupコマンドはWindowsにもあり、基本的な使い方は同じである。nslookupコマンドの使い方は、コマンドの引数を指定する方法と対話する方法の2種類がある。
user% nslookup google.co.jp
user% nslookup
> google.co.jp
traceroute
パケットの経路を調査し、出力するコマンド。
user% traceroute google.co.jp
tracerouteのオプションをいくつか紹介する。
-p port
ポート番号を指定。
-i device
デバイスを指定。
ping
ICMP Echo Requestパケットを送信するコマンド。pingはUNIX系OSだけでなくWindowsでも使用可能である。以下にUNIX系OSのpingのオプションをいくつか紹介する。
-v
詳細な情報を出力。
-b
ブロードキャストで行う。
-R
経路を表示。
-i wait
個々の送信間隔をwait秒分間を置く。標準では1秒。
pingは次のようにして使用する。
user% ping google.co.jp
netstat
ネットワークに関する情報や状態を表示・設定するコマンド。以下にいくつか例を示す。UNIX系OSにもWindowsにもあるコマンドだが、使い方(オプション)は異なる。
ルーティングテーブル
user% netstat -r
UNIX系OS、Windows共に-rは同じである。
user% netstat --route
user% route
ネットワークインタフェース
user% netstat -i
user% netstat --interfaces
使用中のソケット情報を確認(つまりポートの状態も確認できる)
user% netstat -a
user% netstat --all
プロトコル毎のログの統計
user% netstat -s
user% netstat --statistics
なおオプション-nを指定することで、アドレスやポート番号をそのまま数字で表示する。
route
ルーティングテーブルの表示・設定を行うコマンド。routeは基本的に処理とそれに対する引数を指定する。処理を指定しなければ現在のルーティングテーブルを表示する。
add
ルーティングテーブルへの追加処理。
  • user% route add -net 192.168.1.0 netmask 255.255.255.0 dev eth0
  • user% route add -host 192.168.1.2 gw 192.168.1.1 dev eth0
  • user% route add -net default gw 192.168.1.1 dev eth0
del
ルーティングテーブルからの削除処理。
  • user% route del -net 192.168.1.0 netmask 255.255.255.0 dev eth0
  • user% route del -host 192.168.1.2 gw 192.168.1.1 dev eth0
  • user% route del -net default
ifconfig
ipconfig
ネットワークインタフェースの情報を表示・設定するコマンド。UNIX系OSはifconfig、Windowsはipconfigであり、使い方も異なる。
user% ifconfig -a
user% ipconfig /all
設定にはルート権限が必要である。 例えばIPアドレスとネットワークマスクは次のようにして設定する。
user% ifconfig eth0 192.168.1.100 netmask 255.255.255.128 
これ以外にもさまざまな設定がある。例えば通常ネットワークデバイスは自分のIPアドレス以外のパケットは破棄する(データリンク層でユニキャストを実現する)が、プロミスキャスモードというモードを有効にすれば、それを受信できる。
user% ifconfig eth0 promisc
DHCP
5階層TCP/IPモデルのアプリケーション層のDHCPによってIPアドレスを設定する場合、IPアドレスはサーバによって割り当てられる。そして多くのルータはDHCPサーバの機能を持つ。それゆえ多くのルータが使用される環境では、個々のノードが自身のIPアドレスを決めることはないだろう。UNIX系OSでは、DHCPクライアントにdhclientコマンドがある。以下に簡単な使い方を紹介する。
user% dhclient eth0
iwconfig
iwspy
無線のネットワークインタフェースのためのコマンド。
tcpdump
パケットスキャニングツール。5階層TCP/IPモデルのより上位の層のためにも活用できるコマンドで、指定したネットワークインタフェースが扱ったパケット情報を出力する。tcpdumpについてはアプリケーション層のところで詳述する。
user% tcpdump -i eth0
-i interface
ネットワークインタフェースを指定。
-e
イーサネットフレームのヘッダを表示。
-x
-X
パケットの中身を16進数で表示。-Xの場合、それに加えてASCII文字に変換したものも表示。
-n
アドレス(IPアドレスやポート番号)を名前に変換しない。
-N
ホストを名前に変換しない。
expression
パケットフィルタ機能。いかにいくつかの機能を紹介する。
proto
プロトコルを指定。
src host
送信元アドレスを指定。
src port port
送信元のポート番号を指定。
dst host
宛先アドレスを指定。
dst port port
宛先のポート番号を指定。
and
or
not
いくつかの条件を組み合わせる
iptables
PF
パケットフィルタツール。iptablesはLinux用の、pfは主にBSD系で使用されるパケットフィルタである。iptablesの詳細はここを参照されたい。

パケットプログラミング

IPパケットの送信

ネットワーク層のサービスを利用してデータを送信する例を紹介する。IPパケットを生成して送信するプログラムのソースコードは、次のように記述できる。なおこのコードはエラー処理のコードを記述していない。

#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

int main(int argc, char *argv[])
{
  const int ON=1;
  const char* DST_ADDR = "192.168.1.1";
  const unsigned char IP_PACKET[] = {
    0x45, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x40, 0x00,
    0xFF, 0x04, 0x00, 0x00,
    0xad, 0xc2, 0x7e, 0x0d, // src 173.194.126.13
    0xc0, 0xa8, 0x01, 0x01, // dst 192.168.1.1
    0x00, 0x01, 0x02, 0x03, 
    0x04, 0x05, 0x06, 0x07
  };
  int sock;
  struct sockaddr_in sin;
  
  memset(&sin, 0, sizeof(struct sockaddr_in));
  sin.sin_family = PF_INET;
  sin.sin_addr.s_addr = inet_addr(DST_ADDR);
  sin.sin_port = 0;
  
  sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);  
  setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &ON, sizeof(int));
  sendto(sock, IP_PACKET, sizeof(IP_PACKET), 0, (struct sockaddr*)&sin, sizeof(sin));
  
  return 0;
}
このコードは、IPパケットを送信するプログラムである。このプログラムを正常に実行するにはルート権限が必要である。

タイプがSOCK_RAWについては、マニュアル第7章のrawを参照されたい。

user% man 7 raw
マニュアルによると、IPヘッダの大きさやヘッダ・チェックサムは関数によって自動的に計算される。また、ソースアドレスとパケットIDは0の場合に変更される。 このプログラムを実行し、そのパケットをtcpdumpで見た結果を以下に示す。
15:43:32.732162 IP 173.194.126.13 > 192.168.1.1: IP0 [|ip]
     (ipip-proto-4)
     0x0000:  4500 001c 0000 4000 ff04 8e64 adc2 7e0d
     0x0010:  c0a8 0101 0001 0203 0405 0607

IPパケットの受信

ICMPパケットを受信するようなプログラムのコードは次のように記述される。このコードも同様にエラー処理を省略している。

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
  int i;
  int sock;
  unsigned char packet[0x54];
  
  sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
  while (1){
    recv(sock, packet, sizeof(packet), 0);
    for (i=0;i<0x54;i++){
      if (i%4==0) putchar('\n');
      printf("0x%.2x ", packet[i]);
    }
    putchar('\n');
  }
  close(sock);
  return 0;
}
このプログラムもまた正常に実行するにはルート権限が必要である。

このプログラムを起動中に、127.0.0.1宛にpingをすると、次のように画面に出力されるだろう。

0x45 0x00 0x00 0x54 
0x80 0x72 0x00 0x00 
0x40 0x01 0xfc 0x34 
0x7f 0x00 0x00 0x01 
0x7f 0x00 0x00 0x01 
0x00 0x00 0x19 0xed 
0x18 0xaa 0x00 0x01 
0xa9 0x65 0x07 0x53 
0x2c 0xac 0x05 0x00 
0x08 0x09 0x0a 0x0b 
0x0c 0x0d 0x0e 0x0f 
0x10 0x11 0x12 0x13 
0x14 0x15 0x16 0x17 
0x18 0x19 0x1a 0x1b 
0x1c 0x1d 0x1e 0x1f 
0x20 0x21 0x22 0x23 
0x24 0x25 0x26 0x27 
0x28 0x29 0x2a 0x2b 
0x2c 0x2d 0x2e 0x2f 
0x30 0x31 0x32 0x33 
0x34 0x35 0x36 0x37 

一覧