スクリプト ショート・ショート

 

 

テキスト操作スクリプト

■ 設定ファイルのコメント行を外す

通常、コンフィグファイルやシェルスクリプトには多くのコメントがついているが、httpd,conf や squid.conf のようにコメント行があまりにも多く、設定本体を見渡しづらいファイルがある。次のスクリプトは引数1にこのようなファイルを指定し、コメント行を取り除いて出力する。見てわかるとおりこのスクリプトの本体は grep と tr による処理がある一行のみで、他行は引数の評価とファイルの存在確認によるエラー処理である。当然、同じ作業はコマンドラインから
grep -v '^#' ファイル名 | tr -s '\n' としても実行できる。

スクリプトに commentoff など適切な名前をつけ、コマンドパスの通ったディレクトリに設置する。一般論だが、管理者の使用するツールは一般ユーザのアクセスできないディレクトリ( /root/bin など)に設置し、パーミッションを700等に指定しておくべきである。

使用法は次のとおり。機能としては単純なフィルタコマンドなので、ファイル名を指定してリダイレクトすることもできる。

      commentoff ファイル名 ( > リダイレクトファイル名 )



# ---- commentoff -----

#!/bin/bash

if [ $# -eq 0 ] || [ $# -ge 2 ]
then
   echo
   echo "ARGUMENTS INCORRECT  ---  Usage : commentout FILENAME"
   echo
else
   if [  -e "$1" ]
   then
      echo
      echo $1
      echo
      grep -v '^#' "$1" | tr -s '\n'
      echo
   else
      echo
      echo "$1 : No Such File"
      echo
   fi
fi

(注意:本稿ではバックスラッシュを¥記号で代用しているので、UNIX系で使用する場合は確認・訂正すること。)




■ man ページをテキストファイルに掃き出す



man ページをプレーンテキストに変換したい場合、次のようなスクリプトを用意しておくと便利である。このスクリプトの中核になるコマンドは他でもない man のマニュアルページの最後に載っているが、そのままでは強調文字の制御コードが出力されてしまう。本スクリプトではこの制御コードをフィルタしてプレーンテキストを出力する。引数に2つ以上指定すると warning が出るが、出力には特に問題はない。なお、引数に何も指定しないと使用法を表示して終了する。

注意:このスクリプトでは man ページの項目が実際に存在するかどうかのチェックを行っていない。manpath から find で検索を実施し、項目の存在を確認してから動作させることもできるが、検索に時間がかかることがあるので採用しなかった。多くの場合、man ページを一通り眺めてからテキストが必要になるものなので、この仕様でもそれほど問題はない( No manual entry for MANPAGE のエラーが返るだけ)だろうと思う。なお強調文字に対するフィルタロジックについては、何度も sed を起動したりテンポラリファイルを4つも作ったりでいささか要領が悪いが、プログラムの見通しを良くするためにこのままにしておく。


#---- man2text -----

#!/bin/bash

if [ $# -eq 0 ]
   then
       echo
       echo "NO ARGUMENT  ---  Usage : man2text MANPAGE MANPAGE ..."
       echo
   else
   for manpage in $*
   do
       txtpage=$manpage.txt
       man $manpage | col -bfx > $txtpage

       sed 's/1m//g' $txtpage >tmp1
       sed 's/22m//g' tmp1 >tmp2
       sed 's/4m//g' tmp2 >tmp3
       sed 's/24m//g' tmp3 >tmp4
       sed 's/0m//g' tmp4 >$txtpage

       rm -f tmp[1-4]

   done
fi


筆者注:man ページの強調文字の仕様がすでに変わっているため、現在の RedHat EL5.1 では以下のスクリプト中の col -bfx は必要ない。逆に col による処理を残しておくと見出し部分が欠けてしまうので、現行 EL5 系への対応として以下の修正版を上げておく。


#---- man2text -----

#!/bin/bash

if [ $# -eq 0 ]
   then
       echo
       echo "NO ARGUMENT  ---  Usage : man2text MANPAGE MANPAGE ..."
       echo
   else
   for manpage in $*
   do
       txtpage=$manpage.txt
       man $manpage > $txtpage

       sed 's/1m//g' $txtpage >tmp1
       sed 's/22m//g' tmp1 >tmp2
       sed 's/4m//g' tmp2 >tmp3
       sed 's/24m//g' tmp3 >tmp4
       sed 's/0m//g' tmp4 >$txtpage

       rm -f tmp[1-4]

   done
fi


ヒントと応用 :文書化の作業があるときなど man ページを windows 上で引用したり通読したいことがある。このような場合は nkf を使って DOS ファイルに変換し、windows からアクセスできる samba 共有にリダイレクトする。以下に one liner の形で示す。


$
nkf -cs < man.txt > /home/public_samba/man.txt




運用管理用スクリプト

■ 起動用フロッピディスクを作成する

現在の Linux では LILO や GRUB などのブートローダをインストールするのが常識だが、この方法ではブートローダにパスワードをかけておかないかぎり、誰にでも再起動ができてしまう。したがって、管理者の知らないうちにシステムが再起動させられたり、コンソールから直接シングルユーザモードでログインされることもありえる。サーバのファシリティ管理上の理由(専用のサーバルームがなく、サーバがむき出しのままオフィスに置かれているなど)でこのような問題が想定される場合、システムにブートローダをインストールせず、フロッピィディスクから起動する方法を取るとよい。この手法はセキュリティだけではなく、何らかの理由でブートローダにトラブルが発生する可能性を考え、バックアップとして作成する意味がある。(もちろん、フロッピィディスクの管理がきちんとできることが前提であるが…。)

起動用フロッピィを作成する手順は以下のとおり。

      1.デバイス fd0 のマウント
      2.フロッピィディスクのフォーマット
      3.mkbootdisk の起動とブートディスクの作成
      4.デバイス fd0 のアンマウント

mkbootdisk は起動用フロッピィディスク作成用のユーティリティスクリプトである。これを使ってコマンドラインから直接コマンドを叩けばいいだけのことだが、FDのマウント/アンマウントやカーネルバージョンの調査などわずらわしい部分があるので一連の手続きをスクリプト化しておく。


#---- make_bootdisk ----

#!/bin/bash

mount /dev/fd0 /mnt/floppy
fdformat /dev/fd0H1440
mkbootdisk --device /dev/fd0 `uneme -r`
umount /mnt/floppy

起動用ディスクは運用専用とバックアップ用の2組作っておき、それぞれ別の場所に保管することが望ましい。これはセキュリティ上の観点だけではなく、火災や天災等によってすべてのリソースが一度に失われることを防ぐ意味合いである。



■ /etc/hosts ファイルに登録されているホストのPINGリプライを確認する

現在ではDNSによる名前解決が当たり前になっているが、/etc/hosts ファイルは最低限ローカルネットでの通信を確保するために記述するべきである。クライアントに関してはDHCPを利用することが多いので対象外とするが、サーバやルータなどの主要なネットワークノードは hosts ファイルに記述しておくと、以下のようなスクリプト上で ping を使って生存確認ができる。

このスクリプトでは作業ディレクトリを /root/bin としているので、実際に使用する場合は同じディレクトリを作るかパスを変更すること。ここに /etc/hosts を一時的に hosts.tmp としてコピーする。次に hosts ファイルの第二フィールド(ドメインつきホスト名)を切り出し、改行コードをタブに置き換えてリスト化する。あとはリストをシェル変数にロードして ping を実行するLoopを回せばよい。

なお、ping オプションは「4回発呼・4秒で終了」の意。このスクリプトは単に hosts ファイルを参照するだけなので、ファイアウォールの仕様によっては ping が通らないことも当然ありうる。(システム仕様について検討すること。)


#---- arrivehosts ----

#!/bin/bash

cp /etc/hosts /root/bin/hosts.tmp
cut -f 2 /root/bin/hosts.tmp |tr -s '\n' '\t' >/root/bin/hosts.tmp

HOSTS=`cat /root/bin/hosts.tmp`

for hostname in $HOSTS
do
    ping -c 4 -w 4 $hostname
done

rm /root/bin/hosts.tmp

 




■ 現在のすべてのソケットユーザを調べる

調整期のサーバではどのようなサービスが上がっているのかわからなくなることがよくある。このような場合、稼動中のサービスを調査するには netstat で tcp/udp ソケットを調べることが多い。lsof -i で見るのが確実だが、パッケージをインストールしていないシステムが多いことや、lsof の表示が未整理で情報が読み取りづらいという欠点がある。そこで netstat の結果を拾い出して fuser に入力するわけだが、これを手順化したのが以下kのスクリプトである。

なお使用しているポート番号を抜き出す処理にややトリッキーな部分があるが、":" を空白に置き換えて再び awk に渡しているにすぎない。(このような部分を正規表現などで処理しようとするとかえってわかりづらくなりやすい。)



拡張版 fuser  ::  tcp/udp ソケットを使用しているすべてのプロセスを表示する

1.UDPバージョン


    for p in `netstat
    -anu | awk '{ print $4}' | tr  ":" " "| awk '{ print $2 }'`
    do
      echo
      fuser -vn
    udp $p
    done | less

2.TCPバージョン

    for p in `netstat -ant | awk '{ print $4}' | tr  ":" " "| awk '{ print $2 }'`
    do
      echo
      fuser -vn
    tcp $p
    done | less


以下に出力例を示す。


[root@server root]#     for p in `netstat -ant | awk '{ print $4}' | tr  ":" " "| awk '{ print $2 }'` ; do  \
echo ;  fuser -vn tcp $p;  done | less

                         USER        PID ACCESS COMMAND
    32776/tcp      root       3915 f....  kinput2

                          USER        PID ACCESS COMMAND
    4043/tcp        root       4251 f....  httpd
                         root       4254 f....  httpd
                         root       4255 f....  httpd
                         root       4256 f....  httpd
                         root       4257 f....  httpd
                         root       4258 f....  httpd
                         root       4259 f....  httpd
                         root       4260 f....  httpd
                         root       4261 f....  httpd

                         USER        PID ACCESS COMMAND
    111/tcp         root       2643 f....  portmap

                         USER        PID ACCESS COMMAND
    80/tcp           root       4251 f....  httpd
                         root       4254 f....  httpd
                         root       4255 f....  httpd
                         root       4256 f....  httpd
                         root       4257 f....  httpd
                         root       4258 f....  httpd
                         root       4259 f....  httpd
                         root       4260 f....  httpd
                         root       4261 f....  httpd

                         USER        PID ACCESS COMMAND
    6000/tcp        root       3895 f....  X

                         USER        PID ACCESS COMMAND
    22/tcp           root       2696 f....  sshd
                         root       4456 f....  sshd

                         USER        PID ACCESS COMMAND
    8088/tcp        root       4251 f....  httpd
                         root       4254 f....  httpd
                         root       4255 f....  httpd
                         root       4256 f....  httpd
                         root       4257 f....  httpd
                         root       4258 f....  httpd
                         root       4259 f....  httpd
                         root       4260 f....  httpd
                         root       4261 f....  httpd

                         USER        PID ACCESS COMMAND
    443/tcp          root       4251 f....  httpd
                         root       4254 f....  httpd
                         root       4255 f....  httpd
                         root       4256 f....  httpd
                         root       4257 f....  httpd
                         root       4258 f....  httpd
                         root       4259 f....  httpd
                         root       4260 f....  httpd
                         root       4261 f....  httpd

                         USER        PID ACCESS COMMAND
    22/tcp           root       2696 f....  sshd
                         root       4456 f....  sshd





■ 引数リストから複数のサーバデーモンを起動する

このスクリプトは RedHat での起動コントロールを行うディレクトリ /etc/rc.d/init.d/ 以下にある起動スクリプトへサーバ名を渡す。ファイルの存在を実行ファイルかどうかのオプションつきで確認し、存在していれば start し、存在しなければ Not Exist …以下のコメントを表示して終了する。(サーバプロセスがすでに動いている場合は restart 動作になる。)

サーバプロセス名の引数はいくつでも指定できるが、引数がない場合は Usage を表示して終了する。以下に使用例を示す。

      daemon_start httpd squid

なお、このスクリプトの /etc/rc.d/init.d/$daemon start 行の start を stop に書き換えればそのままサーバプロセス停止スクリプトができる。
 

#---- daemon_start ----

#!/bin/bash

if [ $# -eq 0 ]
   then
       echo
       echo "NO ARGUMENT  ---  Usage : daemon_start DAEMONNAME DAEMONNAME …"
       echo
   else
   for daemon in $*
   do
       if [ -x /etc/rc.d/init.d/$daemon ]
       then
          /etc/rc.d/init.d/$daemon start
       else
          echo "Not Exist Script $daemon"
       fi
   done
fi




■ 簡易リモートバックアップ

このスクリプトはローカルマシンのディレクトリを tar で固め、ssh へ渡す処理を行う。通常リモートバックアップを行うには対応するバックアップアプリケーションが必要だが、この方法では ssh が使える状態になっていれば実行可能である。このスクリプトのミソは、前もってこれをリモートマシン側に scp しておけば、リモートマシンのバックアップを手元に取得できるということである。つまり、ssh でリモートホストへログインしたのち、本スクリプトを「向こう側からこちら側へ」使えばよい。

ほとんどワンライナーだけにかえって理解しづらいかもしれないので、以下に処理の概要を述べておく。
まずローカルマシンのルートディレクトリへ移り、etc, root, opt, var/log の各ディレクトリを tar で固めたのち、ssh にパイプする。転送先は仮に 192.168.0.1 としておくが、リモートマシン上で /var/tmp に移動し、容量節約と集約のために bkup.tar.gz ファイルへと gzip する。

なお、本スクリプトは元来シェルコマンドのグループ化の例題として作成したのでエラー処理はしていない。応用する場合はファイルの存在確認およびディスクの容量チェック、通信できなかった場合のエラー処理などを行うこと。また、本スクリプトを実行すると当然リモートホストのパスワード入力が求められるが、無認証sshの設定を行っておけば cron 等を使用してバックアップを自動化することができる。 (ただし、セキュリティの観点からはお勧めできません。)

#---- bkup.sh ----

#!/bin/bash

cd /
tar cf - etc root opt var/log | (ssh 192.168.0.1 -l root "cd /var/tmp; gzip > bkup .tar.gz")

 



■ 複数のインタフェースの IP アドレスの切り出し

このスクリプトはマルチホームドホストの接続セグメントに対応したインタフェースの IP アドレスを取得するための sed ワンライナーである。マルチホームドホストとは2つ以上のネットワークインタフェースを持つホストのことであるが、このような場合は IP アドレスを取得するために以下のようなスクリプトを書いておくとよい。ここでは ifconfig の結果から "inet addr:"を検索語として sed で切り出した値を単に echo しているだけだが、アプリケーションで自ホストの IP アドレスが必要になったときなど、広く応用が可能である。なお、IP アドレスの切り出しは ifconfig | grep "inet addr:" のような形でもよいのだが、複数のインタフェースを持つホストでは eth0, eth1, eth2 …のように行儀よく認識されていないことがあるので、単純な grep を行う場合は注意すること。

なお、ifconfig の結果からは同様にしてネットワークアドレスやブロードキャストアドレス、ネットマスク等が取得できる。いずれも検索語をどう設定するかの問題にすぎないので、読者自ら変更点を考慮されたい。


#------ getipaddr.sh -------

#!/bin/bash

SEG0_IF='eth0'
SEG1_IF='eth1'

SEG0_ADDR=`ifconfig $SEG0_IF | sed -e 's/^.*inet addr:\([^ ]*\).*$/\1/p' -e d`
SEG1_ADDR=`ifconfig $SEG1_IF | sed -e 's/^.*inet addr:\([^ ]*\).*$/\1/p' -e d`

echo "SEGMENT0 INTERFACE = " $SEG0_IF " "$SEG0_ADDR
echo "SEGMENT1 INTERFACE = " $SEG1_IF " "$SEG1_ADDR


 



■ SET UID ビットの立ったファイルを洗い出す

1.SUIDに関する予備知識

UNIX系OSではファイルの属性として owner / group / other の各実行者について read / write / execute のパーミッションを割り当てることができる。これは3桁の8進数で表記されるのが普通だが、こ の他に set userID(suid)、set groupID(sgid)、スティッキー(sticky)という属性をつけることができる。suid / sgid / sticky の機能は次のとおり。

種類

機能

suid 通常、プログラムやコマンド、スクリプト等を実行するときは実行者の権限で動作するが、suid ビットがセットされていると実行ファイル作成者の権限で動作する。このため root が作った実行ファイルにSUIDビットをセットすると、そのファイルは root 権限で実行できてしまい、セキュリティ上問題になることがある。
sgid あるユーザがディレクトリを作成すると、その中に作成されるファイルやディレクトリの所有グループは自動的にユーザの所属するグループになる。SGIDビットをセットすると、他のグループも所有者グループの権限でファイルを実行することができるようになる。root グループのSGIDが問題になるのはSUIDと同じ理由による。
sticky ディレクトリに sticky ビットをセットすると、そのディレクトリ以下にあるファイルの削除やファイル名の変更は所有者にしかできなくなる。(ファイルにセットした場合は、実行が終了しても仮想メモリに残ったままになる。)

SUID・SGID・STICKY は ls -l コマンドでファイルを表示したとき、次のように実行権限部分が x から s または S に変更されて表示される。s と S の違いは、もともと実行権限があった場合となかった場合についての区別である。

対象

本来の実行権限

種類

表示

owner

あり

suid

s

なし

S

group

あり

sgid

s

なし

S

other

あり

sticky

t

なし

T

たとえばSUIDをつける前のファイルパーミッションが -rwxr--r--r だったなら、 -rwsr--r--r になり、 -rw-r--r--r ならば -rwSr--r--r となる。また、これがSGIDビットを立てるなら、本来のパーミッションが drw-r--r--r のとき drw-r-Sr--r となる。

2.検索用コマンドをスクリプト化する

先に述べたとおり、SUIDビットの立った実行ファイルを放置していると、セキュリティ上問題となることがある。管理者はSUIDビットがセットされたファイルをシステムから洗い出し、その数を必要最低限に抑制する必要がある。以下の1行スクリプトは find を使った単純な検索プログラムであるが、システムからこの種のファイルをすべて洗い出すのに役立つ。なお、この手のコマンドスクリプトの実行結果はファイルにリダイレクトしてチェックを行うとよい。また、出力形式を変更したい場合は、ls のオプションを変更する。


# ---- ls_suid_files -----

#!/bin/bash

find / \( -perm -04000 -o -perm -02000 \) -exec ls -ald '{}' '\';
 




■ iptables を初期化する(RedHat 8)

iptables によるファイアウォールを検証中に設定のミスを発見したときなど、一度設定を完全に初期化したいことがある。このような場合、設定をフラッシュしたのち再起動するのが普通だが、設定を iptables-save コマンドでセーブしてしまったときなど、同じ状態のまま再起動してしまうので初期化が面倒になる。このような設定を初期状態に戻すには次のスクリプトを実行する。lsmod の出力を見て、iptables 関係のモジュールが揃っており、iptables -L によってチェインが初期状態に戻っていることが確認できればOKである。

なお、このファイルは一般ユーザのアクセスを禁止したディレクトリに置き、読み・書き・実行もすべて禁止にしておく。もちろん、ファイアウォールの構築が終了したら、運用を開始する前に削除しておくこと。


#---- iptables_reset ----

#!/bin/bash

modprobe="/sbin/modprobe"
iptables="/sbin/iptables"

if [ -f /etc/sysconfig/iptables ]
then
    rm -f /etc/sysconfig/iptables

    $iptables -F
    $iptables -X

    /etc/rc.d/init.d/iptables stop

    $modprobe ip_tables
    $modprobe ip_conntrack
    $modprobe iptable_nat
    $modprobe iptable_filter
    $modprobe iptable_mangle

    lsmod
    echo
    $iptables -L
else
    $iptables -F
    $iptables -X

    /etc/rc.d/init.d/iptables stop

    $modprobe ip_tables
    $modprobe ip_conntrack
    $modprobe iptable_nat
    $modprobe iptable_filter
    $modprobe iptable_mangle

    lsmod
    echo
    $iptables -L
fi


リセットスクリプトを実行後は iptables 設定用スクリプトを書き直し、あらためて検証を行う。iptables はカーネルのステータスを変更するので、/etc/rc.d/init.d/iptables stop によって一度停止・再起動しなければ初期状態に戻らないことに注意すること。最終的にファイアウォールが仕様通りに構築できたことが確認できたら iptables-save コマンドによって設定を /etc/sysconfig/iptables にリダイレクトするか、設定用スクリプトを /etc/rc.local に登録しておけばよい。これによって再起動時にも同じ設定が有効になる。



 

 

[トップ ページ][Linux][ネットワーク管理Tips]

Copyright(c) 2003 My Company. All rights reserved. www.suzu841.com / mrs.suzu841.com