MySql の「unauthenticated user」。

サイトが激重になった調査と解決のログ。

とりあえずログインとプロセスの確認。

[server ~]# top
top - 16:07:35 up 97 days, 14:55,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:  37 total,   2 running,  35 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1998992k total,   577856k used,  1421136k free,   161764k buffers
Swap:        0k total,        0k used,        0k free,   295652k cached

平和だ。

ネットワークを疑う。

[server]# netstat -an
(略)

State "ESTABLISHED" が10個ほど。
そのうちの、全てが MySql のポート。


MySQL のプロセスを確認。

mysql> show processlist;

| 1401878 | root                 | localhost        | NULL | Query   |    0 | NULL  | show processlist | 
| 1401885 | unauthenticated user | xx.xx.xx.xx:pppp | NULL | Connect | NULL | login | NULL             | 
| 1401886 | unauthenticated user | xx.xx.xx.xx:pppp | NULL | Connect | NULL | login | NULL             | 
| 1401887 | unauthenticated user | xx.xx.xx.xx:pppp | NULL | Connect | NULL | login | NULL             | 
| 1401888 | unauthenticated user | xx.xx.xx.xx:pppp | NULL | Connect | NULL | login | NULL             | 
| 1401889 | unauthenticated user | xx.xx.xx.xx:pppp | NULL | Connect | NULL | login | NULL             | 
| 1401890 | unauthenticated user | xx.xx.xx.xx:pppp | NULL | Connect | NULL | login | NULL             | 

調べたところ
MySQLDNSの逆引きをする際に起こるらしい
参考) http://kennyqi.com/archives/70.html


対応もこのサイトの通りに

# vi /etc/my.cnf
[mysqld]
skip-name-resolve

で、すっきり解決しました。


だが何故突然、この現象が発生したのかは謎。
『「ESTABLISHED」10個、「unauthenticated user」が6個』は多いのか? 少ないのか?
MySQL のコネクションはデフォで100なのだから、この程度の量は問題ないと思ったのだが .....

謎は深まる。



ちなみに、MySQLのコネクション最大値。
( my.cnf に何も記述していない場合 )

mysql> show variables like 'max_connections'
    -> ;
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 100   | 
+-----------------+-------+
1 row in set (0.00 sec)

Web サーバーに繋がらないと思ったら iptables のせいでした。

RedHat Enterprise のネットワーク設定に詰まったのでメモ。

Apache 等のプロセスは立ち上げたのに、アクセスできない。
アクセスログも残ってない。

[ローカル]$ telnet xxx.xxx.xxx.xxx
Trying xxx.xxx.xxx.xxx...
telnet: connect to address xxx.xxx.xxx.xxx: Connection refused
telnet: Unable to connect to remote host

サーバーにログインして、自分でアクセスしたらちゃんと応答が返る

[サーバー]$ telnet localhost 80
GET / HTTP/1.1

(略 ちゃんと応答が帰ってる)

なので Apache はちゃんと動いてるっぽい。
ネットワークに問題が?

パケットを監視してみる

[サーバー]# tcpdump port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes

xxxxxxxxx > xxxxxxxxx.http: S xxxxxx:xxxxxx(0) win xxxxx <mss xxxx,nop,wscale 3,nop,nop,timestamp 257328529 0,sackOK,eol>

一行だけでも出力はしているので、パケットはとりあえず到着していると判断。
ここでネットワーク途中のFWではなく、サーバー内のFWを疑う。

[サーバー]# vi /etc/sysconfig/iptables

追記
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT
[サーバー]# /etc/init.d/iptables restart
[サーバー]# /sbin/iptables -L

ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:http 
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:https

http と https が ACCEPT になり、外からのアクセスも成功した。


たまにやる、慣れないディストリビューションの初期設定は地雷 orz

CentOS5.7 で rssh と chroot の設定をする。

CentOS 5.7 に rssh の設定をするログ。

目的

  • FTP はセキュアじゃないから使いたくない
  • FTPS は証明書の購入にお金がかかる
  • ユーザーに SSH のコマンドも打たせたくない
  • ユーザーが移動できるディレクトリを制限したい


※ 参考
rssh完全インストール-scpsftpをchrootしよう!part-1-インストール

1.rssh のインストール

yum 等では配布していないので、rssh の最新版を確認する
http://sourceforge.net/projects/rssh/files/rssh/

以下、サーバーに root でログインしたところから。
今回は、rssh-2.3.3。

# cd /usr/local/src/
# wget http://jaist.dl.sourceforge.net/sourceforge/rssh/rssh-2.3.3-1.src.rpm
# wget http://jaist.dl.sourceforge.net/sourceforge/rssh/rssh-2.3.3.tar.gz

ソースと rpm を両方ダウンロード。
( 後でソースが必要となるため。自分でconfigureとmakeをするならrpmはいらない )

# rpmbuild --rebuild rssh-2.3.3-1.src.rpm
# rpm -ihv  /usr/src/redhat/RPMS/i386/rssh-2.3.3-1.i386.rpm
# which rssh
/usr/bin/rssh

rpm のビルド

# vi /etc/shells
(追記)
/usr/bin/rssh

# vi /etc/rssh.conf
(以下のコメントを外す)
allowscp
allowsftp

2.ユーザーの追加

# adduser -s /usr/bin/rssh -d /home/scptest scptest
# passwd scptest
# cat /etc/passwd
(略)
scptest:x:501:501::/home/scptest:/usr/bin/rssh

3. chroot の設定

# tar zxvf rssh-2.3.3.tar.gz
# cp rssh-2.3.3/mkchroot.sh ~
# cd
# ./mkchroot.sh /home/scptest

# cd /home/scptest/
# vi etc/passwd
(対象のユーザー以外を削除)

ソース内に入っている mkchroot.sh を使い、 対象ディレクトリに chroot の設定をする。
[chrootdir] /etc/passwd 内の不要なユーザー情報を削除する

4.動作確認

別のマシンからアクセスのテスト

$ ssh scptest@192.168.0.100
scptest@192.168.0.100's password: 

This account is restricted by rssh.
Allowed commands: scp sftp 

If you believe this is in error, please contact your system administrator.

Connection to 192.168.0.100 closed.

$ scp dummy.txt scptest@192.168.0.100:.
scptest@192.168.0.100's password: 
dummy.txt                         

$ sftp scptest@192.168.0.100:.
Connecting to 192.168.0.100...
scptest@192.168.0.100's password: 
Changing to: /home/scptest/.
sftp> 

SCP / SFTP のみでアクセスできる事を確認。


5. 備考、まとめ

  • 参照元のサイトでは「mkchroot.sh」を修正していたが、今回は不要だった ( rssh のバージョンが違うからか )
  • rssh.confにユーザー個別の設定を追加できるが、必須ではない
  • エラーが起きた際の「ldd /usr/bin/scp => ライブラリの手動コピー」は覚えておいて損は無さそう
  • /dev/null や syslogd の設定をしなくても動いている。 必要かどうかは要検証

Apacheのバージョンが上がらない。

CentOS5.7 が出たらしいので ApacheKiller に対応した Apache2.2.20 をインストールしてみる。

# yum update httpd

Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: www.ftp.ne.jp
 * extras: www.ftp.ne.jp
 * updates: www.ftp.ne.jp
Setting up Update Process
No Packages marked for Update

あれ?

# cat /etc/redhat-release 
CentOS release 5.6 (Final)

# apachectl -v
Server version: Apache/2.2.17 (Unix)
Server built:   Dec 17 2010 11:58:24

# yum update

(略)

# cat /etc/redhat-release 
CentOS release 5.7 (Final)

# apachectl -v
Server version: Apache/2.2.17 (Unix)
Server built:   Dec 17 2010 11:58:24

え? 何故に?

ApacheKiller のアドバイザイリをちゃんと解釈してみる。

ApacheKiller 対策をしていて、公式のセキュリティアドバイザリをそのまま貼付けるのもコピペプログラマみたいで芸がないので、ちゃんと解釈してみる。

# Drop the Range header when more than 5 ranges.
# CVE-2011-3192
SetEnvIf Range (?:,.*?){5,5} bad-range=1

リクエストの属性に基づいて環境変数を設定する

HTTPリクエストヘッダフィールド(Range) が正規表現にマッチした場合に環境変数 bad-range=1 をセット。
http://httpd.apache.org/docs/2.0/ja/mod/mod_setenvif.html#setenvif

正規表現
『(?: ... )』 拡張正規表現 後方参照しない
『,.*?』の5回(以上)の繰り返しにマッチ

RequestHeader unset Range env=bad-range

RequestHeader リクエストヘッダディレクティブ
bad-range 環境変数がセットされている時に、RequestHeader から Range 属性を削除

http://httpd.apache.org/docs/2.2/ja/mod/mod_headers.html#requestheader

# We always drop Request-Range; as this is a legacy
# dating back to MSIE3 and Netscape 2 and 3.
RequestHeader unset Request-Range

Request-Range を削除。こちらは無条件に削除している。

# optional logging.
CustomLog logs/range-CVE-2011-3192.log common env=bad-range
CustomLog logs/range-CVE-2011-3192.log common env=bad-req-range

環境変数 bad-range、bad-req-range が指定されている時に、カスタムログ出力
ファイル指定(ServerRootからの相対パス)、ログのフォーマットは common(通常)
http://httpd.apache.org/docs/current/ja/mod/mod_log_config.html#customlog



まとめ。

  • 「1. 攻撃っぽかったら 2. ヘッダーだけ捨てて 3. ログを取る」の流れ。
  • 拡張正規表現とか、急に出てくると思い出せない。
  • 「{5,5}」が地味に冗長
  • ログの出力先を変更しているサーバーは、ちゃんと設定しよう。
  • 最後の「env=bad-req-range」って不要なんじゃ ...
  • アドバイザリにも書いてあるけれど、 Apache2.2 以上の設定です。

+Snippets Testing Tool 等。

Facebook の URL Linter (名前が Object Debugger に変わってる?) のような物を Google+ で発見したのでメモ。

Google

Rich Snippets Testing Tool



Google でも普通にOGPが使えてるので、+Snippet を使うよりも OGP だけ対応しておくのが楽かな?
( HEAD の中にまとめて書くので、マークアップ的にも楽 )
あと、Facebook の画面の方が見やすい。

Zend FrameWorkでCLIのスクリプトを実行するルーター

ZFでバッチ処理とかが、どうもすっきり書けないのでちゃんと考えてみた。

こちらの方の記事をかなり参考にさせて頂きました。
CLI(php コマンドライン) から Zend Framework アプリを実行するには - Enjoi Blog

この方のプログラムの Controlelr_Router と Console_Getopt をくっつけただけです。

<?php
require_once 'Zend/Controller/Router/Abstract.php';
require_once 'Zend/Controller/Router/Interface.php';

class Zend_Controller_Router_Cli extends Zend_Controller_Router_Abstract implements Zend_Controller_Router_Interface
{  
	public function assemble($userParams, $name = null, $reset = false, $encode = true)
	{}
	
	public function route(Zend_Controller_Request_Abstract $dispatcher)
	{	
		require_once 'Zend/Console/Getopt.php';
		$opt = new Zend_Console_Getopt(array(
				'action|a=s'		=> 'action',
				'controller|c=s'	=> 'controller',
				'module|m=s'		=> 'module',
			));
		
		$dispatcher->setControllerName($opt->controller)
				->setActionName($opt->action)
				->setModuleName($opt->module);
		
		return $dispatcher;
	}
}


あとは追加のパラメータをどう処理するかが課題。
ini ファイルからでも読み込ませるか?

そんな感じで。