開始行:
#norelated
*Linux socket プログラミング/パケットモニタリングプログラム
*目次 [#le4558a7]
#contents
*概要 [#v6eb036c]
NIC(ネットワークインターフェースカード)が受け取ったネッ...
*プログラムのイメージ [#t2621b90]
このプログラムで使われる関数のイメージを以下に示します。
|>|CENTER:|c
|流れ|解説|h
|socket(PF_PACKET,SOCK_DGRAM, )|BGCOLOR(white):PF_PACKET ...
|BGCOLOR(white):↓ |BGCOLOR(white):|
|ioctl(,SIOCGIFINDEX,)|BGCOLOR(white):インターフェースの...
|BGCOLOR(white):↓ |BGCOLOR(white):|
|setsockopt(,,PACKET_ADD_MEMBERSHIP,,)|BGCOLOR(white):無...
|BGCOLOR(white):↓ |BGCOLOR(white):|
|recvfrom() |BGCOLOR(white):パケットを受信(繰り返す)|
|BGCOLOR(white):↓ |BGCOLOR(white):|
|printf()|BGCOLOR(white):パケットのヘッダーを表示(繰り返...
無差別受信モードへの設定の方法は、かつては、
>''INET ドメインの SOCK_PACKET ソケットを作成し、ifr_flag...
というやり方が主流だったのですが、現在は上記のように
>''PF_PACKET ドメインの SOCK_RAW ソケットもしくは SOCK_DG...
というやり方が主流のようです。(man packet(7) 参照)
*ソースコード [#p7254178]
CENTER:[[pckmon2.c>http://github.com/kaizawa/linux-socket...
1 /*
2 * packet monitor program
3 * pckmon2.c
4 * cc pckmon2.c -lnsl -o pckmon2
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <netinet/in.h>
9 #include <errno.h>
10 #include <netdb.h>
11 #include <netinet/tcp.h>
12 #include <netinet/ip.h>
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
15 #include <sys/ioctl.h>
16 #include <net/if.h>
17 #include <net/ethernet.h>
18 #include <netpacket/packet.h>
19
20 void recv_pkt();
21 int sock ;
22
23 int
24 main(int argc, char *argv[])
25 {
26 struct ifreq ifr;
27 struct packet_mreq mreq;
28
29 if(argc != 2) {
30 printf("Usage: %s interface\n", argv[0]);
31 exit(1);
32 }
33
34 if ((sock = socket(PF_PACKET, SOCK_DGRAM, hto...
35 perror("socket");
36 exit(1);
37 }
38
39 strcpy(ifr.ifr_name, argv[1]);
40
41 if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0 ){
42 perror("ioctl SIOCGIFINDEX");
43 exit(1);
44 }
45
46 memset(&mreq,0,sizeof(mreq));
47 mreq.mr_type = PACKET_MR_PROMISC;
48 mreq.mr_ifindex = ifr.ifr_ifindex;
49
50 if((setsockopt(sock,SOL_PACKET,PACKET_ADD_MEM...
51 perror("setsockopt");
52 exit(1);
53 }
54
55 recv_pkt();
56 }
57
58 /***********************************************
59 * recv_pkt()
60 * Receive and display packets
61 ***********************************************/
62 void
63 recv_pkt()
64 {
65 int rsin_size, count;
66 struct sockaddr_in rsin;
67 struct in_addr insaddr,indaddr;
68 fd_set fds;
69
70 struct buf {
71 struct iphdr ip;
72 struct tcphdr tcp;
73 unsigned char blah[65535];
74 } buf;
75
76 rsin_size = sizeof(rsin);
77
78 FD_ZERO(&fds);
79 FD_SET(sock, &fds);
80
81 for ( count = 0 ;; count++){
82 if( select(sock + 1, &fds , NULL, NULL, N...
83 perror("select");
84 exit(1);
85 }
86
87 if ( FD_ISSET(sock, &fds)){
88 if(recvfrom(sock,&buf,sizeof(buf),0,(...
89 perror("recvfrom");
90 }
91 /*
92 * Ignore the packets other than TCP
93 */
94 if ( buf.ip.protocol != IPPROTO_TCP)
95 continue;
96 insaddr.s_addr = buf.ip.saddr;
97 indaddr.s_addr = buf.ip.daddr;
98
99 printf("Packet number : %d\n", count);
100 printf("----IP Header----------------...
101 printf("version : %u\n",buf.ip.ve...
102 printf("ihl : %u\n",buf.ip.ih...
103 printf("tos : %u\n",buf.ip.to...
104 printf("tot length : %u\n",ntohs(buf...
105 printf("id : %u\n",ntohs(buf...
106 printf("frag_off : %u\n",ntohs(buf...
107 printf("ttl : %u\n",buf.ip.tt...
108 printf("protocol : %u\n",buf.ip.pr...
109 printf("check : 0x%x\n",ntohs(b...
110 printf("saddr : %s\n",inet_ntoa...
111 printf("daddr : %s\n",inet_ntoa...
112
113 printf("----TCP Header---------------...
114 printf("source port : %u\n",ntohs(buf...
115 printf("dest port : %u\n",ntohs(buf...
116 printf("sequence : %u\n",ntohl(buf...
117 printf("ack seq : %u\n",ntohl(buf...
118 printf("frags :");
119 buf.tcp.fin ? printf(" FIN") : 0 ;
120 buf.tcp.syn ? printf(" SYN") : 0 ;
121 buf.tcp.rst ? printf(" RST") : 0 ;
122 buf.tcp.psh ? printf(" PSH") : 0 ;
123 buf.tcp.ack ? printf(" ACK") : 0 ;
124 buf.tcp.urg ? printf(" URG") : 0 ;
125 printf("\n");
126 printf("window : %u\n",ntohs(buf...
127 printf("check : 0x%x\n",ntohs(b...
128 printf("urt_ptr : %u\n\n\n",buf.t...
129 }
130 } /* for() loop */
131 }
ソースファイル [[pckmon2.c>http://github.com/kaizawa/linu...
*実行例 [#o54a6b2f]
プログラム名の後に引数としてパケットをキャプチャする NIC ...
なお、このプログラムは root ユーザで実行する必要がありま...
# ./pckmon2 eth0
Packet number : 0
----IP Header--------------------
version : 4
ihl : 5
tos : 0
tot length : 40
id : 14879
frag_off : 0
ttl : 128
protocol : 6
check : 0xd575
saddr : 172.29.73.2
daddr : 172.29.73.254
----TCP Header-------------------
source port : 1270
dest port : 22
sequence : 1671008060
ack seq : 1093140794
frags : ACK
window : 17340
check : 0x4699
urt_ptr : 0
Packet number : 1
----IP Header--------------------
version : 4
ihl : 5
tos : 16
tot length : 540
id : 11933
frag_off : 0
ttl : 64
protocol : 6
check : 0x1ef4
saddr : 172.29.73.254
daddr : 172.29.73.2
----TCP Header-------------------
source port : 22
dest port : 1270
sequence : 1093140794
ack seq : 1671008060
frags : PSH ACK
window : 6432
check : 0xbbdc
urt_ptr : 0
NIC に到着した TCP のパケットを書き出しています。
内容をみると、SSH のセッションのパケットであることが分か...
*解説 [#d7af81c0]
このプログラムではいままでのプログラムと同様に socket() ...
34 if ((sock = socket(PF_PACKET, SOCK_DGRAM, hto...
これにより、 TCP のデータ部だけでなく、よりデバイスに近い...
-通常はデータしか見れない
|BGCOLOR(gray):Ethernet ヘッダー|
|BGCOLOR(gray):IP ヘッダー|
|BGCOLOR(gray):TCP ヘッダー|
|BGCOLOR(white):データ|
~
-PF_PACKET ドメインの SOCK_DGRAM を指定した場合、IP、TCP ...
|BGCOLOR(gray):Ethernet ヘッダー|
|BGCOLOR(white):IP ヘッダー|
|BGCOLOR(white):TCP ヘッダー|
|BGCOLOR(white):データ|
~
-PF_PACKET ドメインの SOCK_RAW を指定した場合、さらに Eth...
|BGCOLOR(white):Ethernet ヘッダー|
|BGCOLOR(white):IP ヘッダー|
|BGCOLOR(white):TCP ヘッダー|
|BGCOLOR(white):データ|
~
また、データを受け取るときに先の POPクライアントプログラ...
|>|recvfrom()|h
|概要|メッセージの受信|
|インクルードファイル |#include <sys/types.h>&br;#includ...
|形式| int recvfrom(int s, void *buf, int len, unsigned ...
|引数 |int s : socket 記述子&br;void *buf: 受信メッセ...
|戻り値 |成功時: 受信したバイト数&br;エラー: -1|
後は recvfrom で受け取ったデータ(=buf)を以下の構造体に...
70 struct buf {
71 struct iphdr ip; ---> IP ヘッ...
72 struct tcphdr tcp; ---> TCP ヘッ...
73 unsigned char blah[65535]; ---> データ
74 } buf;
IP ヘッダ、TCPヘッダは /use/include/netinet/ip.h および t...
これで受け取ったデータの最初の部分が、ip ヘッダ と tcp ヘ...
IP 、TCP ヘッダ構造体の各メンバの出力時には メンバごとに...
*最後に・・・ [#v5e5142f]
相変わらず自分でも不明な部分が多く、 汚いソースですが、色...
終了行:
#norelated
*Linux socket プログラミング/パケットモニタリングプログラム
*目次 [#le4558a7]
#contents
*概要 [#v6eb036c]
NIC(ネットワークインターフェースカード)が受け取ったネッ...
*プログラムのイメージ [#t2621b90]
このプログラムで使われる関数のイメージを以下に示します。
|>|CENTER:|c
|流れ|解説|h
|socket(PF_PACKET,SOCK_DGRAM, )|BGCOLOR(white):PF_PACKET ...
|BGCOLOR(white):↓ |BGCOLOR(white):|
|ioctl(,SIOCGIFINDEX,)|BGCOLOR(white):インターフェースの...
|BGCOLOR(white):↓ |BGCOLOR(white):|
|setsockopt(,,PACKET_ADD_MEMBERSHIP,,)|BGCOLOR(white):無...
|BGCOLOR(white):↓ |BGCOLOR(white):|
|recvfrom() |BGCOLOR(white):パケットを受信(繰り返す)|
|BGCOLOR(white):↓ |BGCOLOR(white):|
|printf()|BGCOLOR(white):パケットのヘッダーを表示(繰り返...
無差別受信モードへの設定の方法は、かつては、
>''INET ドメインの SOCK_PACKET ソケットを作成し、ifr_flag...
というやり方が主流だったのですが、現在は上記のように
>''PF_PACKET ドメインの SOCK_RAW ソケットもしくは SOCK_DG...
というやり方が主流のようです。(man packet(7) 参照)
*ソースコード [#p7254178]
CENTER:[[pckmon2.c>http://github.com/kaizawa/linux-socket...
1 /*
2 * packet monitor program
3 * pckmon2.c
4 * cc pckmon2.c -lnsl -o pckmon2
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <netinet/in.h>
9 #include <errno.h>
10 #include <netdb.h>
11 #include <netinet/tcp.h>
12 #include <netinet/ip.h>
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
15 #include <sys/ioctl.h>
16 #include <net/if.h>
17 #include <net/ethernet.h>
18 #include <netpacket/packet.h>
19
20 void recv_pkt();
21 int sock ;
22
23 int
24 main(int argc, char *argv[])
25 {
26 struct ifreq ifr;
27 struct packet_mreq mreq;
28
29 if(argc != 2) {
30 printf("Usage: %s interface\n", argv[0]);
31 exit(1);
32 }
33
34 if ((sock = socket(PF_PACKET, SOCK_DGRAM, hto...
35 perror("socket");
36 exit(1);
37 }
38
39 strcpy(ifr.ifr_name, argv[1]);
40
41 if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0 ){
42 perror("ioctl SIOCGIFINDEX");
43 exit(1);
44 }
45
46 memset(&mreq,0,sizeof(mreq));
47 mreq.mr_type = PACKET_MR_PROMISC;
48 mreq.mr_ifindex = ifr.ifr_ifindex;
49
50 if((setsockopt(sock,SOL_PACKET,PACKET_ADD_MEM...
51 perror("setsockopt");
52 exit(1);
53 }
54
55 recv_pkt();
56 }
57
58 /***********************************************
59 * recv_pkt()
60 * Receive and display packets
61 ***********************************************/
62 void
63 recv_pkt()
64 {
65 int rsin_size, count;
66 struct sockaddr_in rsin;
67 struct in_addr insaddr,indaddr;
68 fd_set fds;
69
70 struct buf {
71 struct iphdr ip;
72 struct tcphdr tcp;
73 unsigned char blah[65535];
74 } buf;
75
76 rsin_size = sizeof(rsin);
77
78 FD_ZERO(&fds);
79 FD_SET(sock, &fds);
80
81 for ( count = 0 ;; count++){
82 if( select(sock + 1, &fds , NULL, NULL, N...
83 perror("select");
84 exit(1);
85 }
86
87 if ( FD_ISSET(sock, &fds)){
88 if(recvfrom(sock,&buf,sizeof(buf),0,(...
89 perror("recvfrom");
90 }
91 /*
92 * Ignore the packets other than TCP
93 */
94 if ( buf.ip.protocol != IPPROTO_TCP)
95 continue;
96 insaddr.s_addr = buf.ip.saddr;
97 indaddr.s_addr = buf.ip.daddr;
98
99 printf("Packet number : %d\n", count);
100 printf("----IP Header----------------...
101 printf("version : %u\n",buf.ip.ve...
102 printf("ihl : %u\n",buf.ip.ih...
103 printf("tos : %u\n",buf.ip.to...
104 printf("tot length : %u\n",ntohs(buf...
105 printf("id : %u\n",ntohs(buf...
106 printf("frag_off : %u\n",ntohs(buf...
107 printf("ttl : %u\n",buf.ip.tt...
108 printf("protocol : %u\n",buf.ip.pr...
109 printf("check : 0x%x\n",ntohs(b...
110 printf("saddr : %s\n",inet_ntoa...
111 printf("daddr : %s\n",inet_ntoa...
112
113 printf("----TCP Header---------------...
114 printf("source port : %u\n",ntohs(buf...
115 printf("dest port : %u\n",ntohs(buf...
116 printf("sequence : %u\n",ntohl(buf...
117 printf("ack seq : %u\n",ntohl(buf...
118 printf("frags :");
119 buf.tcp.fin ? printf(" FIN") : 0 ;
120 buf.tcp.syn ? printf(" SYN") : 0 ;
121 buf.tcp.rst ? printf(" RST") : 0 ;
122 buf.tcp.psh ? printf(" PSH") : 0 ;
123 buf.tcp.ack ? printf(" ACK") : 0 ;
124 buf.tcp.urg ? printf(" URG") : 0 ;
125 printf("\n");
126 printf("window : %u\n",ntohs(buf...
127 printf("check : 0x%x\n",ntohs(b...
128 printf("urt_ptr : %u\n\n\n",buf.t...
129 }
130 } /* for() loop */
131 }
ソースファイル [[pckmon2.c>http://github.com/kaizawa/linu...
*実行例 [#o54a6b2f]
プログラム名の後に引数としてパケットをキャプチャする NIC ...
なお、このプログラムは root ユーザで実行する必要がありま...
# ./pckmon2 eth0
Packet number : 0
----IP Header--------------------
version : 4
ihl : 5
tos : 0
tot length : 40
id : 14879
frag_off : 0
ttl : 128
protocol : 6
check : 0xd575
saddr : 172.29.73.2
daddr : 172.29.73.254
----TCP Header-------------------
source port : 1270
dest port : 22
sequence : 1671008060
ack seq : 1093140794
frags : ACK
window : 17340
check : 0x4699
urt_ptr : 0
Packet number : 1
----IP Header--------------------
version : 4
ihl : 5
tos : 16
tot length : 540
id : 11933
frag_off : 0
ttl : 64
protocol : 6
check : 0x1ef4
saddr : 172.29.73.254
daddr : 172.29.73.2
----TCP Header-------------------
source port : 22
dest port : 1270
sequence : 1093140794
ack seq : 1671008060
frags : PSH ACK
window : 6432
check : 0xbbdc
urt_ptr : 0
NIC に到着した TCP のパケットを書き出しています。
内容をみると、SSH のセッションのパケットであることが分か...
*解説 [#d7af81c0]
このプログラムではいままでのプログラムと同様に socket() ...
34 if ((sock = socket(PF_PACKET, SOCK_DGRAM, hto...
これにより、 TCP のデータ部だけでなく、よりデバイスに近い...
-通常はデータしか見れない
|BGCOLOR(gray):Ethernet ヘッダー|
|BGCOLOR(gray):IP ヘッダー|
|BGCOLOR(gray):TCP ヘッダー|
|BGCOLOR(white):データ|
~
-PF_PACKET ドメインの SOCK_DGRAM を指定した場合、IP、TCP ...
|BGCOLOR(gray):Ethernet ヘッダー|
|BGCOLOR(white):IP ヘッダー|
|BGCOLOR(white):TCP ヘッダー|
|BGCOLOR(white):データ|
~
-PF_PACKET ドメインの SOCK_RAW を指定した場合、さらに Eth...
|BGCOLOR(white):Ethernet ヘッダー|
|BGCOLOR(white):IP ヘッダー|
|BGCOLOR(white):TCP ヘッダー|
|BGCOLOR(white):データ|
~
また、データを受け取るときに先の POPクライアントプログラ...
|>|recvfrom()|h
|概要|メッセージの受信|
|インクルードファイル |#include <sys/types.h>&br;#includ...
|形式| int recvfrom(int s, void *buf, int len, unsigned ...
|引数 |int s : socket 記述子&br;void *buf: 受信メッセ...
|戻り値 |成功時: 受信したバイト数&br;エラー: -1|
後は recvfrom で受け取ったデータ(=buf)を以下の構造体に...
70 struct buf {
71 struct iphdr ip; ---> IP ヘッ...
72 struct tcphdr tcp; ---> TCP ヘッ...
73 unsigned char blah[65535]; ---> データ
74 } buf;
IP ヘッダ、TCPヘッダは /use/include/netinet/ip.h および t...
これで受け取ったデータの最初の部分が、ip ヘッダ と tcp ヘ...
IP 、TCP ヘッダ構造体の各メンバの出力時には メンバごとに...
*最後に・・・ [#v5e5142f]
相変わらず自分でも不明な部分が多く、 汚いソースですが、色...
ページ名: