開始行:
#norelated
*Solaris DLPI プログラミング/パケットモニター
*目次 [#m0d7cb0e]
#contents
*概要 [#me4bb584]
まず最初に白状しますが、ここで書いているプログラムの コア...
&br;
DLPI とは Data Link Provider Interface の略で solaris が...
DLPI をつかえばいろいろ面白いものが出来そうですが、ここで...
*プログラムのイメージ [#scd6b08d]
このプログラムの main() の流れを以下に示します。最後の ge...
PPA と SAP ってのが出てきますが、PPA は network Interface...
|CENTER:流れ|CENTER: 解説|h
|CENTER:open()| device(network Interface)をオープン|
|CENTER:↓ ||
|CENTER:dlattachreq()| オープンしたデバイスの PPA(physi...
|CENTER:↓ ||
|CENTER:dlokack() |上記の要求の ACK(確認応答)を受け取...
|CENTER:↓ ||
|CENTER:dlpromisconreq() | promiscast(無差別受信)モード...
|CENTER:↓ ||
|CENTER:dlokack()| 上記の要求の ACK を受け取る。|
|CENTER:↓ ||
|CENTER:dlbindreq()| データリンク層の SAP(service acces...
|CENTER:↓ ||
|CENTER:dlokack()| 上記の要求の ACK を受け取る。|
|CENTER:↓||
|CENTER:strioctl() | ioctl() を通じて device を RAW モー...
|CENTER:↓ ||
|CENTER:ioctl(,I_FLUSH,FLUSHR)| ioctl() を通じてSTREMA ...
|CENTER:↓ ||
|CENTER:getmsg() |STREAM の READ QUEUE から生データをを...
|CENTER:↓ ||
|CENTER:print_pkt()| あとは、読み込んだデータを Ether、I...
*ソースコード [#teaa7bd0]
CENTER:[[dlpi-sniff-0.1.tar.gz>http://github.com/download...
1 /*********************************************
2 * sniff.c
3 *
4 * packet monitor using DLPI
5 *
6 * gcc sniff.c -lnsl -o sniff
7 *
8 ********************************************/
9 #Include <netinet/in.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <sys/stropts.h>
13 #include <sys/dlpi.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <sys/signal.h>
17 #include <sys/stream.h>
18 #include <string.h>
19 #include <net/if.h>
20 #include <netinet/if_ether.h>
21 #include <netinet/in_systm.h>
22 #include <netinet/tcp.h>
23 #include <netinet/ip.h>
24 #include <sys/varargs.h>
25 #include <errno.h>
26 #include <unistd.h>
27
28 #define ERR_MSG_MAX 300
29 #define MAXDLBUFSIZE 8192
30 #define DLBUFSIZE 8192
31 #define TCP_DATA_PRINT_LENGTH 100
32 #define PRINT_MAC_ADDR(ether_addr_octet) { ...
33 int i; ...
34 for ( i =0; i < 6; i++){ ...
35 printf("%02x",(ether_addr_octet[i]));...
36 if(i != 5) ...
37 printf(":"); ...
38 } ...
39 }
40
41 void print_packet(caddr_t, int);
42 void print_usage(char *);
43 int dlattachreq(int, t_uscalar_t, caddr_t );
44 int dlpromisconreq(int, t_uscalar_t, caddr_t);
45 int dlbindreq(int, t_uscalar_t, t_uscalar_t, u...
46 void print_err(int , char *, ...);
47 int dldetachreq(int , caddr_t);
48 int dlpromiscoffreq(int, t_uscalar_t, caddr_t);
49
50 int
51 main(int argc, char *argv[])
52 {
53 char buf[DLBUFSIZE]; // get...
54 struct strbuf databuf; // getmsg(2) ...
55 union DL_primitives *dlp;
56 int flags = 0;
57 int ppa; // NIC のインス...
58 int sap; // Ethernet フレ...
59 int fd; // デバイスをオ...
60 struct strioctl strioc; // stream デバ...
61 char *interface; // 引数で渡...
62 char devname[30] = {0}; //...
63 char devpath[30] = {0}; //...
64 char *instance; // interfac...
65
66 if (argc != 2)
67 print_usage(argv[0]);
68
69 interface = argv[1];
70 if ((instance = strpbrk(interface, "012345678...
71 fprintf(stderr, "%s: no instance specifie...
72 print_usage(argv[0]);
73 }
74
75 ppa = atoi(instance);
76
77 strncpy(devname, interface, instance - interf...
78
79 sprintf(devpath, "/dev/%s",devname);
80
81 /*
82 * デバイスをオープンする
83 */
84 if((fd = open (devpath , O_RDWR)) < 0 ){
85 perror("open");
86 exit(1);
87 }
88
89 /*
90 * PPA(instance) にアッタチする
91 */
92 if(dlattachreq(fd, ppa, buf) < 0){
93 fprintf(stderr, "%s: no such instance\n",...
94 print_usage(argv[0]);
95 }
96
97 /*
98 * プロミスキャスモードをセット
99 */
100 if(dlpromisconreq(fd, DL_PROMISC_PHYS, buf) <...
101 fprintf(stderr, "%s: Cannot set promiscuo...
102 exit(1);
103 }
104
105 /*
106 * SAP(flame type) にバインド
107 */
108 if(dlbindreq (fd, ETHERTYPE_IP, 0, DL_CLDLS, ...
109 fprintf(stderr, "%s: Cannot bind to ETHER...
110 exit(1);
111 }
112
113 /*
114 * RAW モードにセット
115 */
116 strioc.ic_cmd = DLIOCRAW;
117 strioc.ic_timout = -1;
118 strioc.ic_len = 0;
119 strioc.ic_dp = NULL;
120 if(ioctl(fd, I_STR, &strioc) < 0){
121 perror("ioctl: I_STR: DLIOCRAW");
122 exit(1);
123 }
124
125 /*
126 * キューをフラッシュ
127 */
128 if (ioctl(fd, I_FLUSH, FLUSHR) < 0){
129 perror("ioctl: I_FLUSH");
130 exit(1);
131 }
132
133 databuf.maxlen = MAXDLBUFSIZE;
134 databuf.len = 0;
135 databuf.buf = (caddr_t)buf;
136
137 while (getmsg(fd, NULL, &databuf, &flags) == ...
138 if (databuf.len > 0)
139 print_packet(databuf.buf, databuf.len);
140 }
141
142 perror("getmsg");
143 exit(1);
144 }
145
146 void
147 print_packet(caddr_t buf, int len)
148 {
149 struct ether_header *ether;
150 struct tcphdr *tcp;
151 struct ip *ip;
152 u_char *tcpdata;
153 int etherlen;
154 int iphlen;
155 int iptotlen;
156 int tcphlen;
157 int tcpdatalen;
158
159 etherlen = sizeof(struct ether_header);
160 ether = (struct ether_header *)buf;
161
162 /*
163 * Ether Type が IP(0x800) じゃなかったらリタ...
164 */
165 if(ether->ether_type != ETHERTYPE_IP)
166 return;
167
168 /*
169 * 全フレームサイズがデフォルト(最小)の eth...
170 * ヘッダー長の合計よりも小さかったら不正パケ...
171 * リターン。
172 */
173 if(len < etherlen + sizeof(struct ip) + sizeo...
174 return;
175
176 /*
177 * アライメントエラーを避けるため、IP ヘッダ...
178 * したメモリにコピーする。
179 */
180 ip = (struct ip *)malloc(len);
181 memcpy(ip, buf + etherlen, len);
182
183 /*
184 * TCP でなければリターン
185 */
186 if(ip->ip_p != IPPROTO_TCP)
187 goto error;
188
189 iphlen = ip->ip_hl << 2;
190
191 /*
192 * パケット内で申告されている IP ヘッダー長が...
193 * ので改めて、フレーム長を確認。
194 * もし小さかったら不正パケットとみなして無視。
195 */
196 if(len < etherlen + iphlen + sizeof(struct tc...
197 goto error;
198
199 tcp = (struct tcphdr *)((u_char *)ip + iphlen);
200 tcphlen = tcp->th_off << 2;
201
202 /*
203 * パケット内で申告されている TCP ヘッダー長...
204 * ので改めて、フレーム長を確認。
205 * もし小さかったら不正パケットとみなして無視。
206 */
207 if(len < etherlen + iphlen + tcphlen )
208 goto error;
209
210 printf("\n----Ether Header----\n");
211 printf("src addr : ");
212 PRINT_MAC_ADDR(ether->ether_shost.ether_addr_...
213 printf("\n");
214 printf("dest addr : ");
215 PRINT_MAC_ADDR(ether->ether_dhost.ether_addr_...
216 printf("\n");
217 printf("ether type : 0x%x\n",ether->ether_ty...
218
219 printf("----IP Header----\n");
220 printf("version : %d\n",ip->ip_v);
221 printf("header len : %d (%d bytes)\n",ip->ip...
222 printf("tos : %d\n",ip->ip_tos);
223 printf("total len : %d\n",ntohs(ip->ip_len));
224 printf("id : %d\n",ntohs(ip->ip_id));
225 printf("frag offset : %d\n",ip->ip_off);
226 printf("ttl : %d\n",ip->ip_ttl);
227 printf("protocol : %d\n",ip->ip_p);
228 printf("checksum : 0x%x\n",ip->ip_sum);
229 printf("src address : %s\n",inet_ntoa(ip->ip_...
230 printf("dst address : %s\n",inet_ntoa(ip->ip_...
231
232 printf("----TCP Header----\n");
233 printf("source port : %d\n",ntohs(tcp->th_spo...
234 printf("dest port : %d\n",ntohs(tcp->th_dpo...
235 printf("seq : %u\n",ntohl(tcp->th_seq...
236 printf("ack : %u\n",ntohl(tcp->th_ack...
237 printf("data offset : %d (%d bytes)\n",tcp->t...
238 printf("flags : ");
239 if((tcp->th_flags | TH_FIN) == tcp->th_flags)
240 printf("FIN ");
241 if((tcp->th_flags | TH_SYN) == tcp->th_flags)
242 printf("SIN ");
243 if((tcp->th_flags | TH_RST) == tcp->th_flags)
244 printf("RST ");
245 if((tcp->th_flags | TH_PUSH) == tcp->th_flags)
246 printf("PUSH ");
247 if((tcp->th_flags | TH_ACK) == tcp->th_flags)
248 printf("ACK ");
249 if((tcp->th_flags | TH_URG) == tcp->th_flags)
250 printf("URG ");
251 printf("\n");
252 printf("window : %d\n",ntohs(tcp->th_win...
253 printf("check sum : 0x%x\n",tcp->th_sum);
254 printf("urt_ptr : %d\n",tcp->th_urp);
255
256 /*
257 * ヘッダ情報から TCP データサイズを計算
258 * もしヘッダ情報から求めたTCPデータ長が残り...
259 * バイト数より大きかったら、残りのバイト数...
260 */
261 iptotlen = ntohs(ip->ip_len);
262 tcpdatalen = iptotlen - iphlen - tcphlen;
263 if( tcpdatalen > len - etherlen - iphlen - tc...
264 tcpdatalen = len - etherlen - iphlen - tc...
265
266 if( tcpdatalen > 0){
267 int i = 0;
268
269 tcpdata = (u_char *)tcp + tcphlen;
270 printf("------DATA-------\n");
271 printf("data length : %d\n", tcpdatalen);
272 /*
273 * 表示可能データであれば最初の 100 文字...
274 */
275 while ( i < tcpdatalen && i < TCP_DATA_PR...
276 if(isprint(tcpdata[i]))
277 printf("%c",tcpdata[i]);
278 i++;
279 }
280 }
281
282 printf("\n\n");
283
284 error:
285 free(ip);
286 return;
287 }
288
289 /************************************************...
290 * print_usage()
291 *
292 * Usage を表示し、終了する。
293 ************************************************...
294 void
295 print_usage(char *argv)
296 {
297 printf("Usage: %s ifname \n",argv);
298 printf(" Example) %s eri0\n", argv);
299 exit(1);
300 }
301
302 /************************************************...
303 * dlattachreq()
304 *
305 * DLPI のルーチン。putmsg(9F) を使って DL_ATTACH...
306 *
307 ************************************************...
308 int
309 dlattachreq(int fd, t_uscalar_t ppa ,caddr_t buf)
310 {
311 union DL_primitives *primitive;
312 dl_attach_req_t attachreq;
313 struct strbuf ctlbuf;
314 int flags = 0;
315 int ret;
316
317 attachreq.dl_primitive = DL_ATTACH_REQ;
318 attachreq.dl_ppa = ppa;
319
320 ctlbuf.maxlen = 0;
321 ctlbuf.len = sizeof(attachreq);
322 ctlbuf.buf = (caddr_t)&attachreq;
323
324 if (putmsg(fd, &ctlbuf, (struct strbuf*) NULL...
325 fprintf(stderr, "dlattachreq: putmsg: %s"...
326 return(-1);
327 }
328
329 ctlbuf.maxlen = MAXDLBUFSIZE;
330 ctlbuf.len = 0;
331 ctlbuf.buf = (caddr_t)buf;
332
333 if ((ret = getmsg(fd, &ctlbuf, (struct strbuf...
334 fprintf(stderr, "dlattachreq: getmsg: %s\...
335 return(-1);
336 }
337
338 primitive = (union DL_primitives *) ctlbuf.buf;
339 if ( primitive->dl_primitive != DL_OK_ACK){
340 fprintf(stderr, "dlattachreq: not DL_OK_A...
341 return(-1);
342 }
343
344 return(0);
345 }
346
347 /************************************************...
348 * dlpromisconreq()
349 *
350 * DLPI のルーチン。 putmsg(9F) を使って DL_PROMI...
351 *
352 ************************************************...
353 int
354 dlpromisconreq(int fd, t_uscalar_t level, caddr_t...
355 {
356 union DL_primitives *primitive;
357 dl_promiscon_req_t promisconreq;
358 struct strbuf ctlbuf;
359 int flags = 0;
360 int ret;
361
362 promisconreq.dl_primitive = DL_PROMISCON_REQ;
363 promisconreq.dl_level = level;
364
365 ctlbuf.maxlen = 0;
366 ctlbuf.len = sizeof (promisconreq);
367 ctlbuf.buf = (caddr_t)&promisconreq;
368
369 if (putmsg(fd, &ctlbuf, (struct strbuf*) NULL...
370 fprintf(stderr, "dlpromisconreq: putmsg: ...
371 return(-1);
372 }
373
374 ctlbuf.maxlen = MAXDLBUFSIZE;
375 ctlbuf.len = 0;
376 ctlbuf.buf = (caddr_t)buf;
377
378 if ((ret = getmsg(fd, &ctlbuf, (struct strbuf...
379 fprintf(stderr, "dlpromisconreq: getmsg: ...
380 return(-1);
381 }
382
383 primitive = (union DL_primitives *) ctlbuf.buf;
384 if ( primitive->dl_primitive != DL_OK_ACK){
385 fprintf(stderr, "dlpromisconreq: not DL_O...
386 return(-1);
387 }
388
389 return(0);
390 }
391
392 /************************************************...
393 * dlbindreq()
394 *
395 * DLPI のルーチン。 putmsg(9F) を使って DL_BIND_...
396 *
397 ************************************************...
398 int
399 dlbindreq(
400 int fd,
401 t_uscalar_t sap,
402 t_uscalar_t max_conind,
403 uint16_t service_mode,
404 uint16_t conn_mgmt,
405 t_uscalar_t xidtest_flg,
406 caddr_t buf
407 )
408 {
409 union DL_primitives *primitive;
410 dl_bind_req_t bindreq;
411 struct strbuf ctlbuf;
412 int flags = 0;
413 int ret;
414
415 bindreq.dl_primitive = DL_BIND_REQ;
416 bindreq.dl_sap = sap;
417 bindreq.dl_max_conind = max_conind;
418 bindreq.dl_service_mode = service_mode;
419 bindreq.dl_conn_mgmt = conn_mgmt;
420 bindreq.dl_xidtest_flg = xidtest_flg;
421
422 ctlbuf.maxlen = 0;
423 ctlbuf.len = sizeof(bindreq);
424 ctlbuf.buf = (caddr_t)&bindreq;
425
426 if (putmsg(fd, &ctlbuf, (struct strbuf*) NULL...
427 fprintf(stderr, "dlbindreq: putmsg: %s", ...
428 return(-1);
429 }
430
431 ctlbuf.maxlen = MAXDLBUFSIZE;
432 ctlbuf.len = 0;
433 ctlbuf.buf = (caddr_t)buf;
434
435 if ((ret = getmsg(fd, &ctlbuf, (struct strbuf...
436 fprintf(stderr, "dlbindreq: getmsg: %s\n"...
437 return(-1);
438 }
439
440 primitive = (union DL_primitives *) ctlbuf.buf;
441 if ( primitive->dl_primitive != DL_BIND_ACK){
442 fprintf(stderr, "dlbindreq: not DL_BIND_A...
443 return(-1);
444 }
445
446 return(0);
447 }
ソースファイル [[sniff.c>source:sniff.c]]
*実行例 [#i0fb3299]
プログラム名の後に引数としてインターフェース名を入力しま...
以下の 例では Sun の FastEthernet カードである hme0 を指...
なお、このプログラムも root ユーザで実行する必要がありま...
setuid(chmod 4755 sniff )してもいいですけど。&br;
# ./sniff hme0
----Ether Header----
src addr : 08:00:20:c6:69:c7
dest addr : 00:13:d3:a9:8f:40
ether type : 0x800
----IP Header----
version : 4
header len : 5 (20 bytes)
tos : 0
total len : 1292
id : 51935
frag offset : 16384
ttl : 60
protocol : 6
checksum : 0x8497
src address : 172.29.73.55
dst address : 172.29.73.3
----TCP Header----
source port : 23
dest port : 1277
seq : 371774688
ack : 3757417225
data offset : 5 (20 bytes)
flags : ACK
window : 50400
check sum : 0x6420
urt_ptr : 0
------DATA-------
NIC に到着したすべての packet を表示します。&br;
内容をみると、telnet のセッションのパケットであることが分...
この例では出ていませんが、データ部に文字列があればそれも-...
あと、言い忘れましたが これは TCP パケット専用です。ICMP ...
全部のヘッダー対応の source 書くぐらいなら tcpdump や sno...
*解説 [#q678dd85]
DLPI の説明をする上で STREAMS (ストリーム)機構 の解説を...
STREAMS 機構とは Solaris をはじめとする SVR4 準拠の syste...
STREAM とは論理的なデータの通り道であり、STREAM 内で 受け...
#ref(http://www.whiteboard.ne.jp/~admin2/pict/stream.gif)
今回の場合上図の「ストリームデバイスドライバ」とは networ...
DLPI(Data Link Provider Interface)とは この network Int...
以上、簡単に DLPI と STREAM について説明させていただきま...
55 union DL_primitives *dlp;
55 行目に DL_primitives という共用体を 宣言しています。pr...
上の STREAMS 機構の説明のところで、STREAM(データの通り道...
|メッセージタイプ|説明|h
|M_DATA| ユーザプロセスとデバイスドライバ間のデータの受...
|M_PROTO |ユーザプロセスとデバイスドライバ間の制御情報の...
|M_PCPROTO | M_PROTO と同じだが、より優先度の高いメッセー...
DLPI で受け渡しされるメッセージは primitive という構造体...
84 if((fd = open (devpath , O_RDWR)) < 0 ){
84 行目で device、つまり network Interface を open します...
92 if(dlattachreq(fd, ppa, buf) < 0){
84 行目で open した STREAM と、物理的な device を結び付け...
317 attachreq.dl_primitive = DL_ATTACH_REQ;
というのが宣言されています。これは上で説明した DLPI primi...
dl_attach_req_t 構造体は まさに STREAM と PPA を attach ...
/usr/include/sys/dlpi.h より
typedef struct {
t_uscalar_t dl_primitive; /* set to...
t_uscalar_t dl_ppa; /* id of ...
} dl_attach_req_t;
ここでさらに strbuf 構造体(STREAM Buffer 構造体?)という...
/usr/include/sys/stropts.h より
struct strbuf {
int maxlen; /* no. of bytes in buffer...
int len; /* no. of bytes returned */
caddr_t buf; /* pointer to data */
};
strbuf 構造体の中の data のポインターとして dl_attach_req...
|>|CENTER:strbuf 構造体|h
|>|CENTER:maxlen(最大buffer長)|
|>|CENTER:len(data長)|
|>|CENTER:dl_attach_req_t 構造体|
||CENTER:DL_ATTACH_REQ|
||CENTER:ppa|
strbuf と dl_attach_req_t 両構造体の各メンバーに値の代入...
324 if (putmsg(fd, &ctlbuf, (struct strbuf*) NULL...
|>|&size(20){putmsg()};|h
|概要| STREAM へのメッセージの送信|
|インクルードファイル |#include <stropts.h>|
|形式| int putmsg(int fildes, const struct strbuf *ctlpt...
|引数 |int filedes : ファイル記述子&br;const struct cl...
|戻り値 |成功時: 0&br;エラー: -1|
putmsg() システムコールでは STREAM に対してデータバッファ...
さて、これで ATTACHの要求の送信は終了しまして、つづいてAT...
#ref(http://www.whiteboard.ne.jp/~admin2/pict/dlpi_sequen...
333 if ((ret = getmsg(fd, &ctlbuf, (struct strbuf...
ここで今度は getmsg() というシステムコールが出てきます。
|>|&size(20){getmsg()};|h
|概要| STREAM からのメッセージの受信|
|インクルードファイル |#include <stropts.h>|
|形式| int getmsg(int fildes, struct strbuf *ctlptr, str...
|引数 |int filedes : ファイル記述子&br;const struct cl...
|戻り値 |成功時: 実数値&br; 0 --> すべてのメッセージの...
getmsg() は putmsg() とは逆に STREAM HEAD を通じてアップ...
338 primitive = (union DL_primitives *) ctlbuf.buf;
339 if ( primitive->dl_primitive != DL_OK_ACK){
340 fprintf(stderr, "dlattachreq: not DL_OK_A...
341 return(-1);
342 }
ctlbuf は「buf」 というメンバーを持ち、「buf」は DLPI pri...
100 if(dlpromisconreq(fd, DL_PROMISC_PHYS, buf) <...
...
108 if(dlbindreq (fd, ETHERTYPE_IP, 0, DL_CLDLS, ...
100 行目の dlpromisconreq() 及び、108 行目の dlbindreq() ...
|dlpromisconreq|DL_PROMISCON_REQ primitive にて promisca...
|dlbindreq |DL_BIND_REQ primitive にて データリンク層の ...
さて、main() のつづきですが、つぎはいままでの処理とはちょ...
120 if(ioctl(fd, I_STR, &strioc) < 0){
121 perror("ioctl: I_STR: DLIOCRAW");
122 exit(1);
123 }
ここで呼んでいる ioctl() システムコールがまた重要な処理に...
|>|&size(20){ioctl()};|h
|概要|STREAM デバイスの制御|
|インクルードファイル |#include <unistd.h>&br;#include <...
|形式| int ioctl(int fildes, int command, /* arg */ ...);|
|引数 |int filedes : ファイル記述子&br;int command: ...
|戻り値 |成功時: 実数値&br;エラー: -1|
STREAMS ioctl() は ioctl() のサプセットで、ストリーム上の...
では、この ioctl にてどのような内容のメッセージが DOWN ST...
struct strioctl {
int ic_cmd; /* コマンド*/
int ic_timout; /*タイムアウト値 */
int ic_len; /* データ長 */
char *ic_dp; /* データへのポインタ */
};
116 〜 119 行目を見ていただければ分かりますが、上記の構造...
116 strioc.ic_cmd = DLIOCRAW;
117 strioc.ic_timout = -1;
118 strioc.ic_len = 0;
119 strioc.ic_dp = NULL;
これは M_DATA タイプのメッセージに対して RAW モード、つま...
RAW モードへの移行がおわったところで、さらに main() の処...
128 if (ioctl(fd, I_FLUSH, FLUSHR) < 0){
ioctl() システムコール(ここで言っているのは STREAMS ioct...
第三引数のオプションは sys/stropts.h に定義してありまして...
sys/stropts.h より抜粋
#define FLUSHR 0x01 /* flush read queue */
queue(キュー) という言葉が初めて出てきましたが、これも ...
ここではその読み取り用の格納庫を明示的に空にしているとい...
さて、ここまでで packet のキャプチャーの準備が整いました...
133 databuf.maxlen = MAXDLBUFSIZE;
134 databuf.len = 0;
135 databuf.buf = (caddr_t)buf;
136
137 while (getmsg(fd, NULL, &databuf, &flags) == ...
138 if (databuf.len > 0)
139 print_packet(databuf.buf, databuf.len);
140 }
「databuf」というのは strbuf 構造体で、54 行目に宣言して...
getmsg はすでにお話しているのでさらっと流しますが、第二引...
STREAM HEAD から受け取った生データは strbuf 構造体 data ...
print_packet() 内で行っている事は 先ほど getmsg() にて受...
ただ違うのは 今回は Ethernet の ヘッダーも入るので、デー...
*最後に[#l186476e]
というわけで非常ーに長々と、かつおおざっぱに解説させてい...
私自身本当に分からないところだらけで(だったら書くなとい...
*参考資料 [#gd0c4185]
このページを書く上で参考にした資料をご紹介いたします。
|参考資料名 |メモ|h
|UNIX カーネルの魔法&br;(プレンティスホール出版)| SVR4...
|UNIX ネットワークプログラミング&br;(トッパン)| まさに...
|詳解TCP/IP&br;(ソフトバンク) | TCP/IP のプロトコル上の...
|man page| 一番身近な情報源&br;dlpi(7P), le(7D), streamio...
|docs.sun.com | リンクしているのは Solaris 8 の hme の ma...
&aname(tsuiki);
*追記 [#b1795512]
**すべての フレームタイプを受信する [#ma102d9d]
先に書きましたように、このプログラムでは IP のpacket しか...
100 if(dlpromisconreq(fd, DL_PROMISC_SAP, buf) < ...
dlpromisconreq() 関数の中で、この第二引数の DL_PROMISC_SA...
/*
* DLPI promiscuous mode definitions
*/
#define DL_PROMISC_PHYS 0x01 /* promiscuous m...
#define DL_PROMISC_SAP 0x02 /* promiscous mo...
#define DL_PROMISC_MULTI 0x03 /* promiscuous m...
これは promiscuous mode(無差別受信モード)をどのレベルで...
名前のイメージ的には DL_PROMISC_PHYS が すべて受信できて ...
「DL_PROMISC_SAP」にセットすることによって ARP や REVARP ...
**さらに追記 [#h2618cba]
DL_PROMISC_PHYS(PHYが レベル)ではローカルホストによって生...
終了行:
#norelated
*Solaris DLPI プログラミング/パケットモニター
*目次 [#m0d7cb0e]
#contents
*概要 [#me4bb584]
まず最初に白状しますが、ここで書いているプログラムの コア...
&br;
DLPI とは Data Link Provider Interface の略で solaris が...
DLPI をつかえばいろいろ面白いものが出来そうですが、ここで...
*プログラムのイメージ [#scd6b08d]
このプログラムの main() の流れを以下に示します。最後の ge...
PPA と SAP ってのが出てきますが、PPA は network Interface...
|CENTER:流れ|CENTER: 解説|h
|CENTER:open()| device(network Interface)をオープン|
|CENTER:↓ ||
|CENTER:dlattachreq()| オープンしたデバイスの PPA(physi...
|CENTER:↓ ||
|CENTER:dlokack() |上記の要求の ACK(確認応答)を受け取...
|CENTER:↓ ||
|CENTER:dlpromisconreq() | promiscast(無差別受信)モード...
|CENTER:↓ ||
|CENTER:dlokack()| 上記の要求の ACK を受け取る。|
|CENTER:↓ ||
|CENTER:dlbindreq()| データリンク層の SAP(service acces...
|CENTER:↓ ||
|CENTER:dlokack()| 上記の要求の ACK を受け取る。|
|CENTER:↓||
|CENTER:strioctl() | ioctl() を通じて device を RAW モー...
|CENTER:↓ ||
|CENTER:ioctl(,I_FLUSH,FLUSHR)| ioctl() を通じてSTREMA ...
|CENTER:↓ ||
|CENTER:getmsg() |STREAM の READ QUEUE から生データをを...
|CENTER:↓ ||
|CENTER:print_pkt()| あとは、読み込んだデータを Ether、I...
*ソースコード [#teaa7bd0]
CENTER:[[dlpi-sniff-0.1.tar.gz>http://github.com/download...
1 /*********************************************
2 * sniff.c
3 *
4 * packet monitor using DLPI
5 *
6 * gcc sniff.c -lnsl -o sniff
7 *
8 ********************************************/
9 #Include <netinet/in.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <sys/stropts.h>
13 #include <sys/dlpi.h>
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <sys/signal.h>
17 #include <sys/stream.h>
18 #include <string.h>
19 #include <net/if.h>
20 #include <netinet/if_ether.h>
21 #include <netinet/in_systm.h>
22 #include <netinet/tcp.h>
23 #include <netinet/ip.h>
24 #include <sys/varargs.h>
25 #include <errno.h>
26 #include <unistd.h>
27
28 #define ERR_MSG_MAX 300
29 #define MAXDLBUFSIZE 8192
30 #define DLBUFSIZE 8192
31 #define TCP_DATA_PRINT_LENGTH 100
32 #define PRINT_MAC_ADDR(ether_addr_octet) { ...
33 int i; ...
34 for ( i =0; i < 6; i++){ ...
35 printf("%02x",(ether_addr_octet[i]));...
36 if(i != 5) ...
37 printf(":"); ...
38 } ...
39 }
40
41 void print_packet(caddr_t, int);
42 void print_usage(char *);
43 int dlattachreq(int, t_uscalar_t, caddr_t );
44 int dlpromisconreq(int, t_uscalar_t, caddr_t);
45 int dlbindreq(int, t_uscalar_t, t_uscalar_t, u...
46 void print_err(int , char *, ...);
47 int dldetachreq(int , caddr_t);
48 int dlpromiscoffreq(int, t_uscalar_t, caddr_t);
49
50 int
51 main(int argc, char *argv[])
52 {
53 char buf[DLBUFSIZE]; // get...
54 struct strbuf databuf; // getmsg(2) ...
55 union DL_primitives *dlp;
56 int flags = 0;
57 int ppa; // NIC のインス...
58 int sap; // Ethernet フレ...
59 int fd; // デバイスをオ...
60 struct strioctl strioc; // stream デバ...
61 char *interface; // 引数で渡...
62 char devname[30] = {0}; //...
63 char devpath[30] = {0}; //...
64 char *instance; // interfac...
65
66 if (argc != 2)
67 print_usage(argv[0]);
68
69 interface = argv[1];
70 if ((instance = strpbrk(interface, "012345678...
71 fprintf(stderr, "%s: no instance specifie...
72 print_usage(argv[0]);
73 }
74
75 ppa = atoi(instance);
76
77 strncpy(devname, interface, instance - interf...
78
79 sprintf(devpath, "/dev/%s",devname);
80
81 /*
82 * デバイスをオープンする
83 */
84 if((fd = open (devpath , O_RDWR)) < 0 ){
85 perror("open");
86 exit(1);
87 }
88
89 /*
90 * PPA(instance) にアッタチする
91 */
92 if(dlattachreq(fd, ppa, buf) < 0){
93 fprintf(stderr, "%s: no such instance\n",...
94 print_usage(argv[0]);
95 }
96
97 /*
98 * プロミスキャスモードをセット
99 */
100 if(dlpromisconreq(fd, DL_PROMISC_PHYS, buf) <...
101 fprintf(stderr, "%s: Cannot set promiscuo...
102 exit(1);
103 }
104
105 /*
106 * SAP(flame type) にバインド
107 */
108 if(dlbindreq (fd, ETHERTYPE_IP, 0, DL_CLDLS, ...
109 fprintf(stderr, "%s: Cannot bind to ETHER...
110 exit(1);
111 }
112
113 /*
114 * RAW モードにセット
115 */
116 strioc.ic_cmd = DLIOCRAW;
117 strioc.ic_timout = -1;
118 strioc.ic_len = 0;
119 strioc.ic_dp = NULL;
120 if(ioctl(fd, I_STR, &strioc) < 0){
121 perror("ioctl: I_STR: DLIOCRAW");
122 exit(1);
123 }
124
125 /*
126 * キューをフラッシュ
127 */
128 if (ioctl(fd, I_FLUSH, FLUSHR) < 0){
129 perror("ioctl: I_FLUSH");
130 exit(1);
131 }
132
133 databuf.maxlen = MAXDLBUFSIZE;
134 databuf.len = 0;
135 databuf.buf = (caddr_t)buf;
136
137 while (getmsg(fd, NULL, &databuf, &flags) == ...
138 if (databuf.len > 0)
139 print_packet(databuf.buf, databuf.len);
140 }
141
142 perror("getmsg");
143 exit(1);
144 }
145
146 void
147 print_packet(caddr_t buf, int len)
148 {
149 struct ether_header *ether;
150 struct tcphdr *tcp;
151 struct ip *ip;
152 u_char *tcpdata;
153 int etherlen;
154 int iphlen;
155 int iptotlen;
156 int tcphlen;
157 int tcpdatalen;
158
159 etherlen = sizeof(struct ether_header);
160 ether = (struct ether_header *)buf;
161
162 /*
163 * Ether Type が IP(0x800) じゃなかったらリタ...
164 */
165 if(ether->ether_type != ETHERTYPE_IP)
166 return;
167
168 /*
169 * 全フレームサイズがデフォルト(最小)の eth...
170 * ヘッダー長の合計よりも小さかったら不正パケ...
171 * リターン。
172 */
173 if(len < etherlen + sizeof(struct ip) + sizeo...
174 return;
175
176 /*
177 * アライメントエラーを避けるため、IP ヘッダ...
178 * したメモリにコピーする。
179 */
180 ip = (struct ip *)malloc(len);
181 memcpy(ip, buf + etherlen, len);
182
183 /*
184 * TCP でなければリターン
185 */
186 if(ip->ip_p != IPPROTO_TCP)
187 goto error;
188
189 iphlen = ip->ip_hl << 2;
190
191 /*
192 * パケット内で申告されている IP ヘッダー長が...
193 * ので改めて、フレーム長を確認。
194 * もし小さかったら不正パケットとみなして無視。
195 */
196 if(len < etherlen + iphlen + sizeof(struct tc...
197 goto error;
198
199 tcp = (struct tcphdr *)((u_char *)ip + iphlen);
200 tcphlen = tcp->th_off << 2;
201
202 /*
203 * パケット内で申告されている TCP ヘッダー長...
204 * ので改めて、フレーム長を確認。
205 * もし小さかったら不正パケットとみなして無視。
206 */
207 if(len < etherlen + iphlen + tcphlen )
208 goto error;
209
210 printf("\n----Ether Header----\n");
211 printf("src addr : ");
212 PRINT_MAC_ADDR(ether->ether_shost.ether_addr_...
213 printf("\n");
214 printf("dest addr : ");
215 PRINT_MAC_ADDR(ether->ether_dhost.ether_addr_...
216 printf("\n");
217 printf("ether type : 0x%x\n",ether->ether_ty...
218
219 printf("----IP Header----\n");
220 printf("version : %d\n",ip->ip_v);
221 printf("header len : %d (%d bytes)\n",ip->ip...
222 printf("tos : %d\n",ip->ip_tos);
223 printf("total len : %d\n",ntohs(ip->ip_len));
224 printf("id : %d\n",ntohs(ip->ip_id));
225 printf("frag offset : %d\n",ip->ip_off);
226 printf("ttl : %d\n",ip->ip_ttl);
227 printf("protocol : %d\n",ip->ip_p);
228 printf("checksum : 0x%x\n",ip->ip_sum);
229 printf("src address : %s\n",inet_ntoa(ip->ip_...
230 printf("dst address : %s\n",inet_ntoa(ip->ip_...
231
232 printf("----TCP Header----\n");
233 printf("source port : %d\n",ntohs(tcp->th_spo...
234 printf("dest port : %d\n",ntohs(tcp->th_dpo...
235 printf("seq : %u\n",ntohl(tcp->th_seq...
236 printf("ack : %u\n",ntohl(tcp->th_ack...
237 printf("data offset : %d (%d bytes)\n",tcp->t...
238 printf("flags : ");
239 if((tcp->th_flags | TH_FIN) == tcp->th_flags)
240 printf("FIN ");
241 if((tcp->th_flags | TH_SYN) == tcp->th_flags)
242 printf("SIN ");
243 if((tcp->th_flags | TH_RST) == tcp->th_flags)
244 printf("RST ");
245 if((tcp->th_flags | TH_PUSH) == tcp->th_flags)
246 printf("PUSH ");
247 if((tcp->th_flags | TH_ACK) == tcp->th_flags)
248 printf("ACK ");
249 if((tcp->th_flags | TH_URG) == tcp->th_flags)
250 printf("URG ");
251 printf("\n");
252 printf("window : %d\n",ntohs(tcp->th_win...
253 printf("check sum : 0x%x\n",tcp->th_sum);
254 printf("urt_ptr : %d\n",tcp->th_urp);
255
256 /*
257 * ヘッダ情報から TCP データサイズを計算
258 * もしヘッダ情報から求めたTCPデータ長が残り...
259 * バイト数より大きかったら、残りのバイト数...
260 */
261 iptotlen = ntohs(ip->ip_len);
262 tcpdatalen = iptotlen - iphlen - tcphlen;
263 if( tcpdatalen > len - etherlen - iphlen - tc...
264 tcpdatalen = len - etherlen - iphlen - tc...
265
266 if( tcpdatalen > 0){
267 int i = 0;
268
269 tcpdata = (u_char *)tcp + tcphlen;
270 printf("------DATA-------\n");
271 printf("data length : %d\n", tcpdatalen);
272 /*
273 * 表示可能データであれば最初の 100 文字...
274 */
275 while ( i < tcpdatalen && i < TCP_DATA_PR...
276 if(isprint(tcpdata[i]))
277 printf("%c",tcpdata[i]);
278 i++;
279 }
280 }
281
282 printf("\n\n");
283
284 error:
285 free(ip);
286 return;
287 }
288
289 /************************************************...
290 * print_usage()
291 *
292 * Usage を表示し、終了する。
293 ************************************************...
294 void
295 print_usage(char *argv)
296 {
297 printf("Usage: %s ifname \n",argv);
298 printf(" Example) %s eri0\n", argv);
299 exit(1);
300 }
301
302 /************************************************...
303 * dlattachreq()
304 *
305 * DLPI のルーチン。putmsg(9F) を使って DL_ATTACH...
306 *
307 ************************************************...
308 int
309 dlattachreq(int fd, t_uscalar_t ppa ,caddr_t buf)
310 {
311 union DL_primitives *primitive;
312 dl_attach_req_t attachreq;
313 struct strbuf ctlbuf;
314 int flags = 0;
315 int ret;
316
317 attachreq.dl_primitive = DL_ATTACH_REQ;
318 attachreq.dl_ppa = ppa;
319
320 ctlbuf.maxlen = 0;
321 ctlbuf.len = sizeof(attachreq);
322 ctlbuf.buf = (caddr_t)&attachreq;
323
324 if (putmsg(fd, &ctlbuf, (struct strbuf*) NULL...
325 fprintf(stderr, "dlattachreq: putmsg: %s"...
326 return(-1);
327 }
328
329 ctlbuf.maxlen = MAXDLBUFSIZE;
330 ctlbuf.len = 0;
331 ctlbuf.buf = (caddr_t)buf;
332
333 if ((ret = getmsg(fd, &ctlbuf, (struct strbuf...
334 fprintf(stderr, "dlattachreq: getmsg: %s\...
335 return(-1);
336 }
337
338 primitive = (union DL_primitives *) ctlbuf.buf;
339 if ( primitive->dl_primitive != DL_OK_ACK){
340 fprintf(stderr, "dlattachreq: not DL_OK_A...
341 return(-1);
342 }
343
344 return(0);
345 }
346
347 /************************************************...
348 * dlpromisconreq()
349 *
350 * DLPI のルーチン。 putmsg(9F) を使って DL_PROMI...
351 *
352 ************************************************...
353 int
354 dlpromisconreq(int fd, t_uscalar_t level, caddr_t...
355 {
356 union DL_primitives *primitive;
357 dl_promiscon_req_t promisconreq;
358 struct strbuf ctlbuf;
359 int flags = 0;
360 int ret;
361
362 promisconreq.dl_primitive = DL_PROMISCON_REQ;
363 promisconreq.dl_level = level;
364
365 ctlbuf.maxlen = 0;
366 ctlbuf.len = sizeof (promisconreq);
367 ctlbuf.buf = (caddr_t)&promisconreq;
368
369 if (putmsg(fd, &ctlbuf, (struct strbuf*) NULL...
370 fprintf(stderr, "dlpromisconreq: putmsg: ...
371 return(-1);
372 }
373
374 ctlbuf.maxlen = MAXDLBUFSIZE;
375 ctlbuf.len = 0;
376 ctlbuf.buf = (caddr_t)buf;
377
378 if ((ret = getmsg(fd, &ctlbuf, (struct strbuf...
379 fprintf(stderr, "dlpromisconreq: getmsg: ...
380 return(-1);
381 }
382
383 primitive = (union DL_primitives *) ctlbuf.buf;
384 if ( primitive->dl_primitive != DL_OK_ACK){
385 fprintf(stderr, "dlpromisconreq: not DL_O...
386 return(-1);
387 }
388
389 return(0);
390 }
391
392 /************************************************...
393 * dlbindreq()
394 *
395 * DLPI のルーチン。 putmsg(9F) を使って DL_BIND_...
396 *
397 ************************************************...
398 int
399 dlbindreq(
400 int fd,
401 t_uscalar_t sap,
402 t_uscalar_t max_conind,
403 uint16_t service_mode,
404 uint16_t conn_mgmt,
405 t_uscalar_t xidtest_flg,
406 caddr_t buf
407 )
408 {
409 union DL_primitives *primitive;
410 dl_bind_req_t bindreq;
411 struct strbuf ctlbuf;
412 int flags = 0;
413 int ret;
414
415 bindreq.dl_primitive = DL_BIND_REQ;
416 bindreq.dl_sap = sap;
417 bindreq.dl_max_conind = max_conind;
418 bindreq.dl_service_mode = service_mode;
419 bindreq.dl_conn_mgmt = conn_mgmt;
420 bindreq.dl_xidtest_flg = xidtest_flg;
421
422 ctlbuf.maxlen = 0;
423 ctlbuf.len = sizeof(bindreq);
424 ctlbuf.buf = (caddr_t)&bindreq;
425
426 if (putmsg(fd, &ctlbuf, (struct strbuf*) NULL...
427 fprintf(stderr, "dlbindreq: putmsg: %s", ...
428 return(-1);
429 }
430
431 ctlbuf.maxlen = MAXDLBUFSIZE;
432 ctlbuf.len = 0;
433 ctlbuf.buf = (caddr_t)buf;
434
435 if ((ret = getmsg(fd, &ctlbuf, (struct strbuf...
436 fprintf(stderr, "dlbindreq: getmsg: %s\n"...
437 return(-1);
438 }
439
440 primitive = (union DL_primitives *) ctlbuf.buf;
441 if ( primitive->dl_primitive != DL_BIND_ACK){
442 fprintf(stderr, "dlbindreq: not DL_BIND_A...
443 return(-1);
444 }
445
446 return(0);
447 }
ソースファイル [[sniff.c>source:sniff.c]]
*実行例 [#i0fb3299]
プログラム名の後に引数としてインターフェース名を入力しま...
以下の 例では Sun の FastEthernet カードである hme0 を指...
なお、このプログラムも root ユーザで実行する必要がありま...
setuid(chmod 4755 sniff )してもいいですけど。&br;
# ./sniff hme0
----Ether Header----
src addr : 08:00:20:c6:69:c7
dest addr : 00:13:d3:a9:8f:40
ether type : 0x800
----IP Header----
version : 4
header len : 5 (20 bytes)
tos : 0
total len : 1292
id : 51935
frag offset : 16384
ttl : 60
protocol : 6
checksum : 0x8497
src address : 172.29.73.55
dst address : 172.29.73.3
----TCP Header----
source port : 23
dest port : 1277
seq : 371774688
ack : 3757417225
data offset : 5 (20 bytes)
flags : ACK
window : 50400
check sum : 0x6420
urt_ptr : 0
------DATA-------
NIC に到着したすべての packet を表示します。&br;
内容をみると、telnet のセッションのパケットであることが分...
この例では出ていませんが、データ部に文字列があればそれも-...
あと、言い忘れましたが これは TCP パケット専用です。ICMP ...
全部のヘッダー対応の source 書くぐらいなら tcpdump や sno...
*解説 [#q678dd85]
DLPI の説明をする上で STREAMS (ストリーム)機構 の解説を...
STREAMS 機構とは Solaris をはじめとする SVR4 準拠の syste...
STREAM とは論理的なデータの通り道であり、STREAM 内で 受け...
#ref(http://www.whiteboard.ne.jp/~admin2/pict/stream.gif)
今回の場合上図の「ストリームデバイスドライバ」とは networ...
DLPI(Data Link Provider Interface)とは この network Int...
以上、簡単に DLPI と STREAM について説明させていただきま...
55 union DL_primitives *dlp;
55 行目に DL_primitives という共用体を 宣言しています。pr...
上の STREAMS 機構の説明のところで、STREAM(データの通り道...
|メッセージタイプ|説明|h
|M_DATA| ユーザプロセスとデバイスドライバ間のデータの受...
|M_PROTO |ユーザプロセスとデバイスドライバ間の制御情報の...
|M_PCPROTO | M_PROTO と同じだが、より優先度の高いメッセー...
DLPI で受け渡しされるメッセージは primitive という構造体...
84 if((fd = open (devpath , O_RDWR)) < 0 ){
84 行目で device、つまり network Interface を open します...
92 if(dlattachreq(fd, ppa, buf) < 0){
84 行目で open した STREAM と、物理的な device を結び付け...
317 attachreq.dl_primitive = DL_ATTACH_REQ;
というのが宣言されています。これは上で説明した DLPI primi...
dl_attach_req_t 構造体は まさに STREAM と PPA を attach ...
/usr/include/sys/dlpi.h より
typedef struct {
t_uscalar_t dl_primitive; /* set to...
t_uscalar_t dl_ppa; /* id of ...
} dl_attach_req_t;
ここでさらに strbuf 構造体(STREAM Buffer 構造体?)という...
/usr/include/sys/stropts.h より
struct strbuf {
int maxlen; /* no. of bytes in buffer...
int len; /* no. of bytes returned */
caddr_t buf; /* pointer to data */
};
strbuf 構造体の中の data のポインターとして dl_attach_req...
|>|CENTER:strbuf 構造体|h
|>|CENTER:maxlen(最大buffer長)|
|>|CENTER:len(data長)|
|>|CENTER:dl_attach_req_t 構造体|
||CENTER:DL_ATTACH_REQ|
||CENTER:ppa|
strbuf と dl_attach_req_t 両構造体の各メンバーに値の代入...
324 if (putmsg(fd, &ctlbuf, (struct strbuf*) NULL...
|>|&size(20){putmsg()};|h
|概要| STREAM へのメッセージの送信|
|インクルードファイル |#include <stropts.h>|
|形式| int putmsg(int fildes, const struct strbuf *ctlpt...
|引数 |int filedes : ファイル記述子&br;const struct cl...
|戻り値 |成功時: 0&br;エラー: -1|
putmsg() システムコールでは STREAM に対してデータバッファ...
さて、これで ATTACHの要求の送信は終了しまして、つづいてAT...
#ref(http://www.whiteboard.ne.jp/~admin2/pict/dlpi_sequen...
333 if ((ret = getmsg(fd, &ctlbuf, (struct strbuf...
ここで今度は getmsg() というシステムコールが出てきます。
|>|&size(20){getmsg()};|h
|概要| STREAM からのメッセージの受信|
|インクルードファイル |#include <stropts.h>|
|形式| int getmsg(int fildes, struct strbuf *ctlptr, str...
|引数 |int filedes : ファイル記述子&br;const struct cl...
|戻り値 |成功時: 実数値&br; 0 --> すべてのメッセージの...
getmsg() は putmsg() とは逆に STREAM HEAD を通じてアップ...
338 primitive = (union DL_primitives *) ctlbuf.buf;
339 if ( primitive->dl_primitive != DL_OK_ACK){
340 fprintf(stderr, "dlattachreq: not DL_OK_A...
341 return(-1);
342 }
ctlbuf は「buf」 というメンバーを持ち、「buf」は DLPI pri...
100 if(dlpromisconreq(fd, DL_PROMISC_PHYS, buf) <...
...
108 if(dlbindreq (fd, ETHERTYPE_IP, 0, DL_CLDLS, ...
100 行目の dlpromisconreq() 及び、108 行目の dlbindreq() ...
|dlpromisconreq|DL_PROMISCON_REQ primitive にて promisca...
|dlbindreq |DL_BIND_REQ primitive にて データリンク層の ...
さて、main() のつづきですが、つぎはいままでの処理とはちょ...
120 if(ioctl(fd, I_STR, &strioc) < 0){
121 perror("ioctl: I_STR: DLIOCRAW");
122 exit(1);
123 }
ここで呼んでいる ioctl() システムコールがまた重要な処理に...
|>|&size(20){ioctl()};|h
|概要|STREAM デバイスの制御|
|インクルードファイル |#include <unistd.h>&br;#include <...
|形式| int ioctl(int fildes, int command, /* arg */ ...);|
|引数 |int filedes : ファイル記述子&br;int command: ...
|戻り値 |成功時: 実数値&br;エラー: -1|
STREAMS ioctl() は ioctl() のサプセットで、ストリーム上の...
では、この ioctl にてどのような内容のメッセージが DOWN ST...
struct strioctl {
int ic_cmd; /* コマンド*/
int ic_timout; /*タイムアウト値 */
int ic_len; /* データ長 */
char *ic_dp; /* データへのポインタ */
};
116 〜 119 行目を見ていただければ分かりますが、上記の構造...
116 strioc.ic_cmd = DLIOCRAW;
117 strioc.ic_timout = -1;
118 strioc.ic_len = 0;
119 strioc.ic_dp = NULL;
これは M_DATA タイプのメッセージに対して RAW モード、つま...
RAW モードへの移行がおわったところで、さらに main() の処...
128 if (ioctl(fd, I_FLUSH, FLUSHR) < 0){
ioctl() システムコール(ここで言っているのは STREAMS ioct...
第三引数のオプションは sys/stropts.h に定義してありまして...
sys/stropts.h より抜粋
#define FLUSHR 0x01 /* flush read queue */
queue(キュー) という言葉が初めて出てきましたが、これも ...
ここではその読み取り用の格納庫を明示的に空にしているとい...
さて、ここまでで packet のキャプチャーの準備が整いました...
133 databuf.maxlen = MAXDLBUFSIZE;
134 databuf.len = 0;
135 databuf.buf = (caddr_t)buf;
136
137 while (getmsg(fd, NULL, &databuf, &flags) == ...
138 if (databuf.len > 0)
139 print_packet(databuf.buf, databuf.len);
140 }
「databuf」というのは strbuf 構造体で、54 行目に宣言して...
getmsg はすでにお話しているのでさらっと流しますが、第二引...
STREAM HEAD から受け取った生データは strbuf 構造体 data ...
print_packet() 内で行っている事は 先ほど getmsg() にて受...
ただ違うのは 今回は Ethernet の ヘッダーも入るので、デー...
*最後に[#l186476e]
というわけで非常ーに長々と、かつおおざっぱに解説させてい...
私自身本当に分からないところだらけで(だったら書くなとい...
*参考資料 [#gd0c4185]
このページを書く上で参考にした資料をご紹介いたします。
|参考資料名 |メモ|h
|UNIX カーネルの魔法&br;(プレンティスホール出版)| SVR4...
|UNIX ネットワークプログラミング&br;(トッパン)| まさに...
|詳解TCP/IP&br;(ソフトバンク) | TCP/IP のプロトコル上の...
|man page| 一番身近な情報源&br;dlpi(7P), le(7D), streamio...
|docs.sun.com | リンクしているのは Solaris 8 の hme の ma...
&aname(tsuiki);
*追記 [#b1795512]
**すべての フレームタイプを受信する [#ma102d9d]
先に書きましたように、このプログラムでは IP のpacket しか...
100 if(dlpromisconreq(fd, DL_PROMISC_SAP, buf) < ...
dlpromisconreq() 関数の中で、この第二引数の DL_PROMISC_SA...
/*
* DLPI promiscuous mode definitions
*/
#define DL_PROMISC_PHYS 0x01 /* promiscuous m...
#define DL_PROMISC_SAP 0x02 /* promiscous mo...
#define DL_PROMISC_MULTI 0x03 /* promiscuous m...
これは promiscuous mode(無差別受信モード)をどのレベルで...
名前のイメージ的には DL_PROMISC_PHYS が すべて受信できて ...
「DL_PROMISC_SAP」にセットすることによって ARP や REVARP ...
**さらに追記 [#h2618cba]
DL_PROMISC_PHYS(PHYが レベル)ではローカルホストによって生...
ページ名: