ホーム » コンピュータ (ページ 3)

コンピュータ」カテゴリーアーカイブ

サーバ⚙

アーカイブ

カテゴリー

ファイアウォールとiptables

インターネットからの攻撃を防ぐには、ファイアウォールが必要となる。外部からの接続をうけるコンピュータは、ファイアウォールがどう設定されているのか把握することが重要。

ファイアウォールとDMZ

ファイアウォールは、パケットの(送信元IPアドレス,送信元ポート番号)、(宛先IPアドレス,宛先ポート番号)を見て、通信を制限するルータであり、専用のファイアウォールではさらに細かい制限を加えたり、通信履歴を保存することができる。

組織向けの外部公開のWebサーバやメールサーバを持つ組織では、外部からの接続をうける必要があり、脆弱性があればサーバは乗っ取りなどの被害に会いやすい。サーバが被害を受けたらファイアウォール内部のコンピュータに被害が広がる(トロイの木馬)のは危険であることから、(1) DMZ(非武装地帯)内部に外部公開のサーバを置き、(2) 対外FireWallで外部からのパケットはすべてDMZだけに通す。(3) 内部FireWall では、DMZ の特定の受信パケットだけ流す様にする。

DMZ内部のサーバは、外部からの攻撃をうけるため、極めて慎重にセキュリティ対策を行う必要がある。

iptables

Linux で FireWall を構築するときには、iptables を用いる。iptables では、主に以下の3つのルール(チェイン)でパケットを制限できる。

  • コンピュータに入ってくるパケットに対するルール(INPUT チェイン)、
  • コンピュータから出ていくパケットに対するルール(OUTPUTチェイン)、
  • コンピュータで中継するパケットに対するルール(FORWARDチェイン)

iptables の設定を見るには、iptables -L を実行する。

$ sudo iptables -L  # すべてのルールを表示
Chain INPUT (policy DROP)
target     prot opt source           destination         
DROP       all  --  anywhere         anywhere      state INVALID
ACCEPT     all  --  192.168.11.0/24  anywhere            
ACCEPT     tcp  --  anywhere         anywhere      tcp dpt:http
ACCEPT     tcp  --  anywhere         anywhere      tcp dpt:https
:
Chain FORWARD (policy DROP)
target     prot opt source           destination         
DROP       all  --  anywhere         anywhere      state INVALID
ACCEPT     all  --  127.0.0.0/8      anywhere            
ACCEPT     all  --  192.168.11.0/24  anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source           destination         
ACCEPT     all  --  anywhere         anywhere      state RELATED,ESTABLISHED

iptables で制限のための設定を間違えると、通信ができなくなるので、基本的な考え方だけを紹介する。

「条件にマッチしたパケットをどうするのか」というルールを、チェインに並べておき、パケットが届くとチェインの先頭からルールを適用し、ACCEPT/REJECT/DROPなどの対応を決める。

iptables でルールを登録する場合は、一般的に以下の書式で、条件1,条件2… をすべて満たすパケットをどうするのかのラベルを最後に記載する。

$ iptables -A チェイン 条件1 条件2 … -j ラベル

$ iptables -P INPUT DROP            # デフォルトポリシーの設定
  # INPUT のルールにどれもマッチしない場合はDROP(パケット廃棄)
$ iptables -P OUTPUT ACCEPT
  # OUTPUT のどのルールにもマッチしなければACCEPT(受信許可)

$ iptables -A INPUT -s 127.0.0.1 -j ACCEPT
  # INPUT の末尾に、"送信元IPが 127.0.0.1 ならACCEPT" を追加

$ iptables -A INPUT --dport 80 -j ACCEPT
  # INPUT の末尾に、"宛先ポートが 80 ならACCEPT" を追加

$ iptables -A INPUT -s 11.22.33.44 -j DROP
  # INPUT の末尾に、"送信元IPが 11.22.33.44 ならDROP" を追加

iptablesのオプション引数
  -P      デフォルトポリシーの設定
  -A      末尾にルールを追加
  -s      送信元IPアドレスの条件指定
  -d      宛先IPアドレスの条件指定
  --sport 送信元ポート番号の条件指定
  --dport 宛先ポート番号の条件指定
  -j      指定ラベルに移動

INPUT chain
  |
<送信元IPが127.0.0.1なら>----ACCEPT
  |
<宛先ポートが80なら>----------ACCEPT
  |
<送信元IPが11.22.33.44なら>--DROP
  |
  DROP

ユーザとリモート処理

Linux ではユーザを切替えながら処理を実行したり、ネットワークを越えて命令を実行することができる。外部から攻撃を受けてバックドアが仕掛けられていて不正侵入をうけているのか確認する時に、どういったユーザの処理を実行しているのか把握し、リモート接続で処理ができるような状態なのか知ることが重要。

ユーザとユーザの切り替え

ユーザ,グループの管理

unix では、ユーザ情報は /etc/passwd , /etc/group で管理している。passwdファイル先頭の、ユーザ番号 0 は、なんでもできる権限を持つシステム管理者 root となっている。ユーザ番号 1~999 は、システムを動かすための特殊なユーザとなっている。1000以上は、実際のユーザに割り当てることが多い。

((( /etc/passwd )))
root:x:0:0:root:/root:/bin/bash
sshd:x:111:65534::/var/run/sshd:/usr/sbin/nologin
tsaitoh:x:1000:1000:Tohru Saitoh,,,:/home/tsaitoh:/bin/zsh
| tsaitoh = ユーザ名
| x       = 昔はパスワードが書いてあった, *ならアカウントロック
| 1000    = ユーザ番号
| 1000    = グループ番号
| Tohru Saitoh,,, = ユーザの名前など
| /home/tsaitoh   = ホームディレクトリ
| /bin/zsh        = シェル
  
((( /etc/group )))
root:x:0:
ssh:x:112:
home:x:1000:tsaitoh
| home = グループ名
| x    = 昔はパスワードが書いてあった, *ならアカウントロック
| 1000 = グループ番号
| tsaitoh = グループに所属するユーザ名(コンマ区切り)

ただし、/etc/passwd, /etc/group は、全ユーザが読めるファイルで、暗号化されたパスワードを覚えるには不向きなので、/etc/shadow , /etc/gshadow に保存されている。

ユーザの確認

自分の情報を確認するには、whoamiid , finger コマンドを用いる。

$ whoami    # ユーザ名を表示
tsaitoh

$ id        # UIDやGIDなどの情報を表示
uid=1000(tsaitoh) gid=1000(home) ....

$ finger    # ユーザの詳しい情報を表示
Login    Name           Tty      Idle  Login Time   Office          Office Phone
tsaitoh  Tohru Saitoh   pts/0          Feb 17 22:47 (192.168.11.xx) 12-3456

su コマンド

ユーザを切り替えるには、su コマンドを用いる(Set User)。別ユーザで命令を実行することもできる。ただし、その別ユーザのパスワードが必要。

$ su root
Password: ●●●●●●●●
# exit

$ su -c whoami root
Password: ●●●●●●●●
root

システム管理者での作業は、危険な命令も実行できる状態なので、作業ミスを減らすためにプロンプトが、# に切り替わる。

ただし、su コマンドは、切り替えるユーザのパスワードが必要である。システム管理作業を複数人で行う場合、管理者パスワードを複数人に教えることになり、セキュリティ的に危険である。

sudo コマンド

そこで、管理者などに登録した人であれば、自分のパスワードで管理者権限を得ることができる sudo (set user do) コマンドを使うのが一般的である。

$ sudo bash
Password: ●●●●●●●● 自分のパスワード
# exit
$ sudo whoami     # 管理者で whoami を実行
root

$ sudo -u foobar  # ユーザ foobar に変更
$ whoami
foobar
$ exit
$ whoami
tsaitoh

システム管理者になれるユーザの設定は、/etc/sudoers に記載されている。一般的に、sudo グループに所属していれば、管理者になれるように設定されていることが多い。

su id bit / スティッキービット

パスワードを変更するpasswdコマンドでは自分のパスワードを変更でき、/etc/passwd や /etc/shadow が書き換えられる。unixのr,w,xの権限だけの知識だと、通常ユーザ自身がpasswd,shadowファイルを書き換えられるのなら、同じファイルに記録されている他のユーザ情報(特にパスワードを変更できるはずである。であれば、他人のパスワードも変更できてしまうのではないのか? 当然、こんなことはできてはいけない。

実は、一時的に他のユーザ権限を借りて作業をするため(システム管理者の権限を借りて作業するため)に、su id bit (スティッキービット)という属性がある。

$ sudo bash
$ passwd
Password: ●●●●●●●
Re enter Password: ●●●●●●●

$ which passwd
/usr/bin/passwd

ls -al /bin/ls
-rwxr-xr-x 1 root root 138856  8月  7  2019 /bin/ls
$ ls -al /bin/passwd
-rwsr-xr-x 1 root root  63960  2月  7 23:54 /usr/bin/passwd

上記の passwd コマンドでは、ファイル属性が – rws r-x r-x となっている。(通常の ls コマンドでは、– rwx r-x r-x となっている。)

su id bit が ON になっているコマンドは、一時的に そのファイル所有者 (/usr/bin/passwd の所有者は root) の権限を借りて命令を実行できる。

ただし、スティッキービットが ON だと、管理者権限で命令を実行することができるが、そのコマンドに不備(脆弱性)があると、システムを乗っ取るためにクラッカーが悪用する場合がある。

((( suid ビットが ON のファイルを探す )))
$ find /usr/bin -perl /u=s -print
/usr/bin/password

リモート作業

ネットワークを越えて命令を実行するには、telnetrshssh コマンドを使う。telnet や rsh コマンドは、通信内容が暗号化されていないため、パケットキャプチャを使われると、パスワードなどを盗むこともできるため、通常は使ってはならない。

telnet (暗号化なしのリモート接続)

$ telnet remote-host   # remote-host という名前のコンピュータに telnet で接続
login: ユーザ名
password: パスワード
$ exit

ssh (暗号化されたリモート接続)

ssh は、通信内容を暗号化して安全にリモートコンピュータで命令を実行するコマンド。リモートコンピュータへの接続(slogin)、リモートコンピュータで命令の実行(ssh)、リモートコンピュータとのファイル転送(scp) などができる。

$ slogin remote-host   # 別コンピュータにlogin
Password: ●●●●●●●●
$ hostname             # 使っているコンピュータ名を調べるコマンド
remote-host
$ exit

$ slogin foobar@remote-host  # 指定したユーザ名(foobar)で接続
Password: foobarのパスワード
$ whoami
foobar
$ exit

$ ssh remote-host ls   # remote-host 上で ls を実行
Maildir

$ ssh foobar@remote-host whoami
foobar

$ scp test.c remote-host:~
  # ファイル test.c を remote-host のホームディレクトリにコピー(アップロード)

$ scp foobar@remote-host:hoge.txt dest-dir
  # リモートホストの hoge.txt を、dest-dir にコピー(ダウンロード)

ネットワークサービスとポートスキャン

外部からネットワーク接続を受けて、どういった処理を実行するようになっているのかを知るための方法を説明する。

ポート番号

ネットワーク通信では、通信する相手を指定するために IP アドレスが用いられるが、サーバでは、複数のプログラムが動いており、どのプログラムと接続するのかを指定するには、ポート番号を用いる。

IPアドレスを電話番号に例えるならば、ポート番号は内線電話番号に相当する。

特に、サーバではクライアントからの通信を待つために、このサービスならばこのポート番号を使うという標準番号が決まっている

SSH    = 22   # リモート接続(暗号化)
TELNET = 23   # リモート接続
SMTP   = 25   # メール送信
DNS    = 53   # DNSサービス
HTTP   = 80   # Web サーバ
POP    = 109,110 # メール受信
IMAP   = 143  # メール受信
HTTPS  = 443  # Web サービス(暗号化)
SMTPS  = 465  # メール送信(暗号化)
IMAPS  = 993  # メール受信(暗号化)
POPS   = 995  # メール受信(暗号化)

ネットワークサービス

サーバでは、クライアントからの接続の受信を待つために、あらかじめプログラムを起動しておく必要がある。
こういうサーバプログラムは、Linux の世界では デーモン と呼ぶことも多い。

ネットワークサービスを起動する方式には、いくつかの方法がある。

スーパーサーバを使う場合

ネットワーク処理のプログラムは、複雑な処理を行うためそのプログラムを起動しておくと、メモリを大量に使用する。古いコンピュータでは、処理速度の低下となるため、利用頻度の低いサーバは、汎用的なサーバを起動しておき、必要に応じてプログラムを起動する。この方法には、inetd とか xinetd が用いられる。

$ vi /etc/inetd.conf
echo stream tcp nowait tsaitoh コマンド名

上記の例では、echo=7番ポート に tcp で接続すると、ユーザ名 tsaitoh の権限で、コマンド名を実行してくれる。

デーモンを起動しておく場合

Linux では ランレベル という状態が決められている。

  • シングルユーザモード(S) – 管理者が作業中で他のネットワーク接続とかを受け付けない状態
  • システム停止(0) – 他の状態からシステム停止に移るための仮想的なランレベル
  • マルチユーザモード(2) – 複数のユーザの接続ができる状態
  • GUI環境付きのマルチユーザモード(5) – X11ディスプレイマネージャが動く状態
((( /etc/inittab の中に以下の記載がある )))
$ cat /etc/inittab
:
# The default runlevel.
id:2:initdefault:
:

$ runlevel   # 現在のランレベルを確認する方法
N 5

sysv-rc 方式

Linux では、ランレベルを変更する init コマンド(init 0 を実行すると、システムを停止できる)を実行すると、

  • /etc/rc移行元ランレベル.d 配下のKで始まるプログラムをファイル名順に実行する。
  • /etc/rc移行先ランレベル.d 配下のSで始まるプログラムをファイル名順に実行する。
$ ls /etc/rc2.d
K01aprx                         S17sudo
K01onedrive                     S17unattended-upgrades
README                          S17uuidd
S01lvm2-lvmpolld                S18acpid
S01pulseaudio-enable-autospawn  S18amavis
S14nfs-common

$ sudo /etc/init.d/apache2 start   # apache2のサーバ起動
$ sudo /etc/init.d/apache2 stop    # 停止
$ sudo /etc/init.d/apache2 restart # 再起動

systemd 方式

上記の sysv-rc 方式は、プログラムの起動スクリプトが shell で書かれているので、(システムが単純な頃は)メンテナンスが容易だったが、(システムが複雑になると)起動処理に時間がかかるのが問題となった。このため、新しい Linux では、systemd というプログラムでサーバを起動する方式にかわった。

$ ls /etc/systemd
journald.conf  network        pstore.conf    sleep.conf  system.conf     user
logind.conf    networkd.conf  resolved.conf  system      timesyncd.conf  user.conf

$ sudo systemctl list-units        # systemd のユニット一覧

$ sudo systemctl list-sockets      # 使用中のソケット一覧

$ sudo systemctl status apache2    # systemd で起動している特定のサーバの状態確認

$ sudo systemctl start   apache2   # systemd でサーバ起動
$ sudo systemctl stop    apache2   # systemd でサーバ停止
$ sudo systemctl restart apache2   # systemd でサーバ再起動

起動中のプログラムの確認

システムが通常状態で起動しているプログラムを確認するには、ps ax を用いる。

$ ps ax    # a 全プロセス表示 x 端末を持たないプロセスも表示
    PID TTY      STAT   TIME COMMAND
      1 ?        Ss     2:57 /sbin/init
      2 ?        S      0:00 [kthreadd]
      :
2229038 ?        S      0:03 /usr/sbin/apache2 -k start
      :

PIDがプロセス番号、STATは、S:処理待ち状態、R:実行状態、TIME欄は、のべ実行時間を表す。

各プロセスの親プロセスと子プロセスの関係が知りたい場合には、pstree コマンドを用いる。

$ pstree
systemd-+-/usr/sbin/amavi---2*[/usr/sbin/amavi]
        |-/usr/sbin/apach---11*[/usr/sbin/apach]
        |-ModemManager---2*[{ModemManager}]
        |-NetworkManager---2*[{NetworkManager}]

ここで、見たことのないプログラムが動いている様なら、システムの進入を受けた可能性を疑わないといけない。

ネットワーク通信で受信待ちのプログラムの確認

Linuxで開いているポートを確認するためには、netstat コマンドを用いる。

$ sudo netstat -ltup4
  # -l Listenポート、-t TCP、-u UDP、-p ポートを開いている、-4 IPv4
稼働中のインターネット接続 (サーバのみ)
Proto 受信-Q 送信-Q 内部アドレス     外部アドレス  状態        PID/Program name    
tcp       0     0 localhost:3551  0.0.0.0:*  LISTEN      841/apcupsd         
tcp       0     0 0.0.0.0:imaps   0.0.0.0:*  LISTEN      418280/dovecot  
:

nmap でポートスキャン

netstat コマンドは、対象コンピュータを使っている時には有効だが、他のコンピュータを調べるには、ポートスキャン専用の nmap を使うのが一般的。
ポートスキャンとは、相手のコンピュータに接続するポート番号を変更しながら、通信可能か調べること。

$ sudo nmap localhost
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-17 14:45 JST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.0000090s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 982 closed ports
PORT      STATE SERVICE
22/tcp    open  ssh
25/tcp    open  smtp
:

nmap で調べるための様々なオプション

$ sudo nmap -A localhost  # OSなどを調べる

$ sudo nmap -p 1-1023 localhost # 1〜1023 までのポート番号を調べる

$ sudo nmap -sU localhost  # UDPのポートスキャン

$ sudo nmap -O localhost   # OSの検出

攻撃を受けているのであれば、wireshark などのパケットキャプチャを使って、パケットの中身を調べる必要がある。

ネットワーク関連の基本

なぜか家族チームで Micro Hardening のイベントに参加予定なので、ネットワーク関連の基礎の説明を家族向けにまとめる。以下の説明は基本的に、Linux 環境に login してのお話。

ネットワークの確認(ifconfig)

接続しているネットワークの状態を確認するには、ifconfig を使う。(Linuxの場合)
Windows であれば、cmd.exe を起動して、ipconfig を使う。

((( Linux の場合 )))
$ ifconfig -a
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.11.2  netmask 255.255.255.0  broadcast 192.168.11.255
        :
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        :
$ ifconfig eth0   # 特定のインタフェースだけ確認
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.11.2  netmask 255.255.255.0  broadcast 192.168.11.255
        :
$ ip link    # 新しい Linux 系では、ifconfig が無い場合もある。
             # ip link がその代用

((( Windows の場合 )))
C:> ipconfig /all    # Linux の ifconfig -a と同じ

上記のコンピュータでは、IPアドレス(例:192.168.11.2)とサブネットマスクの値(255.255.255.0)が設定されている。IPアドレス AND サブネットマスクの値はネットワーク番号と呼ばれ、192.168.11.0 が同じであれば、同じサブネット内と判断できる。サブネットマスクは、上位bitの1の数で表現することもあり、192.168.11.2/24 という書き方もある。

こういったIPアドレスは、各コンピュータに対してあらかじめ決めた値を設定しておく方法(静的アドレス)と、IPアドレスを管理しているサーバにアドレスを一時的に貸し出してもらう方法(動的アドレス)があり、後者のアドレスを貸し出すサーバは、DHCPサーバと呼ばれる。(DHCPでは、アドレス貸し出しを頼んできた端末に、IPアドレス,サブネットマスク,ゲートウェイ,DNSサーバを通知してくれる。後述)

周囲のコンピュータの確認(arp/ping)

基本、インターネットでは IP アドレスで通信相手を判断するが、同じサブネット内では、各コンピュータに割り振られているMACアドレスでコンピュータを識別している。

arp

このため、同じサブネット内では、IPアドレスとMACアドレスの対照表が必要となってくる。この対照表の情報を交換するためのプロトコルが ARP であり、この対照表を確認・操作する命令が arp コマンド。

$ arp -an    # -a で全ての一覧を表示、-n でホスト名を調べない
? (192.168.11.24) at <不完全> on eth0
? (192.168.11.13) at 62:84:bd:28:xx:xx [ether] on eth0
? (192.168.11.36) at b8:27:eb:ee:xx:xx [ether] on eth0
:
$ ip neigh   # 新しい Linux 系では arp コマンドがない場合もある。
             # ip neigh が替わりになる。

ただし、コンピュータが「このMACアドレスは私のIPアドレスですよ」とアナウンスした結果を一定時間覚えているだけなので、かならずそのコンピュータが生きているかは別の話。サブネットの中で、偽のARPを流すことで他のコンピュータ宛のパケットを盗むことも可能(ARPスプーフィング)である。このため、セキュリティ対策としてMACアドレスとIPアドレスの対応(arp)を監視も重要となる。

ping

ping は、潜水艦のソナー音をイメージするコマンドで、ICMPプロトコルのパケットを、指定した IP アドレスor ホスト名に送って、返答の有無や応答時間を表示する。ping では通常、相手に連続してパケットを送る。ネットワークが不安定な場合には、パケットが相手に届かない場合もあるので、パケット欠落があると icmp_sec= の番号が不連続になる。

$ ping 192.168.11.2
PING 192.168.11.2 (192.168.11.2) 56(84) bytes of data.
64 bytes from 192.168.11.2: icmp_seq=1 ttl=64 time=0.054 ms
^C
$ ping www.google.com
PING www.google.com (172.217.161.228) 56(84) bytes of data.
64 bytes from kix06s05-in-f4.1e100.net (172.217.161.228): icmp_seq=1 ttl=54 time=5.62 ms
64 bytes from kix06s05-in-f4.1e100.net (172.217.161.228): icmp_seq=2 ttl=54 time=5.89 ms
64 bytes from kix06s05-in-f4.1e100.net (172.217.161.228): icmp_seq=3 ttl=54 time=5.93 ms
^C

ただし ping は、特殊な ICMP パケットを送ることで相手コンピュータを攻撃できた事例もあり、返答を返さないシステムもある。

ブロードキャストパケット(ping -b)

IPアドレスで、サブネットマスクとANDをとったネットワーク番号の残りの部分は、ホスト番号と呼ばれる。(例:192.168.11.2/24 であれば、2 の部分) IPアドレスでホスト番号の全bitが1のアドレス(この場合は、192.168.11.255)は、ブロードキャストアドレスと呼ばれ、同じサブネット内の全部のコンピュータにデータを送るときに使う。

((( pingでブロードキャストする場合は、-b オプションが必要 )))
$ ping -b 192.168.11.255
WARNING: pinging broadcast address
PING 192.168.11.255 (192.168.11.255) 56(84) bytes of data.
64 bytes from 192.168.11.19: icmp_seq=1 ttl=64 time=70.5 ms
64 bytes from 192.168.11.18: icmp_seq=1 ttl=64 time=70.8 ms (DUP!)

ルーティング

インターネットでは、コンピュータに固有のIPアドレスを割り振り、サブネットを越えて通信ができる。(インターネットプロトコルIP)

基本的に、通信相手のIPアドレス AND サブネットマスク で求まるネットワーク番号が異なれば、サブネットが異なるので直接通信ができない。この場合は、ルータにパケットの中継を依頼することになる。ルータはゲートウェイとも呼ばれる。

ルータは、複数のサブネットを中継する装置であり、どのネットワーク番号ならばどのルータに送る(ルーティングと呼ぶ)というテーブルを持っている。一般的に、下流の末端のネットワークでは、どのネットワークならこの装置、それ以外はこの装置に送る…といった一覧表を持っている。(静的ルーティング)

一方、様々な末端からのデータが集まる上流のルータでは、末端ネットワークの構成が変化することも多いので、RIPというプロトコルで、ルータが相互にルーティング情報を交換している。(動的ルーティング)

ルーティングの確認(netstat -r)

ルーティングの情報を調べるには、netstat -r コマンドを用いる。

$ netstat -rn   # -r ルーティング情報 -n ホスト名を調べない
カーネルIP経路テーブル
受信先サイト     ゲートウェイ    ネットマスク      フラグ   MSS Window  irtt インタフェース
0.0.0.0        192.168.11.1  0.0.0.0         UG        0 0          0 eth0
192.168.11.0   0.0.0.0       255.255.255.0   U         0 0          0 eth0

$ ip route      # 新しい Linux 系では、ip route を使う

この例では、192.168.11.0/255.255.255.0 というサブネットでは直接通信ができ(ゲートウェイが0.0.0.0)、それ以外のパケット(受信先サイトが0.0.0.0)は 192.168.11.1 のルータに送ることになっている。(デフォルトゲートウェイ)

ルートの確認 traceroute

どういった経路で相手コンピュータまでデータが届いているのかを確認するには、traceroute コマンドを用いる。

traceroute コマンドは、ルーティングを調べながら、各ルータに ping を送った結果を表示する。

((( Linux の場合 )))
$ traceroute www.fukui-nct.ac.jp
traceroute to www.fukui-nct.ac.jp (104.215.53.205), 30 hops max, 60 byte packets
 1  xxxx.xxxx.xxxx (192.168.xx.1)  0.299 ms  0.251 ms  0.354 ms
 2  yyyy.yyyy.yyyy (192.168.yy.254)  0.790 ms  1.976 ms  1.343 ms
 3  ttn103-198-212-1.ttn.ne.jp (103.198.212.1)  4.304 ms  5.127 ms  4.343 ms
 4  ftth-sw1-po-11.ntwk.ttn.ne.jp (202.127.81.33)  3.742 ms  5.580 ms  4.296 ms
 5  core-sw2-la-2.ntwk.ttn.ne.jp (202.127.81.29)  5.477 ms  4.692 ms  4.655 ms
 6  bbr2-2-4.ntwk.ttn.ne.jp (202.127.81.17)  4.895 ms  2.025 ms  1.904 ms
 7  103.246.232.116 (103.246.232.116)  6.707 ms  5.499 ms  6.583 ms
((( Windows の場合 )))
C:> tracert www.fukui-nct.ac.jp  # Windowsではコマンド名が違うので注意

DNSによる名前解決

ここまでの話の中で、IPアドレスは、192.168.11.123 といった値であったが、極めて覚えにくい。このために、コンピュータそれぞれに名前をつけることができる。これをホスト名という。ホスト名も組織化されていると、組織を区別する名前が必要でドメイン名と呼ぶ。ホスト名とドメイン名の全体を単純にホスト名とかコンピュータ名と呼ぶことも多いが、正式には、FQDN と呼ぶ。

FQDN = www.fukui-nct.ac.jp (コンピュータ名とかドメイン名と呼ぶことも多い)
ホスト名 = www
ドメイン名 = fukui-nct.ac.jp

コンピュータ名とIPアドレスの情報を管理するのが、DNS(Domain Name Service) であり、下流の DNS の情報を調べながら 上流の DNS と組み合わされて管理されている。

nslookup or dig

この DNS に問い合わせを行うのが nslookup コマンドや dig コマンドである。コンピュータ名からIPアドレスを調べるには、一般的には nslookup コマンドを用いる。(正引き)

$ nslookup www.fukui-nct.ac.jp
Server:		192.168.11.xxx
Address:	192.168.11.xxx#53

Non-authoritative answer:
Name:	www.fukui-nct.ac.jp
Address: 104.215.53.205

$ dig www.fukui-nct.ac.jp   # もっと詳しい情報を調べる場合はdigを使う

利用者が多いサービスでは、1台のコンピュータで処理するのは大変なので、負荷分散を行うために、同じサービスを提供するコンピュータを何台も並べ、コンピュータ名を調べる度に、その複数のコンピュータのIPアドレスを返す場合もある。(ラウンドロビンDNS)

逆引き

迷惑メールを大量に送ってくるとか、クラッキングをしてくるようなコンピュータの中には、きちんと管理されていない怪しいネットワーク組織からの接続の場合がある。こういう場合には、IPアドレスに対して名前が割り振られていない場合も多い。また、攻撃の踏み台に使われている場合、どういった組織のコンピュータが悪用されているのか調べる必要がある。こういう場合には、IPアドレスからコンピュータ名を調べることも多い。(逆引き)

$ nslookup 192.156.146.100
100.146.156.192.in-addr.arpa	name = sv1.ip.fukui-nct.ac.jp.

$ dig -x 192.156.146.100      # dig で逆引きするときは、-x オプションが必要

逆引きでホスト名が調べられないとか、逆引きしたホスト名で再びIPアドレスを調べるとホスト名が異なる場合は、IPアドレスとドメイン名の管理が怪しい危険なコンピュータの可能性がある。場合によっては、DNSサーバが汚染されていて、コンピュータ名でアクセスしたら悪意のあるサーバに接続される危険性もある。(DNSポイズニング)

パブリック DNS

末端組織のDNSの場合、IPアドレスは組織内でしか使えないプライベートアドレス(例:10.xx.xx.xx , 192.168.xx.xx)の場合、組織内専用の DNS が動いていることが多い。この場合、組織内の DNS と組織外の DNS では、異なる情報が得られる場合もある。

こういう場合は、DNS に問い合わせをする場合に、外部の DNS を指定する。特に、Google パプリック DNS は、DNSサーバのIPアドレスが 8.8.8.8 という覚えやすい値が使われている。

$ nslookup 192.156.146.100 8.8.8.8
100.146.156.192.in-addr.arpa	name = sv1.ip.fukui-nct.ac.jp.

$ dig @8.8.8.8 192.156.146.100      # dig でDNSサーバを指定するときは、@の後ろで指定

DNS の特殊な情報

DNS には、IPアドレスとホスト名以外にも、様々な情報が登録されている。この情報を調べるには、タイプを指定する。(-query=タイプ のオプションをつける)

$ nslookup -query=a www.google.com 8.8.8.8     # IPv4 アドレスを調べる
Name:	www.google.com
Address: 216.58.199.228

$ nslookup -query=aaaa www.google.com 8.8.8.8  # IPv6アドレスを調べる
Name:	www.google.com
Address: 2404:6800:400a:80c::2004

$ nslookup -query=mx fukui-nct.ac.jp 8.8.8.8   # メールを送るサーバを調べる  
fukui-nct.ac.jp	mail exchanger = 10 ews.ip.fukui-nct.ac.jp.

$ nslookup -query=txt tsaitoh.net 8.8.8.8      # その他のTXT情報を調べる
tsaitoh.net	text = "v=spf1 +ip4:xx.xx.xx.xx..."
  # この例では、メールサーバの検証方法 SPF の情報が見れた。

DMARCレポートを出力

DMARCの設定をして、なりすましなどのレポートをメールで送る設定をしたけど、xmlファイルはzip圧縮でメール添付だし、xml ファイルも内容が読みづらい。

dmarc-catを使ってみる

“aptitude search dmarc”を実行すると、dmarc-cat というソフトが見つかり、”sudo aptitude install dmarc-cat” インストールして使ってみる。

dmarc-cat 0.9.2/j4 by Ollivier Robert

Reporting by: google.com — noreply-dmarc-support@google.com
From 2020-02-12 09:00:00 +0900 JST to 2020-02-13 08:59:59 +0900 JST

Domain: tsaitoh.net
Policy: p=quarantine; dkim=r; spf=r

Reports(1):
IP                      Count   From        RFrom       RDKIM   RSPF    
xxxxx-xx-x-x.xxx.ne.jp. 1       xxxxxxx.xxx xxxxxxx.xxx pass    pass    

これなら、なんとなく読みやすい。でも、どちらにしろ、添付ファイルのzip抽出、zip解凍、dmarc-cat の実行、んで、これらの内容を最終的にメールで読みたい。

メールを dmarc-cat で変換してレポート

ということで、その一連の処理を、procmail から実行させるための perl script をチロっと書いてみた。

#!/usr/bin/perl

# DMARC のレポートメールを dmarc-cat で文字情報にして送信しなおす
#
#       .procmailrc に以下を記載
#       | dmarc-report-mail.pl メールアドレス

my $mailto = $ARGV[0] ; # 送りなおすメールアドレス

# 添付ファイルを抽出するディレクトリ
my $tmpdir = "/tmp/dmarc-report-$USER-$$" ;

if ( mkdir( $tmpdir ) ) {
  # 標準入力のメールから添付ファイルを抽出
  system( "/usr/bin/munpack -q -C $tmpdir > /dev/null 2>&1" ) ;

  if ( opendir( my $dh , $tmpdir ) ) {

    # 保存された全ての添付ファイルの処理
    while( my $file = readdir( $dh ) ) {
      if ( -f "$tmpdir/$file" ) {

        # .zip ファイルだけ処理を行う
        if ( $file =~ /\.zip$/ ) {
          my $zipfile = "$tmpdir/$file" ;
          my $xmlfile = $zipfile ;
          $xmlfile =~ s/\.zip$/.xml/ ;
          $xmlfile =~ s/X/!/g ;

          # 圧縮解除 .zip => .xml
          system( "/usr/bin/unzip -q -d $tmpdir '$tmpdir/$file'" ) ;
          if ( -f $xmlfile ) {

            # .xml => dmarc-cat の出力をメールに送る
            if ( $mailto ne ""
                 && open( $mh , "| /usr/sbin/sendmail $mailto" ) ) {
              print $mh "Subject: DMARC report\n\n" ;
              if ( open( my $fh , "/usr/bin/dmarc-cat '$xmlfile' |" ) ) {
                while( <$fh> ) {
                  print $mh $_ ;
                }
                close( $fh ) ;
              }
              close( $mh ) ;
            }
            unlink( $xmlfile ) ;    # 解凍されたファイルを消す
          }
        }
        unlink( "$tmpdir/$file" ) ;     # 添付ファイルを消す
      }
    }
    closedir( $dh ) ;
  }
  rmdir( $tmpdir ) ;
}

この script を以下の様な procmailrc にかけて、report-a 宛のレポートを変換後 report-a-dmarc 宛に再転送させる。

:0
* ^To.*report-a@xxxxxxx\.xxx
| /...path.../dmarc-report-mail.pl report-a-dmarc@xxxxxxx.xxx

:0
* ^To.*report-f@xxxxxxx\.xxx
| /...path.../dmarc-report-mail.pl report-f-dmarc@xxxxxxx.xxx

postfixのサーバ間暗号化

DKIM, DMARC などの設定をしていたが、gmail 宛のメールの状態を確認していたら、DMARC p=quarantine に変更したのを確認できたけど、サーバ間のメール転送で暗号化がされていない様子。

この手の暗号化はデフォルトで行われているものと思っていたが甘かった。

postfix に以下の設定を追加する。

(((/etc/postfix/main.cf )))
smtp_tls_security_level = may

上記の状態の確認をしていたけど、外部サイトと25番ポートで繋がるんだな。プロバイダのファイアウォールで OP25 などの対策で、smtp(25番ポート)って接続禁止で、starttls(587) とか、smtps(over SSL:465) とかを優先的に使うと思っていたけど、google さんの smtp と 25 番ポートと繋がるな…。

DNSにDMARCを設定

SPF, DKIM の設定がうまく動いているようなので、DMARC も設定してみよう。

DMARC は、SPF, DKIM にてメールの送信者認証で問題が発生した際にそのメールをどう扱ってほしいかを受け取り側に伝えるための設定。なりすましを受けたら報告してもらえるという意味でも便利かも。

DMARCの設定

ひとまず、なりすましは無いと思うけど、DMARCの設定ミスでメールが消えても困るから、p=none を設定し、問題が起こっても特になにもしてもらわないことにする。メール受信時の成功などの統計用情報が送られてくるメールアドレスと、失敗(なりすまりが発生?やばい!?)のメールアドレスを設定

mydns.jp の自宅ドメインの設定で、以下のような情報を返すように設定を行う。

_dmarc.tsaitoh.net IN TXT “v=DMARC1;
     p=none;
     rua=mailto:report-a@tsaitoh.net;
     ruf=mailto:report-f@tsaitoh.net”

p=none(なにもしない)でなく、p=quarantine(隔離), p=reject(廃棄), に設定すると、レポートメールが送られるようになる。

DMARCの状態レポートの受信設定

上で設定した、統計用メール、失敗用メールの受取先を実際に配送できるように、/etc/aliases に登録。

$ sudo vi /etc/aliases # 以下を追加
report-a: root
report-f: root
$ sudo newaliases

試しに Google のメールアドレスにメールを送ったら、dmarc=pass が表示されるようになった。(現時点では、p=none なので report-a 宛などのメールは送られてこない)

Authentication-Results: mx.google.com;
       dkim=pass header.i=@tsaitoh...
       dkim=pass header.i=@tsaitoh...
       spf=pass (google.com: domain of ...
       dmarc=pass (p=NONE sp=NONE dis=NONE) ...

DMARCレポート

後日 p=quarantine にレベルを上げたら、以下の様なレポートが届く様になった。なりすまし被害なしってことで。

自宅メールサーバをDKIM対応へ

Yahoo のメールアカウントに、迷惑メール対策のため「DMARC」導入を開始しますとのメールが届いている。送信側ドメイン認証のひとつで、なりすましだった場合の取り扱いを設定することができるらしい。

しかし、自宅メールサーバは、mydns.jp を用いたダイナミックDNSを用いたサイト。このため、メールサーバを立ち上げても spam 送信元と誤認(なりすましと誤認)される可能性も高く、自宅サーバからのメールは、受け取り側で迷惑メールフォルダに落ちないか心配したり、すぐに相手に届くか不安であった。

ということで、DMARC の前に、DKIM にて信用してもらえるように設定を行う。DKIMは受信したメールが正しいメールサーバから送られ改ざんされていないか確認する方式SPFは以前に導入済みだけど、正しいメールサーバから発信されたか確認する方式なので、DKIM ほどの信頼はない。

opendkim のインストール

Debian では、opendkim のパッケージが配布されているので必要なパッケージをインストールする。設定のために セレクタ名 を postfix としてプライベートキーを生成する。/etc/dkimkeys/postfix.txt には、DNS に登録する “IN TXT” の設定が生成される。

$ sudo aptitude install opendkim opendkim-tools
$ cd /etc/dkimkeys
$ sudo opendkim-genkey -D /etc/dkimkeys -b 1024 -d tsaitoh.net -s postfix
$ sudo chown opendkim:opendkim /etc/dkimkeys/*

opendkim の設定として、上記処理で作られたプライベートキーを登録し、DKIM キーを付加する処理のためのサーバと接続するためのソケットを定義する。

((( 以下のファイルを編集 )))
$ sudo vi /etc/opendkim.conf
Domain   tsaitoh.net
KeyFile  /etc/dkimkeys/postfix.private
Selector postfix

Socket   inet:8892@localhost

DKIM 電子署名を付加するための postifix の設定

postfix でメールを送信する時に opendkim に接続し DKIM の電子署名を付加するために、前述のソケットに対応する設定を以下の様に記載する。

((( /etc/postfix/main.cf )))
$ sudo vi /etc/postfix/main.cf
smtpd_milters = inet:127.0.0.1:8892

DKIM のための DNS の設定

DNSに、公開鍵などの設定を行う。mydns.jp を使っているので、mydns.jp にログインし、DOMAIN INFO にて、以下の設定を加える。

_adsp._domainkey   IN TXT dkim=unknown
postfix._domainkey IN TXT v=DKIM1; h=sha256; k=rsa; p=XXX...XXX

DNS設定が正しく反映されているか確認。

$ nslookup -query=TXT _adsp._domainkey.tsaitoh.net 8.8.8.8
_adsp._domainkey.tsaitoh.net    text = "dkim=unknown"
$ nslookup -query=TXT postfix._domainkey.tsaitoh.net 8.8.8.8
postfix._domainkey.tsaitoh.net  text = "v=DKIM1; h=sha256; k=rsa; p=XXX...XXX

サーバの再起動とDKIMの確認

$ sudo service opendkim start
$ sudo service postfix restart

試しに Google のアカウントにメールを送ったら、メールヘッダに以下が表示されるようになった。SPF は、以前に設定済みなので、自宅サーバからのメールは、確実に相手に届くようになったと思われる。

ARC-Authentication-Results: i=1; mx.google.com;
        dkim=pass header.i=@tsaitoh.net ....
        spf=pass (google.com: domain of ....

ラズパイのインタフェース名

自宅の raspberry-pi の設定を触っていて、何気に raspi-config を起動して設定を確認していたら、適当にポチポチさわってて、Network Options, N3 Network Interface Names の設定を触ったようで、再起動がかかったらネットワークがつながらない。

しかたがないので USBキーボードとHDMI のモニタつなげて、直接設定を触ろうとするものの、HDMI に信号が出てこない。

これでは、設定を触ろうにも何もできない。

raspi-config を使わないで設定を変更

もう raspberry-pi 単独では触りようがないので、micro-SD を外して、母艦のサーバで 起動時の設定を触ることとした。

間違って触った Network Interface Names は、古い eth0 などのインタフェース名でなく、enx112233aabbcc みたいな MAC アドレス を交えた新しいインタフェース名を使うような設定(predictable interface naming)。この機能が動き出したおかげで、インタフェースの初期化に失敗している。この設定を戻さないと。

$ sudo bash
((( raspberry-piの/bootフォルダをマウント )))
# mount -t vfat /dev/sdd1 /mnt  デバイス名/sddの部分は要変更

((( predictable interface naming を無効化 )))
# vi /mnt/cmdline.txt
net.ifnames=0  ファイル末尾に追加

((( sshサーバ機能を有効化 ))) 
# touch /mnt/ssh

((( HDMI の出力を有効化 )))
# vi /mnt/config.txt
hdmi_safe=1    先頭の方のこの行をコメントアウト
               低解像度のsafeモードでHDMIを設定

# umount /mnt
((( raspberry-piのrootをマウント )))
# mount -t ext4 /dev/sdd2 /mnt
((( ネットワークの設定ファイルを変更 )))
# vi /mnt/etc/dhcpcd.conf
...

んで、母艦で編集していた micro-SD を raspberry-pi に差し戻して起動。

Raspberry-Pi のファーム壊れた

Raspberry-Pi、ネットワーク越しに rpi-update してた途中でWiFi中継器のネットワークが切れてしまった。おかげでファームウェアの更新に失敗。どうもファームウェアがぶっ飛んだようで、起動しなくなった。タイミング最悪。

その RPi は、ITオンチな1F両親向けに、家族の予定をLED掲示板に表示させてるために使ってた。でも、買い替えるといっても RPi4 買うほどの処理じゃないしな。

難しい話抜きで、Google Nest 買った方が便利かな。でも、OK,Google、使いこなせないだろうしなぁ…

検索 🔎

  My Google     Yahoo

便利サイト