LinuxでDHCPについて勉強してみた

DHCPについてあんまりよく分かってない部分もあったので、手を動かしながら確認した時のメモ

# 環境

+ Amazon Linux AMI 2016.03.0 (HVM)
+ dhclient isc-dhclient-4.1.1-P1


# 参考

+ [インフラエンジニア教本　――ネットワーク構築技術解説 ](http://www.amazon.co.jp/gp/product/B00ZQJRF4O/ref=s9_simh_gw_g351_i1_r?pf_rd_m=AN1VRQENFRJN5&pf_rd_s=desktop-1&pf_rd_r=1PK6HZNQYK6GMN0BGJ3V&pf_rd_t=36701&pf_rd_p=302362649&pf_rd_i=desktop)

# 基本知識

参考にさせて頂いた書籍の通りですが、DHCPによるIPアドレスの取得はクライアントとサーバーで以下のような流れで通信を行い、IPアドレスやDNSなどの設定を行っています。

+ DHCP-DISCOVER(Clinet->Server)->ブロードキャストでDHCPサーバーを探してIPアドレス割当を要求
+ DHCP-OFFER(Server->Clinet)->DHCP-DISCOVERに対して割り当て候補のIPアドレスを通知
+ DHCP-REQUEST(Client->Server)->DHCP-OFFERで提示されたIPアドレスの使用を要求。もしくは利用期間の延長要求
+ DHCP-ACK(Server->Client)->クライアントの要求受け入れ


# 実際のファイルを確認する

[Linux ネットワーク基本設定 其の三](http://kazmax.zpp.jp/network/net1.html)

[14.2.1. Ethernet Interfaces](https://www.centos.org/docs/5/html/5.2/Deployment_Guide/s2-networkscripts-interfaces-eth0.html)

[CentOS > dhclientの設定](http://sweng.web.fc2.com/ja/linux/centos/dhclient.html)

まずはDHCPでプライベートIPを割り当てるネットワークインターフェースeth0の設定を確認してみます。

```text:/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet
USERCTL=yes
PEERDNS=yes
IPV6INIT=no
PERSISTENT_DHCLIENT=yes
RES_OPTIONS="timeout:2 attempts:5"
```

+ DEVICE->インターフェース名
+ BOOTPROTO->IPアドレスの指定をDHCPを使ってやるのでdchpを指定
+ ONBOOT->起動時にこのネットワークインターフェースを有効にするか。起動時に有効にしたいのでyes
+ TYPE->インターフェースの種類。Ethernetを指定
+ USERCTL->一般ユーザーがインターフェースの有効無効を指定できるか。yesだと一般ユーザーが有効無効を切り替えることができる。
+ PEERDNS->DNSの設定をする/etc/resolv.confをDHCPやDNSディレクティブの設定によって変更するか。NOだと既に設定してある/etc/resolv.confを変更することはなく、YESだと変更する可能性がある
+ IPV6INIT->インターフェースに対してIPv6を有効化するか
+ PERSISTENT_DHCLIENT->DHCP-DISCOVERYリクエストに対してDHCP-OFFERがない場合に再送するか否か。YESにすると再送を行う。
+ RES_OPTIONS->これが明確なドキュメントが見つけられなかったのですが、タイムアウト2秒、接続確認が5回ということを意味していると思われます。

また、DHCPサーバーから取得した割り当てを行う設定(IPアドレスやDNSなど）や設定の期限などは以下のファイルに追記されていきます。

```text:/var/lib/dhclient/dhclient-eth0.leases
・・・
lease {
  interface "eth0";
  fixed-address 172.31.27.76;
  option subnet-mask 255.255.240.0;
  option routers 172.31.16.1;
  option dhcp-lease-time 3600;
  option dhcp-message-type 5;
  option domain-name-servers 172.31.0.2;
  option dhcp-server-identifier 172.31.16.1;
  option interface-mtu 9001;
  option broadcast-address 172.31.31.255;
  option host-name "ip-172-31-27-76";
  option domain-name "ap-northeast-1.compute.internal";
  renew 6 2016/04/23 23:50:36;
  rebind 0 2016/04/24 00:18:19;
  expire 0 2016/04/24 00:25:49;
}

lease {
  interface "eth0";
  fixed-address 172.31.27.76;
  option subnet-mask 255.255.240.0;
  option routers 172.31.16.1;
  option dhcp-lease-time 3600;
  option dhcp-message-type 5;
  option domain-name-servers 172.31.0.2;
  option dhcp-server-identifier 172.31.16.1;
  option interface-mtu 9001;
  option broadcast-address 172.31.31.255;
  option host-name "ip-172-31-27-76";
  option domain-name "ap-northeast-1.compute.internal";
  renew 0 2016/04/24 00:19:59;
  rebind 0 2016/04/24 00:43:06;
  expire 0 2016/04/24 00:50:36;
}
```

# 実際に動かして挙動を確認する

ネットワークインターフェースを再起動し、ログより挙動を確認してみます。

```bash
$sudo service network restart
Shutting down interface eth0:                              [  OK  ]
Shutting down loopback interface:                          [  OK  ]
Bringing up loopback interface:                            [  OK  ]
Bringing up interface eth0:
Determining IP information for eth0... done.
                                                           [  OK  ]
```

```text:/var/log/messages
Apr 24 01:34:22 ip-172-31-27-76 dhclient[32184]: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x5fce2d16)
Apr 24 01:34:22 ip-172-31-27-76 dhclient[32184]: DHCPACK from 172.31.16.1 (xid=0x5fce2d16)
Apr 24 01:34:24 ip-172-31-27-76 NET[32231]: /sbin/dhclient-script : updated /etc/resolv.conf
Apr 24 01:34:24 ip-172-31-27-76 dhclient[32184]: bound to 172.31.27.76 -- renewal in 1607 seconds.
```

+ 1行目->eth0がDHCPによってIPアドレスの取得を行う設定になっているのでDHCP-REQUESTを要求
+ 2行目->DHCPサーバー(172.31.16.1)からDHCP-ACKリクエストを受信
+ 3行目->/sbin/dhclient-script(シェルスクリプト)を実行して/etc/resolv.confを更新
+ 4行目->eth0に172.31.27.76を設定

という事が分かります。

DHCP-DISCOVERについてのリクエストを行っていませんが、`/var/lib/dhclient/dhclient-eth0.leases`に既に情報がある場合にはこの情報を利用し、再度同じIPアドレスの使用をDHC-REQUESTで行っているためです。

試しにファイルを削除して確認してみます。

```bash
# 退避
$mv /var/lib/dhclient/dhclient-eth0.leases /tmp/

# 再起動
$sudo service network restart
```

```text:/var/log/messages
Apr 24 01:58:11 ip-172-31-27-76 dhclient[32699]: DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 8 (xid=0x4c3b386d)
Apr 24 01:58:11 ip-172-31-27-76 dhclient[32699]: DHCPOFFER from 172.31.16.1
Apr 24 01:58:11 ip-172-31-27-76 dhclient[32699]: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x4c3b386d)
Apr 24 01:58:11 ip-172-31-27-76 dhclient[32699]: DHCPACK from 172.31.16.1 (xid=0x4c3b386d)
Apr 24 01:58:12 ip-172-31-27-76 NET[32746]: /sbin/dhclient-script : updated /etc/resolv.conf
Apr 24 01:58:12 ip-172-31-27-76 dhclient[32699]: bound to 172.31.27.76 -- renewal in 1669 seconds.
```

上記のようにDHCP-DISCOVERのリクエストから確認出来ました。

# bootからdhclientプロセスが起動するまでの流れを確認してみる

DHCPサーバーとのやりとりはdhclientというプロセスが起動しているようなのですが、どのように呼ばれているか分からなかったので確認してみました。

```bash
# 以下のオプションでプロセスが起動している
$ps aux |grep dhc|grep -v grep
root       817  0.0  0.1   9360  1344 ?        Ss   02:17   0:00 /sbin/dhclient -q -lf /var/lib/dhclient/dhclient-eth0.leases -pf /var/run/dhclient-eth0.pid eth0

# initプロセスから起動
$pstree -p
init(1)-+-agetty(2502)
        |-atd(2469)
        |-auditd(2086)---{auditd}(2087)
        |-crond(2455)
        |-dbus-daemon(2199)
        |-dhclient(817)

```

rcスクリプトでnetworkのサービスを起動するスクリプトがあり、その内容を確認します。

```bash:/etc/rc.d/init.d/network
# /etc/sysconfig/network-scripts/ifupスクリプトを実行
action $"Bringing up loopback interface: " ./ifup ifcfg-lo
```

```bash:/etc/sysconfig/network-scripts/ifup

OTHERSCRIPT="/etc/sysconfig/network-scripts/ifup-${DEVICETYPE}"

# OTHERSCRITP変数に指定されたファイルが存在するか確認
if [ ! -x ${OTHERSCRIPT} ]; then
    OTHERSCRIPT="/etc/sysconfig/network-scripts/ifup-eth"
fi

exec ${OTHERSCRIPT} ${CONFIG} $2
```

```bash:/etc/sysconfig/network-scripts/ifup-eth

# /sbin/dhclientが存在し、DYNCONFIG変数が指定されたか確認
if [ -n "${DYNCONFIG}" -a -x /sbin/dhclient ]; then
    if [[ "${PERSISTENT_DHCLIENT}" =  [yY1]* ]]; then
       ONESHOT="";
    else
       ONESHOT="-1";
    fi;
    generate_config_file_name
    # copy any lease obtained by the initrd
    for file in /dev/.dhclient-${DEVICE}.leases /dev/.initramfs/net.${DEVICE}.lease ; do
        if [ -f "${file}" ]; then
            mv -f $file /var/lib/dhclient/dhclient-${DEVICE}.leases
            [ -x /sbin/restorecon ] && restorecon /var/lib/dhclient/dhclient-${DEVICE}.leases > /dev/null 2>&1
        fi
    done
:
    DHCLIENTARGS="${DHCLIENTARGS} ${DHCP_HOSTNAME:+-H $DHCP_HOSTNAME} ${ONESHOT}
 -q ${DHCLIENTCONF} -lf /var/lib/dhclient/dhclient-${DEVICE}.leases -pf /var/run
/dhclient-${DEVICE}.pid"
    echo
    echo -n $"Determining IP information for ${DEVICE}..."
    if [[ "${PERSISTENT_DHCLIENT}" !=  [yY1]* ]] && check_link_down ${DEVICE}; t
hen
        echo $" failed; no link present.  Check cable?"
        exit 1
    fi

    ethtool_set

    ##　ここでプロセスを起動
    if /sbin/dhclient ${DHCLIENTARGS} ${DEVICE} ; then
                echo $" done."
                dhcpipv4="good"
    else
```

最後の`/etc/sysconfig/network-scripts/ifup-eth`のシェルスクリプトの部分でプロセスを起動するコマンドが確認できました。

`/var/log/messages`を見るとこのプロセスがDHCPサーバーにたまに問い合わせを行っているので`/var/lib/dhclient/dhclient-eth0.leases`などのリースファイルを確認し、期限切れの場合やIPアドレス利用の延長依頼などを行っているようです。