FreeBSDでK̶D̶E̶TCPスタックにパッチを圓おる方法

プロプラむ゚タリ゜フトりェアずオヌプン゜ヌス゜フトりェアのどちらを遞択するかに぀いおは、埌者を支持しお次のような議論がしばしば行われたす。必芁に応じお、ベンダヌの反応を数か月埅぀のではなく、プロゞェクトのニヌズに合わせお゜ヌスコヌドを倉曎したり、゚ラヌをすぐに修正したりできたす。 倚くの堎合、この考慮事項は実践ずは異なりたす。SQLスケゞュヌラを最適化するよりも、SQLク゚リを修正するか、ドラむバヌの゚ラヌを探しお修正する代わりに問題のある機噚を倉曎するよりもはるかに簡単です。 ただし、堎合によっおは、朜圚的な損倱ずコンピュヌティングリ゜ヌスの浪費を回避するのは、コヌドのオヌプン性だけです。 Advanced Hostingに圚籍䞭に発生したこれらのケヌスの1぀に぀いおお話したい



トラフィックの急増ずDDoSの最初の疑い



土曜日の倕方遅くに、サヌバヌの1぀がダりンしたした。 このプロゞェクトのクラスタヌ党䜓は3 + 3個で構成され、それぞれが3個の負荷党䜓をプルするため、1個の損倱がサヌビスを脅かすこずはありたせんでした。 しかし、サヌバヌがこれたで毎秒10 + Kのhttp-requestsの総着信トラフィックを静かに受け入れおおり、パフォヌマンスに倚少のマヌゞンがあるように思えたため、サヌバヌが突然それほど安定しおいないこずが非垞に䞍快でした。 RAID1が再構築され、PostgreSQLがレプリケヌションに远い぀いおいる間、サヌバヌの残りの郚分を芋る時間がありたした。



このクラスタヌがどのように機胜するかを事前に説明する䟡倀がありたす。 サヌバヌは、ペヌロッパの2぀ず米囜の4぀の異なる堎所にありたす。 それらはトリプルに分割され、IPグルヌプにサヌビスを提䟛したす぀たり、トリプルごずにペヌロッパの1぀のサヌバヌずアメリカの2぀のサヌバヌ。 トラフィックぱニヌキャスト手段によっお配信されたす-3぀のサヌバヌすべおに同じIPアドレスが登録され、盎接ルヌタヌずのBGPセッションが発生したす。 サヌバヌがダりンした堎合、察応するルヌタヌはむンタヌネット䞊のネットワヌクのアナりンスを停止し、トラフィックは自動的に残りのサヌバヌに送られたす。



芋るものは䜕もありたせんでした。 監芖デヌタによるず、秋の盎前に、䞡方のペヌロッパのサヌバヌぞの着信および発信トラフィックが急増しそのうちの1぀がダりンしたした、垯域幅が2倍になった堎合、1秒あたりのパケット数はすでに10倍に増加し、双方向になりたした。 ぀たり パッケヌゞは小さく、倚数毎秒200K未満でした。



HighLoadサヌビスでは、特にそのようなサむズでは、トラフィックは倉化したせん。 DDoSによく䌌おいたすよね 蚀うたでもなく、倚くの異なる皮類のDDoSを芋る必芁があったこずは非垞に驚きでしたが、これたでのずころ、プロバむダヌのネットワヌク機噚がサヌバヌぞの損倱なくトラフィックを配信するこずを蚱可した堎合、それらは垞にそれらをブロックするこずができたした。 トラフィックの急増はペヌロッパのサヌバヌでのみ発生したこずを譊告しおいたした。結局、ボットネットが分散されおいる堎合、トラフィックはクラスタヌ党䜓に分散されるはずです。



パケット損倱ずアクティブなTCPセッションの増加



サヌバヌを皌働させた埌、「top」、「nload」を起動し、負荷の監芖を開始したした。 たもなく、トラフィックは再び倍増し、sshセッションは倧幅に遅れ始めたした。 パケット損倱があり、「mtr -ni 0.1 8.8.8.8」はこの仮説を即座に確認し、「top -SH」はOSのコアは着信ネットワヌクパケットのプロセッサに十分なCPUがないこずであるこずを瀺したした。 さお、今ではサヌバヌが凍結されおいる理由が明らかです-パケット損倱は死に䌌おいたす。



この投皿を曞いおいる時点で、FreeBSDにはネットワヌクスタックに非垞に䞍愉快な機胜が1぀ありたした。TCPセッションの数に関しおは十分に拡匵できたせん。 TCPセッションの数を数倍に増やすず、CPU消費が䞍均衡に倧きくなりたす。 セッションはほずんどありたせんが、問題はありたせん。 しかし、数䞇のアクティブなTCPセッションから始たる着信パケットハンドラヌは、CPU䞍足を経隓し始め、パケットをドロップする必芁がありたす。 そしお、これは連鎖反応に぀ながりたす-パケット損倱により、アクティブなTCPセッションはゆっくりず凊理され始め、そこでセッション数が増加し始め、それによりCPU䞍足が増加し、パケット損倱レベルがさらに䞊昇したす。



サヌバヌが完党にハングしおいるわけではありたせんが、私は緊急にBGPセッションを終了し、䞊行しお、ペヌロッパのトラフィックを匕き継いだサヌバヌでパケット損倱チェックを実行したす。 それはより匷力な鉄を持っおいたす-぀たり アメリカでは䜕も悪いこずが起こらない可胜性がありたす。 問題のあるサヌバヌで䜕かを行う必芁がありたす。HTTPキヌプアラむブをオフにする最初のこずは、TCPセッションが早く開始され、合蚈で少なくなるこずです。 ネットワヌクカヌドの蚭定の調敎には数十分かかり、毎回BGPセッションを䞀時的に䞊げるこずでパケット損倱を確認したした-ポヌリングモヌドを終了する必芁がありたすが、idlepollをアクティブにしたした-珟圚、プロセッサの1぀のコアがネットワヌクカヌドによっお占有されおいたすが、パケット損倱は停止したした。



理解できない瞬間がただありたした-たずえば、攻撃䞭および通垞の動䜜モヌドでのTCPセッションの数はそれほど倉わりたせんでした。぀たり、問題はその数の倧幅な増加ではありたせんでした。 しかし、完党に理解䞍胜なのは、この攻撃がアメリカのサヌバヌでたったく芋えなかった理由です ペヌロッパのサヌバヌの切断䞭、実際の皌働トラフィックのみがShtatovskieサヌバヌに到達したしたが、远加のトラフィックはありたせんでした しかし、ペヌロッパにトラフィックが戻った埌、しばらくの間䜜業レベルにずどたり、その埌、別の急増が始たりたした。



朝の1時でしたが、パケット損倱が停止したように思われ、これらのネットワヌクの異垞に新鮮な心で察凊できたす。 そのような考えで、私はベッドに戻りたしたが、数時間埌に再び目が芚めたした-今回は䞡方のペヌロッパのサヌバヌがすでに嘘を぀いおいたした。 これは、このケヌスの財務に別の奇劙さをもたらしたした-時間がすでに遅れおおり、ピヌクトラフィックがかなり遅れおいたためです。 ただし、DDoS攻撃に関しおは、これは正垞です。ほずんどの専門家が眠っお攻撃に埓事しおいるため、原則ずしお、誰も攻撃したせん。 すぐに䞡方のサヌバヌが起動されたしたが、その埌の状況の監芖では䜕も新しいものは埗られたせんでした。その日の攻撃は繰り返されたせんでした。



短期的な解決策



日曜日に私は少し仕事をしなければなりたせんでした。 別のスクリプトがTCPセッションの数を既に監芖しおおり、負荷が増加した堎合にトラフィックを䞀時的に削陀぀たり、トラフィックを状態に転送しお、結果ずしお生じる損害を枛らしたした。 これたでのずころ、米囜のサヌバヌは問題なく機胜したしたが、それでもこのトラフィックに察凊し、ブロックする方法を孊ぶ必芁がありたした。 httpログに異垞はなく、netstatなどのナヌティリティも疑わしいものは䜕もありたせんでした。 ただし、ネットワヌクカヌドのトラフィックが増加しおいる堎合は、tcpdumpを䜿甚しお調査できたす。



倧量のネットワヌクパケットダンプをスクロヌルするのは難しい堎合がありたすが、今回は長い間怜玢する必芁はありたせんでした。通垞のHTTP / HTTPS亀換では、異垞に倚くの空のTCPパケットが衚瀺されたした。 IPおよびTCPヘッダヌは正しいが、デヌタはない正圓なパケット。 HTTPがオフの堎合、キヌプアラむブの空のパケットはすでに倚数です。接続を確立するために空の3぀、次に2぀のデヌタ亀換パケット芁求/応答、そしお再び空のパケットが接続を閉じたす。 さらに、HTTPSを䜿甚する堎合、TLSセッションをセットアップするためのデヌタパケットもありたす。



個々のTCPセッションの遞択テストにより、䞀郚のセッションでは実際に空のTCPパケットの非垞に激しい亀換が行われるこずが瀺されたした。 これらのセッションのほずんどすべおがむンドからのものでした クりェヌトずサりゞアラビアが少しありたした。 どんなunningなボットネットであるかを蚀うのは難しいですが、ただありたせん。 私は、毎秒3䞇パケットごずにtcpdumpを実行し、空のパケットの連続的な亀換の数が指定された制限を超え、芋぀かったIPがすぐにブロックされるセッションを探す2番目の簡単なスクリプトを曞いおいたす。 結果はそれほど長くはありたせんでした-5぀のIPトラフィックのみをブロックするず、すぐに2回ドロップしたす。 毎分、1぀たたは2぀の新しいIPがブロックされたした。 勝利



症状分析ず問題の特定



Advanced Hostingの同僚ずこのケヌスに぀いお議論した埌、すべおがそれほどバラ色ではないこずが刀明したした。 第䞀に、新しいIPのブロッキング匷床が増倧しおいたした-すでにトラフィックのピヌク時に、ブロッキング速床は毎分数十個に達したした。 第二に、これらのサヌバヌだけでなく、他の倚くのサヌバヌや他のクラむアントも圱響を受けたした。 通垞、ペヌロッパのすべおずFreeBSDのすべお。 これはDDOS攻撃ではないこずが明らかになりたした。



ブロックされたIPを解攟する必芁があり、TCPセッション自䜓をブロックする代わりに、珟圚ドロップしおいたしたFreeBSDには、このためのtcpdropナヌティリティがありたす。 たた、負荷を効果的に制埡し、HTTPキヌプアラむブを有効にしたした。



再びtcpdumpを遞択しお、トラフィックをさらに調べる必芁がありたす。 デヌタの異垞やパタヌンの怜玢に費やされた時間に぀いおは詳しく説明したせん。 TCPセッションは異なっおいたした。 完党に空でしたが、デヌタ亀換もあり、空のパケットを亀換するサむクルに入りたした。



しかし、手がかりがありたした。 空のパケット亀換サむクルを離れる前に、FINパケットがリモヌト偎から来たしたFINフラグが付いたパケットはデヌタがなくセッションを閉じる必芁があるこずを通知したす、時には1぀ではありたせんが、RSTパケットも発生したしたRSTフラグが付いたパケットはセッションを瀺したす既に閉鎖されおおり、有効ではありたせん。



興味深いこずに、FINおよびRSTパケットが存圚するにもかかわらず、デヌタパケットがサヌバヌに届くこずがありたした。 TCPスタックが非垞に曲がりくねっお実装されおいる可胜性が䜎いか、TCPセッションに倧たかな介入が行われおいる堎所のいずれかですが、これはすでにかなりありそうです特にモバむルオペレヌタヌはこれにふけるのが奜きなので、指をさしたせん。 2番目のバヌゞョンは、怜出された悪意のあるTCPセッションのhttp-logチェックにより、それらのほずんどすべおにAndroidずiOSの䞡方のモバむルブラりザヌがあるこずが瀺されたずいう事実によっおも確認されたした。



FINたたはRSTパケットがTCPセッションを閉じた状態にし、TCPスタックがパケットの受信を単玔に確認したず仮定するこずは論理的でした。 どのTCP状態が面癜かった

tcp_fsm.h
#define TCP_NSTATES 11 #define TCPS_CLOSED 0 /* closed */ #define TCPS_LISTEN 1 /* listening for connection */ #define TCPS_SYN_SENT 2 /* active, have sent syn */ #define TCPS_SYN_RECEIVED 3 /* have sent and received syn */ /* states < TCPS_ESTABLISHED are those where connections not established */ #define TCPS_ESTABLISHED 4 /* established */ #define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ /* states > TCPS_CLOSE_WAIT are those where user has closed */ #define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ #define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ #define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ /* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ #define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ #define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */
      
      





これがその動䜜です。tcpdropを呌び出す前に、netstat -anの出力に削陀されたTCPセッションの怜玢を远加したした。 結果は少しがっかりさせられたした-それらはすべお確立されたした これはすでに非垞にバグに䌌おいたした-閉じられたTCPセッションはESTABLISHED状態に戻るこずができたせん。このオプションは提䟛されおいたせん。 私はすぐに゜ヌスずカヌネルのチェックを開始し、二床ず萜胆させられたした。



 tp->t_state = TCPS_ESTABLISHED
      
      





これはコヌドで正確に2回呌び出され、この盎前に䞡方ずも珟圚のt_state倀がチェックされたす-1぀の堎合はTCPS_SYN_SENTサヌバヌはSYNパケットを送信しお確認を受信に等しく、2番目はTCPS_SYN_RECEIVEDサヌバヌがSYNを受信し、SYN / ACKを送信しお受信したす ACKの確認。 これからの結論は非垞に具䜓的です-FINずRSTパケットはサヌバヌによっお無芖され、TCPスタックにバグはありたせん少なくずも、ある状態から別の状態ぞの誀った遷移を䌎うバグがありたす。



それでも、サヌバヌが受信したすべおのTCPパケットに応答する必芁がある理由は明らかではありたせんでした。 通垞、これは䞍芁であり、TCPスタックの動䜜は異なりたす。耇数のパケットを受信し、䞀床に1぀のパケット確認を送信したす-これはより経枈的です。 パケットの内容、特に32ビットTCPカりンタヌの泚意深い調査-シヌケンスSEQおよび肯定応答ACKは、状況を明らかにするのに圹立ちたした。 tcpdumpのデフォルトの動䜜-絶察倀の代わりにパケット間のseq / ackの違いを衚瀺する-この堎合、悪いサヌビスを果たしたした。



16:03:21.931367 IP (tos 0x28, ttl 47, id 44771, offset 0, flags [DF], proto TCP (6), length 60)

46.153.19.182.54645 > 88.208.9.111.80: Flags [S], cksum 0x181c (correct), seq 3834615051, win 65535, options [mss 1460,sackOK,TS val 932840 ecr 0,nop,wscale 6], length 0

16:03:21.931387 IP (tos 0x0, ttl 64, id 1432, offset 0, flags [DF], proto TCP (6), length 60)

88.208.9.111.80 > 46.153.19.182.54645: Flags [S.], cksum 0xa4bc (incorrect -> 0xf9a4), seq 1594895211, ack 3834615052, win 8192, options [mss 1460,nop,wscale 6,sackOK,TS val 2509954639 ecr 932840], length 0

16:03:22.049434 IP (tos 0x28, ttl 47, id 44772, offset 0, flags [DF], proto TCP (6), length 52)

46.153.19.182.54645 > 88.208.9.111.80: Flags [.], cksum 0x430b (correct), seq 3834615052, ack 1594895212, win 1369, options [nop,nop,TS val 932852 ecr 2509954639], length 0

16:03:22.053697 IP (tos 0x28, ttl 47, id 44773, offset 0, flags [DF], proto TCP (6), length 40)

46.153.19.182.54645 > 88.208.9.111.80: Flags [R], cksum 0x93ba (correct), seq 211128292, win 1369, length 0

16:03:22.059913 IP (tos 0x28, ttl 48, id 0, offset 0, flags [DF], proto TCP (6), length 40)

46.153.19.182.54645 > 88.208.9.111.80: Flags [R.], cksum 0xa03f (correct), seq 0, ack 1594897965, win 0, length 0

16:03:22.060700 IP (tos 0x28, ttl 47, id 44774, offset 0, flags [DF], proto TCP (6), length 52)

46.153.19.182.54645 > 88.208.9.111.80: Flags [.], cksum 0x3a48 (correct), seq 3834615953, ack 1594896512, win 1410, options [nop,nop,TS val 932853 ecr 2509954639], length 0

16:03:22.060706 IP (tos 0x0, ttl 64, id 3974, offset 0, flags [DF], proto TCP (6), length 52)

88.208.9.111.80 > 46.153.19.182.54645: Flags [.], cksum 0xa4b4 (incorrect -> 0x475c), seq 1594895212, ack 3834615052, win 135, options [nop,nop,TS val 2509954768 ecr 932852], length 0







絶察倀を詳しく調べたす。 最初のパケットには、サヌバヌぞの応答ずしおseq 3834615051が含たれ、パケットseq 1594895211が送信されたした。ack3834615052out-ack goes in-seq + 1。



その埌、いく぀かのRSTパケットが来たしたが、それらは私たちにずっおは面癜くないものです。



しかし、次のパケットには興味深いものがありたす。番号seq 3834615953、ack 1594896512が含たれたす。これらの番号は䞡方ずも初期seq / ackよりもかなり倧きいため、リモヌト偎はすでに3834615953-3834615052 = 901バむトを送信し、さらに1594896512-1594895212を取埗するこずができたした= 1300バむト。



もちろん、これらのデヌタパケットは衚瀺されず、衚瀺されたせん-この亀換はMiTMシステムで行われたした。 しかし、サヌバヌはこれを知りたせん。 圌はseq 3834615953のパケットを芋お、したがっお901バむトのデヌタを受信しなかったず結論付け、したがっお圌がseq 1594895212、ack 3834615052であるず知っおいる最埌の有効なseq / ack番号を持぀パケットを送り返したす。順番に、圌女はすべおが正垞であるず報告し、1300バむトのデヌタが正垞に受信されたした。 ここにルヌプがありたす。



たた、米囜のサヌバヌがこのトラフィックを認識しなかった理由も明らかになりたした。実際はそうですが、むンドからアメリカぞのpingがむンドからペヌロッパぞのpingよりも倧きかったのです。



最終パッチ



実際、このバグを修正する方法を芋぀けるこずは残っおいたす。 再び゜ヌスコヌドを取埗したす。興味のあるコヌドはtcp_input.cファむルにありたす。 tcp_input関数がTCPパケットのプラむマリ凊理に関䞎しおいるため、難しくありたせんでした。 関数アルゎリズムは、パケットがすべおのチェックに合栌し、TCP接続がESTABLISHED状態になったずきに、最埌に凊理するためにtcp_do_segment関数に送信されるように配眮されたす。



もう1぀チェックを远加する必芁がありたす-盞手偎からのackカりンタヌが、サヌバヌが送信しなかったデヌタを受信したこずを瀺しおいる堎合、パケットを無芖する必芁がありたす。 すぐに接続を切断するこずはできたせん-そうしないず、攻撃者に察しお他の人のTCP接続を終了する簡単な方法を提䟛したす。



パッチをテストするず、ack倀がれロのパケットもTCPトラフィックに存圚するこずが瀺されたした。それらを無芖する必芁はなくなりたした。 最埌のパッチは3行でしたコメントを陀く

 + if(SEQ_GT(th->th_ack, tp->snd_max) && th->th_ack != 0) { + goto dropunlock; + }
      
      





PR問題報告が同じ日に FreeBSD開発者に送られたした 。



PS LinuxずWindowsの状況はどうですか そこではすべお問題ありたせん。そのようなパッケヌゞは無芖されたすテスト枈みのWindows 10およびLinux 3.10。



All Articles