Ubuntu:DHCPで動的に取得したIPアドレスを自動でDNSに登録するスクリプト

# はじめに

初心者がChef serverとBIND9サーバをChefを使いながら、設定していました。n番煎じかはわかりませんが、後日手順を公開いたします。

そして、無事にDNSサーバを構築することができたのです。しかし、問題がありました。それはDHCPでIPアドレスを取得したクライアント側が、いちいち`nsupdate`を使ってDNSサーバに通知するのが面倒な事です。
ですので、[ubuntu 12.04 を起動しても DNS に名前登録されない](http://www.compnet.jp/archives/2655)のスクリプトを少し改造して、自動化するようにします。
既に当たり前なのかもしれないのですが、探すのに苦労したので記事にしてみました。

## 登場PC

| 役割　　　　　　　| FQDN                 | IPアドレス     | OS                   |
|:---------------|:---------------------|:--------------|:---------------------|
| DNSサーバ       | yakitori.example.jp  | 192.168.11.5  | Ubuntu 15.10 Server  |
| DHCPクライアント | karaage.example.jp   | 192.168.11.51 | Ubuntu 15.10 Desktop |
| ゲートウェイ     | 無線ルーター           | 192.168.11.1  | Buffaloのなんか       |

# 手順

## スクリプトを書く（振りをしたコピー＆ペースト）

以下のスクリプトを適当なファイル名で保存します。
そして、`chmod u+x スクリプト名`で実行権限を忘れずに付与します。

```bash:IP取得およびリリース時などにDNSへ通知する
#!/bin/bash
SED=/bin/sed
PHASE=`echo "$script" | $SED -r 's%^.*/[^/]*-(enter|exit)-.*/[^/]*$%\1%i'`
NSUPDATE=/usr/bin/nsupdate

AWK=/usr/bin/awk
convert_ip4_inaddr() {
  #=- $1  ... ip4 address
  #=- ret ... in-addr string
  ###
  [ -n "$1" ] && echo `echo $1 | $AWK -F . '{ printf( "%d.%d.%d.%d.in-addr.arpa.", $4, $3, $2, $1 ) }'`
}

case ${reason} in
  BOUND|RENEW|REBIND|REBOOT)
    if [ $PHASE = "exit" ]; then
      new_fqdn=`hostname -f`
      new_inaddr=`convert_ip4_inaddr ${new_ip_address}`
      if [ ! -z ${new_fqdn} ]; then
        echo "nsupdate update add ${new_fqdn} 3600 IN A ${new_ip_address}."
        echo "nsupdate update delete ${new_inaddr} 3600 IN PTR ${new_fqdn}."
        $NSUPDATE <<__END__
update add ${new_fqdn} 3600 IN A ${new_ip_address}
send
update add ${new_inaddr} 3600 IN PTR ${new_fqdn}
send
__END__
      fi
    fi
    ;;
  EXPIRE|FAIL|RELEASE|STOP)
    if [ $PHASE = "enter" ]; then
      old_fqdn=`hostname -f`
      old_inaddr=`convert_ip4_inaddr ${old_ip_address}`
      if [ ! -z ${old_fqdn} ]; then
        echo "nsupdate update delete ${old_fqdn} 3600 IN A ${old_ip_address}."
        echo "nsupdate update delete ${old_inaddr} 3600 IN PTR ${old_fqdn}."
        $NSUPDATE <<__END__
prereq yxrrset ${old_fqdn} IN A ${old_ip_address}
update delete ${old_fqdn} 3600 IN A ${old_ip_address}
send
prereq yxrrset ${old_inaddr} IN PTR ${old_fqdn}
update delete ${old_inaddr} 3600 IN PTR ${old_fqdn}
send
__END__
      fi
    fi
    ;;
esac
```

## フックディレクトリに貼り付ける

以下の２つのディレクトリに、スクリプトを配置します。
`sudo cp`でコピーすることをお忘れなく。
`/etc/dhcp/dhclient-enter-hooks.d`
`/etc/dhcp/dhclient-exit-hooks.d`

#　実行する

Windowsの`ipconfig /renew`的なコマンドで実行確認してみます。
わたしは面倒なので、`alias dhcprenew="sudo dhclient -v -r eth0 && sudo dhclient -v eth0"`として、エイリアス登録してます。

```bash:スクリプトを実行する
$cd ~
$ sudo dhclient -v -r eth0 && sudo dhclient -v eth0
Killed old client process
Internet Systems Consortium DHCP Client 4.3.1
Copyright 2004-2014 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/eth0/00:15:5d:40:7f:1c
Sending on   LPF/eth0/00:15:5d:40:7f:1c
Sending on   Socket/fallback
DHCPRELEASE on eth0 to 192.168.11.1 port 67 (xid=0x3de9b062)
nsupdate update delete karaage.example.jp 3600 IN A 192.168.11.51.
Internet Systems Consortium DHCP Client 4.3.1
Copyright 2004-2014 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/eth0/(省略)
Sending on   LPF/eth0/(省略)
Sending on   Socket/fallback
DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3 (xid=0x15086907)
DHCPREQUEST of 192.168.11.51 on eth0 to 255.255.255.255 port 67 (xid=0x7690815)
DHCPOFFER of 192.168.11.51 from 192.168.11.1
DHCPACK of 192.168.11.51 from 192.168.11.1
nsupdate update add karaage.example.jp 3600 IN A 192.168.11.51.
bound to 192.168.11.51 -- renewal in 75222 seconds.
```

# 検証する

本当にDNSサーバーに登録されているか確認します。

```bash:名前でIPアドレスを引く
$ dig karaage.example.jp

; <<>> DiG 9.9.5-11ubuntu1.1-Ubuntu <<>> karaage.example.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63215
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;karaage.example.jp.	IN	A

;; ANSWER SECTION:
karaage.example.jp. 3600	IN	A	192.168.11.51

;; AUTHORITY SECTION:
example.jp.	10800	IN	NS	yakitori.example.jp.

;; ADDITIONAL SECTION:
yakitori.example.jp. 10800	IN	A	192.168.11.5

;; Query time: 0 msec
;; SERVER: 192.168.11.5#53(192.168.11.5)
;; WHEN: Thu Jan 07 16:00:36 JST 2016
;; MSG SIZE  rcvd: 107
```

次は逆引きをしてみます。

```bash:逆引きでホスト名を問い合わせる
$ dig -x 192.168.11.51

; <<>> DiG 9.9.5-11ubuntu1.1-Ubuntu <<>> -x 192.168.11.51
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3505
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;51.11.168.192.in-addr.arpa.	IN	PTR

;; ANSWER SECTION:
51.11.168.192.in-addr.arpa. 3600 IN	PTR	karaage.example.jp.

;; AUTHORITY SECTION:
11.168.192.in-addr.arpa. 86400	IN	NS	yakitori.example.jp.

;; ADDITIONAL SECTION:
yakitori.example.jp. 10800	IN	A	192.168.11.5

;; Query time: 0 msec
;; SERVER: 192.168.11.5#53(192.168.11.5)
;; WHEN: Thu Jan 07 16:06:30 JST 2016
;; MSG SIZE  rcvd: 131
```

無事できました。ヤッター！

# おわりに

ネットワークにほとんど詳しくないので、間違いがあればご指摘ください。
お読みいただきありがとうございました。

# 参考サイト

* [ubuntu 12.04 を起動しても DNS に名前登録されない](http://www.compnet.jp/archives/2655)