2013/10/30
2013/10/02
国別フィルタの自動生成ツール
bsdhack.org ドメインは FreeBSD でサーバを構築しているのだが、
特定の国からのアタックや迷惑メイルが非常に多いので
ipfw (8) によるフィルタリングを利用して
指定した国からのパケットを拒否する設定を自動生成するツールを作成した。
APNIC から IPアドレスの割当リストを取得して、
IPアドレスを CIDR 型式に修正した上で
ipfw (8) のコマンドラインパラメタを自動生成している。
スクリプトは FreeBSD の ipfw (8) 向けだが、
出力部分を適宜修正する事で Linux の iptables (8) 向けの
設定も出力可能だと思う。
1#!/usr/bin/perl 2use Socket; 3 4# IP アドレス割当リスト取得 URL 5$url = "http://ftp.apnic.net/stats/apnic/delegated-apnic-latest"; 6 7# FreeBSD の ipfw (8) のルール番号 8if(@ARGV < 1){ 9 $rule = 2000; 10} 11else{ 12 $rule = $ARGV[0]; 13} 14 15# 拒否対象の国コード 16@country = ('KR', 'CN'); 17 18foreach $i (@country){ 19 $country{$i} = 1; 20} 21 22if(open(IN, "fetch -q -o - $url|")){ 23 # 拒否対象の国の場合は IP アドレスを保存 24 while(<IN>){ 25 if(/^apnic\|(..)\|ipv4\|(\d+.\d+.\d+.\d)\|(\d+)/){ 26 if($country{$1}){ 27 $table{inet_aton($2)} = $3; 28 } 29 } 30 } 31 close(IN); 32 33 # 取得した IP 割当リストから開始アドレスと個数を取得 34 foreach $net (sort keys %table){ 35 $addr = unpack('N', $net); 36 $num = $table{$net}; 37 while($num == $num[0] && ($addr ^ $addr[0]) == $num){ 38 shift @addr; 39 shift @num; 40 $addr &= ~$num; 41 $num <<= 1; 42 } 43 unshift(@addr, $addr); 44 unshift(@num, $num); 45 } 46 47 # IP アドレスと個数を CIDR 型式に変換して出力 48 while (@addr){ 49 for($num = pop(@num), $mask = 32; $num > 1; $num >>= 1, $mask--){} 50 $filt = inet_ntoa(pack('N', pop(@addr))) . "/$mask"; 51 # FreeBSD の ipfw(8) 向け出力 52 print "\${fwcmd} add $rule deny ip from $filt to any in recv \${wan}\n"; 53 # Linux の iptables(8) 向け出力 54 # print "\${iptables} -A INPUT -s $filt -j DROP\n"; 55 $rule++; 56 } 57} 58 590;
FreeBSD の場合は WAN 側のインタフェイス名が '${wan}' 変数に、 iptables コマンドの実行ファイル名が '${ipfw}' 変数に それぞれ格納されている事を前提としたスクリプトになっているので、 利用する際は適宜変更しながら使って下さい。
2013/09/18
main 関数の書き方
こちらの記事に触発されて、 C で同じお題のプログラム (echo (1) のサブセット)を書いてみた。
main には殆ど処理を記述せずに
パラメタ解析や割り込みなどの初期設定のみをしてから、
実際のメイン処理(この場合は echo)を実行するというスタンスは同じです。
ただし、今回の例で言えば getopt(3) を利用して
オプション解析を済ませた(実際に echo 出力する)パラメタ群のループは
main 側で行う方が好きかな。
1#include <stdio.h> 2#include <unistd.h> 3 4void echo(const char *p, int nonl) 5{ 6 7 /* 8 * ここは以下の様にすると printf(3)、putchar(3) の呼び出しを 9 * printf(3) の呼び出しのみに変更できソースもスッキリする。 10 * 1 文字の出力を '%s' で変換する無駄が微妙に気になるのだが、 11 * どちらかと言えば改行を出力する事の方が多いと思うので 12 * putchar(3) の呼び出しがない方が良いのか 13 14 printf("%s%s", p, nonl ? "" : "\n"); 15 16 */ 17 18 printf("%s", p); 19 if(!nonl) 20 putchar('\n'); 21 22} 23 24int main(int argc, char *argv[]) 25{ 26 27 int i, 28 nonl = 0; 29 30 while((i = getopt(argc, argv, "n")) != EOF){ 31 switch(i){ 32 case 'n': 33 nonl = 1; 34 break; 35 36 default: 37 break; 38 } 39 } 40 41 for(i=optind; i<argc; i++) 42 echo(argv[i], nonl); 43 44 exit(0); 45 46}
2013/08/02
シェルスクリプトでループ
シェルスクリプトでループ処理をする場合、
最も多用するのは while だと思う。
良く見かけるのは次の様な書き方だろう。
: while true do 処理 if 条件 then break fi done :勿論この書き方でも問題なく動作するが、 条件がコマンドの戻り値の場合は以下の方が簡潔に記述できる。
コマンドの戻り値が 0 (正常終了の場合) ループを続けたい場合。
: while コマンド do 処理 done :コマンドの戻り値が 0 以外(正常終了以外の場合) ループを続けるのであれば while の替わりに until が利用できる。
例えば再起動中のリモートサーバに ssh (1) 接続したい場合、 以下の方法で繰り返し接続を試行する事ができる。
until ssh -o 'ConnectTimeout 5' リモートサーバ do sleep 10 donessh (1) が成功するとリモートサーバから exit した時点で until の条件が真になるのでループを抜ける事ができる。
2013/07/31
MySQL データベースを Amazon S3 にバックアップするスクリプト
自宅サーバで運用している MySQL データベースのデータを Amazon S3 にバックアップするためのスクリプトを作成したので公開。
今回作成したスクリプトでは、
ローカルディレクトリに YYYYMMDD 型式で 7 世代分のデータをフルダンプし、
毎週日曜日の深夜に Amason S3 に当日分のバックアップを転送している。
mysqldump で取得したバックアップデータに VIEW 情報が含まれていると
データベースのレストア時にエラーが発生する可能性がある様なので、
mysqldump 時に VIEW 定義は除外してダンプを取得し
VIEW 情報のみを別途ダンプする様にしている。
Amason S3 への転送は S3 tools が公開している
s3cmd を利用しているので、
s3cmd と python のインストールは必須。
当然 Amazon S3 も利用できる様にしておく必要がある。
以下のスクリプトは MySQL の接続用パスワードや
Amazon S3 のアクセスキーなどを平文で保存しているので、
ファイルのアクセス権限には十分に注意が必要である。
バックアップは root 権限で実行する様にし
ファイルの権限は 500 に設定しておく事が望ましい。
1#!/bin/sh 2 3# MySQL 用の設定 4database="データベース名" 5user="-uユーザ -pパスワード" 6 7# Amazon S3 用の設定 8backet="backet 名" 9PASSPHRASE="パスフレーズ" 10AWS_ACCESS_KEY_ID="アクセスキーID" 11AWS_SECRET_ACCESS_KEY="SECRET アクセスキー" 12 13# ローカルにバックアップする世代数 14max=7 15# Amazon S3 に転送する曜日指定 (0: 日曜 … 6: 土曜) 16dayofweek=0 17 18# コマンド定義 19ls="/bin/ls -1" 20wc="/usr/bin/wc -l" 21rm="/bin/rm -r" 22head="/usr/bin/head -1" 23mkdir="/bin/mkdir -p" 24 25# ファイルとディレクトリ定義 26logfile="/var/log/`basename ${0}`.log" # ログファイル名 27backupdir="/var/db/backup" # バックアップ先ディレクトリ 28target="`date '+%Y/%m/%d'`" # Amason S3 でバックアップを格納するディレクトリ名 29targetdir="${backupdir}/`date '+%Y%m%d'`" # ローカルでバックアップを格納するディレクトリ名 30backupfile="${targetdir}/all_dump.sql" # バックアップファイル名 31createview="${targetdir}/create_view.sql" 32createtable="${targetdir}/create_table.sql" 33 34# MySQL コマンドの定義 35mysql="/usr/bin/mysql ${socket} ${user} -B -N -s -r " 36mysqldump="/usr/bin/mysqldump ${user} 37 -R --hex-blob --single-transaction" 38sql="select TABLE_NAME from information_schema.TABLES 39 where TABLE_SCHEMA = '${database}' and TABLE_TYPE = 'VIEW';" 40 41# s3cmd の定義 42s3cmd="/usr/bin/s3cmd put -rr" 43export PASSPHRASE AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY 44 45# ロギング開始 46umask 700 47exec > ${logfile} 2>&1 48set -x 49 50# ローカルディレクトリの準備 51# 最大世代数以上の場合は一番古い世代を削除する 52test `${ls} ${backupdir} | ${wc}` -ge ${max} && 53 ${rm} ${backupdir}/`${ls} ${backupdir} | ${head}` 54${mkdir} ${targetdir} 55 56echo "DB backup: start: `date`" 57 58# ダンプから除外するために VIEW を取得し create view 文をダンプする 59for i in `${mysql} ${database} -e "${sql}"` 60do 61 view="${view} --ignore-table=${database}.${i}" 62 ${mysql} ${database} -e "show create view ${i}" 63done > ${createview} 64 65# 全データダンプ 66${mysqldump} ${view} ${database} > ${backupfile} 67 68# create table 文のダンプ 69${mysqldump} --no-data ${view} ${database} > ${createtable} 70 71# 指定された曜日の場合は Amazon S3 に転送する 72# 以下の 1行をコメントとすると 毎日 Amazon S3 に転送する 73test `date '+%w'` -eq ${dayofweek} && 74 ${s3cmd} ${targetdir}/ s3://${backet}/${target}/ 75 76echo "DB backup: end: `date`"
2013/07/30
awk による正規表現にマッチした部分の抜き出し
入力行に "running"、"stopping"、
"stopped"、"pendding" のいずれかの単語が含まれる場合に
その単語を抽出したい場合。
awk (1) の sub()、gsub() 組み込み関数では
後方参照ができないので
マッチしたパターンに応じた変換を一度に行う事ができず、
それぞれのパターンにマッチングさせて処理をするしかない。
awk ' /^INSTANCE.*running/{ print running; } /^INSTANCE.*stopping/{ print stopping; } /^INSTANCE.*stopped/{ print stopped; } /^INSTANCE.*pending/{ print pending; } 'しかしこれではあまりにも悲しいのでマニュアルをじっくりと調べた所、 組み込み関数 match() で正規表現にマッチ処理を行うと 組み込み変数 RSTART にマッチした文字の位置、 RLENGTH にマッチした文字列の長さが設定されるので 組み込み関数 substr() と併用する事で マッチした部分を抽出する事ができる事に気がついた。
awk ' /^INSTANCE/{ if(match($0, /running|stopping|stopped|pending/)) print substr($0, RSTART, RLENGTH); if(match($0, /ec2.*\.amazonaws\.com/)) print substr($0, RSTART, RLENGTH); } 'awk (1) で正規表現によるパターン抽出を行う場合に便利だと思います。
文字列はあくまでも例であって特別な意味を持っていません。
万が一類似する文字列があった場合でもそれは偶然の一致です。
ぐ、偶然ですからねっ(汗
2013/07/09
PATH の扱い
unix 系 OS では ${PATH} 環境変数を参照して
コマンドの検索パスを指定する事ができる。
通常はログイン時にシステムデフォルトのコマンド検索パスが
${PATH} に自動で設定されているが、
ユーザ毎のシェルのログインファイル (.profile 等)で
自分用のコマンド検索パスを追加設定する事が多い。
ここで気をつけるべきは ${PATH} 中のヌルパス ("::") は
カレントディレクトリ (".") と同等に扱われてしまう事だ。
例えば
PATH="${PATH}:${mypath}:${HOME}/bin"と設定した時に ${mypath} が設定されていない場合
PATH="${PATH}::${HOME}/bin"と展開されてしまうので、 結果としてカレントディレクトリが ${PATH} に含まれてしまう。
この挙動は POSIX (IEEE Std 1003.1, 2004 Edition) の 8.3 Other Environment Variables) にも明記されている。
The prefixes shall be separated by a colon ( ':' ). When a non-zero-length prefix is applied to this filename, a slash shall be inserted between the prefix and the filename. A zero-length prefix is a legacy feature that indicates the current working directory.過去互換性の様だが非常に迷惑な仕様である。
カレントディレクトリをコマンド検索パスに含める事は
どんな場合でもセキュリティ上のリスクを伴うので避けるべきでなので、
PATH を設定する場合は注意が必要だ。
例えば .profile で ${PATH} を設定する場合、
以下の様にする事は防衛手段として悪く無い考えだと思う。
PATH="`echo ${PATH}:${mypath}:${HOME}/bin | sed 's/::*/:/g'`"
2013/07/08
バーベキュー
金曜日の夕方過ぎに自宅から連絡があり、
唐突に土曜日は朝から道志川界隈にバーベキューに行くことに。
実はご近所さんにご一緒にと誘って頂いたのだが、
娘もとても仲良くしているお友達なので勿論行ってきました。
しかも場所の選定、バーベキューの道具(グリルやらテーブルやら)から
食材に至るまで完パケで用意して頂けたので感謝感激です。
仕事に行くよりも断然早く、朝 6 時に起きて 7 時出発。
車 2 台で向かったのは道志川沿いの「道志の森キャンプ場」。
ちゃんとしたキャンプ場ですがバーベキューなどのデイキャンプも可の様で、
しっかりテントを貼ったキャンパー風の一行から、
我々の様なバーベキューを楽しみに来た家族連れまで賑わっていました。
川の水はとっても冷たかったのですが、
娘達と一緒に脚まで水に浸かって目一杯楽しんだ後は
美味しいバーベキューに舌鼓の乱れ打ち。
ちゃんと火おこしや調理など頑張って働きましたよ!
河原でのバーベキューなんて 10 年以上ぶりの事なので、 娘よりも親の方がはしゃいでしまったけど、 暑すぎず寒くもなくとても楽しい一日でした。
お誘い頂いて本当にありがとございました♪
2013/06/12
久々の迷惑メイル
先ほど携帯に届いた迷惑メイル。
やりくちがあまりにも下衆なので修正なしで晒す。
From: A1yxESBRcL@sda12.hkdsf0fbgw.net最近の迷惑メイルの特長として From アドレスがランダムな文字列になっていて、 docomo の迷惑メイルフィルターに引っかからない様になっているらしい。
To: XXXX@docomo.ne.jp
Date: 2013/ 6/12 18:30
Subject: 各携帯会社とご契約のお客様へ
携帯電話ご使用のお客様へのご請求額
今回の請求に対する確認はこちら。
http://sda12.hkdsf0fbgw.net/wxp/?vu=XXXXXXXXXXXXXXX&mop=1&XXXXXXXX
▼メインメニュー▼
http://sda12.hkdsf0fbgw.net/menu.php?vu=XXXXXXXXXXXXXXX
◆『18才』未満 不可◆
【Follow-Me】
【お問い合わせ】
support@yes-follow-me.com
はなはだ鬱陶しい限りだ。
世の中には救い様のないクズがいるという事を改めて認識する
2013/05/27
レアチーズケーキ
KRAFT の PHILADELPHIA クリームチーズを使ったレアチーズケーキのレシピ。
基本的にはクリームチーズに同梱されているレシピ集に従うのだけれど、
一部、以前アルバイトをしていた喫茶店での作り方を参考に
独自のアレンジを加えてあります。
割と手軽に本格的なレアチーズケーキができるのでお勧めです。
KRAFT PHILADELPHIA クリームチーズ
200g (1箱)
中沢サワークリーム
90ml (1パック)
ホイップクリーム
200ml (1パック)
砂糖
70g
レモン汁
大さじ1
バニラエッセンス
適宜
粉末ゼラチン
7g
白ワイン (ゼラチン用)
70ml
森永ビスケットチョイス
90g (10枚)
バター
40g
-
バターを室温に戻す
-
ゼラチンを白ワインに振り入れて暫くふやかす
-
ビスケットを密封袋にいれる
-
ビスケットを麺棒などを利用して細かく砕く
-
砕いたビスケットと室温に戻したバターを馴染む様に良く混ぜ合わせる
-
混ぜ合わせたビスケットを型の底に敷き詰めてスプーンの背などで押さえつける
-
弱火にかけた鍋にクリームチーズと砂糖を入れて混ぜ合わせる
-
良く混ざったら火を止めてサワークリーム、レモン汁、バニラエッセンスを加えて更によく混ぜる
-
ホイップクリームを六分立てにする
-
ホイップクリームの上に裏ごし器を置く
-
混ぜ合わせたクリームチーズを裏ごししてホイップクリームとまぜる
-
湯煎して溶かしたゼラチンをクリームチーズに加えて更に良く混ぜる
-
型に流し込みラップで蓋をして数時間冷やしたら出来上がり
お好みでジャムやブランデーをふりかけて美味しくいただきましょう