OVSカーネルが一緒に接続追跡システム(接続追跡システム)を使用することができる、接続追跡機能を意味し、オープンフローストリームは、UDP、ICMP等の接続状態のTCPと一致するために使用することができます (接続追跡システムトラックは、ステートフルとステートレスプロトコルをサポート)。
このチュートリアルでは、接続追跡システムOVS使用する方法を示します。削除接続するTCPセグメントに接続しているから試合を確立します。OVSとLinuxカーネルは、このプレゼンテーションのためのデータパスとして一緒モジュール。(処理を実行するLinuxカーネルモジュールを使用してOpenvswitchデータ)。
このデモでは、Open vSwitchのの「マスター」ブランチで試験しました。
定義
接続追跡:コネクション追跡モジュール。ステートフルパケットインスペクション。
パイプライン:パケット処理パイプライン。パケットがテーブル通る経路を横断しながら、メッセージがストリームにテーブル内の照合フィールドと一致する必要があり、このストリームに所定の操作を行うときです。
ネットワーク名前空間は:単一のLinuxカーネルでは、複数の仮想ルーティングドメインのメソッドを作成します。各ネットワークは、独自のネットワーク名前空間テーブルインスタンス(ARP、ルーティング)、および特定のインタフェース接続を有します。
フロー:このチュートリアルでは、OpenFlowの流れである、またはOVS-ofctlツール本明細書中で使用することは、プログラミングのコマンドラインツールOVSのOpenFlowコントローラを使用することができます。照合フィールドとactionフィールドを持つストリーム。
接続追跡関連分野
マッチングフィールド
OVSはの接続追跡に関連する次の試合のフィールドをサポートしています。
- ct_state:
接続ステータスメッセージをマッチング可能な値は以下のとおりです。
- *new*
- *est*
- *rel*
- *rpl*
- *inv*
- *trk*
- *snat*
- *dnat*
発現接頭語としての「+」記号とそれぞれ設定する必要があり、または「 - 」の接頭辞を設定することができないように符号が示されています。また、新しい例えばct_state = + TRK +、複数のフラグを指定することができます。ここでは、使用のいくつかの兆候が表示されます。詳細な手順は、参照文書のOVSフィールドを。
- ct_zone:コネクショントラッキングエリアは、CTを設定することにより、独立したコンテキスト操作です。
(接続追跡エントリに位置フローオープンフローによって)最新のCTアクション16設定ct_zone
値は、他のフローフィールド内の一致エントリとして使用することができます。
-
ct_mark:現在の32ビット・データ・パケットが属するの接続に設定されたアクションにCTによるExecの動作パラメータ。
-
ct_label:
EXECタグCT操作に128ビットのパラメータで操作者によって提出されたが、現在のパケットが属する接続されています。 -
ct_label:
現在のアクションでCTによるExecのアクションパラメータ128は、ラベルを属するパケットを接続するために設けられています。 -
ct_nw_src / ct_ipv6_src:
接続トラッキング方向元のタプルのマッチのIPv4 / IPv6送信元アドレス。 -
ct_nw_dst / ct_ipv6_dst:
元のタプルのターゲット・アドレスはIPv4 / IPv6の接続トラッキング方向に一致します。 -
ct_nw_proto:
IPプロトコルタイプタプルを追跡する相手コネクタオリジナルの方向。 -
ct_tp_src:
元のトラッキング方向のマッチングタプルのトランスポート層接続元ポート。 -
ct_tp_dst:
相手コネクタポートタプルオブジェクトオリジナル輸送層トラッキング方向。
アクション
OVSは、接続追跡サポートと関連し、「CT」アクションを接続追跡しました。
*ct([argument][,argument...])*
CTアクションアクションは、接続されているトラッカーにパケットを送信します。
これは、次のパラメータをサポートします。
-
コミット:
接続は、接続追跡モジュール、パイプラインのライフサイクルを超えて、この接続のパケットのためのストレージモジュールに提出。 -
力:
上記に加えてコミット外フラグ、フラグ力を効果的に既存の接続を終了し、現在の方向に新しい接続を開始するために使用することができます。 -
=番号表:
2に配管処理。元のメッセージは、アクション追跡されていないパケットのリストの形式で現在のアクションに対処していきます。メッセージの別の例は、接続され、それは再注入管オープンフローテーブルし、引き続き追跡プログラムに送られるnumber
ことがct_state CTマッチマッチング状態および他のフィールドを設定した場合には処理を。 -
ゾーン=値またはSRC =ゾーン[...開始終了]:
16ビットのコンテキストID、および接続が別のドメインで単離することができる、ネットワークアドレスの重複の異なる領域の使用を可能にします。なし値領域場合は、デフォルトのエリア0が使用されています。 -
Execの([アクション] [、...アクション]) :
接続追跡コンテキストの制限されたセットの動作を実行します。でexec
アクションのリストのみ変更が確定しますct_markまたはct_labelアクションのフィールド。 -
= ALG <FTP / TFTPは>:
特定の接続の種類を追跡するためにALG(アプリケーションレイヤーゲートウェイALG)を指定します。 -
NATは:
追跡NATアドレス変換とポートを指定します。
トポロジの例
このチュートリアルでは、次のトポロジを使用してテストを実行します。
+ +
| |
| +-----+ |
| | | |
| | | |
| +----------+ | OVS | +----------+ |
| | left | | | | right | |
| | namespace| | | |namespace | |
+-----+ A +------+ +-----+ B +--------+
| | | A'| | B' | | |
| | | | | | | |
| +----------+ | | +----------+ |
| | | |
| | | |
| | | |
| +-----+ |
| |
| |
+ +
192.168.0.X n/w 10.0.0.X n/w
A = veth_l1
A' = veth_l0
B = veth_r1
B' = veth_r0
トポロジを作成するには、上記の手順に従います。
「左」ネットワークの名前空間を作成します。
$ ip netns add left
「右」の名前空間を作成します。
$ ip netns add right
VETHは、インターフェイスの最初のペアを作成しました。
$ ip link add veth_l0 type veth peer name veth_l1
「左」ネットワークの名前空間にveth_l1を追加します:
$ ip link set veth_l1 netns left
vEthインターフェイスの第二の対を作成します。
$ ip link add veth_r0 type veth peer name veth_r1
「右」のネットワーク名前空間にveth_r1を追加します:
$ ip link set veth_r1 netns right
ブリッジBR0の作成:
$ ovs-vsctl add-br br0
ブリッジBR0にveth_l0とveth_r0インターフェイスを追加::
$ ovs-vsctl add-port br0 veth_l0
$ ovs-vsctl add-port br0 veth_r0
データパケット内のネットワークの名前空間生成されたソース/宛先IPアドレスは192.168.0.xの/ 10.0.0.xデータパケットであり、「左」に表示されます生成された反対方向「右」ネットワークの名前空間でOVSスイッチ、二つのネットワーク(192.168.0.Xと10.0.0.X)通信のホスト場合。
これは、実質的に中央OVSを介して2つのホストまたはネットワークのサブネット間の通信をシミュレートします。
注:
二つのネットワークの名前空間との間で通信するために一組のvEthインターフェイスを、本実施の形態のみ提示。
TCPパケット生成ツール
Scapyは、TCPパケットを生成するために使用することができます。私たちは、Ubuntuの16.04で行われ、この試験のためのscapyの手順を使用していました。(Scapyは範囲を超えて、内部に装着しました)。
あなたは、各名前空間にscapy 2のアクティブセッションを維持することができます。
$ sudo ip netns exec left sudo `which scapy`
$ sudo ip netns exec right sudo `which scapy`
注:次のエラーが発生する場合があります。
ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",LOOPBACK_NAME))
IOError: [Errno 99] Cannot assign requested address
このコマンドを実行します。
$ sudo ip netns exec <namespace> sudo ip link set lo up
TCPパケットをマッチング
TCP接続が確立されています
OVSは、単純な二つの流れに添加してもよく、二つの流れは、名前空間「右」の名前空間に、「右」から「左」のパケットに「左」から転送されます。
$ ovs-ofctl add-flow br0 \
"table=0, priority=10, in_port=veth_l0, actions=veth_r0"
$ ovs-ofctl add-flow br0 \
"table=0, priority=10, in_port=veth_r0, actions=veth_l0"
外のこれら2つのストリームを追加することに加えて、我々はまた、流れの状態に一致するTCPパケットを追加します。
「左」のネットワーク名前空間のホスト192.168.0.2のSYN、SYN-ACKのACKパケットと10.0.0.2に位置し、「右」の名前空間のホストとの間に位置している:私たちは、すなわち、TCPコネクション確立メッセージを送信します。
まず、受信したメッセージにOVSを追跡する「トラッキング」を開始するためにストリームを追加します。
それはどのようにメッセージを追跡し始めましたか?
メッセージの追跡を開始するには、まず「CT」ストリームとして行動を一致させる必要があります。このアクションは、トラッカーを接続するためのメッセージを送信します。メッセージが「追跡されていない」未追跡パケットストリーム一致フィールドがあるかどうかを決定するために、ct_state
「-trk」、すなわち、それが追跡されていないパケットに設定されなければなりません。メッセージが接続されているトラッカーに送信されると、唯一のものだから我々は、接続状態を追跡していることがわかりました。(すなわち、パケットように既存の接続や不正な形式のパケットに属し、新たな接続またはパケットを表すかどうか)。
我々は、次のストリームを追加します。
(flow #1)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=-trk, tcp, in_port=veth_l0, actions=ct(table=0)"
パケットがポートOVS veth_l0から入り、追跡されていないとして、「左」の名前空間から送信されたTCP SYNパケットは、ストリーム#1と一致します。(メッセージがちょうどOVSに入ったので。OVSに初めてすべてのパケットは「人跡未踏」です)。
設定「CT」動作は、フローは、接続パケットトラッカーに報告されます。「CT」動作パラメータ「テーブル= 0」の2つの部分にパイプ処理。「追跡されていない」メッセージの一例として、元のメッセージは、現在のアクションリストの処理を続行します。(その後何も操作がないので、元のメッセージは破棄されます。)。
別の二股コネクタトラッカーに送信されたパケットの例には、次に、パイプラインに再注入し続ける状態がct_state CT値を設定されており、他のフィールドが一致したときに、指定されたオープンフローフローテーブルを処理します。このような状況下では、マッチングのCT ct_state状況や他のフィールドを持つパケットは、リスト0に戻ります。
次に、我々は、接続追跡から返されたデータグラムパケットを一致させるためにストリームを追加します。
(flow #2)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=+trk+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0"
パケットは、接続の追跡から返されるので、ct_state状態が「TRK」に設定する必要があります。
また、これはTCPコネクションの最初のパケットである場合、ct_state状態が「新しい」フラグを設定する必要があります。(192.168.0.2と10.0.0.2の間にTCPコネクションが存在しないので、それは、現在のケースである)ct
のパラメータは、「コミット」コネクション追跡モジュールに提出接続します。これの重要性は、接続情報の操作は、接続追跡モジュールに格納され、パケットは、パイプの寿命を超えることです。
私たちは(「左」の名前空間scapyセッションにあります)TCP SYNパケットを(フラグ= 0×02がSYNである)を送信scapyを使用します。
$ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x02, seq=100), iface="veth_l1")
このメッセージは、フロー#1と一致して#2を流れます。
接続追跡接続追跡モジュールは、この接続のエントリを持つことになります。
$ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=SYN_SENT)
TCP SYNパケットの再送信は、それが一致する場合は、この段階で、再び#1(新しいメッセージが常に追跡されていないため)流れ、そしてそれはまた、ストリーム#2と一致します。注意してください。その理由は、それがこの接続に関する接続追跡情報にもかかわらず、フロー#2で一致したが、それはこのように一致する「新」再び、「ESTABLISHED」状態ではありません。
次に、TCP SYN + ACKパケットが反対/サーバ方向から、我々は次のようOVSストリームが必要になります。
(flow #3)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=-trk, tcp, in_port=veth_r0, actions=ct(table=0)"
(flow #4)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_r0, actions=veth_l0"
マッチングサーバ(10.0.0.2)バック追跡されていないパケットが#3を流れ、接続追跡にこのメッセージを送信する。(また、我々は、#1の流れ及び#3マージプロセスが「IN_PORT」を除去することで流れることができます。照合フィールド)
TCP SYN + ACKパケットは、接続追跡処理後、ct_stateは「EST」接続確立フラグを設定します。
注:接続追跡双方向のトラフィックを見た後、「EST」状態に接続するように設定ct_stateが、それは、クライアントの第三ACKパケットを見ていない、接続追跡の短期エントリにカウンタをリセット設定されていますデバイス。
scapyを使用してTCP SYN + ACKパケット( "右" の名前空間scapyセッション)(ACKフラグおよびSYNなど= 0x12に)を送信します。
$ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0x12, seq=200, ack=101), iface="veth_r1")
このメッセージは、フロー#3と一致し、#4を流れます。
接続追跡エントリ:
$ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=ESTABLISHED)
唯一のSYNとSYN ACKパケットを受信した後、接続追跡状態が「ESTABLISHED」になります。それが(クライアントから)三ACKパケットを受信しない場合でも、この時点では、この接続はすぐに接続追跡から削除されます。
次に、クライアントの方向からのTCP ACKパケットが、我々は、このメッセージに一致する次のフローを追加することができます。
(flow #5)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_l0, actions=veth_r0"
scapyを使用して( "左" の名前空間scapyセッションで)第三に、送信TCPのACKパケット(ACKとしてフラグ=の0x10の):
$ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=101, ack=201), iface="veth_l1")
このメッセージは、フロー#1と一致して#5を流れます。
接続追跡エントリ:
$ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048), \
reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024), \
protoinfo=(state=ESTABLISHED)
すべてのデータはこの接続で受信されていない場合でも、接続追跡状態は「ESTABLISHED」の状態のままであるが、今では、クライアントからのACKを受け取った、それは長い時間のために、この状態のままになります。
TCPデータ
TCPセグメントは、10.0.0.2に192.168.0.2から送信されたペイロードバイトを搬送する際に、データ・パケットを搬送するセグメントは、ストリーム#1、ストリーム#5以降に一致します。
Scapyは、TCPセグメント(「左」の名前空間scapyセッション中)(フラグ= 0x10のがACKされる)を使用してバイトを送信::
$ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=101, ack=201)/"X", iface="veth_l1")
(「右」の名前空間scapyセッションで)ACK応答セグメント(フラグ= 0x10のがACKされる)を介して送信scapyを使用::
$ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0X10, seq=201, ack=102), iface="veth_r1")
ACK応答データパケットは、フロー#3と一致し、#4を流れるべき。
TCPコネクションの涙
TCPコネクションを切断するには、さまざまな方法があります。私たちは、サーバが「FIN + ACK」メッセージを返信し、その後、クライアントは、「ACK」メッセージ解体接続の最後を送信し、クライアントからの「FIN」パケットを送信します。
クライアントからサーバーへのすべてのパケットが#1とフロー#5フローマッチします。サーバからクライアントへのすべてのパケットは#3とフロー#4フローと一致します。注目すべき点は、TCP接続がされている場合でも、ということである
解体、すべてのパケットがまだ「+ EST」の状態と一致した(実際の接続を切断します)。メッセージ、またはそれが接続追跡エントリは「ESTABLISHED」の状態であるだった場合、それはOVS「+ EST」記号のct_stateと一致し続けなければなりません。
注:実際には、接続状態が接続追跡ある「TIME_WAIT」状態(所望のすべてのTCP接続の涙液交換FINとACKパケット)、再送パケット(> 10.0.0.2 192.168.0.2-から) 、トラフィックは#1と#5を押してください。
TCP FINパケット送信( "左" の名前空間scapyセッション)scapyの使用(ACKとFINのフラグを=の0x11を):
$ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x11, seq=102, ack=201), iface="veth_l1")
このパケットマッチングフロー#1とフロー#5。
接続追跡エントリ:
$ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=FIN_WAIT_1)
TCP FIN + ACKパケット( "右" の名前空間scapyセッション)(ACKとFINのフラグを=の0x11を)scapyの使用を送ります:
$ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0X11, seq=201, ack=103), iface="veth_r1")
このメッセージは、#3を流れ、#4を流し打ちます。
接続追跡エントリ:
$ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=LAST_ACK)
scapyを使用して(ACKとしてフラグ=の0x10を)(名前空間のscapyセッションを "左")TCP ACKパケットを送信します:
$ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=103, ack=202), iface="veth_l1")
このメッセージフロー#1ヒットとフロー#5。
接続追跡エントリ:
$ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=TIME_WAIT)
概要
次の表は、TCPパケットストリームと照合フィールドとの関係をまとめたもの
+-------------------------------------------------------+-------------------+
| TCP Segment |ct_state(flow#) |
+=======================================================+===================+
| **Connection Setup** | |
+-------------------------------------------------------+-------------------+
|192.168.0.2 → 10.0.0.2 [SYN] Seq=0 | -trk(#1) then |
| | +trk+new(#2) |
+-------------------------------------------------------+-------------------+
|10.0.0.2 → 192.168.0.2 [SYN, ACK] Seq=0 Ack=1 | -trk(#3) then |
| | +trk+est(#4) |
+-------------------------------------------------------+-------------------+
|192.168.0.2 → 10.0.0.2 [ACK] Seq=1 Ack=1 | -trk(#1) then |
| | +trk+est(#5) |
+-------------------------------------------------------+-------------------+
| **Data Transfer** | |
+-------------------------------------------------------+-------------------+
|192.168.0.2 → 10.0.0.2 [ACK] Seq=1 Ack=1 | -trk(#1) then |
| | +trk+est(#5) |
+-------------------------------------------------------+-------------------+
|10.0.0.2 → 192.168.0.2 [ACK] Seq=1 Ack=2 | -trk(#3) then |
| | +trk+est(#4) |
+-------------------------------------------------------+-------------------+
| **Connection Teardown** | |
+-------------------------------------------------------+-------------------+
|192.168.0.2 → 10.0.0.2 [FIN, ACK] Seq=2 Ack=1 | -trk(#1) then |
| | +trk+est(#5) |
+-------------------------------------------------------+-------------------+
|10.0.0.2 → 192.168.0.2 [FIN, ACK] Seq=1 Ack=3 | -trk(#3) then |
| | +trk+est(#4) |
+-------------------------------------------------------+-------------------+
|192.168.0.2 → 10.0.0.2 [ACK] Seq=3 Ack=2 | -trk(#1) then |
| | +trk+est(#5) |
+-------------------------------------------------------+-------------------+
注意:確認応答シーケンス番号とシリアル番号はtsharkのキャプチャ反対に表示されます。
フローテーブル
(flow #1)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=-trk, tcp, in_port=veth_l0, actions=ct(table=0)"
(flow #2)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=+trk+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0"
(flow #3)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=-trk, tcp, in_port=veth_r0, actions=ct(table=0)"
(flow #4)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_r0, actions=veth_l0"
(flow #5)
$ ovs-ofctl add-flow br0 \
"table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_l0, actions=veth_r0"