Cuishark version 2.0開発の雑記
cuishark内部でのパケット解析をlibwiresharkを用いて行うことで, wiresharkの対応プロトコルを全てcuisharkでいじれるようにするという素晴らしい話のための雑記.
開発方針
version1は以下のようになっていた.
version2では以下のようにしようと思う.
そのようにした理由を論す. バックエンドに関しては単純に「wiresharkのdissectorを持ってきたい. 」という単純な理由である. しかしlibwireshark はドキュメントがなかったり少しめんどくさいので苦労すると思われる.
フロントエンドに関しては「TUI書くのクソだるい」という理由である. さすがにcuisharkのフロントエンドをCでゴリゴリ書くよりは書きやすい言語でやりたいなということ.
グルー部分に関しては, バックエンドを「libwiresharkpy」見たいな形にしてctypesでpythonラップしてフロントから叩こうかなと思っている. 今時, linuxのネットワークインターフェースとpcap/pcapngからパケットが読めれば満足なはず(DPDKでもtapリダイレクトは簡単)なので. パケット入力はその二種類でやろうかなと思っている.
Cuishark ver2 設計
以下のコンポーネントを考えている
libws_cpp
以下tsharkを参考にしている.
- dissector_new/freeは一回しか行わない
- dissectorは1パケットごとにresetする
- 以下の機能を自由に使えることを確認する
- pcapファイルから受信
- netifから受信
- dfilterが使える
- packet summaryが表示できる
- packet detail が表示できる (ツリー構造)
libws_py
pythonから以下のことができればOKと思っている.
- パケットフィルタ(display filter)を叩ける
- 入力IFを選べる (pcap/pcapng/netif)
- パケットの生dataが取れる
- パケットの dissect結果がツリーレベルで取れる.
これらのことを可能にするC/C++プログラムをまずかいて, それをpythonでラップすることにしている.
余談: libwiresharkのいじり方
libwiresharkとは
libwiresharkとは, wiresharkの中で利用されている. パケット解析のライブラリである. wiresharkは莫大な量のプロトコルに対応しているが, それらのプロトコルの解析部分 (wireshark内部ではdissectorと呼ぶ) はlibwiresharkのサブセットとして, wiresharkとは独立している. libwiresharkはwiresharkの開発者があとから実装の一部を分離しただけの「ドキュメントもほとんどない. 使用方法が謎なライブラリである.」
しかし, これを使いこなすことができれば, 事実上ではwiresharkの対応している豊富なプロトコルが簡単に解析できるプログラムがかけるはずである. (そのようなソフトウェアはとても少ない.)
もっともシンプルなコード
write soon
typedef struct _packet_info { const char *current_proto; /**< name of protocol currently being dissected */ struct epan_column_info *cinfo; /**< Column formatting information */ guint32 presence_flags; /**< Presence flags for some items */ guint32 num; /**< Frame number */ nstime_t abs_ts; /**< Packet absolute time stamp */ nstime_t rel_ts; /**< Relative timestamp (yes, it can be negative) */ frame_data *fd; union wtap_pseudo_header *pseudo_header; wtap_rec *rec; /**< Record metadata */ GSList *data_src; /**< Frame data sources */ address dl_src; /**< link-layer source address */ address dl_dst; /**< link-layer destination address */ address net_src; /**< network-layer source address */ address net_dst; /**< network-layer destination address */ address src; /**< source address (net if present, DL otherwise )*/ address dst; /**< destination address (net if present, DL otherwise )*/ guint32 vlan_id; /**< First encountered VLAN Id if present otherwise 0 */ const char *noreassembly_reason; /**< reason why reassembly wasn't done, if any */ gboolean fragmented; /**< TRUE if the protocol is only a fragment */ struct { guint32 in_error_pkt:1; /**< TRUE if we're inside an {ICMP,CLNP,...} error packet */ guint32 in_gre_pkt:1; /**< TRUE if we're encapsulated inside a GRE packet */ guint32 in_erspan_i:1; /**< TRUE if we're encapsulated inside an ERSPAN type I packet */ } flags; port_type ptype; /**< type of the following two port numbers */ guint32 srcport; /**< source port */ guint32 destport; /**< destination port */ guint32 match_uint; /**< matched uint for calling subdissector from table */ const char *match_string; /**< matched string for calling subdissector from table */ gboolean use_endpoint; /**< TRUE if endpoint member should be used for conversations */ struct endpoint* conv_endpoint; /**< Data that can be used for conversations */ guint16 can_desegment; guint16 saved_can_desegment; int desegment_offset; /**< offset to stuff needing desegmentation */ #define DESEGMENT_ONE_MORE_SEGMENT 0x0fffffff #define DESEGMENT_UNTIL_FIN 0x0ffffffe guint32 desegment_len; guint16 want_pdu_tracking; guint32 bytes_until_next_pdu; int p2p_dir; GHashTable *private_table; /**< a hash table passed from one dissector to another */ wmem_list_t *layers; /**< layers of each protocol */ guint8 curr_layer_num; /**< The current "depth" or layer number in the current frame */ guint16 link_number; guint16 clnp_srcref; /**< clnp/cotp source reference (can't use srcport, this would confuse tpkt) */ guint16 clnp_dstref; /**< clnp/cotp destination reference (can't use dstport, this would confuse tpkt) */ int link_dir; /**< 3GPP messages are sometime different UP link(UL) or Downlink(DL) */ GSList* proto_data; /**< Per packet proto data */ GSList* dependent_frames; /**< A list of frames which this one depends on */ GSList* frame_end_routines; wmem_allocator_t *pool; /**< Memory pool scoped to the pinfo struct */ struct epan_session *epan; const gchar *heur_list_name; /**< name of heur list if this packet is being heuristically dissected */ } packet_info; struct epan_dissect { struct epan_session *session; tvbuff_t *tvb; proto_tree *tree; packet_info pi; }; typedef struct epan_dissect epan_dissect_t; struct data_source { tvbuff_t *tvb; char *name; };