iptables -F でネットにつながらなくなりました

Q. リモートからネットワーク設定作業をしており、いざと言うときのために、

sleep 300 && iptables -F

を裏で実行するようにしましたが、iptables -F を実行した瞬間にネットに一切つながらなくなりました。何が原因ですか?
 
A.iptables -F はデフォルトポリシー以外の全てのルールを消去します。
iptables -F を実行した直後はデフォルトポリシーだけの状態になるため、
たとえば iptables-save が次のように始まるような場合…

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

このように、INPUT DROP の設定になっている場合、もし iptables -F を実行すると、入力パケット(INPUT)を常に破棄(DROP)してしまうため、外部から(ping = ICMP すら)一切つながらなくなってしまいます。
 
こういう環境で作業する場合、代替として次のようにして確実に繋げる設定を復旧させるとよいでしょう。

sleep 300 && ( iptables-restore < iptables-free )

あるいは、環境に依存しますが例えば次のようにして /etc/sysconfig/iptables の状態を復元するのもいいでしょう。

sleep 300 && /etc/init.d/network restart

Apache httpdの現在のプロセス数、TCP 接続本数を調べる

ab(Apache Bench) コマンドなどを実行する場合など、HTTP サーバのパフォーマンスの分析を簡易的にしたい場合に、
topなどで監視するのもいいのですが、Apacheが現在何プロセス、何本のコネクションか定期的に監視できると便利です。

今回は毎秒Apacheのプロセス数とHTTP/HTTPS接続本数を調べて結果を出力し続けるというコードを書いてみました。

続きを読む Apache httpdの現在のプロセス数、TCP 接続本数を調べる

Awk マニュアル日本語版

gawk マニュアル
見覚えのある書き方だなと思ったら、拙訳 GNU Make と似ているんですね。さすが RMS 著。
 
sed, awk は頻繁に使ってるんですが、次のように

cat access_log | sed -e ‘/googlebot/d’ -e ‘/\/robots\.txt /d’ | awk ‘{ print $(11); }’ # access_log で googlebot や /robots.txt を含まない行のうち 11 列目の要素を出力

とか、ただ列を抽出するだけというかわいそうな使い方しかしていなかったのでなかなか目から鱗です。

ファイルへのアクセス状況を調べる

fstat, lsof, fuser などのコマンドを使うと、現在開かれている全てのファイルと開いているユーザ、プログラム、プロセス、読み書きのモードが調べられます。
fstat は FreeBSD の場合で、fuser は Linux の場合、lsof は Linux, BSD を含む UNIX 互換 OS で利用可能です。BSD でlsof を使う場合は、 ports/sysutils/lsof を入れます。lsof は機能が豊富なので、lsof の利用をお勧めします。

fstat:
fstat [-fmnv] [-p pid] [-u user] [-N system] [-M core] [file …]
 
fuser:
fuser [-a|-s|-c] [-4|-6] [-n space] [-k [-i] [-signal] ] [-muvf] name

fuser -l
fuser -V
 
lsof:
lsof [ -?abChlnNOPRstUvVX ] [ -A A ] [ -c c ] [ +c c ] [ +|-d d ] [
+|-D D ] [ +|-f [cfgGn] ] [ -F [f] ] [ -g [s] ] [ -i [i] ] [ -k k ] [
+|-L [l] ] [ +|-m m ] [ +|-M ] [ -o [o] ] [ -p s ] [ +|-r [t] ] [ -S
[t] ] [ -T [t] ] [ -u s ] [ +|-w ] [ -x [fl] ] [ -z [z] ] [ — ]
[names]

たとえば、ログファイルを開いているプロセス, ファイルを調べるには

lsof +D /var/log

等とします。
デバッグや問題究明に便利です。
 
参考:
LSOF設置及び使用ガイド

sh での変数とワイルドカードの落とし穴

sh, bash, csh, zshのようなシェルでは

echo *.sh

などというように、ワイルドカードでファイル一覧を取得することができます。
シェルで使えるワイルドカードはアスタリスク(*)、クエスチョンマーク(?)の2種類で、それぞれ、0文字以上の任意の文字列、1文字の任意の文字(英数記号など)を表します。

ワイルドカード文字を、ワイルドカードとしてではなくただの * や ? という1つの文字として扱いたい場合は、次のようにクオート記号で囲むか、エスケープします。

echo "*.sh"
echo "What's up?"

# 結果
# *.sh
# What's up? 
# が表示される

ここに変数が関係してくると、少し厄介なことになります。

# 間違った例
foo="SELECT * FROM table"
echo $foo

この結果は、

SELECT * FROM table

と表示されるかと思いきや、アスタリスクがワイルドカードとして展開されてしまうため、

SELECT FROM table

とアスタリスクが消える、または、現在の作業フォルダのファイル一覧が展開されて、

SELECT bin boot home root var FROM table

のように意図しない結果になってしまいます。

これはかなり怖いことで、この動きにより、最悪致命的なセキュリティホールや、データ消失につながる場合があります。

これを回避するためには, ワイルドカード文字を含む変数の参照時は常にダブルクオート/シングルクオートの中で参照するというテクニックを使います。

# 正しい例
foo="SELECT * FROM table"
echo "$foo"

この結果は、期待通り

SELECT * FROM table

となります。

多段になってもこの動きは変わりません。

foo="SELECT * FROM table"
boo="$foo"
echo "$boo"
# foo, boo 両方の参照をダブルクォートでくくっていることに注意

この結果も、期待通り

SELECT * FROM table

となります。ここで

echo $boo

としていると、やはり変数展開されてしまうため、注意しましょう。
お約束として、変数を参照するときで、変数に記号が入る可能性がある場合は必ずダブルクオートで囲む癖をつけると、こういう間違いがなくなるので幸せになれます。

おまけ

一歩踏み込んだ例として、変数の遅延展開の例を紹介します。

export table=book # 1
# ↑これは全く利用されない
text='SELECT * FROM ${table}' # 2
# ↑シングルクオートなので、textに入る時点ではtableが展開されない。

export table=member # 3
# ↑これが利用される。子プロセスで参照できるよう export している
query=$(sh -c "echo \"$text\"") #4
# ↑ここでtableの中身が展開されます。* の展開を防ぐため $text をダブルクォートで囲んでいることに注意
echo "$query" # 5

この結果は、

SELECT * FROM member

と出力されます。
処理の流れは以下のとおりです。

1: table 変数に book をセット
2: text 変数に SELECT * FROM ${table} をセット(table変数の中身はここでは見ない)
3: table 変数の内容を member に書き換え
4:

sh -c "echo \"$text\""

を実行、shが立ち上がり、

echo "SELECT * FROM ${table}"

を実行する。(ここでtableが初めて展開される)
query 変数に、echo が出力した SELECT * FROM member をセットする。(ここでは変数代入だけで画面には出力されない)
5: query 変数の内容、SELECT * FROM member を表示する

あまりやらないですが、こういう複雑な処理でも期待通り動作するのは、適切にクオートしているおかげですね。

グループ権限あれこれ

– 以降作るファイル, ディレクトリをグループ権限で書き込めるようにする。

$ umask 0002

※影響範囲は全ディレクトリについて、自身のプロセスと子プロセス。
– 指定したグループとして作業する(作ったファイルの所有グループを任意のものにする)。

$ sg groupname

– ディレクトリに対しての sgid の効果。
指定したディレクトリ以下に作成したファイルのグループを全て sgid したディレクトリのグループ所有とする。

$ ls -ld foo/
drwxrwxr-x 4 user mygroup – 512 Nov 10 09:33 foo/
$ touch foo/file1
$ ls -l foo/file1
-rw-r–r– 1 user users 0 Dec 13 12:30 foo/file1
$ chmod g+s foo/
$ ls -ld foo/
drwxrwsr-x 4 user mygroup – 512 Nov 10 09:33 foo/
$ touch foo/file2
-rw-r–r– 1 user mygroup 0 Dec 13 12:35 foo/file2

jvim での文字コード明示読み込み

jvim がファイルの文字コードを誤って解釈してくれた時や新規作成の時は文字コード明示をするとよい。

jvim -k s foo.txt

“-k” オプションで一文字で文字コードを指定する。

SJIS: s
EUC: e
UTF-8: t

など。その他 u とかもあるけど忘れた。
 
忘れていたのでメモしとく。

マウントしているファイルシステムのタイプを調べる

df -T

でOK. 結果は次の通り

Filesystem Type 1K-blocks Used Available Use% Mounted on
/dev/hda1 ext3 36867308 3663864 31330672 11% /
tmpfs tmpfs 452704 0 452704 0% /dev/shm

FreeBSD 4.10 付属のものにはないオプションだけど、FreeBSD ではどう調べるのだろう。

lsvfs
df -t nullfs,ufs

とかしていくしかないのかな。

xargs が標準入力が空のときにも実行されてしまう

find . -type f | xargs wc -c

など xargs を使うときに、標準入力が空だと実行されないのかと思っていたら、標準入力がなくても一度は必ず実行するというのがデフォルトだった。このため、上の結果は wc -c < /dev/null のようにとられて 0 になる。
これを避けるには、 -r オプションを使う。

xargs -r <command>

上の例だと次のようにすればよい。

find . -type f | xargs -r wc -c