Personal tools
You are here: Home ブログ matsuyama Categories network
Document Actions

network

Up one level

Document Actions

httptunnel + sshでセキュアなトンネルを掘る

会社から外部のsvnにアクセスできないのがつらすぎるのでトンネル掘ります。以下は外のsshに接続することを想定しています。

まずはsshなしでのトンネル。

サーバー:

% hts -F localhost:22 80

クライアント:

% htc -F 10000 -P proxy:port server:80

接続:

% ssh -p 10000

次はsshをかましたトンネル。

サーバー:

% hts -F localhost:22 80
% /etc/init.d/sshd start

クライアント:

% htc -F 10000 -P proxy:port server:80
% ssl -f -N -L 20000:localhost:10000 localhost

接続:

% ssh -p 20000

肝心なトンネルサーバーがないので動作確認していません。manページからの推測です。(ないとおもいますが)ステガノグラフィーもかましちゃえばほとんどはじかれる心配はないかと思われます。

PS: こういう記事問題あったら連絡ください(同時に技術に対する閉塞性の証明にもなっちゃいますが)、以後書かないので。まあ僕は健全なネットワーク管理テクニックだと思っていますが。

Category(s)
network
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/matsuyama/httptunnel-ssh30bb30ad30e530a2306a30c830f330cd30eb30926398308b/tbping

Re:httptunnel + sshでセキュアなトンネルを掘る

Posted by inoue at 2006-08-27 18:37
> こういう記事問題あったら連絡ください

問題はありません。

何が健全で何が不健全か、ぼくには分かりません。
何を守りたいかは人それぞれ違うので。

Re:httptunnel + sshでセキュアなトンネルを掘る

Posted by matsuyama at 2006-08-29 13:50
会社の人に迷惑かかったらやだなあというだけで、僕自身は別にどうでもよかったりします。

syslog-ngでログウォッチ

旧Blogでも書いたことですが、結構役に立つと思うので再掲します。

これからログウォッチを行おうと思っている方ならおそらくswatchの名前ぐらいは聞いたことがあるかもしれませんが、swatchはPerlで書かれている上、よくわからないロジックで実装されており正直バグだらけです(確証はありません)。ログというのは意外に負荷がかかるもので、それを独自にtail -fしつつperlのregexをかけるのはあまりにも現実的ではありません。それでswatchなどの(しょぼい)外部アプリよりログをそもそも出力している部分にログウォッチの処理を入れたくなるのが普通の欲求になるのですが、残念ながら一般的なログツールであるsyslogとsyslog-ngはともにその役割を十分に果たすには多少力が足りません。syslogはともかく、syslog-ngは冗長なconfig文法の割には拡張性がしょぼくて、かろうじて正規表現マッチはそなえているものの、同じ処理を一定期間停止するというログウォッチには必須なスロットル機能が書けているのです。まあおそらく作者の意図としては、そういうのは外部でやってくれということなのでしょうが、やはりあの冗長な文法の割にこのカスみたいな拡張性はいかんせん納得できないのです。 というわけで、スロットル機能の欲求をみたすべく簡単なアプリケーションを作ってみました。

throttle.cpp:

#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <utility>
#include <cstdio>
#include <cctype>
#include <ctime>
#include <cassert>
#include <unistd.h>
#include <fcntl.h>

// recommended to fix
static const char* record_file = "/var/state/throttle";
static const char* mailer = "/usr/sbin/sendmail";

using namespace std;

struct span_t {
    int hour;
    int minute;
    int second;
};

bool parse_hhmmss(const char* hhmmss, span_t* span) {
    assert(span);
    int* successor[3];
    successor[0] = &span->second;
    successor[1] = &span->minute;
    successor[2] = &span->hour;
    memset(span, 0, sizeof(span_t));
    const char* p = hhmmss + strlen(hhmmss) - 1;
    for (int i = 0; i < 3; i++) {
        int* cell = successor[i];
        for (int m = 1; p >= hhmmss; p--, m *= 10) {
            if (*p == ':') {
                p--;
                break;
            } else if (isdigit(*p))
                *cell += (*p - '0') * m;
            else
                return false;
        }
    }
    return true;
}

void exact_getline(string& s, istream& in) {
    char c;
    while (c = in.get(), !in.eof() && c != '\n')
        s.append(1, c);
}

void action_exec(int argc, char* argv[], const char* in) {
    cout << ">exec" << endl;
    string command;
    for (char** p = argv; p < argv + argc; p++) {
        command += string("\"") + *p + "\" ";
    }
    if (!command.empty())
        system(command.c_str());
    else
        cerr << "can not execute empty command" << endl;
}

void action_mail(int argc, char* argv[], const char* in) {
    if (argc < 2) {
        cout << "mail usage: to subject body" << endl;
        return;
    }
    cout << ">mail" << endl;
    
    string mail = string(mailer) + " -io -t";
    FILE* fp = popen(mail.c_str(), "w");
    if (fp == 0) {
        cerr << "can not open mailer pipe: " << mailer << endl;
        return;
    }
    
    fputs("To: ", fp); fputs(argv[0], fp); fputc('\n', fp);
    fputs("Subject: ", fp); fputs(argv[1], fp); fputc('\n', fp);
    fputc('\n', fp);
    if (argc > 2)
        fputs(argv[2], fp);
    else
        fputs(in, fp);

    pclose(fp);
}

int main(int argc, char** argv) {
    bool perline = false;
    if (argc > 1 && strcmp(argv[1], "-l") == 0) {
        perline = true;
        argc--;
        argv++;
    }
    if (argc > 3) {
        span_t span;
        if (!parse_hhmmss(argv[2], &span)) {
            cerr << "invalid span format: " << argv[2] << endl;
            return 1;
        }

        do {
            string line;
            if (perline) {
                exact_getline(line, cin);
                if (line.empty())
                    break;
            }

            time_t current_time;
            time(&current_time);
            
            // read all id and recorded time from the file and action if expired or new
            bool action = true;
            list<pair<string, time_t> > records;
            ifstream ifs(record_file, fstream::in | fstream::binary);
            if (ifs.is_open()) {
                while (!ifs.eof()) {
                    string id;
                    time_t recorded_time;
                    exact_getline(id, ifs);
                    ifs.read(reinterpret_cast<char*>(&recorded_time), sizeof(time_t));
                    if (id.empty())
                        break;
                    else if (id == argv[1]) {
                        double seconds = difftime(current_time, recorded_time);
                        if (seconds <= (span.hour * 360 + span.minute * 60 + span.second))
                            action = false;
                    } else
                        records.push_back(make_pair(id, recorded_time));
            }
                ifs.close();
            }
            records.push_back(make_pair(argv[1], current_time));
            
            // write all records
            ofstream ofs(record_file, fstream::out | fstream::binary);
            if (ofs.is_open()) {
                for (list<pair<string, time_t> >::iterator ite = records.begin();
                     ite != records.end(); ++ite) {
                    ofs << ite->first << endl;
                    ofs.write(reinterpret_cast<const char*>(&ite->second), sizeof(time_t));
                }
                ofs.close();
            } else {
                cerr << "can not open the record file: " << record_file << endl;
                return 2;
            }        
            
            if (action) {
                string command = argv[3];
                int    command_argc = argc - 4;
                char** command_argv = argv + 4;            
                if (command == "exec")
                    action_exec(command_argc, command_argv, line.c_str());
                else if (command == "mail") {
                    action_mail(command_argc, command_argv, line.c_str());
                } else
                    cerr << "unknown command: " << command << endl;
            }
        } while (perline);
    } else {
        cout << "Usage: [option] id span(HH:MM:SS) (exec|mail) [...]" << endl;
    }

    return 0;
}

これを適当に保存してコンパイルしてインストールしてください。

% g++ throttle.cpp -o throttle && cp throttle /usr/local/bin

使いかたは簡単です。

% /usr/local/bin/throttle
Usage: throttle [option] id span(HH:MM:SS) (exec|mail) [...]

optionには -l を指定することができます。これはsyslog-ngがプロセスを維持して使いまわすための対策オプションです。idにはthrottleのIDを指定します。spanにはHH:MM:SS形式で期間を指定します。HHとMMはともに省略可能です。execは...部のプログラムを実行します。mailは...部にto subject bodyというオプションを渡します。bodyを省略すればログ本文がbodyになります。

では実際にユーザーがログインに失敗したときにメールで管理者に通知するウォッチを書いてみましょう。

syslog-ng.conf:

filter f_authfail { match("authentication failure"); };
destination d_notifyadmin { program("/usr/local/bin/throttle -l notifyadmin 5:00 mail admin@somewhere \"Authentication failure!\""); };
log { source(s_local); filter(f_authfail); destination(d_notifyadmin); };

これで5分以内に何回ログインに失敗しようがメールが複数送られてくることはありません。sendmailといいprocmailといいsyslog-ngといい簡単なものをわざわざ難しくする才能には勝てません。

Category(s)
linux
network
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/matsuyama/syslog-ng30ed30a630a930c330c1/tbping

Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.