AtCoderでテストを簡単に行うツールを作成した

少し前から競技プログラミングに興味を持ち、AtCoderの過去問を解いている。
AtCoderの過去問は以下のサイトにまとめられている。
AtCoder Problems

解答プログラムのテストについて

解答プログラムができたらテストを行いたいと考える。
AtCoderのサイトでは、各問題に対して入力値と出力値のサンプルが提供されている。
テストを行いたい場合は、この入力値を作成した解答プログラムに与え、
プログラムの出力値とサイトに書いてある出力値と比較することで作成した解答プログラムの正しさを確認できる。
しかしながら、このテストを行う流れが割と面倒くさいという問題がある。
普段、自分はプログラムをターミナルエミュレータの上で書いて、更にその上でコンパイル、テスト実行を行っているのだが、
このやり方ではブラウザとターミナルエミュレータをいちいち切り替える必要があり手間が掛かる。
できれば全てをターミナルエミュレータ上で行いたい。
というわけでテストをコマンド1つで行えるツールを自作した。
似たようなツールはいくつか存在しているのだが、
個人的にあまり馴染めなかったため車輪の再発明を行ってしまった。

Atarg

ツールはAtargと名付けた。特に意味はない。
github.com

Pythonモジュールとして提供しているため、以下のコマンドで簡単に導入できる。

pip3 install atarg

使い方は簡単で以下通り。

usage: atarg [-h]
             {ABC,ARC,AGC} contest_no {A,B,C,D}
             command [command ...]]

具体例を挙げる。
Beginner Contestの018の問題Aをテストしたい場合はこうだ。

atarg ABC 018 A ./A

ここではカレントディレクトリにある実行ファイルAが解答プログラムとしている。
このコマンドを叩くと、Atargは問題の掲載されているWebページからサンプルの入力値と出力値を取ってくる。
その後、入力値を実行ファイルの標準入力へ与え、解答プログラムの出力値をWebページから取ってきた出力値と比較する。

個人的な使用法

これでもまだ問題はあって、Atargは与えるべき引数が多いため面倒くさい。
自分はAtCoderのプログラムを置くディレクトリを、例えばABC007であったら$HOME/Works/atcoder/ABC/007としている。
また解答プログラムについてはRustで作成しており、A.rsのようなファイル名を付けているため、rustcでコンパイルするとAという実行ファイルが出来上がる。
なのでatcというファイル名で以下のようなシェルスクリプトを書いて$HOME/.local/binに置いている。

gistdd42730cf48bf9be9a189eb2aa639d41
やっていることは簡単で、ディレクトリのパスにコンテスト名ABCと番号007が含まれているので、
切り出してAtargに与えている。
このスクリプトを利用することにより、Atargをそのまま使用するよりも簡潔に以下のようなコマンドでテストが行える。

atc A

これで明示的には解くべき問題(タスク)名だけを与えてやればよくなった。
これならタイプ量が減りより楽である。

課題

取り敢えずテストはできるようになったので、プログラムの提出も行えるようにしたい。
また、実行したプログラムが使用した時間とメモリ量も出力できるようにしたい。
これは作者自身のレベルが低く、まだ時間とメモリ量を意識するような問題を解いていないため後回しになる可能性がある。
更に困難な課題として、解答が複数個あるタイプの問題(例えば、ABC006のC問題など)には対応できていない。
上2つの課題がやるだけなのに対して、この問題については具体的な解決法が思いつかない。

まとめ

AtCoderでテストを簡単に行えるようにするプログラムを作成した。

React+Express+Node.js+MongoDBでブログっぽい何かを作る (2)React編前半

前回はExpressでAPIサーバを作った。
itto-ki.hatenablog.com

今回はReact+Reduxでフロントエンドを作っていく。
ただ、フロントエンドはやたらとコード量が増えたので、
ReactやReduxのtutorialを見れば分かるようなことには触れず、要点だけをまとめていく。

index.js

まずはエントリポイントとなるfrontend/project/src/index.jsについて。

gistced49142b1051759a64602b4a88d60b3

今回は非同期処理にredux-saga、ページ遷移処理にconnected-react-routerを使用している。
これらの仕様にはMiddlewareを用意してやる必要があるで、それを行っているのが13~15目。
ここで作ったMiddlewareを17~25行目でstoreに入れている。
複数のMiddlewareをstoreに渡す際にはapplyMiddlewareでまとめられる。

connected-react-router

今回のプロジェクトではルーティング処理にconncted-react-routerを使用した。
reactを補助するルーティングライブラリにはreact-router, react-router-reduxそしてconnected-react-routerと種類が豊富にあり、
どれを使用するのが良いのか非常に悩まされた。
様々な技術記事を読むとreact-router-reduxを使用している場合が多いみたいだが、サンプル通りコーディングしてもまともに動作しなかった。
α版だからかもしれないが、原因は現在調査中。


gist8a2c3c2ffc1b51ae382e9e1a297bc2de

今回はアクセスされるURLパスに応じて、それぞれ'/'ならArticleListに, '/new'ならCreatorコンポーネントに振り分けている。
ArticleListはトップページとなるもので、記事の一覧が表示される。
Creatorはその名の通り、新しい記事を作成するためのもの。
上記のコードの様に、Switchタグの外にTopBarタグを記述することによって、
TopBarコンポーネントはいずれのURLパスであっても表示される。
ただし、ConnectedRouterタグはchildren elementとして1つしかelementを持てないため、
divタグで全体を囲う必要がある。

非同期処理

これが今回のコードを書いていく上で1番感動した。
redux-sagaを使用すると非同期処理が同期処理の様に記述できる。
こんな感じに。

gist3ff31487571ea48a5a99a7ef4e839ef5

非同期処理として呼び出される関数がジェネレーター関数として定義されている。
50~54行目でジェネレーター関数と対応するaction typeを結びつけていて、
actionが発生するとそれに対応するジェネレーター関数が別スレッドで実行される。
このように記述できるおかげで、同期処理の様に書けることはもちろん、
シンタックスの上で同期処理とは独立しているように書けるためコードが簡潔になる。

まとめ

ブログっぽい何かについて、記事一覧と記事作成機能を作成した。
要点は2つで、ルーティング処理と非同期処理。
それぞれconnected-react-routerとredux-sagaを使用することで簡潔に記述することが可能になる。

ここまででとりあえずはブログっぽいものが動くようになった(ブログよりTodoリストに近いが)。
コードは以下にある。
github.com

ここまでのコードはv0.1タグとしてまとめてある。

React+Express+Node.js+MongoDBでブログっぽい何かを作る (2)Express編

前回はDocker上で環境の構築を行った。
詳細は以下の記事の通り。
itto-ki.hatenablog.com

今回はExpressフレームワークAPIサーバを作っていく。

API設計

純化のため、ユーザ認証機能などは省く。
記事一覧と単体の記事に関するAPIさえあれば良い。
よってAPIは以下の通りになる。

/articles/ GET 記事一覧取得
/articles/ POST 記事作成
/articles/:id GET idで指定した記事を取得
/articles/:id PUT idで指定した記事を更新
/articles/:id DELETE idで指定した記事を削除

スキーマ定義

まずは記事のスキーマを定義する。
MongoDBとの通信にはmongooseを用いるため、
backend/project/db/articleModel.jsに以下の様に書く。

gista61bca482b6fdd5c5602164d9d56c378

記事のタイトルと本文、作成日と更新日をそれぞれ定義している。
作成日と更新日にはデフォルトの値として現在の日時を指定している。

API処理

続いてAPI呼び出し時の処理を書いていく。
ファイル分割のため、backend/project/routes/articles.jsに処理を書き、/backend/project/app.jsから読み込むという流れを取る。
backend/project/routes/articles.jsは以下の通り。

gist1b2b67b340ccac544c9900a57235e7c6

routerインスタンスを作り、それぞれGETをget、POSTをpost...というように各HTTP リクエストメソッドに対するrouterインスタンスのメソッドを定義する。
例えば/articles/に対するGETメソッドに対する処理は5行目から始まるrouter.getメソッドで定義される。
なお、ここでは/articles/に対する処理にも関わらず、URLとの対応を指定するgetメソッドの第一引数は'/'となっている。
これを/articlesに対応させる処理は/backend/project/app.jsからbackend/project/routes/articles.jsを読み込む時に行う。

データベースへの接続処理とarticles.jsのインポート

上記の/backend/project/routes/articles.jsを作成したら、/backend/project/app.jsの中でインポートする。

gist3368c7cbb0658a1500fc5561db9e7c1c

9行目で先程作成した/backend/project/routes/articles.jsをインポートしている。
そして32行目で/backend/project/routes/articles.jsで定義した各メソッドを/articlesのURLと対応付けている。
例えば先程'/'と対応付けたgetメソッドは/aritclesのプレフィックスが付き、
URL /articles/にGETリクエストメソッドを送った場合に実行されることになる。
その他、このファイルで重要な点としては、以下の2点が挙げられる。

  • 14行目でデータベースへとコネクションを張っている
  • 27行目でオリジン間リソース共有をどのドメインからも許可する設定としている

まとめ

以上で簡単なAPIサーバが完成した。
Postmanやcurlを使って対応するHTTPリクエストを投げてみると正しく動く事が確認できるだろう。

次はいよいよReactでフロントエンドを作っていく。

自宅ネットワークを見直した話

3月末に今の部屋に引っ越してきてから約3ヶ月が経つ。
それ以来、自宅のネットワーク構成は、ISPから貸与されたモデムルータに全ての機器をぶら下げているという面白みのない状態が続いていた。
このままではいけない、ちゃんとしたネットワークを組まねばとは思いつつも面倒で放置していた。
しかしながらこの間新しくルータを買ったことをきっかけにネットワーク構成を多少見直したので記録として残しておく。

3月末からのネットワーク構成

以下の記事に載せた構成図と同様
自宅ネットワーク内にハニーポット(T-Pot)をVMで構築する - 雑記でザキザキ

f:id:itto-ki:20180702222903p:plain
唯一サーバマシン上に立てたVMだけはDMZに置いている。
その他は全てモデムルータの配下。

新しいネットワーク構成

以下のような構成になった。
f:id:itto-ki:20180704231211p:plain
3つのLANにネットワークを分けている。
1つ目はHG100R-02JGによって提供される192.168.0.0/24のネットワーク。
このネットワークの下に他の2つのLANである192.168.1.0/24と192.168.2.0/24のネットワークがぶら下がっている。
またハニーポットもこのルータによって提供されるDMZにGS105E経由で配置している。
何故スイッチを噛ませてるのかというと、たまに常用マシンの余っているNICと接続してポートミラーリングすることでハニーポットの通信を観測したいため。
よく見ると冗長化を考慮したとしてもHG100R-02JGは無駄なのだが、
何故使用しているのかというと、現在大元は同軸ケーブルで配線されており同軸ケーブルがつながるルータがこれしかないためである。

2つ目はEdge Routerによって提供される192.168.1.0/24のネットワーク。
Edge Routerには無線機能はないため、この下にはWRC-F1167ACFをWi-FI APとして配置している。
今回新しく買ったルータはこのWRC-F1167ACFなんだが、ルータとして使うのではなくAPとして使うことにした。
その他、常用しているマシンとサーバもこの下に配置している。

3つ目はAterm WG1800HP2によって提供される192.168.2.0/24のネットワーク。
このルータにはWi-FIルータとしての機能があるため、無線ネットワークをそのまま提供している。
このネットワークの下にも常用マシンとサーバを192.168.1.0/24に繋いでいるのとは別のNICで繋いでいる。
これはEdge RouterとAtermのどちらかが死んでしまっても常用マシンとサーバがインターネットに接続されるようにするための冗長化である。

また、スマートフォンタブレット端末等は、AtermまたはWRC-F1167ACFにより提供されるSSIDを用いてインターネット接続する。

問題点

Edge RouterとAtermによって冗長化しているとは言うものの、
現状の構成ではHG100R-02JGが死んでしまうと意味がない。
この問題は近々解決される予定である。
というのも今住んでるマンションにNuro光回線が引かれるらしいので時期が来たら契約してEdge Routerに接続する予定である。
こうすることでHG100R-02JGが死んでしまってもEdge Routerがインターネットと接続されているため、
常用マシンとサーバ共に問題なく使用できる。

今後の予定

IPv6

まとめ

自宅のネットワーク構成を冗長化を考慮して見直した。
Wi-Fi電波が2.5GHz帯と5GHz帯が2ずつの計4つ飛んでいる。特に意味はない。
家庭のネットワークで冗長化を考慮する必要があるのかというと全くない。
全ては自己満足である。

自宅ネットワーク内にハニーポット(T-Pot)をVMで構築する

「セキュリティ」という単語を見続けていたらハニーポットを構築したくなった。

T-Pot

手軽に構築できるハニーポット環境としてはT-Potが有名だろうということで、
これを用いてハニーポットを構築していく。
github.com
詳しくは他のブログ等を参照していただきたいのだが、
T-PotはISO形式で提供されているハニーポット環境で、
このOSをインストールするとCowrieやDionaeaを始めとする各種ハニーポットソフトウェアがDockerで良い感じに立ち上がるという大変便利なもの。

2年ほど前に一度構築した時はバージョン16.10だったが、現在は17.10が提供されていた。

構成

今回は諸々の事情もあって、VM上にでT-Pot環境を構築し、自宅ネットワークのDMZに配置することとする。
構成図は以下のような感じ。
f:id:itto-ki:20180702222903p:plain
VMを動かすマシンには2つのNICが挿してあるため、片方のNICDMZに接続しハニーポットを動かすVMにブリッジ接続する。

ハニーポットVMの作成

今回のホストマシンにはデスクトップ環境が入ってないため、ホストマシンに対してSSH接続した後、全てコマンドで操作していく。
前提としてハニーポットを構築し動作を確認するまではホストマシンのNICは共にLAN内に接続したまま作業をする。
今回は仮想マシンQEMU(KVM)上に作成し、macvtapでゲストOSのNICをホストOSのNICにブリッジ接続する。
まずは以下のコマンドでqcow2形式のディスクイメージを作成。

qemu-img create -f qcow2 /var/lib/libvirt/images/tpot.qcow2 128G

T-Pot 17.10 - Multi-Honeypot Platform rEvolutionのSystem Rquirementsでは64GB(128GB推奨)となっていたので、128GBとする。

続いてこのディスクイメージに対してOSをインストールしていく。
以下のコマンドを実行するとVMのインストールが始まる。

virt-install --connect qemu:///system \
--name tpot \
--virt-type kvm \
--ram 6000 \
--vcpus 2 \
--arch x86_64 \
--os-type linux \
--disk /var/lib/libvirt/images/tpot.qcow2 \
--network=type=direct,source=enp2s0f0,model=virtio \
--graphic vnc,listen=0.0.0.0 \
--cdrom=tpot.iso

使用するホストマシンのNICとしてenp2s0f0を選んだ。
上のコマンドを実行した後、VMホストマシンのポート5901にVNCクライアントより接続を行うと、ハニーポットであるゲストOSがVNC経由で操作できる。
OSインストールに関して特筆するべきことはないので適宜環境に合わせてセッティングしていく。

セッティングが終わりOSが再起動するとルータのDHCPによってIPアドレスがに割り当てられる。
今後IPアドレスが動的に変化すると面倒なので、ゲストOSの/etc/network/interfacesとルータの設定を編集して固定IPにする。
固定IPを割り当てたら、ルータの設定を変更して割り当てた固定IPをDMZに配置。

T-Potではポート64297でT-Pot内のハニーポットの様子を可視化するダッシュボードを提供している。
早速ブラウザからダッシュボードを見てみると、立ち上げてから数分も立っていないのにも関わらず攻撃がドカドカ来ている。

SSHの設定

ダッシュボードはグラフィカルで見ていて面白いのだが、攻撃の詳細は分からない。
詳細を知るためには生のログを見る必要がある。
T-Potは64295番ポートが管理用のSSHポートとして開かれている。
まずはscpコマンドを用いて公開鍵をT-Potに送る。

scp -P 64295 $HOME/.ssh/id_rsa.pub tsec@<T-PotのIPアドレス>:/home/tsec

公開鍵を送ったら一度パスワード認証でT-Potへ入り、公開鍵を.ssh/authorized_keysに追記
また/etc/ssh/sshd_configを編集してパスワード認証を禁止する。
それらが終わったら以下のコマンドでSSHデーモンの再起動

systemctl restart sshd

これで公開鍵を用いてT-Potへ入れる様になった。
ユーザ名やらポート番号が普段と違うので.ssh/configにT-Pot用の設定を書いておくと便利になる。

色々と探してみるとどうやらハニーポットのログは/data以下に置かれているらしい。
ログの詳細を見ていこうかと思ったけど疲れたのでまた後日。

まとめ

QEMU(KVM)上のVMにT-Potをインストールし、自宅ネットワークのDMZに配置した。
・けっこうな勢いで攻撃が来ている。

React+Express+Node.js+MongoDBでブログっぽい何かを作る (1)環境構築編

今までWebアプリケーションを作る時には、バックエンドであればDjango+Postgres+nginx(もしくはApache)、フロントエンドであればjQueryやその周辺を主に用いてきた。
しかし、そろそろ何か別のものを学習したくなってきたので、React + Express + Node.js + MongoDBでやっていく。
どれも触ったことがないので新鮮。

とにかくまずは環境構築をする必要がある。
今回作る環境はこんな感じ。

f:id:itto-ki:20180701054452p:plain

フロントエンド(React)を提供するためフロントエンドサーバ、APIを提供するバックエンドサーバ、データベースの3つをDockerコンテナとして用意する。

ディレクトリ構成

ディレクトリの構成はこんな感じ

blog
├── backend
│   ├── dockerfile
│   └── project
├── data
│   └── .
├── docker-compose.yml
└── frontend
    ├── dockerfile
    └── project

frontend/projectをフロントエンドコンテナに、backend/projectをバックエンドコンテナに、dataをデータベースコンテナにそれぞれマウントする。

docker-compose.ymlは以下の通り。

docker-compose.yml


gistf1da8a2e4bc697870988241df76035b1
フロントエンドコンテナのポート3000をホストの8888に、バックエンドコンテナのポート3000をホストの8080に、
データベースコンテナのポート27017をホストの27017にそれぞれおポートフォワードしている。
バックエンドとデータベースに関してはサービスを運用する上ではポートフォワードをする必要はないのだが、
このようにしておいたほうが開発時にホスト側から動作確認ができて便利である。


また、backendとfrontendのdockerfileは以下の通り。
ディレクトリの作成とグローバルに必要なモジュールのインストールのみを行っている。

dockerfile(backend)

dockerfile(frontend)

以上の3つのファイルを作成したら、docker-compose.ymlのあるディレクトリで以下のコマンドを叩くとそれぞれのイメージがビルドされる。

docker-compose build

以降でも特別な記述がない限り、docker-compose.ymlのあるディレクトリでコマンドを叩いてるものとする。

モジュールのインストール

続いて書くイメージに必要なモジュールをインストールしていく。
まずはバックエンドサーバから。
以下のコマンドでコンテナを起動する。

docker run -it -v $(pwd)/backend/express:/home/node/backend blog_backend /bin/bash

これでバックエンドコンテナに入ることができる。
続いてプロジェクトに必要な設定ファイルを作り、さらにモジュールをインストールするために以下のコマンドを順に実行。

express --view=pug --git
yarn add http-errors mongoose nodemon

これでバックエンドコンテナの環境が出来上がる。
現在のディレクトリはホストの$(pwd)/backend/expressディレクトリにマウントされているため、
上記のコマンドで生成された設定ファイル、モジュール等はホストからも操作することができる。

続いてフロントエンドコンテナにも必要な環境を作っていく。
先程とほぼ同じように、以下のコマンドでコンテナを起動する。

docker run -it -v $(pwd)/frontend/react:/home/node/frontend blog_frontend /bin/bash

これで先程と同じくフロントエンドコンテナに入ることができた。
さらに同様に環境・モジュールのセットアップを以下のコマンドで行う。

npx create-react-app .
yarn add redux react-redux react-router react-router-dom history @material-ui/core

以上でフロントエンド、バックエンド共に起動させるのに必要な設定、モジュールの準備が出来た。
モジュールはとりあえずこんなもんかなという感じなので必要に応じて適宜追加していく予定。

あとは追加でバックエンドコンテナにインストールしたnodemonモジュールを用いるための設定を行う。
/frontend/project/package.jsonのを以下の様に書き換える。

重要なのはstartコマンドの内容で、このように書き換えることでnodemonを用いてサーバを起動させることになる。
nodemonはコードに変更がある度にサーバをリスタートしてくれるモジュールで、用いることで開発が楽になる。

サービスの開始

以上が全て完了したら以下のコマンドを実行する。

docker-compose up -d

docker-compose.ymlで定義した3つのコンテナが立ち上がりサービスが開始される。
ホストのブラウザからlocalhostの8888, 8080, 27017ポートに接続してみることによって、
それぞれのサービスが稼働していることが確認できるだろう。

環境構築は以上で終了。
次回からはサービスを作り始めていく。

セグメンテーションでのメモリ管理について

IA-32 プロセッサには以下に挙げる2つの動作モードがある。

リアルモード
  • 8086用に書かれたプログラムを実行するモード
  • 16bitで動作する
プロテクトモード
  • メモリ管理やタスク管理、保護機能等の80386で拡張された機能を利用するためのモード
  • 32bitで動作する

今回はプロテクトモードについて特にセグメンテーションでのメモリ管理に注目して取り上げる。

プロテクトモードのメモリ管理

GDTとセグメントディスクリプタ

プロテクトモードではセグメントを用いてメモリ管理を行う。これをセグメンテーションと呼ぶ。
セグメンテーションのためにはメモリ上にGDT(Global Discriptor Table)と呼ばれるセグメントディスクリプタのテーブルを作成する必要がある。
GDTを作るタイミングはリアルモードからプロテクトモードに移行する時。
セグメントディスクリプタはメモリ上に存在するセグメントの位置を指定する。
この様子を以下の図に示す。
f:id:itto-ki:20180413011326p:plain

セグメントレジスタ

また、プロセッサにはセグメントレジスタと呼ばれるセグメントを管理するためのCS,DS,ES,FS,SSの5つのレジスタがある。
これらのレジスタを用いてGDTの中に複数個あるセグメントディスクリプタのうち、どれを使用するのかを指定する。
この様子を以下に示す。
f:id:itto-ki:20180413012838p:plain

この時、セグメントレジスタにあるデータ構造をセグメントセレクタと呼び、以下の様な構造になっている。
f:id:itto-ki:20180413015224p:plain

セグメントセレクタのindex値によって使用するセグメントディスクリプタを指定している。

アドレス指定

さて先程、GDT内のセグメントディスクリプタを用いてメモリ上に存在するセグメントの位置を指定すると書いたが、
これではセグメントの先頭アドレスしか分からない。
一方で、プログラムからは◯◯セグメントの△△番地のアドレスを指定される場合がある。
この様な場合にどうするのか。
ここでセグメントディスクリプタの構造を見てみると以下の様になっている。
f:id:itto-ki:20180413193804p:plain

注目するべきなのは以下の3つのフィールドである。

フィールド 説明
Base Address Low ベースアドレスの下位16bit
Base Address Mid ベースアドレスの中位8bit
Base Address Hi ベースアドレスの上位8bit

これら3つのフィールドを合わせて(32bitsで)ベースアドレスを表す。
プログラムからのメモリアクセスの時は、このベースアドレスとプログラムによって指定されたアドレス(これを論理アドレスと呼ぶ)から、
実際のメモリ上のアドレス(これを物理アドレスと呼ぶ)への変換作業がCPUにより行われる。
また、これによりメモリがどのようにセグメンテーションされていようと、
プログラムに対してはメモリを先頭から使用できるように見せかけることができる。

感想

前に一度理解していたつもりだったけど、ほとんど覚えてなかったので復習した。
セグメンテーションは複雑すぎる機能でLinuxでは使われていないため触れる機会もないので仕方ない。