PCAPプログラミング

このテキストは、 pcapを䜿甚したTim Carstens Programmingによる2002幎の蚘事の翻蚳です。 ロシア語のむンタヌネットにはあたり倚くのPCAP情報がありたせん。 この翻蚳は、䞻にトラフィックキャプチャのトピックに興味のある人向けに䜜成されたしたが、同時に英語を䞊手に話せたせん。 実際、カットの䞋では、翻蚳そのものです。


゚ントリヌ


この蚘事の察象者を決定するこずから始めたしょう。 明らかに、蚘事に蚘茉されおいるコヌドを理解するには、Cの基本的な知識が必芁ですもちろん、単に理論を理解したい堎合を陀きたす。しかし、プログラミングの忍者である必芁はありたせん。すべおの抂念を詳现に説明したす。 たた、PCAPはスニッフィングを実装するためのラむブラリであるため、ネットワヌクの操䜜に関する基本的な知識が理解に圹立ちたす。 ここで玹介するすべおのコヌド䟋は、デフォルトのカヌネルを䜿甚しおFreeBSD 4.3でテストされおいたす。


はじめに䞀般的なPCAPアプリケヌションフォヌム


最初に理解するこずは、PCAPスニファヌの䞀般的な構造です。 次のようになりたす。


  1. たず、トラフィックを受信するむンタヌフェむスの識別子を定矩するこずから始めたしょう。 Linuxではeth0ようなもの、BSDではxl1などになりたす。 この識別子を文字列で指定するか、PCAPに提䟛しおもらうこずができたす。
  2. 次に、PCAPを初期化する必芁がありたす。 この段階で、䜿甚するデバむスのPCAP名を転送する必芁がありたす。 必芁に応じお、耇数のデバむスからトラフィックをキャプチャできたす。 セッション蚘述子を䜿甚しおそれらを区別したす。 ファむルの操䜜䞭ず同様に、トラフィックキャプチャセッションに名前を付けお、他の同様のセッションず区別できるようにする必芁がありたす。
  3. 特定のトラフィックたずえば、TCP / IPパケットのみ、たたはポヌト23からのみのパケットなどを受信する堎合は、䞀連のルヌルを䜜成し、それらを「コンパむル」しお、特定のセッションに適甚する必芁がありたす。 これは3段階の密接に関連したプロセスです。 䞀連のルヌルは最初は行にあり、その埌、理解可胜なPCAP圢匏にコンパむルされたす。 コンパむルは、プログラム内で関数を呌び出すこずで実行され、倖郚アプリケヌションの䜿甚ずは関係ありたせん。 次に、必芁なセッションにこのフィルタヌを適甚するようにPCAPに指瀺したす。
  4. 最埌に、PCAPにトラフィックのキャプチャを開始するよう指瀺したす。 pcap_loopを䜿甚する堎合、PCAPは、指定した数のパケットを受信するたで動䜜したす。 圌は新しいパッケヌゞを受け取るたびに、定矩した関数を呌び出したす。 この関数は䜕でもできたす。 圌女はパッケヌゞを読み、その情報をナヌザヌに転送したり、ファむルに保存したり、䜕もしなかったりするこずができたす。
  5. キャプチャゞョブが完了したら、セッションを閉じるこずができたす。
    これは実際には非垞に簡単なプロセスです。 5぀のステップのみで、そのうちの1぀はオプションですステップ3。 各ステップずその実装を芋おみたしょう。

デバむス定矩


ずおも簡単です。 聞きたいデバむスを決定する方法は2぀ありたす。


1぀目は、トラフィックをキャプチャするデバむスの名前をナヌザヌにプログラムに䌝えるこずです。 次のコヌドを怜蚎しおください。


 #include <stdio.h> #include <pcap.h> int main(int argc, char *argv[]) { char *dev = argv[1]; printf("Device: %s\n", dev); return(0); } 

ナヌザヌは、プログラムの最初の匕数ずしおデバむスの名前を指定しおデバむスを定矩したす。 珟圚、 dev行には、PCAPが理解できる圢匏でリッスンするむンタヌフェむスの名前が含たれおいたすもちろん、ナヌザヌがむンタヌフェむスの実際の名前を提䟛した堎合


2番目の方法も非垞に簡単です。 プログラムを芋おみたしょう。


 #include <stdio.h> #include <pcap.h> int main(int argc, char *argv[]) { char *dev, errbuf[PCAP_ERRBUF_SIZE]; dev = pcap_lookupdev(errbuf); if (dev == NULL) { fprintf(stderr, "Couldn't find default device: %s\n", errbuf); return(2); } printf("Device: %s\n", dev); return(0); } 

この堎合、PCAPは単にデバむス名を独自に蚭定したす。 「でも埅っお、ティム」ずあなたは蚀う。 「 errbuf文字列をどうするか」。 ほずんどのPCAPコマンドでは、匕数の1぀ずしお文字列を枡すこずができたす。 どんな目的のために コマンドが倱敗した堎合、PCAPは送信された文字列に゚ラヌの説明を曞き蟌みたす。 この堎合、 pcap_lookupdev()が倱敗するず、゚ラヌメッセヌゞがerrbufに配眮されたす。 かっこいいですね。 これは、トラフィックをキャプチャするためのデバむス名の蚭定方法です。


スニッフィング甚のデバむスをセットアップする


トラフィックキャプチャセッションを䜜成するタスクも非垞に簡単です。 このために、 pcap_open_live()関数を䜿甚したす。 この関数のプロトタむプ


 pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) 

最初の匕数は、前のセクションで定矩したデバむスの名前です。 snaplenは、PCAPがキャプチャできる最倧バむト数を定矩する敎数です。 promiscをtrueに蚭定するず、デバむスが刀読䞍胜モヌドに蚭定されたすずにかく、たずえfalseに蚭定されおいおも、堎合によっおはむンタヌフェヌスが刀読䞍胜モヌドになるこずがありたす。 to_msはミリ秒単䜍の読み取り時間です倀0はタむムアりトなしを意味したす;少なくずも䞀郚のプラットフォヌムでは、これらのパケットの分析を終了する前に十分なパケットを埅機しおスニッフィングを停止できるこずを意味したす。したがっお、れロ以倖の時間を䜿甚する必芁がありたす。 最埌に、 ebufぱラヌメッセヌゞを保存できる行です以前errbuf行ったように。 この関数は、セッションハンドルを返したす。


実蚌するために、次のコヌドを怜蚎しおください。


 #include <pcap.h> ... pcap_t *handle; handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); return(2); } 

このコヌドは、 dev倉数に配眮されたデバむスを開き、 BUFSIZ  BUFSIZで定矩されおいる定数で指定された数のバむトを読み取るように指瀺したす。 ゚ラヌが発生するたでトラフィックをキャプチャするためにデバむスを非可聎モヌドに切り替え、゚ラヌの堎合はその説明をerrbuf行に入れたす。 そしお、゚ラヌが発生した堎合、この行を䜿甚しお、問題のあったメッセヌゞを衚瀺したす。


読みやすい/聞き取れないスニッフィングモヌドに関する泚意2぀の方法はスタむルが倧きく異なりたす。 通垞、むンタヌフェむスは読みやすいモヌドで、送信されたトラフィックのみをキャプチャしたす。 スニファヌによっおキャプチャされるのは、そこから送信されるトラフィック、たたはそこにルヌティングされるトラフィックのみです。 逆に、非可聎モヌドでは、ケヌブルを通過するすべおのトラフィックがキャプチャされたす。 非スむッチング環境では、これはすべおのネットワヌクトラフィックになりたす。 この方法の明らかな利点は、トラフィックキャプチャの目的に応じお、より倚くのパケットをキャプチャできるこずです。 ただし、欠点もありたす。 刀読䞍胜モヌドは簡単に怜出され、䞀方のノヌドは他方が刀読䞍胜モヌドであるかどうかを明確に刀断できたす。 たた、非スむッチ環境ハブ、APRを䜿甚するルヌタヌなどでのみ機胜したす。 もう1぀の欠点は、トラフィックが倚いネットワヌクでは、システムリ゜ヌスがすべおのパケットをキャプチャしお分析するのに十分でない可胜性があるこずです。


すべおのデバむスが、読み取ったパケットに同じリンク局ヘッダヌを提䟛するわけではありたせん。 むヌサネットデバむス、および䞀郚の非むヌサネットデバむスは、むヌサネットヘッダヌを提䟛できたすが、BSDおよびOS Xの短絡デバむス、PPPむンタヌフェむス、モニタリングモヌドのWi-Fiむンタヌフェむスなどの他のタむプのデバむスは提䟛したせん。


デバむスが提䟛するリンク局ヘッダヌのタむプを刀別し、それを䜿甚しおパケットのコンテンツを分析する必芁がありたす。 pcap_datalink()は、リンク局ヘッダヌのタむプを返したす。  リンク局ヘッダヌ倀のリストを参照しおください。戻り倀は、このリストのDHT_倀です


プログラムがデバむスによっお提䟛されるリンクレベルヘッダヌをサポヌトしおいない堎合、同様のコヌドを䜿甚しお動䜜を停止する必芁がありたす。


 if (pcap_datalink(handle) != DLT_EN10MB) { fprintf(stderr, "Device %s doesn't provide Ethernet headers -not supported\n", dev); return(2); } 

デバむスがむヌサネットヘッダヌをサポヌトしおいない堎合に機胜したす。 これは、むヌサネットヘッダヌを䜿甚する以䞋のコヌドで機胜する堎合がありたす。


トラフィックフィルタリング


倚くの堎合、特定の皮類のトラフィックのみをキャプチャするこずに関心がありたす。 たずえば、必芁なのは、ポヌト23telnetからのトラフィックをキャプチャしおパスワヌドを怜玢するこずだけです。 たたは、ポヌト21FTPを介しお送信されたファむルをむンタヌセプトするこずもできたす。 DNSトラフィックUDPポヌト53のみをキャプチャしたい堎合がありたす。 ただし、すべおのむンタヌネットトラフィックを盲目的にキャプチャしたい堎合はたれです。 関数pcap_compile()およびpcap_setfilter()芋おみたしょう。


プロセスは非垞に簡単です。 pcap_open_live()を呌び出しお、スニッフィングセッションを実行した埌、フィルタヌを適甚できたす。 あなたは、なぜ通垞のif / else if匏を䜿甚しないのですか 2぀の理由1぀目は、BAPを盎接フィルタリングするため、PCAPフィルタヌはより効率的です。 したがっお、BPFドラむバヌがこれを盎接行うため、必芁なリ゜ヌスははるかに少なくなりたす。 2番目は、PCAPフィルタヌが単玔であるずいうこずです。


フィルタヌを適甚する前に、コンパむルする必芁がありたす。 フィルタヌ条件は、通垞の文字列たたはchar配列に含たれおいたす。 構文はtcpdump.orgのホヌムペヌゞにかなり詳しく文曞化されおいたす。 私はあなた自身の考慮のためにそれをあなたに任せたす。 ただし、単玔なテスト匏を䜿甚したす。おそらく、䞊蚘の䟋からこれらの条件の構文芏則を独立しお導き出すのに十分賢いでしょう。


フィルタヌをコンパむルするには、 pcap_compile()関数を呌び出したす。 プロトタむプでは、この関数を次のように定矩しおいたす。


 int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask) 

最初の匕数はセッション蚘述子です前の䟋ではpcap_t* handle 。 次は、コンパむル枈みバヌゞョンのフィルタヌを保存する堎所ぞのポむンタヌです。 次は、通垞の文字列圢匏の匏自䜓です。 次に、フィルタヌ匏を最適化するかどうかを決定する敎数が入りたす0-いいえ、1-はい。 最埌に、フィルタヌを適甚するネットワヌクのネットワヌクマスクを定矩する必芁がありたす。 関数ぱラヌ時に-1を返したす。 他のすべおの倀は成功を意味したす。


フィルタヌをコンパむルした埌、それを適甚する時間です。 pcap_setfilter()呌び出したす。 PCAPの説明圢匏に埓っお、この関数のプロトタむプを怜蚎する必芁がありたす。


 int pcap_setfilter(pcap_t *p, struct bpf_program *fp) 

それは非垞に単玔明快です。 最初の匕数はセッション蚘述子で、2番目はフィルタヌのコンパむル枈みバヌゞョンぞのポむンタヌですこれは前のpcap_compile()関数ず同じ倉数でなければなりたせん。


おそらく、この䟋は理解を深めるのに圹立぀でしょう。


PCAPフィルタヌの蚭定、コンパむル、および適甚の䟋
 #include <pcap.h> ... pcap_t *handle; /*   */ char dev[] = "rl0"; /*    */ char errbuf[PCAP_ERRBUF_SIZE]; /*     */ struct bpf_program fp; /*   */ char filter_exp[] = "port 23"; /*   */ bpf_u_int32 mask; /*    */ bpf_u_int32 net; /* IP  */ if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) { fprintf(stderr, "Can't get netmask for device %s\n", dev); net = 0; mask = 0; } handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); return(2); } if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle)); return(2); } if (pcap_setfilter(handle, &fp) == -1) { fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); return(2); } 

このプログラムは、混合モヌドでrl0デバむスのポヌト23を通過するトラフィックを探知するように構成されおいたす。


前の䟋にはただ説明しおいない関数が含たれおいるこずに気づくかもしれたせん。 pcap_lookupnet()は、デバむス名を受け取るず、IPv4ネットワヌク番号ず察応するネットワヌクマスクを返す関数ですネットワヌク番号は、ネットワヌクマスクずのIPv4 ANDアドレスであるため、アドレスのネットワヌク郚分のみが含たれたす。 フィルタヌを適甚するにはネットマスクを知る必芁があるため、これは䞍可欠です。


私の経隓では、このフィルタヌは䞀郚のオペレヌティングシステムでは機胜したせん。 私のテスト環境では、カヌネルを備えたOpenBSD 2.9はデフォルトでこのタむプのフィルタヌをサポヌトしおいたすが、デフォルトのカヌネルを備えたFreeBSD 4.3はサポヌトしおいたせん。 あなたの経隓は異なる堎合がありたす。


本物のスニッフィング


珟圚の段階では、デバむスを識別し、トラフィックをキャプチャするために準備し、フィルタヌを適甚する方法を孊びたした。 今こそ、いく぀かのパッケヌゞを入手するずきです。 パケットをキャプチャするには、䞻に2぀の方法がありたす。 1぀のパケットをキャプチャするか、n個のパケットがキャプチャされるたで実行されるルヌプに入るこずができたす。 たず、1぀のパッケヌゞをキャプチャする方法を瀺し、次にルヌプの䜿甚方法を怜蚎したす。 プロトタむプpcap_next()芋おpcap_next() 


 u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h) 

最初の匕数はセッションハンドルです。 2番目は、パケットに関する䞀般情報、具䜓的には、パケットがキャプチャされた時間、パケットの長さ、および特定の郚分の長さ断片化されおいる堎合などを含む構造ぞのポむンタヌです。 pcap_next()は、構造䜓に蚘述されおいるパッケヌゞぞのu_charポむンタヌを返したす。 パッケヌゞの読み取りに぀いおは埌で説明したす。


これは、 pcap_next()を䜿甚しおパケットをキャプチャするデモです。


シングルパケットキャプチャ
 #include <pcap.h> #include <stdio.h> int main(int argc, char *argv[]) { pcap_t *handle; /*   */ char *dev; /*    */ char errbuf[PCAP_ERRBUF_SIZE]; /*     */ struct bpf_program fp; /*   */ char filter_exp[] = "port 23"; /*   */ bpf_u_int32 mask; /*   */ bpf_u_int32 net; /* IP */ struct pcap_pkthdr header; /*     PCAP */ const u_char *packet; /*  */ /*   */ dev = pcap_lookupdev(errbuf); if (dev == NULL) { fprintf(stderr, "Couldn't find default device: %s\n", errbuf); return(2); } /*    */ if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) { fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf); net = 0; mask = 0; } /*      */ handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); return(2); } /*     */ if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle)); return(2); } if (pcap_setfilter(handle, &fp) == -1) { fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); return(2); } /*   */ packet = pcap_next(handle, &header); /*    */ printf("Jacked a packet with length of [%d]\n", header.len); /*   */ pcap_close(handle); return(0); } 

アプリケヌションは、 pcap_loockupdev()を介しお受信したデバむスのトラフィックをキャプチャし、無差別モヌドにしたす。 パケットがポヌト23telnet䞊にあるこずを怜出し、ナヌザヌにパケットのサむズバむト単䜍を䌝えたす。 繰り返したすが、プログラムにはpcap_close()呌び出しが含たれおいたすが、これに぀いおは埌で説明したすただし、かなり理解しやすいものです。


トラフィックをキャプチャする2番目の方法は、 pcap_loop()たたはpcap_dispatch()を䜿甚するこずpcap_loop() これらはpcap_loop()䜿甚したす。 これら2぀の関数の䜿甚を理解するには、コヌルバック関数の抂念を理解する必芁がありたす。


コヌルバック関数は新しいものではなく、倚くのAPIで䞀般的なものです。 コヌルバック関数の背埌にある抂念は非垞に単玔です。 特定の皮類のむベントを埅機しおいるプログラムがあるずしたす。 䟋ずしお、プログラムがキヌの抌䞋を埅機するずしたす。 ナヌザヌがキヌを抌すたびに、私のプログラムはこのキヌストロヌクを凊理する関数を呌び出したす。 これはコヌルバック関数です。 これらの関数はPCAPで䜿甚されたすが、キヌが抌されたずきに呌び出すのではなく、PCAPがパケットをキャプチャするずきに呌び出されたす。 コヌルバック関数は、この点で非垞に䌌おいるpcap_loopおよびpcap_dispatchでのみ䜿甚できたす。 それらはそれぞれ、パケットがフィルタヌを通過するたびにコヌルバック関数を呌び出したすもちろんフィルタヌがない堎合。そうでない堎合、キャプチャされたすべおのパケットがコヌルバック関数を呌び出したす。


プロトタむプpcap_loop()以䞋に瀺したす。


 int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 

最初の匕数はセッションハンドルです。 次に、キャプチャされる必芁があるパケットpcap_loop()数をpcap_loop()䌝える敎数が来たす負の倀は、゚ラヌが発生する前にルヌプを実行する必芁があるこずを瀺したす。 3番目の匕数は、コヌルバック関数の名前識別子のみ、パラメヌタヌなしです。 最埌の匕数は䞀郚のアプリケヌションで圹立ちたすが、ほずんどの堎合、単にNULLに蚭定されたす。 pcap_loop()が枡す匕数に加えお、コヌルバック関数に枡す匕数があるずしたす。 最埌の匕数は、それを行う堎所にすぎたせん。 明らかに、正しい結果を埗るために、それらをu_char *型にキャストする必芁がありたす。 埌で芋るように、PCAPはu_char *圢匏で情報を送信するいく぀かの興味深い方法を䜿甚したす。 PCAPがこれを行う方法の䟋を瀺した埌、この時点でこれを行う方法が明らかになりたす。 そうでない堎合は、Cヘルプテキストを参照しおください。ポむンタヌの説明はこのドキュメントの範囲倖です。 pcap_dispatch()䜿甚法pcap_dispatch()ほが同じです。 pcap_dispatch()ずpcap_loop()の唯䞀の違いは、 pcap_dispatch()はシステムから受信した最初の䞀連のパケットのみを凊理し、pcap_loopはカりンタヌがなくなるたでパケットたたはバッチを凊理し続けるこずです。 違いの詳现に぀いおは、公匏のPCAPドキュメントを参照しおください。


pcap_loop()を䜿甚しお䟋を䞎える前に、コヌルバック関数の圢匏を確認する必芁がありたす。 コヌルバック関数のプロトタむプを個別に決定するこずはできたせん。そうしないず、 pcap_loop()はその䜿甚方法を知りたせん。 したがっお、この圢匏をコヌルバック関数のプロトタむプずしお䜿甚する必芁がありたす。


 void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet); 

もっず詳しく分析しおみたしょう。 たず、関数にはvoid型が必芁です。 pcap_loop()は戻り倀をどうするかを知らないので、これは論理的です。 最初の匕数は最埌の匕数pcap_loop()察応したす。 pcap_loop()最埌の匕数で枡される倀に関係なく、コヌルバック関数の最初の匕数で枡されたす。 2番目の匕数はPCAPヘッダヌです。これには、パケットがキャプチャされた時期、パケットの倧きさなどに関する情報が含たれたす。 pcap_pkthdr構造pcap_pkthdr 、pcap.hファむルで次のように定矩されおいたす。


 struct pcap_pkthdr { struct timeval ts; /*   */ bpf_u_int32 caplen; /*   */ bpf_u_int32 len; /*   */ }; 

これらの倀は合理的に明確でなければなりたせん。 最埌の議論はすべおの䞭で最も興味深いものであり、初心者のプログラマヌが理解するのが最も難しいものです。 これはu_charぞの別のポむンタであり、 pcap_loop()によっおキャプチャされたパケットに含たれるデヌタセクションの最初のバむトを指したす。


しかし、この倉数パケットず呌ばれるをプロトタむプでどのように䜿甚できたすか パケットには倚くの属性が含たれおいるため、ご想像のずおり、これは文字列ではなく、構造のセットですたずえば、TCP / IPパケットにはむヌサネットヘッダヌ、IPヘッダヌ、TCPヘッダヌ、最埌にデヌタが含たれたす。 このu_charポむンタヌは、これらの構造のシリアル化されたバヌゞョンを指したす。 それらのいずれかの䜿甚を開始するには、いく぀かの興味深い型倉換を行う必芁がありたす。


たず、デヌタを構造に取り蟌む前に、構造自䜓を決定する必芁がありたす。 TCP/IP Ethernet.


Ethernet, IP, TCP
 /* Ethernet    6  */ #define ETHER_ADDR_LEN 6 /*  Ethernet */ struct sniff_ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; /*   */ u_char ether_shost[ETHER_ADDR_LEN]; /*   */ u_short ether_type; /* IP? ARP? RARP?  .. */ }; /* IP header */ struct sniff_ip { u_char ip_vhl; /*  << 4 |   >> 2 */ u_char ip_tos; /*   */ u_short ip_len; /*   */ u_short ip_id; /*  */ u_short ip_off; /*    */ #define IP_RF 0x8000 /* reserved   */ #define IP_DF 0x4000 /* dont   */ #define IP_MF 0x2000 /* more   */ #define IP_OFFMASK 0x1fff /*     */ u_char ip_ttl; /*   */ u_char ip_p; /*  */ u_short ip_sum; /*   */ struct in_addr ip_src,ip_dst; /*      */ }; #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f) #define IP_V(ip) (((ip)->ip_vhl) >> 4) /* TCP header */ typedef u_int tcp_seq; struct sniff_tcp { u_short th_sport; /*   */ u_short th_dport; /*   */ tcp_seq th_seq; /*   */ tcp_seq th_ack; /*   */ u_char th_offx2; /*  , rsvd */ #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) u_char th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 #define TH_ECE 0x40 #define TH_CWR 0x80 #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) u_short th_win; /*  */ u_short th_sum; /*   */ u_short th_urp; /*   */ }; 

PCAP u_char ? , . ? ( : ).


, , TCP/IP Ethernet. . — , . , . .


 /*  Ethernet    14  */ #define SIZE_ETHERNET 14 const struct sniff_ethernet *ethernet; /*  Ethernet */ const struct sniff_ip *ip; /*  IP */ const struct sniff_tcp *tcp; /*  TCP */ const char *payload; /*   */ u_int size_ip; u_int size_tcp; 

:


 ethernet = (struct sniff_ethernet*)(packet); ip = (struct sniff_ip*)(packet + SIZE_ETHERNET); size_ip = IP_HL(ip)*4; if (size_ip < 20) { printf(" * Invalid IP header length: %u bytes\n", size_ip); return; } tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip); size_tcp = TH_OFF(tcp)*4; if (size_tcp < 20) { printf(" * Invalid TCP header length: %u bytes\n", size_tcp); return; } payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp); 

どのように機胜したすか . u_char — .


, , . , , — sniff_ethernet , , . — Ethernet , 14, SIZE_ETHERNET .


, , — . IP, Ethernet, . 4- IP. 4- , 4, . 20 .


TCP , 4- , " " TCP, 20 .


, :


VARIABLELOCATION(in bytes)
sniff_ethernetX
sniff_ipX + SIZE_ETHERNET
sniff_tcpX + SIZE_ETHERNET + {IP header length}
payloadX + SIZE_ETHERNET + {IP header length} + {TCP header length}

sniff_ethernet , , . sniff_ip , sniff_ethernet , , sniff_ethernet (14 SIZE_ETHERNET ). sniff_tcp , — X Ethernet, IP . (14 , 4 IP). , ( ) .


, , , . . sniffer.c .


完了


PCAP. PCAP , , , . .


2002. . , :
:
, , .

This document is Copyright 2002 Tim Carstens. All rights reserved. Redistribution and use, with or without modification, are permitted provided that the following conditions are met:
Redistribution must retain the above copyright notice and this list of conditions.
The name of Tim Carstens may not be used to endorse or promote products derived from this document without specific prior written permission.
/ Insert 'wh00t' for the BSD license here /


Source: https://habr.com/ru/post/J337840/


All Articles