モーグルとカバとパウダーの日記 このページをアンテナに追加 RSSフィード Twitter

モーグルやカバ(EXカービングスキー)、山スキー(BC)の山行記録などがメインの日記です。
いろんな条件のいろんなところを、その時々の条件にあった滑り方で楽しむ、フリースキーをして遊んでいます。

検索で来られた方は、上の検索窓から再度検索していただくか、右サイドバーのカテゴリーやトピックスの項目で絞り込んでみてください。
仕事柄、コンピュータ系のネタも多いので、スキー関連ネタだけ読みたい方は[ski]、コンピュータ関連ネタは[pc]、スパム関連ネタは[spam]で絞り込んでください。

2015-04-21 (Tue)

[]MySQL WorkbenchがWin7/8でSSH経由で接続してる時selectが止まる問題 MySQL WorkbenchがWin7/8でSSH経由で接続してる時selectが止まる問題を含むブックマーク MySQL WorkbenchがWin7/8でSSH経由で接続してる時selectが止まる問題のブックマークコメント

他の人のWin7環境にMySQL Workbenchを入れてテーブルを見ようとしたところ、テーブルを見ようとselectしただけで止まってしまう(ハングしてる感じ)問題が起きました。

これ、全てのテーブルがダメなわけではなく、一部のテーブルを見ようとしただけでこの状況が起き、見れるテーブルは全く問題なく見れるのです。

止まってしまうテーブルは、limitの設定を小さくしてもやはり止まってしまいました。

また、自分のWin8.1で同じバージョン、設定で見ても問題なく見れました。ただ、一度同じような問題が発生したことがありました。(その後再現せず)


それで同じ問題にはまってる人がいないかぐぐってみたのですが、日本語の情報はなかなか無く、でも英語だともろそのものな感じの情報が見つかりました。

MySQL Bugs: #73343: Workbench Freezes on Remote SSH Server Query

MySQL Workbench hang on fetching more than some size of data - Stack Overflow


どうも

という条件でのみこの問題が発生するようで、自分の例のように同条件でも発生したりしなかったりするようです。


MySQLのmax_allowed_packet設定を大きくすることで改善したという報告もありましたが、確実ではないようです。

MySQL Workbench 6.0.9にダウングレードすると確実に改善するようです。

MySQL :: Download MySQL Workbench(6.0.9)のダウンロードページ


結局、6.0.9にダウングレードすることで対処しました。

なぜこんな謎現象が発生するのか不思議です…


(追記)

6.3.xなら治ってるかな…?と思って探してみたのですが、まだダメらしいです。

http://bugs.mysql.com/bug.php?id=74557

トラックバック - http://d.hatena.ne.jp/stealthinu/20150421

2015-04-02 (Thu)

[]javascript重複チェックとソート javascriptで重複チェックとソートを含むブックマーク javascriptで重複チェックとソートのブックマークコメント

「grape,apple,orange」のように、カンマ区切りで入力された内容を重複チェックするために、ハッシュにいれることで行いました。

例えばこんな感じです。

  input = "grape,apple,orange,apple";

  var results = {};
  var inputs = input.split(",");
  for (var i = 0; i < inputs.length; i++) {
    results[inputs[i]] = true;
  }

  for (var result in results) {
    console.log(result);
  }
grape
apple
orange

この結果をソートしたいという要望が出たため、ハッシュ results をソートしようとして results.sort() としたのですが、出来ないのですね。

あれ?出来なかったっけ?と思ったんですが、javascriptだと出来ない感じ… perlなら出来るのに。


というわけで、一度配列に突っ込み直してソートしました。

  input = "grape,apple,orange,apple";

  var results = {};
  var inputs = input.split(",");
  for (var i = 0; i < inputs.length; i++) {
    results[inputs[i]] = true;
  }

  var resultsArray = [];
  for (var result in results) {
    resultsArray.push(result);
  }
  resultsArray.sort();

  for (var i = 0; i < resultsArray.length; i++) {
    console.log(resultsArray[i]);
  }
apple
grape
orange

なんかひと手間感ありますね。


これってもっと良い方法あるのかな?

こうするといいよってのありましたら教えてください。


(追記)

@kotyさんから

input.split(',').reduce(function(prev,curr){if(prev.indexOf(curr)===-1)prev.push(curr); return prev;}, []).sort();

通りすがりさんから、ES6ならば

[...new Set(input.split(','))].sort();

といただきました。

関数型の威力をみせつけられましたねえ…

kkotyykkotyy 2015/04/02 16:42 input.split(',').reduce(function(prev,curr){if(prev.indexOf(curr)===-1)prev.push(curr); return prev;}, []).sort();

でいけました。IE8以前だと動きませんが。

stealthinustealthinu 2015/04/02 18:16 おお、すばらしい。なるほどreduceこういう感じに使うといいのか。
これ見て思ったんですが、sortしてからシュリンクすればもっと単純になりそうですね。

stealthinustealthinu 2015/04/02 18:21 …と思ったんだけどあんまりうまくいかないや。
全部と検索するんじゃなくて一つ前のと比べるだけだから単純になると思ったんだけど、別にpushする先がないとだめなのか。

kkotyykkotyy 2015/04/03 08:35 ちなみにTypeScriptだと
input.split(',').reduce((prev,curr) => {if(prev.indexOf(curr)===-1)prev.push(curr); return prev;}, []).sort();
と書けてプチハッピーです。filter/map/reduceはラムダ式と相性が良いです。

通りすがり通りすがり 2015/04/03 16:38 reduceとかを使う必要はありません。ES6なら
[...new Set(input)].sort()
だけで可能です。

stealthinustealthinu 2015/04/06 09:56 うおお、ほんとだ。なにこれすごい!
「...」になに埋めたらいいんだろ?と思ったら、これそのままで動くのですね。SetやMapはいわゆるSetやMapだろうということでわかるのですが、「...」の文法がよくわからんうえにググりにくい…
勉強してきます。

stealthinustealthinu 2015/04/06 10:20 Rest Parameters
http://odetocode.com/blogs/scott/archive/2014/08/18/features-of-es6-part-4-rest-parameters.aspx
というものでいいのでしょうか。
可変長引数をちゃんと渡せるようになる仕組み、という感じなのかな?
この手のことはnode界隈の人がよく扱ってる感じ。nodeだとブラウザのバージョンとか考えずに使えるもんね。うう、いいなあ。

通りすがり通りすがり 2015/04/08 07:15 「...」はRest/Spreadの関係で幾つかの構文が用意されています。
今回のは引数の方ではなく配列の要素として機能する方です。
また、Restは受け取り側なので、
var [a,b, ...c] = hoge;
とする時はRestですが、今回はSpreadです。
ですので「スプレッド要素」とでも呼ぶといいと思います。
全てをまとめて呼ぶときは「スプレッド構文」になると思います。
正式な名前が付いているわけではありません。

stealthinustealthinu 2015/04/08 10:48 ありがとうございます。
なるほど、newしたコレクションを「...」の場所にSpreadしてくれるのですね。
可変長引数のほうだけでイメージしてたのでわかりにくかったのですが、Spreadって言われるとわかりやすいですわ。
大変勉強になりました。ありがとうございます。

kkotyykkotyy 2015/06/29 18:04 今更コメントに気づいたんですが、ES6はすごいですね。
しかしブラウザの実装が追いついてないので、Babelってのを使うことになるんでしょうか。
http://codezine.jp/article/detail/8717

stealthinustealthinu 2015/06/30 09:51 FBとかみたいに通知飛ばないですからね… コメントでtwitterアカウント入ってたら通知飛ぶようになったらいいのに。
しかし、Babelってまた厨二心をくすぐられるネーミングですなw
ES6で書いたのをこれでコンパイルすれば良いのか。Typescriptとか使っている場合だとどうせコンパイルするんだから、それでぜんぜん構わんわけですよね。

kkotyykkotyy 2015/06/30 10:17 どこかで見かけましたが、近頃のJSは「コンパイルするもの」だそうです。なのでgulpやwebpackとかが流行っているのだろうと。

stealthinustealthinu 2015/06/30 14:21 そうなんですねえ。全然世の中の流れについていけてなくて悲しいです…

トラックバック - http://d.hatena.ne.jp/stealthinu/20150402

2015-03-17 (Tue)

[]Gmailで「ソーシャル」タブ等に自動分類されたものを排除して検索 Gmailで「ソーシャル」タブ等に自動分類されたものを排除して検索を含むブックマーク Gmailで「ソーシャル」タブ等に自動分類されたものを排除して検索のブックマークコメント

Gmailの受信トレイに、どうしても未読が5件残ってしまっていて気持ち悪い…という状況になっていました。


こういうときは検索で「in:inbox is:unread」と条件を指定すると、受信トレイにある未読を検索してくれます。

が「ソーシャル」タブに分類されているもの、例えばtwitterの反応とかの未読が大量にソーシャルタブにたまっているため、それを除いた真の未読を探そうとしても見つけきれませんでした。


twitterで嘆いていたところ「category:social」でソーシャルタブを指定出来ることを教えていただきました。

in:inbox is:unread -category:social -category:promotions


よく見ると、Gmailの上の検索のところで「検索オプションを指定」から「ソーシャル」を選ぶとこの条件指定がわかります。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150317

2015-03-10 (Tue)

[]Javaサーブレットでユーザのセッション数を取得する Javaサーブレットでユーザのセッション数を取得するを含むブックマーク Javaサーブレットでユーザのセッション数を取得するのブックマークコメント

Tomcatで動いているWebアプリケーションで、ユーザアカウント毎のセッション数制限を実装する必要が出ました。


調査したところ、3通りの方法が考えられました。


1. サーブレットにプローブを挿しといてそこから取得する

2. セッション生成削除のリスナーを設定してセッション情報コピーを作る

3. セッション情報をDBに持つように設定してDB経由で見る


このうち、1と2の方法を実際に作って試しました。


1の「サーブレットにプローブを挿しといてそこから取得する」という方法は、下記ページのやり方を真似しました。

DAY2907 セッション情報の一覧を取得する(Tomcat限定) - LHD Peugeot

ContainerServletのsetWrapperメソッドをオーバーライドしておいて、渡されてきた containerWrapper を保持しておき、セッション情報を見たいときにはそれ経由でセッションリストにアクセスするというものです。


取得した後の値のセッション情報の触り方などは、tomcatが標準で提供しているmanagerサーブレットのソースが参考になりました。

GC: ManagerServlet - org.apache.catalina.manager.ManagerServlet (.java) - GrepCode Class Source


ただ、この方法はtomcat依存になってしまう、という問題と、このサーブレット自体をJSPなどに埋め込むことはできない(オブジェクトとして持てない)ため、サーブレットに対してWebAPIなどを通じて情報を取得する必要がありました。



そこで2の「セッション生成削除のリスナーを設定してセッション情報コピーを作る」を試しました。


これは下記のページを参考にしました。

8. リスナー2 | TECHSCORE(テックスコア)

javax.servlet.http.HttpSessionListener は、web.xmlに<listener>で設定しておくと、サーブレットセッションが生成されたときと削除された時に呼び出されるように出来ます。


この時に得られるセッションオブジェクトは、単にその時のセッション状況コピーではなくて、サーブレット内のセッションオブジェクトそのものなので、そのまま保持しておくとセッション生成後に行われた変更も含めて全てのセッション情報を取得することが出来ます。

なので、セッション生成後にログイン処理がされてユーザ名のセットがされても、ちゃんと取得することが出来ます。

(最初その認識がなかったため、この手法は使えないと思っていた)


下記程度の簡単な内容でセッション情報を保持することが出来るようになり、JSPから普通にUserCounterオブジェクトを生成してユーザのセッション数などを得ることが出来ます。

public class UserCounter {
    private static final UserCounter INSTANCE = new UserCounter();
    private final Map<String, HttpSession> sessions = new HashMap<>();

    private UserCounter() {
    }
    
    public static UserCounter getInstance() {
        return INSTANCE;
    }
    
    synchronized public void addSession(HttpSession session) {
        sessions.put(session.getId(), session);
    }

    synchronized public void delSession(HttpSession session) {
        sessions.remove(session.getId());
    }
    
    synchronized public int countAllSessions() {
        return sessions.size();
    }
    
    synchronized public int countUserSessions(String username) {
        int userCounter = 0;
        for (HttpSession session: sessions.values()) {
            String sessionUsername = (String) session.getAttribute("username");
            if (sessionUsername != null && sessionUsername.equals(username)) {
                userCounter ++;
            }
        }
        return userCounter;
    }
}

public class UserCountListner implements HttpSessionListener {
    private final UserCounter counter = UserCounter.getInstance();

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        HttpSession session = event.getSession();
        counter.addSession(session);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        HttpSession session = event.getSession();
        counter.delSession(session);
    }
}

これはtomcat依存ではないため他のWebコンテナでも動くはずです。

ただ、1の方法のように全サーブレットセッション情報を取得するのではなく、listnerの設定をしたサーブレットセッションのみになります。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150310

2015-03-09 (Mon)

[]ムービーメーカー2012で縦長になる問題 ムービーメーカー2012で縦長になる問題を含むブックマーク ムービーメーカー2012で縦長になる問題のブックマークコメント

Lenovo G560でムービーメーカーが起動できない問題 でちょっと書いてたのですが、幼稚園のアルバム作成で付けるDVDの作成のため、ムービーメーカー2012を使って作っていました。(嫁が)


で、使いにくい部分が多々ありつつまあなんとか出来たのですが、最後DVD焼くところで問題が。

普通にPC上で作成した動画を確認すると普通に見えるのに、DVDに焼いたものを確認すると画像や動画がなぜか縦長になるのです。

ムービーメーカー 2012 縦長」あたりでぐぐると、マイクロソフトコミュニティサイトとかでも結構話題に上がっているのですが、そこで提示されている回答(ワイドスクリーン16:9を選択する)を試しても解決しませんでした。


非常に困ったのですが、下記サイトの方法で解決しました。

Windows ムービーメーカー 2012 で DVD を作成するとアスペクト比が 4:3 固定になる件 - hd 4.0

1. ムービーメーカーから直接 DVD 書き込みではなく、 mp4 形式で「高解像度用ディスプレイ用」で動画ファイルとして保存する

2. Windows DVD メーカー以外の DVD オーサリングソフトで DVD 書き込みを行う


また、こうやって作成したほうが画質もよくなるようです。

この問題はムービーメーカー2012のバグらしく、上記ページやぐぐって出てくるサイトを見ると結構多くの方が困っていることがわかります。

なんでこんなすぐわかりそうなバグが何年も放置されてるんだろ?と不思議です。

まあ、ちゃんと動画編集するような人はムービーメーカーなんて使わないってことなんでしょうね。

2015-02-20 (Fri)

[]Tomcatが動いているJavaだけ古いバージョンになる問題 Tomcatが動いているJavaだけ古いバージョンになる問題を含むブックマーク Tomcatが動いているJavaだけ古いバージョンになる問題のブックマークコメント

慣れないJavaTomcat用にサーブレットを書いていたのですが、それが開発PC上のNetBeansでは動くものの、テストサーバの上に持って行くと動かない、という状況になりました。


開発PC環境はWindows8+NetBeans8+Java7+Tomcat8で、(本番環境と同じにした)テストサーバ環境はCentOS6+Java7+Tomcat6という構成でした。


サーブレットTomcatのクラスを利用するものだったため、Tomcat8とTomcat6の違いの問題と考え、開発環境側のTomcatを6にしたりテストサーバTomcatを8にしたりして試したのですがダメでした。


最初、明確にTomcatのバージョンが違ったのでそっちのせいだろう、と思ってたのですが、よくよくcatalina.outのエラーを確認してみると

java.lang.UnsupportedClassVersionError: …

と言われており、TomcatのバージョンではなくJavaのバージョンが違うっぽいのが原因、とわかりました。

でもさすがに最初にそこは確認してたはず、と思ってNetBeansの利用ライブラリのバージョンが「JDK 1.7」であることを確認し、テストサーバ上でも

% java -version
java version "1.7.0_75"

となることを確認しました。


しかし、TomcatのWeb Application Manager

http://【テストサーバIP】:8080/manager/status

で確認すると、JVM Versionが「1.6.0_30」になっていることが確認できました。

というわけで、/etc/init.d/tomcat6 から起動されるTomcatはJava6を利用してしまうっぽい、ということがわかったのですが、なぜ1.7ではなく1.6が使われてしまうのかわからないという状況になりました。


そしてその時のtweet@_hito_ さんと @satoh_fumiyasu さんのからのリプライ。

この後、お二人から色々とアドバイスいただきました。超感謝です!

そのやりとり詳細見たい方は僕の最初のtweetとかから参照してみてください。


そのアドバイスと、そこから調査した結論をまとめると

  • JAVA_HOMEは /etc/tomcat6/tomcat6.conf で指定しとくべき

(じゃないとなにかちょっとしたことでJavaのバージョンが変わってしまうから)

  • JAVA_HOMEが指定されてない時のtomcat6のJavaのバージョンはjavacのバージョンになる

(/usr/share/java-utils/java-functions の set_jvm() 中でjavacのバージョン見てる)

ということになりました。


そこで /etc/tomcat6/tomcat6.conf の最初にコメントアウトされたJAVA_HOMEのところを /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.75.x86_64 にすることで、無事にTomcatもJava7で動かすことが出来るようになりました。


ただ、疑問だったのがなぜこの状況になったのか、ということです。

実は /etc/alternatives/java* を確認していて、javaだけが1.7を指しており、javacなど他のものはみな1.6系を指していることがわかっていました。

そこでyumで入れたjava系のものを確認すると

% yum list installed | grep java
java-1.5.0-gcj.x86_64  1.5.0.0-29.1.el6 @base
java-1.6.0-openjdk.x86_64
java-1.6.0-openjdk-devel.x86_64
java-1.7.0-openjdk.x86_64

と、develが入っているのは1.6だけで1.7は入っていないことがわかりました。

yumJavaの1.7を入れるとき、公開サーバ用だからdevelは要らないよね?ということで「java-1.7.0-openjdk」のほうだけを入れていたのでした。

ただ、java-1.6.0-openjdk-develは入っていたので /var/log/yum.log を確認したところ、なにかで ant が必要だった時に yumant を入れた際に java-1.6.0-openjdk-devel が入っていたことがわかりました。

すると、javacのバージョンは1.6になるため、前述のとおりjava-functionsの中で javac のバージョンを見て Java6 が選択されてしまう、という流れになったようです。


ということで最終的な結論。

CentOS6 で tomcat6 使っててjavaのバージョンを変更したい場合、java-1.7.0-openjdk-develなど「devel」のほうを入れて、/etc/tomcat6/tomcat6.conf で JAVA_HOME も明示的に指定しておくのが良い、ということでした。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150220

2015-02-18 (Wed)

[]WindowsNetBeans 8組み込みのTomcatでユーザとロールの設定場所 WindowsのNetBeans 8組み込みのTomcatでユーザとロールの設定場所を含むブックマーク WindowsのNetBeans 8組み込みのTomcatでユーザとロールの設定場所のブックマークコメント

NetBeansTomcat用のservletを作っていたのですが、Tomcat Webアプリケーションマネージャなどを使うためのユーザとロールの設定場所がわからずに困ったのでメモ。


まず最初に、Tomcatインストールされているディレクトリ以下の、conf/tomcat-users.xml ファイル

C:\Program Files\Apache Software Foundation\Apache Tomcat 8.0.1\conf\tomcat-users.xml

を修正してみたのですが反映されませんでした。


そこでNetBeansのサイトで、ここの設定について書いてるページを見ると

NetBeans IDEでのWebアプリケーションのセキュリティ保護

https://netbeans.org/kb/docs/web/security-webapps_ja.html


「サービス」→「Tomcat 8.x」→「プロパティ」→「ユーザ名/パスワード

あたりで変更できそうな感じになっているのですが、ここをやってもうまくいきませんでした。

というか、それ以前にユーザ名パスワードとも変更出来ない感じでした。


ここの「接続」タブの「Catalinaのベース」を確認すると

C:\Users\【ユーザ名】\AppData\Roaming\NetBeans\8.0.2\apache-tomcat-8.0.15.0_base

となっており、Windowsの場合だとこの下の設定が実際には効いているようです。


ここに conf/tomcat-users.xml ファイルが存在しているため、これにロールとユーザを追記します。

  <role rolename="manager-gui"/>
  <role rolename="manager-script"/>
  <role rolename="manager-jmx"/>
  <role rolename="manager-status"/>
  <user username="admin" password="admin" roles="manager-gui,manager-script,manager-jmx,manager-status"/>

修正後は先程のNetBeansの右クリックメニューから「リフレッシュ」で完了です。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150218

2015-02-09 (Mon)

[][]prelinkによりlsなどの基本的なバイナリのmd5sum値が変化してしまう prelinkによりlsなどの基本的なバイナリのmd5sum値が変化してしまうを含むブックマーク prelinkによりlsなどの基本的なバイナリのmd5sum値が変化してしまうのブックマークコメント

先日、すんごい焦った事例がありました。


サーバクラックされると、クラッカーにより/bin/lsや/bin/psなどの基本的なコマンドが置き換えられ、クラックされて置かれたファイルや動いているプロセスだけが見えなくなるようにして、クラックされていることがわからなくなるよう細工させられる場合があります。

そのため、そういったバイナリが置き換えられていないか、定期的にmd5sum値を取って確認するような簡単なチェック機構を入れていました。

(こういった用途にはTripwireのような専用ツールがありますが、あくまで簡易的な確認のためでここでは使っていませんでした。)

それが、確認するとmd5sumが先週と違っているという相談を受けました。

環境は CentOS 6.x です。


早速調べてみると、タイムスタンプは変化していないのにmd5sum値は違っていました。

また、md5sum値はサーバ毎に違っていたものの、バイナリサイズはどれも一緒でした。

ただ、先週はglibc脆弱性対応があり、/var/yum.log を確認してもupdateされていることが確認出来ました。

なので通常ならば glibcアップデートのせいだね〜、で済むところなのですが、今回の glibcアップデートは gethostbyname の脆弱性なので /bin/ls なんかが影響が受けるとは考えにくいところでした。


そこで、クラックされている可能性もある、という前提で調べてみることになりました。

とりあえず、新たに同じVPSで新規にCentOS6を生成して、そのmd5sum値を確認しました。

すると、その素のmd5sum値と、クラックされたことを疑っているサーバ群のmd5sum値はどれも違っており、バイナリサイズすら違っている状況でした。

また、glibcアップデートを掛けて、その後の変化を確認したのですが、md5sum値もバイナリサイズも、どちらも変化ないことを確認できました。

となると、クラックされてしまったと考えるほうが俄然優勢になってきます…


そこに救世主が!

prelinkとは共有ライブラリのリンク情報から事前にリンクを行うというものです。

それまで、確かにcronの中で見かけるものの、prelinkが何やってくれるものなのか、良く認識していませんでした。


先ほどの新規で生成したCentOS6環境に対して、

# prelink /bin/ls

すると、見事にmd5sum値が変わり、他サーバのファイルサイズと同じになることが確認できました。

また、glibcアップデート前にmd5sumを取ったものと、glibcアップデート後に取ったものを比較したところ、これも同様に変化しました。

これで、今回の変化はglibcアップデート+prelinkによるもの、と考えることが出来ました。


これまでもglibcのような基本的なライブラリに変更があった場合、md5sum値が変わっていたはずですが、それは「glibc更新したからだね」ということで流していたのだと思います。

それが今回は「gethostbyname」使っているものしか影響がない、というふうに、予測される影響範囲がわかりやすく限定されていたため、「lsならば影響受けないはず」という心理が働いて、クラックの可能性を考えてしまったのでしした。


そもそも、rpm(yum)で入れたバイナリは、同じバイナリがコピーされるわけだから、サーバが違っていてもmd5sum値は同じになる気がするのに、なんでサーバ間で違ってるんだろう?という疑問はあったのですが、これまではあまり深く考えていませんでした。

実際、インストールされたprelinkが掛かる前のバイナリと、rpmからrpm2cpioで直接取り出したバイナリとをmd5sum値を比べたところ、まったく同じものになりました。

また

# prelink -u /bin/ls

でprelinkの処理を戻すと、やはりmd5sum値がおなじになることがわかります。


CentOS6だとprelinkは cron.dailyに設定入っていて、デイリーで動くようになっています。

しかし、CentOS7だとデフォルト設定ではprelinkされないようになっているそうです。

prelinkのせいでAIDEのような改竄検知が誤動作したりやrubyのバイナリが破壊したりする問題があったそうなので、そういったことが考慮されたのかもしれません。


また今回のようにrpmで入れたバイナリのチェックには、独自にmd5sumを取るのではなく、「rpm -Va」を使ったほうが良いようです。

この場合だと、内部で prelink を戻してから比較されるため問題ないそうです。


これ、prelinkについてどんなものか知らないと、なかなか真の理由に辿りつけないと思います。

なにかの際に遭遇して、クラックされたか!?と思って焦らないように、ちょこっと覚えておいていただければ。


僕が泣き入ってる時にtwitterで色々とアドバイスいただいた、@hATrayfloodさん、@DQNEOさん、そして@hkobaさんに多謝です!!


(関連)

rpmで入れたバイナリのchecksumが一致しないと思ったらprelinkのせいだった - As a Futurist...

CentOS7からprelinkが無効に変更されていた件 - Qiita

CentOS 4.7 では prelink が ruby 1.9.1 のバイナリを破壊する - MoreslowlyWiki

CentOS6にアップグレードしたときのAIDE(改ざん検知)の注意点 | 気になるボックス

SIOS "OSSよろず" ブログ出張所: prelink されたバイナリの "rpm -V" での検証は無問題Linux Hacks:Linuxのパフォーマンスを改善する3つのTips (3/3) - ITmedia エンタープライズ

トラックバック - http://d.hatena.ne.jp/stealthinu/20150209

2015-01-05 (Mon)

[]javaのSimpleDateFormatで「YYYY」指定した時の挙動 javaのSimpleDateFormatで「YYYY」指定した時の挙動を含むブックマーク javaのSimpleDateFormatで「YYYY」指定した時の挙動のブックマークコメント

年末に突如発生したバグがあったのだけど、理由がよくわからない、というので調べてみました。


SimpleDateFormatで現在時間から日付を得ている部分があり、そこが問題だったようなのですが、その年のフォーマット指定が「yyyy」ではなく「YYYY」になっていました。

で、実はそれだと思ったんですが、テストで走らせてみると今はちゃんと動くのです。

不思議に思って下記のようにして日付を変えてテストしてみました。

Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date testDate = sdf.parse("2014-12-28");

SimpleDateFormat sdf1 = new SimpleDateFormat("YYYY-MM-dd");
String date1 = sdf1.format(testDate);

SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
String date2 = sdf2.format(testDate);

すると「2014-12-27」まではちゃんと「2014」を返すのですが「2014-12-28」からは「2015」を返すようになっていました。


で、なんでそんな仕様になってるの?と思ったら

と教えてもらいました。

Androidの公式アプリでもこの地雷を踏んでいたとは…


ややこしい日付の書式について - dechnostick's blog

日付フォーマット yyyy と YYYY の違い - 強火で進め


Java 7 から存在する仕様で「Y」は「暦週の基準年」を表すんだそうです。

SimpleDateFormat (Java Platform SE 7 )


これ、年末になってからはじめて発火するから、ほんと嫌がらせのようなバグになりますね。

トラックバック - http://d.hatena.ne.jp/stealthinu/20150105

2014-12-24 (Wed)

[][]CakePHPのUploadPackにPDFの画像化とサムネイル生成対応 CakePHPのUploadPackにPDFの画像化とサムネイル生成対応を含むブックマーク CakePHPのUploadPackにPDFの画像化とサムネイル生成対応のブックマークコメント

これはCakePHP Advent Calendar 2014の15日目の記事です。大変遅くなってしまってすみません…


CakePHPにはたくさんの便利なプラグインがあります。

その中に、UploadPackという簡単にファイルのアップロードを行えるプラグインがあります。

特に、画像のアップロードを行うとそのサムネイルや指定サイズにリサイズした画像を作る機能があり、便利に使えます。

ただUploadPackでサムネイル対応してくれるのは画像ファイルだけで、PDFのサムネイルや画像化の機能はありません。

以前の案件でその機能が必要だったため、UploadPackにPDFも画像化とサムネイル生成をするための機能を追加したので、公開します。

https://github.com/stealthinu/uploadpack/commits/convert_pdf_to_image


PDFから画像を生成するためには、GhostScriptを外部コマンドを呼んで行っています。

実は始めのバージョンではImageMagickで(内部でGhostScriptが呼ばれて)行っていました。

しかし、実際に稼働させてみるとCMYK(0,0,0,0)の色と透明色で色の違いが出てしまいました。

RGBではこの問題は起きず、CMYKの場合でのみ発生しました。

これを作ったのは印刷関係向けのWebサービスだったため、RGBの画像データよりもCMYKの画像データでアップロードされてきていたのでした。

最初、色ズレあるということで、ICCプロファイルの問題かと思い(ImageMagickで色味がおかしい、という話はだいたいICCプロファイルの問題に帰着するので)色々と調べたのですが、ICCプロファイルの問題ではなく、CMYK(0,0,0,0)と透明色とで色の違いが出ているということがわかりました。

また調査していく中で、GhostScriptを直接呼び出した場合はこの色ズレの問題が起こらず、変換後の画像品質も良い、ということがわかりました。

さらに色々とぐぐっていた中でGS直呼び出しよりImageMagick経由のほうがパフォーマンスがだいぶ悪くなるという話もありました。


というわけで、最終的にはImageMagickを使わずに直接gsコマンドを呼び出して使うような形になっています。

PHPでImageMagick使うこと自体がなにかと大変だったり、この案件Windowsサーバだったため、ImageMagickをWindowsのxamppに入れるのはだいぶ大変なので、そういう点からもImageMagick入れずに済むならそっちのほうが良いと思います。


CakePHPアドベントカレンダーなのに、ほぼImageMagickネタとなってしまいましたがお許しを…

[][]postscreenってどんなもの? postscreenってどんなもの?を含むブックマーク postscreenってどんなもの?のブックマークコメント

これはPostfix Advent Calendar 2014の18日目の記事です。こちらも大変遅くなってしまってすみません…


Postfixには2.8以降からpostscreenという機能があります。が、あまり知られていないと思います。

これはひとことで言うと、超軽量簡易スパムフィルタです。


Postfixにはsmtpd_*_restrictionsをはじめ、policydやfilterなど色々とスパムフィルタするための仕組みが用意されています。

にもかかわらずpostscreenが用意された理由は、postscreenは超軽量のためフィルタをすることで負荷も下げることが出来るからでしょう。

やまやさんPostfix Postscreen Howto - どさにっきで「トリアージ」と表現されているのですが、まさにそんな感じで、postscreenで怪しいメールだけをより詳しいチェックへと回してやり、大丈夫そうなメールは通常の処理で行う、という大まかなよりわけが行えるというものです。


PostfixSMTPセッション毎に一つsmtpdのプロセスが立ち上がるため、例えばtarpittingでのフィルタを掛けると、スパムによりsmtpdの同時起動数が増えてしまい、メモリ消費量などが増えてしまうという問題がありました。(そのため、接続が切れたら即smtpdプロセスが死ぬようなパッチを書いたりしました)

これに対してpostscreenでは、smtpdの前段に位置して1プロセスで処理を行うため、大量のスパムからの接続があってもプロセスの爆発が起こらずにフィルタすることが出来るようになっています。


postscreenで使えるフィルタは下記Howtoページから確認することが出来ます。

2.8.2のころから使えるフィルタは増えていないので、日本語訳の情報がそのまま使えます。


公式のPostscreen Howto

Postfix Postscreen Howto


Postfix-2.8.2のものですが、やまやさんによるPostscreen Howtoの日本語訳。

Postfix Postscreen Howto


マニュアルにpostscreenではどんなフィルタが利用できるのかが書いてありますが、どんなものかざっとわかるように短くまとめてみました。

  • Pregreet test

以前pregreet detectionでエントリーを書いたのですが、「220-server.example.com ESMTP Postfix」みたいに嘘のグリーティングメッセージを返して、答えを返しちゃったら負け、という手法

  • DNS White/blacklist test

複数の(DNSBL毎に重み付けした)DNSBLでマッチさせトータルが閾値以上になったかどうかを見る。

  • Command pipelining test

SMTPにはpipeliningをアナウンスされていなければ一応答ごとに一コマンドしか受け付けないのだが、スパムはそれを無視して連続してコマンドを送ってくる場合が多いため、それで判断する。

  • Non-SMTP command test

オープンプロキシを使って送ってくるbotだと、例えばHTTPで使われるCONNECTのようなSMTPには存在しないコマンドを使ってくることがあるため、そのようなコマンドで検知する。

  • Bare newline test

SMTPでは行が「CR LF」で終了することになっているのだが、単に「LF」だけで送ってくるものを引っ掛ける。


こうやって見るとどれも結構トリッキーなもので引っ掛けているなと感じるのではないかと思いますが、結構な確度でbotが引っ掛けられるのではと思います。


ほとんど、昔やまやさんが書かれたものをまとめただけ、というエントリーになってしまいましたが、これでpostscreenの認知度が少しでもあがればいいなと思います。


(参考)

Postfix Postscreen Howto

Postfix manual - postscreen(8)

2010年11月17日(水) Postfix Postscreen Howto - どさにっき

2011年4月8日(金) Postfix Postscreen Howto - どさにっき

Postfix Postscreen HowtoPostfix 2.8.2 に同梱の POSTSCREEN_README の翻訳)

pregreet detection - モーグルとカバとパウダーの日記