PHPでfsockopen関数を使うと「Permission Denied」というエラーが出てしまって、うまく動作してくれないという問題に出会いました。。
前置き:この問題に出会った理由
別記事「phpでActiveMQのQueueとstompを使ってやりとりする方法」を実施する際に、Stompがうまく動作しませんでした。
Stompの説明は別記事参照。
とにかく、Stomp内の以下のコードでエラーが出ていました。
$this->_socket = @fsockopen($scheme . '://' . $host, $port, $connect_errno, $connect_errstr, $this->_connect_timeout_seconds);
最初はActiveMQ側に問題があると思って調べていたのですが、実際のところ、そうではなくて、php側(というか、phpの動作しているサーバ側)に問題がありました。
エラーの内容は「13:Permission Denied」というものです。これはActiveMQ側のサーバで権限が足りないわけではなくて、phpプログラムを実行しているユーザに、ソケット通信をする権限がありませんという話でした。
SELinuxという罠
本当は罠ではなくて、セキュリティ上の重要な役割を果たしてくれる存在であるSELinuxが今回は悪さをしていました。
SELinuxがphpの実行ユーザ(Apache?)にソケット通信を許可していなかったんです。
こういう思いもしないことって見つけるの難しいですね。。
解決方法は2つ
1.SELinuxの無効化
ちょっと乱暴だけど、そもそも外部からの侵入はないし、また別のところでトラブルを起こされたらかなわない!!という場合は、以下のようにして、SELinux自体を無効化してしまえます。
設定を反映させるにはサーバの再起動が必要みたいです。
# vi /etc/selinux/config # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=disabled # SELINUXTYPE= can take one of these two values: # targeted - Targeted processes are protected, # mls - Multi Level Security protection. SELINUXTYPE=targeted (:wqで保存して終了)
一時的に無効化したいときは以下。
こちらは即時反映されます!
# setenforce 0
ちなみに、SELinuxの状態を確認したいときは以下のコマンド。
# getenforce Enforcing : 有効 Permitted : 実質無効(注意は出る?) Disabled : 無効
2.SELinuxの設定変更
今回の問題だけを解決したいときは、以下のコマンドでOK。
# setsebool -P httpd_can_network_connect 1
これで、phpでfsockopenを使ってもエラーは起きなくなります。
ちなみに、設定が有効になっているかを確認するには以下のコマンドです!
# getsebool -a | grep httpd … httpd_builtin_scripting --> on httpd_can_check_spam --> off httpd_can_network_connect --> on httpd_can_network_connect_cobbler --> off httpd_can_network_connect_db --> off …
おしまい
思ってもみないところでハマることがあると勉強になりますね。ということで、SELinuxに関する勉強もしたいと思った次第です!