Slide 1

Slide 1 text

© 2024 ANDPAD All Rights Reserved. 1 Rubyでつくるパケットキャプチャツール 2025/01/17 東京Ruby会議12 前夜祭 @ydah 株式会社アンドパッド 開発本部 SWE

Slide 2

Slide 2 text

Confidential © 2024 ANDPAD All Rights Reserved. 2 $ whoami •ydah(わいだー) •GitHub: @ydah / 旧Twitter: @ydah_ •株式会社アンドパッドSWE •Kyobashi.rb創設メンバ、Ruby関西メンバ •大阪Ruby会議04のチーフオーガナイザ •#LR_parser_gangs •「終まで飲めば #rubyfamily」 •新米Rubyコミッター(2024/12~)

Slide 3

Slide 3 text

Confidential © 2024 ANDPAD All Rights Reserved. 3 LTなので大事なことをはじめに言います

Slide 4

Slide 4 text

Confidential © 2024 ANDPAD All Rights Reserved. 4 今年の6月は京都で会いましょう 関西Ruby会議08 場所: 先斗町歌舞練場 開催日: 2025年6月28日(土) 共催: Ruby関西、Kyoto.rb、Kobe.rb Kyobashi.rb、AKASHI.rb、Ruby舞鶴 Ruby Tuesday、Shinosaka.rb、naniwa.rb

Slide 5

Slide 5 text

Confidential © 2024 ANDPAD All Rights Reserved. 5 本日のトークのゴール ネットワークプログラミングを             完全に理解する

Slide 6

Slide 6 text

Confidential © 2024 ANDPAD All Rights Reserved. 6 だがしかし、このトーク

Slide 7

Slide 7 text

Confidential © 2024 ANDPAD All Rights Reserved. 7 LT(5分)

Slide 8

Slide 8 text

Confidential © 2024 ANDPAD All Rights Reserved. 8 本日のトークのゴール Linuxネットワークプログラミングを      雰囲気だけでも完全に理解する

Slide 9

Slide 9 text

Confidential © 2024 ANDPAD All Rights Reserved. 9 今日のコード https://github.com/ydah/redhound

Slide 10

Slide 10 text

Confidential © 2024 ANDPAD All Rights Reserved. 10 まず必要最低限の知識 (多分、スキップする)

Slide 11

Slide 11 text

Confidential © 2024 ANDPAD All Rights Reserved. 11 パケットとは ネットワーク上でデータを送受信する際に小さく分割されたデータの 単位。大きなデータを効率的かつ信頼性を持って送るために、データ はパケットに分割され、宛先に届いた後に再構成される。 パケット ホスト パケット パケット パケット パケット

Slide 12

Slide 12 text

Confidential © 2024 ANDPAD All Rights Reserved. 12 第7層 (L7) アプリケーション層 アプリケーション間の通信 (HTTP、FTP) 第6層 (L6) プレゼンテーション層 データ形式の変換(暗号化、圧縮) 第5層 (L5) セッション層 通信の開始・維持・終了 (セッション管理) 第4層 (L4) トランスポート層 エンドツーエンドの通信 (TCP/UDP、セグメント) 第3層 (L3) ネットワーク層 ネットワーク間のルーティング (IPアドレス、パケット) 第2層 (L2) データリンク層 隣接ノード間の通信 (MACアドレス、フレーム) 第1層 (L1) 物理層 電気信号やビットの伝送 (ケーブル、コネクタ) コンピューターが通信するために利用するネットワークの機能を7つ の階層に分類したもの。階層ごとに通信プロトコルが定義されてい る。 OSI参照モデル

Slide 13

Slide 13 text

Confidential © 2024 ANDPAD All Rights Reserved. 受信側 送信側 13 FCS データ L7 ヘッダ L4 ヘッダ L3 ヘッダ L2 ヘッダ データ L7 ヘッダ L4 ヘッダ L3 ヘッダ データ L7 ヘッダ L4 ヘッダ データ L7 ヘッダ FCS データ L7 ヘッダ L4 ヘッダ L3 ヘッダ L2 ヘッダ データ L7 ヘッダ L4 ヘッダ L3 ヘッダ データ L7 ヘッダ L4 ヘッダ データ L7 ヘッダ 電気信号 電気信号 OSI参照モデルとデータ(カプセル化/非カプセル化)

Slide 14

Slide 14 text

Confidential © 2024 ANDPAD All Rights Reserved. 14 ざっくりとした理解でおk

Slide 15

Slide 15 text

Confidential © 2024 ANDPAD All Rights Reserved. 15 ここからつくりかた

Slide 16

Slide 16 text

Confidential © 2024 ANDPAD All Rights Reserved. 16 まずはソケットをつくる

Slide 17

Slide 17 text

Confidential © 2024 ANDPAD All Rights Reserved. 17 ソケットとは ネットワーク通信に使うインターフェース。アプリケーション間で データの送受信を行うために、OSが提供するAPIで、通信のエンドポ イントとして機能する。 サーバーアプリケーション クライアント アプリケーション1 クライアント アプリケーション2 ソケット ソケット ソケット ソケット

Slide 18

Slide 18 text

Confidential © 2024 ANDPAD All Rights Reserved. 18 ソケットをつくる Socket.new(domain, type, protocol=0) -> Socket 通信の種類(アドレスタイプ) 通信方式(ソケットタイプ) 使用するプロトコル

Slide 19

Slide 19 text

Confidential © 2024 ANDPAD All Rights Reserved. 19 パケットキャプチャツールが 必要とするソケット #トハ

Slide 20

Slide 20 text

Confidential © 2024 ANDPAD All Rights Reserved. 20 データリンク層のヘッダが扱えて 全てのプロトコルを受信できればおk

Slide 21

Slide 21 text

Confidential © 2024 ANDPAD All Rights Reserved. 21 組み合わせはこんな感じ 扱いたいもの ソケットの設定 アドレスタイプ ソケットタイプ プロトコル UDPデータ部以上 AF_INET SOCK_DGRAM IPPROTO_UDP(17) or 0 TCPデータ部以上 AF_INET SOCK_STREAM IPPROTO_TCP(6) or 0 UDPヘッダ部以上 AF_INET SOCK_RAW IPPROTO_UDP(17) TCPヘッダ部以上 AF_INET SOCK_RAW IPPROTO_TCP(6) ICMPヘッダ部以上 AF_INET SOCK_RAW IPPROTO_ICMP(1) IPヘッダ部以上 AF_PACKET SOCK_DGRAM htons(ETH_P_IP) ARPヘッダ部以上 AF_PACKET SOCK_DGRAM htons(ETH_P_ARP) Ethernetヘッダ部以上 AF_PACKET SOCK_RAW htons(ETH_P_IP)

Slide 22

Slide 22 text

Confidential © 2024 ANDPAD All Rights Reserved. 22 組み合わせはこんな感じ 扱いたいもの ソケットの設定 アドレスタイプ ソケットタイプ プロトコル UDPデータ部以上 AF_INET SOCK_DGRAM IPPROTO_UDP(17) or 0 TCPデータ部以上 AF_INET SOCK_STREAM IPPROTO_TCP(6) or 0 UDPヘッダ部以上 AF_INET SOCK_RAW IPPROTO_UDP(17) TCPヘッダ部以上 AF_INET SOCK_RAW IPPROTO_TCP(6) ICMPヘッダ部以上 AF_INET SOCK_RAW IPPROTO_ICMP(1) IPヘッダ部以上 AF_PACKET SOCK_DGRAM htons(ETH_P_IP) ARPヘッダ部以上 AF_PACKET SOCK_DGRAM htons(ETH_P_ARP) Ethernetヘッダ部以上 AF_PACKET SOCK_RAW htons(ETH_P_IP)

Slide 23

Slide 23 text

Confidential © 2024 ANDPAD All Rights Reserved. 23 なのでこうする r equi r e 'socket' ETH_P_ALL = 768 # NOTE : htons(ETH_P_ALL) = > linux/if_ethe r .h Socket.new(Socket : : AF_PACKET, Socket : : SOCK_RAW, ETH_P_ALL)

Slide 24

Slide 24 text

Confidential © 2024 ANDPAD All Rights Reserved. 24 ソケットをインターフェースに バインドする

Slide 25

Slide 25 text

Confidential © 2024 ANDPAD All Rights Reserved. 25 バインドする Socket#bind(my_sockaddr) -> 0 ソケットアドレス構造体を pack した文字列

Slide 26

Slide 26 text

Confidential © 2024 ANDPAD All Rights Reserved. 26 こうする PACKED_ETH_P_ALL = [ETH_P_ALL].pack('S').unpack1('S>') s = Socket.new(Socket : : AF_PACKET, Socket : : SOCK_RAW, ETH_P_ALL) sll = [Socket : : AF_PACKET, PACKED_ETH_P_ALL, m r _if i ndex] s.bind(sll.pack('SS>a16'))

Slide 27

Slide 27 text

Confidential © 2024 ANDPAD All Rights Reserved. 27 こうする PACKED_ETH_P_ALL = [ETH_P_ALL].pack('S').unpack1('S>') s = Socket.new(Socket : : AF_PACKET, Socket : : SOCK_RAW, ETH_P_ALL) sll = [Socket : : AF_PACKET, PACKED_ETH_P_ALL, m r _if i ndex] s.bind(sll.pack('SS>a16')) ソケットを作って

Slide 28

Slide 28 text

Confidential © 2024 ANDPAD All Rights Reserved. 28 こうする PACKED_ETH_P_ALL = [ETH_P_ALL].pack('S').unpack1('S>') s = Socket.new(Socket : : AF_PACKET, Socket : : SOCK_RAW, ETH_P_ALL) sll = [Socket : : AF_PACKET, PACKED_ETH_P_ALL, m r _if i ndex] s.bind(sll.pack('SS>a16')) sockaddr_ll構造体に詰める

Slide 29

Slide 29 text

Confidential © 2024 ANDPAD All Rights Reserved. 29 struct sockaddr_llᾇ st r uct sockadd r _ll { unsigned sho r t sll_family; / * Always AF_PACKET * / unsigned sho r t sll_p r otocol; / * Physical - laye r p r otocol * / int sll_if i ndex; / * Inte r face numbe r * / unsigned sho r t sll_hatype; / * ARP ha r dwa r e type * / unsigned cha r sll_pkttype; / * Packet type * / unsigned cha r sll_halen; / * Length of add r ess * / unsigned cha r sll_add r [8]; / * Physical - laye r add r ess * / }; ᾇ https://man7.org/linux/man-pages/man7/packet.7.html

Slide 30

Slide 30 text

Confidential © 2024 ANDPAD All Rights Reserved. 30 struct sockaddr_llᾇ st r uct sockadd r _ll { unsigned sho r t sll_family; / * Always AF_PACKET * / unsigned sho r t sll_p r otocol; / * Physical - laye r p r otocol * / int sll_if i ndex; / * Inte r face numbe r * / unsigned sho r t sll_hatype; / * ARP ha r dwa r e type * / unsigned cha r sll_pkttype; / * Packet type * / unsigned cha r sll_halen; / * Length of add r ess * / unsigned cha r sll_add r [8]; / * Physical - laye r add r ess * / }; ᾇ https://man7.org/linux/man-pages/man7/packet.7.html この3つに詰める

Slide 31

Slide 31 text

Confidential © 2024 ANDPAD All Rights Reserved. 31 どうやって?

Slide 32

Slide 32 text

Confidential © 2024 ANDPAD All Rights Reserved. 32 Cの構造体のように詰める方法 Array#pack(template) -> String 自身のバイナリとしてパックするためのテンプレート

Slide 33

Slide 33 text

Confidential © 2024 ANDPAD All Rights Reserved. 33 struct sockaddr_llᾇ st r uct sockadd r _ll { unsigned sho r t sll_family; / * Always AF_PACKET * / unsigned sho r t sll_p r otocol; / * Physical - laye r p r otocol * / int sll_if i ndex; / * Inte r face numbe r * / unsigned sho r t sll_hatype; / * ARP ha r dwa r e type * / unsigned cha r sll_pkttype; / * Packet type * / unsigned cha r sll_halen; / * Length of add r ess * / unsigned cha r sll_add r [8]; / * Physical - laye r add r ess * / }; ᾇ https://man7.org/linux/man-pages/man7/packet.7.html ushort, ushort, intの順

Slide 34

Slide 34 text

Confidential © 2024 ANDPAD All Rights Reserved. unsigned short (2byte) sll_family unsigned short (2byte) sll_protocol int (4byte) sll_i fi ndex 12byte Not set 34 Cの構造体のように詰める方法 pack('SSa16') [Socket : : AF_PACKET, PACKED_ETH_P_ALL, m r _if i ndex]

Slide 35

Slide 35 text

Confidential © 2024 ANDPAD All Rights Reserved. 35 Cの構造体のように詰める方法 unsigned short (2byte) sll_family unsigned short (2byte) sll_protocol int (4byte) sll_i fi ndex 12byte Not set pack('SSa16') [Socket : : AF_PACKET, PACKED_ETH_P_ALL, m r _if i ndex] Arrayに設定したい値を詰める

Slide 36

Slide 36 text

Confidential © 2024 ANDPAD All Rights Reserved. 36 Cの構造体のように詰める方法 unsigned short (2byte) sll_family unsigned short (2byte) sll_protocol int (4byte) sll_i fi ndex 12byte Not set .pack('SSa16') [Socket : : AF_PACKET, PACKED_ETH_P_ALL, m r _if i ndex] バイナリとしてパックした文字列にする

Slide 37

Slide 37 text

Confidential © 2024 ANDPAD All Rights Reserved. 37 こうする PACKED_ETH_P_ALL = [ETH_P_ALL].pack('S').unpack1('S>') s = Socket.new(Socket : : AF_PACKET, Socket : : SOCK_RAW, ETH_P_ALL) sll = [Socket : : AF_PACKET, PACKED_ETH_P_ALL, m r _if i ndex] s.bind(sll.pack('SS>a16')) ソケットに割り当てる

Slide 38

Slide 38 text

Confidential © 2024 ANDPAD All Rights Reserved. 38 プロミスキャスモードを指定

Slide 39

Slide 39 text

Confidential © 2024 ANDPAD All Rights Reserved. 39 プロミスキャスモードとは ネットワークインターフェースの動作モードの一つで、電気的に受信 したすべてのデータを読み込むモード。宛先が自分のMACアドレス になっていないフレームも受信する。 NIC (normal) NIC (promisc) ネットワーク内の全パケット 自分宛 自分宛 他人宛 他人宛

Slide 40

Slide 40 text

Confidential © 2024 ANDPAD All Rights Reserved. 40 設定する BasicSocket#setsockopt(level, optname, optval) -> 0 値を設定するソケット オプション オプションが定義されているレベル 設定値

Slide 41

Slide 41 text

Confidential © 2024 ANDPAD All Rights Reserved. 41 やり方 s.setsockopt(SOL_PACKET, PACKET_ADD_MEMBERSHIP, mq_ r eq) パケットソケットのオプション バインドを追加 プロミスキャスモードの設定を渡す

Slide 42

Slide 42 text

Confidential © 2024 ANDPAD All Rights Reserved. 42 やり方 s.setsockopt(SOL_PACKET, PACKET_ADD_MEMBERSHIP, mq_ r eq) パケットソケットのオプション バインドを追加 packet_mreq構造体に詰めて渡す プロミスキャスモードの設定を渡す

Slide 43

Slide 43 text

Confidential © 2024 ANDPAD All Rights Reserved. 43 struct packet_mreqᾇ st r uct packet_m r eq { int m r _if i ndex; / * inte r face index * / unsigned sho r t m r _type; / * action * / unsigned sho r t m r _alen; / * add r ess length * / unsigned cha r m r _add r ess[8]; / * physical - laye r add r ess * / }; ᾇ https://man7.org/linux/man-pages/man7/packet.7.html

Slide 44

Slide 44 text

Confidential © 2024 ANDPAD All Rights Reserved. 44 それぞれはこう詰める def m r _if i ndex i = Socket.getifadd r s.f i nd { |ifadd r | ifadd r .name = = @ifname }&.if i ndex [[i].pack('c')].pack('a4') end def m r _type PACKET_MR_PROMISC = 0 x 0001 # NOTE : netpacket/packet.h [PACKET_MR_PROMISC].pack('S') end def m r _alen [0].pack('S') end def m r _add r ess [0].pack('C') * 8 end

Slide 45

Slide 45 text

Confidential © 2024 ANDPAD All Rights Reserved. 45 それぞれはこう詰める def m r _if i ndex i = Socket.getifadd r s.f i nd { |ifadd r | ifadd r .name = = @ifname }&.if i ndex [[i].pack('c')].pack('a4') end def m r _type PACKET_MR_PROMISC = 0 x 0001 # NOTE : netpacket/packet.h [PACKET_MR_PROMISC].pack('S') end def m r _alen [0].pack('S') end def m r _add r ess [0].pack('C') * 8 end Socket.getifaddrs でI/F名から indexを取得する

Slide 46

Slide 46 text

Confidential © 2024 ANDPAD All Rights Reserved. 46 それぞれはこう詰める def m r _if i ndex i = Socket.getifadd r s.f i nd { |ifadd r | ifadd r .name = = @ifname }&.if i ndex [[i].pack('c')].pack('a4') end def m r _type PACKET_MR_PROMISC = 0 x 0001 # NOTE : netpacket/packet.h [PACKET_MR_PROMISC].pack('S') end def m r _alen [0].pack('S') end def m r _add r ess [0].pack('C') * 8 end PACKET_MR_PROMISC を設定

Slide 47

Slide 47 text

Confidential © 2024 ANDPAD All Rights Reserved. 47 それぞれはこう詰める def m r _if i ndex i = Socket.getifadd r s.f i nd { |ifadd r | ifadd r .name = = @ifname }&.if i ndex [[i].pack('c')].pack('a4') end def m r _type PACKET_MR_PROMISC = 0 x 0001 # NOTE : netpacket/packet.h [PACKET_MR_PROMISC].pack('S') end def m r _alen [0].pack('S') end def m r _add r ess [0].pack('C') * 8 end mr_alen と mr_address は0埋め

Slide 48

Slide 48 text

Confidential © 2024 ANDPAD All Rights Reserved. 48 ソケットは出来たので

Slide 49

Slide 49 text

Confidential © 2024 ANDPAD All Rights Reserved. 49 パケットの受信

Slide 50

Slide 50 text

Confidential © 2024 ANDPAD All Rights Reserved. 50 パケットを受信する Socket#recvfrom(maxlen, flags=0) -> [String, Addrinfo] ソケットから受けとるデータの最大値 フラグ

Slide 51

Slide 51 text

Confidential © 2024 ANDPAD All Rights Reserved. 51 ループを回しつつ受信してアナライズしていく loop do msg, = s. r ecvf r om(2084) analyze(msg) end

Slide 52

Slide 52 text

Confidential © 2024 ANDPAD All Rights Reserved. 52 ヘッダを解析していく

Slide 53

Slide 53 text

Confidential © 2024 ANDPAD All Rights Reserved. 53 FCS データ DNS UDP IP Ether データ DNS UDP IP データ DNS UDP データ DNS L7: メッセージ L4: セグメント/データグラム L3: パケット L2: フレーム ヘッダを解析していく例:UDPぐらいまで

Slide 54

Slide 54 text

Confidential © 2024 ANDPAD All Rights Reserved. 54 FCS データ L7 ヘッダ L4 ヘッダ L3 ヘッダ L2 ヘッダ データ L7 ヘッダ L4 ヘッダ L3 ヘッダ データ L7 ヘッダ L4 ヘッダ データ L7 ヘッダ L7: メッセージ L4: セグメント/データグラム L3: パケット L2: フレーム ヘッダを解析していく例:UDPぐらいまで FCS データ DNS UDP IP Ether データ DNS UDP IP データ DNS UDP データ DNS

Slide 55

Slide 55 text

Confidential © 2024 ANDPAD All Rights Reserved. 55 FCS データ DNS UDP IP Ether 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 宛先MACアドレス 送信元MACアドレス λΠϓ L3ヘッダ含むデータ イーサネットⅡヘッダ

Slide 56

Slide 56 text

Confidential © 2024 ANDPAD All Rights Reserved. 56 FCS データ DNS UDP IP Ether 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 宛先MACアドレス 送信元MACアドレス λΠϓ L3ヘッダ含むデータ イーサネットⅡヘッダ タイプを見れば次のレイヤーの ヘッダが決まる

Slide 57

Slide 57 text

Confidential © 2024 ANDPAD All Rights Reserved. 57 FCS データ L7 ヘッダ L4 ヘッダ L3 ヘッダ L2 ヘッダ データ L7 ヘッダ L4 ヘッダ L3 ヘッダ データ L7 ヘッダ L4 ヘッダ データ L7 ヘッダ L7: メッセージ L4: セグメント/データグラム L3: パケット L2: フレーム ヘッダを剥がしつつ出力するだけ FCS データ DNS UDP IP Ether データ DNS UDP IP データ DNS UDP データ DNS

Slide 58

Slide 58 text

Confidential © 2024 ANDPAD All Rights Reserved. 58 FCS データ DNS UDP IP Ether 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 バージョン ヘッダ長 サービス種別 全長 識別子 フラグ 断片位置 生存時間 プロトコル チェックサム 送信元アドレス 宛先アドレス 拡張情報 L4ヘッダ含むデータ IPv4ヘッダ

Slide 59

Slide 59 text

Confidential © 2024 ANDPAD All Rights Reserved. 59 FCS データ DNS UDP IP Ether 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 バージョン ヘッダ長 サービス種別 全長 識別子 フラグ 断片位置 生存時間 プロトコル チェックサム 送信元アドレス 宛先アドレス 拡張情報 L4ヘッダ含むデータ IPv4ヘッダ プロトコルを見れば次のレイヤーの ヘッダが決まる

Slide 60

Slide 60 text

Confidential © 2024 ANDPAD All Rights Reserved. 60 FCS データ L7 ヘッダ L4 ヘッダ L3 ヘッダ L2 ヘッダ データ L7 ヘッダ L4 ヘッダ L3 ヘッダ データ L7 ヘッダ L4 ヘッダ データ L7 ヘッダ L7: メッセージ L4: セグメント/データグラム L3: パケット L2: フレーム ヘッダを剥がしつつ出力するだけ FCS データ DNS UDP IP Ether データ DNS UDP IP データ DNS UDP データ DNS

Slide 61

Slide 61 text

Confidential © 2024 ANDPAD All Rights Reserved. 61 FCS データ DNS UDP IP Ether 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 送信元ポート番号 宛先ポート番号 パケット長 チェックサム データ UDPヘッダ

Slide 62

Slide 62 text

Confidential © 2024 ANDPAD All Rights Reserved. 62 あとはサポートするヘッダ用の 解析処理を書いていけば…

Slide 63

Slide 63 text

Confidential © 2024 ANDPAD All Rights Reserved. 63 完成!!!!!

Slide 64

Slide 64 text

Confidential © 2024 ANDPAD All Rights Reserved. 64 おわりにかえて •ソケット作って、I/Fへバインドして、プロミスキャスモードを設定 して、あとはループ内で受信して解析していくだけでおk •解析も基本はヘッダをレイヤーごとに解析していけばおk •Macでは動作しないんや…すまんな… •Wiresharkで見れるpcap形式での出力も実装はある!が、発表時間 はない… •みんなもやろうネットワークプログラミング!