Goでバイナリを作る

ネットワークパケットを作るために,構造体や変数からバイト型のスライスへの変換方法を調べた.

テストで書いてみたプログラムは次の通り.
とりあえずint型の変数をいくつか対象としてバイト変換を試してみた.

何らかの型(構造体やint等のプリミティブ型)からバイト型のスライスに変換するには, encoding/binary パッケージの Write メソッドを使用すると良い.

binary.Write() メソッドは次のような定義になっている.

func Write(w io.Writer, order ByteOrder, data interface{}) error

第3引数に指定したデータを,第2引数で指定したバイトオーダーで第1引数の w に書き込む.

このメソッドを使うために,まず io.Writer インタフェースを実装したものが必要になる.
バイト型のデータを書き込みたいので, bytes パッケージの Buffer を使用することにする.

buf := new(bytes.Buffer)

注意点として, new() を使う点が挙げられる.
bytes.BufferWrite() メソッドはポインタ型( *bytes.Buffer )がレシーバとなっているため, new() を使ってポインタを取得して上げる必要がある.

これで io.Writer を用意できたので, binary.Write() を使ってデータを書き込む.
適当にint型の変数を用意して binary.Write() による書き込みを行う.
なお,今回はネットワークパケットを作りたいので,第2引数のバイトオーダはビッグエンディアンを指定する.

var val32bit int32
val32bit = 123

err = binary.Write(buf, binary.BigEndian, val32bit)
if err != nil {
    log.Fatalln(err)
}
fmt.Printf("uint32: % x\n", buf.Bytes())

これで無事書き込みができた.

サンプルプログラムの実行結果

uint8: 7b
uint16: 00 7b
uint32: 00 00 00 7b

今回はint型のみを扱ったが,構造体を書き込みたいときも同じようにして扱うことができるようだ.

HTTPリダイレクトについて調査した

HTTPのリダイレクトには,大きく分けて次の二つ存在する.

  • 一時的なリダイレクト
  • 恒久的なリダイレクト

一般的に用いられるリダイレクトのステータスコードは 301302 である(個人的な考えですが).
しかし,他にもいくつかリダイレクトのステータスコードは存在する.

また,似たような意味を持つステータスコードもあるので,整理するために少し調査した.

今回対象とするリダイレクトのステータスコード

今回は,次の4つを対象とする.

  • 301 Moved Permanently
  • 302 Found
  • 307 Temporary Redirect
  • 308 Permanent Redirect

それぞれのステータスコードについて,RFCを参考に概要を以下に示す.
308以外はRFC 7231,308はRFC 7238で定義されている.

301 Moved Permanently

  • 恒久的なリダイレクトを表す
  • 歴史的な経緯から,301を受け取ったクライアントはリクエストメソッドをPOSTからGETに変更する可能性がある
    • これを望まない場合,代わりに307を用いることができる
    • しかし,307とは意味が異なる(恒久的↔一時的)
      • 308が新しく定義された

302 Found

  • 一時的なリダイレクトを表す
  • 歴史的な経緯から,301を受け取ったクライアントはリクエストメソッドをPOSTからGETに変更する可能性がある
    • これを望まない場合,代わりに307を用いることができる

307 Temporary Redirect

  • 一時的なリダイレクトを表す
  • これを受け取ったクライアントはリクエストメソッドを変更してはいけない

308 Permanent Redirect

  • 恒久的なリダイレクトを表す
  • これを受け取ったクライアントはリクエストメソッドを変更してはいけない

挙動の確認

それぞれのステータスコードに対する挙動を確認するため,簡単なサーバプログラムをGoで作成し,そのサーバに4種類のクライアントで接続した.
作成したサーバプログラムは mas9612/http-redirect-test に置いている.

用いたクライアント
* curl 7.43.0
* Safari 11.1.2
* Google Chrome 67.0.3396.99
* Firefox 59.0.2

上記それぞれのクライアントから,GETとPOST2つのメソッドで作成したサーバに接続した.
結果を次の表に示す.

Method GET

client 301 302 307 308
curl GET GET GET GET
Safari GET GET GET GET
Chrome GET GET GET GET
Firefox GET GET GET GET

Method POST

client 301 302 307 308
curl POST POST POST POST
Safari GET GET POST POST
Chrome GET GET POST POST
Firefox GET GET POST POST

実験結果より,curl以外のクライアントは,POSTリクエストの応答結果が301と302の時,リダイレクト先へのリクエストメソッドをGETに変更していることがわかった.
また,RFCの定義どおり,307と308はきちんとリクエストメソッドが維持されていることが確認できた.

References

HTTP Keep-Aliveについて

HTTP Keep-Aliveについて調査した.
とりあえず調査しただけなので,次回にでも実際に挙動確認をしたい.

  • 1つのTCPコネクションで複数リクエストを処理できるしくみ
  • HTTP/1.1ではKeep-Aliveがデフォルトでオン
    • オフにするにはそれを明示的に指定する必要がある
      • Connection: close ヘッダを指定

Apache

Keep-Aliveの設定

KeepAlive ディレクティブで,Keep-Aliveを有効にするかどうかを設定できる.
Keep-Aliveによるコネクション持続時間は, KeepAliveTimeout ディレクティブで設定する.

例) コネクション持続時間を10秒に設定する

KeepAlive On
KeepAliveTimeout 10

また,1つのKeep-Aliveによるコネクションで処理できるコネクション数を制限するには, MaxKeepAliveRequests ディレクトティブを使用する.
例えば, MaxKeepAliveRequests 10 と設定すると,1つのコネクションで10個までのコネクションを処理することができる.

Nginx

Keep-Aliveの設定

Nginxでは,Keep-AliveのOn/Offは keepalive_timeout の値によって決まる.
* keepalive_timeout0 : Keep-Alive Off
* keepalive_timeout0 以外: Keep-Alive On

Keep-Aliveによるコネクション持続時間は,On/Offの設定同様 keepalive_timeout で設定する.

例) コネクション持続時間を10秒に設定する

keepalive_timeout 10

References

USENIX 2018の論文読み

軽く読んだので,雑なまとめ.
ほぼ自分用のメモ.

Elastic Scaling of Stateful Network Functions

  • https://www.usenix.org/conference/nsdi18/presentation/woo
  • NFV(Network Functions Virtualization)におけるスケーリングの弾力性は重要な要素
    • 実用レベルでの実現は難しかった
      • 多くのNFs(Network Functions)はステートフル
      • NFを構成するインスタンス同士での状態共有が必要である
      • NFでのスループットとレイテンシの要件を満たしたステート共有の実装は難しい
  • S6を提案
    • パフォーマンスの低下なしにNFにスケーリングの弾力性を提供するフレームワーク
    • ステートをDSO(distributed shared object)とする
      • 弾力性と高パフォーマンスの要件を満たすために拡張したもの
    • NFの管理者は,ステートがどのように分散・共有されているかを気にすることなくプログラミングできる
      • S6が透過的に処理をしてくれる(データの局所性や整合性等を抽象化する)
  • 実験・評価の結果
    • 現在のNFの動的スケーリング手法と比較
      • スケーリング: 100倍のパフォーマンス向上
      • 通常時: 2〜5倍のパフォーマンス向上

Stroboscope: Declarative Network Monitoring on a Budget

  • https://www.usenix.org/conference/nsdi18/presentation/tilmans
  • ISPにとって,ネットワークの動作がどうなっているのか等を正確に知ることは困難
    • エンドホストを制御するのは不可能
    • 大量にトラフィックの統計を取る,という方法に頼るしかなかった
      • 情報の粒度が粗いという問題がある
  • Stroboscopeを提案
    • どんなトラフィックフローでもきめ細かいモニタリングが可能
    • 高レベルのクエリを入力すると,自動でいろいろやってくれる
      • どのフローをミラーリングするか
      • ルールをどこに配置するか
      • カバレッジを最大化するためにはいつルールをスケジューリングすれば良いか
    • 既存のルータ上で動作する

SafeBricks: Shielding Network Functions in the Cloud

  • Network Function Virtualization (NFV) の出現により,企業等ではネットワークでの処理をクラウド側に任せることが増えた
    • セキュリティリスクもある
    • クラウドは攻撃の影響を受けやすい
  • SafeBricksを提案
    • 信頼できないクラウドからNFを守るシステム
    • 暗号化されたトラフィックのみがクラウドプロバイダの方に流れる
      • トラフィックとNFの両方の完全性を保つ
    • クライアントに最小権限を強制する
    • SafeBricks leverages a combination of hardware enclaves and language-based enforcement
    • SafeBricksによるオーバーヘッドは0〜15%