* copy vendor drop to trunk
[lab.git] / Dev / utvpn / utvpn-unix-v101-7101-public / src / Cedar / BridgeUnix.c
1 // SoftEther UT-VPN SourceCode\r
2 // \r
3 // Copyright (C) 2004-2010 SoftEther Corporation.\r
4 // Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
5 // Copyright (C) 2003-2010 Daiyuu Nobori.\r
6 // All Rights Reserved.\r
7 // \r
8 // http://utvpn.tsukuba.ac.jp/\r
9 // \r
10 // This program is free software; you can redistribute it and/or\r
11 // modify it under the terms of the GNU General Public License\r
12 // version 2 as published by the Free Software Foundation.\r
13 // \r
14 // This program is distributed in the hope that it will be useful,\r
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
17 // GNU General Public License for more details.\r
18 // \r
19 // You should have received a copy of the GNU General Public License version 2\r
20 // along with this program; if not, write to the Free Software\r
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
22 // \r
23 // このファイルは GPL バージョン 2 ライセンスで公開されています。\r
24 // 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
25 // することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
26 // を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
27 // 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
28 // \r
29 // この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
30 // ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
31 // および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
32 // ホストされています。\r
33 // 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
34 // および、試験または研究のために利用が行われることを想定して配布\r
35 // しています。\r
36 // SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
37 // あります。\r
38 // 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
39 // の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
40 // いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
41 // ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
42 // に組み込みさせていただきます。\r
43 // \r
44 // GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
45 // 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
46 // \r
47 // 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
48 // (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
49 // ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
50 // 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
51 // ください。\r
52 // \r
53 // お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
54 // セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
55 // UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
56 // 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
57 // および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
58 // 公益保護にご協力いただきますようお願い申し上げます。\r
59 // \r
60 // ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
61 // 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
62 // を保護するための努力を行います。\r
63 // \r
64 // ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
65 // 日本国内の脆弱性情報届出受付公的機関:\r
66 //         独立行政法人 情報処理推進機構\r
67 //         http://www.ipa.go.jp/security/vuln/report/\r
68 // \r
69 // 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
70 // 連絡先: http://www.softether.co.jp/jp/contact/\r
71 \r
72 // -----------------------------------------------\r
73 // [ChangeLog]\r
74 // 2010.05.20\r
75 //  新規リリース by SoftEther\r
76 // -----------------------------------------------\r
77 \r
78 // BridgeUnix.c\r
79 // Ethernet ブリッジプログラム (UNIX 版)\r
80 //#define       BRIDGE_C\r
81 //#define       UNIX_LINUX\r
82 \r
83 #ifdef  BRIDGE_C\r
84 \r
85 #include <stdio.h>\r
86 #include <stdlib.h>\r
87 #include <string.h>\r
88 #include <wchar.h>\r
89 #include <stdarg.h>\r
90 #include <time.h>\r
91 #include <errno.h>\r
92 #include <Mayaqua/Mayaqua.h>\r
93 #include <Cedar/Cedar.h>\r
94 \r
95 #ifdef UNIX_SOLARIS\r
96 #include <sys/sockio.h>\r
97 #endif\r
98 \r
99 #ifdef BRIDGE_PCAP\r
100 #include <pcap.h>\r
101 #endif // BRIDGE_PCAP\r
102 \r
103 #ifdef BRIDGE_BPF\r
104 #include <sys/ioctl.h>\r
105 #include <net/bpf.h>\r
106 #include <net/if_types.h>\r
107 #include <net/if_dl.h>\r
108 #include <ifaddrs.h>\r
109 #endif // BRIDGE_BPF\r
110 \r
111 // 初期化\r
112 void InitEth()\r
113 {\r
114 }\r
115 \r
116 // 解放\r
117 void FreeEth()\r
118 {\r
119 }\r
120 \r
121 // Unix のデバイスの説明文字列の取得がサポートされているかどうか取得\r
122 bool EthIsInterfaceDescriptionSupportedUnix()\r
123 {\r
124         bool ret = false;\r
125         DIRLIST *d = EnumDir("/etc/sysconfig/networking/devices/");\r
126 \r
127         if (d == NULL)\r
128         {\r
129                 return false;\r
130         }\r
131 \r
132         if (d->NumFiles >= 1)\r
133         {\r
134                 ret = true;\r
135         }\r
136 \r
137         FreeDir(d);\r
138 \r
139         return ret;\r
140 }\r
141 \r
142 // Unix のデバイスの説明文字列を取得\r
143 bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size)\r
144 {\r
145         char tmp[MAX_SIZE];\r
146         bool ret = false;\r
147         BUF *b;\r
148         // 引数チェック\r
149         if (name == NULL || str == NULL)\r
150         {\r
151                 return false;\r
152         }\r
153 \r
154         StrCpy(str, size, name);\r
155 \r
156         Format(tmp, sizeof(tmp), "/etc/sysconfig/networking/devices/ifcfg-%s", name);\r
157 \r
158         b = ReadDump(tmp);\r
159         if (b != NULL)\r
160         {\r
161                 char *line = CfgReadNextLine(b);\r
162 \r
163                 if (IsEmptyStr(line) == false)\r
164                 {\r
165                         if (StartWith(line, "#"))\r
166                         {\r
167                                 char tmp[MAX_SIZE];\r
168 \r
169                                 StrCpy(tmp, sizeof(tmp), line + 1);\r
170 \r
171                                 Trim(tmp);\r
172                                 tmp[60] = 0;\r
173 \r
174                                 StrCpy(str, size, tmp);\r
175 \r
176                                 ret = true;\r
177                         }\r
178                 }\r
179 \r
180                 Free(line);\r
181 \r
182                 FreeBuf(b);\r
183         }\r
184 \r
185         return ret;\r
186 }\r
187 \r
188 // Raw ソケットを開く\r
189 int UnixEthOpenRawSocket()\r
190 {\r
191 #ifdef  UNIX_LINUX\r
192         int s;\r
193 \r
194         s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));\r
195         if (s < 0)\r
196         {\r
197                 return INVALID_SOCKET;\r
198         }\r
199         else\r
200         {\r
201                 return s;\r
202         }\r
203 #else   // UNIX_LINUX\r
204         return -1;\r
205 #endif  // UNIX_LINUX\r
206 }\r
207 \r
208 // Ethernet 操作がサポートされているかどうか\r
209 bool IsEthSupported()\r
210 {\r
211         bool ret = false;\r
212 \r
213 #if             defined(UNIX_LINUX)\r
214         ret = IsEthSupportedLinux();\r
215 #elif   defined(UNIX_SOLARIS)\r
216         ret = IsEthSupportedSolaris();\r
217 #elif   defined(BRIDGE_PCAP)\r
218         ret = true;\r
219 #elif   defined(BRIDGE_BPF)\r
220         ret = true;\r
221 #endif\r
222         return ret;\r
223 }\r
224 \r
225 #ifdef  UNIX_LINUX\r
226 bool IsEthSupportedLinux()\r
227 {\r
228         int s;\r
229 \r
230         // Raw ソケットを開いてみる\r
231         s = UnixEthOpenRawSocket();\r
232         if (s == INVALID_SOCKET)\r
233         {\r
234                 // 失敗\r
235                 return false;\r
236         }\r
237 \r
238         // 成功\r
239         closesocket(s);\r
240 \r
241         return true;\r
242 }\r
243 #endif  // UNIX_LINUX\r
244 \r
245 #ifdef  UNIX_SOLARIS\r
246 bool IsEthSupportedSolaris()\r
247 {\r
248         return true;\r
249 }\r
250 #endif  // UNIX_SOLARIS\r
251 \r
252 #ifdef  UNIX_SOLARIS\r
253 // アダプタ一覧を取得 (Solaris)\r
254 TOKEN_LIST *GetEthListSolaris()\r
255 {\r
256         TOKEN_LIST *t;\r
257         int i, s;\r
258         LIST *o;\r
259 \r
260 \r
261         o = NewListFast(CompareStr);\r
262         s = socket(AF_INET, SOCK_DGRAM, 0);\r
263         if (s != INVALID_SOCKET)\r
264         {\r
265                 struct lifnum lifn;\r
266                 lifn.lifn_family = AF_INET;\r
267                 lifn.lifn_flags = 0;\r
268                 if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) >= 0)\r
269                 {\r
270                         struct lifconf lifc;\r
271                         struct lifreq *buf;\r
272                         UINT numifs;\r
273                         UINT bufsize;\r
274                         \r
275                         numifs = lifn.lifn_count;\r
276                         Debug("NumIFs:%d\n",numifs);\r
277                         bufsize = numifs * sizeof(struct lifreq);\r
278                         buf = Malloc(bufsize);\r
279 \r
280                         lifc.lifc_family = AF_INET;\r
281                         lifc.lifc_flags = 0;\r
282                         lifc.lifc_len = bufsize;\r
283                         lifc.lifc_buf = (char*) buf;\r
284                         if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) >= 0)\r
285                         {\r
286                                 for (i = 0; i<numifs; i++)\r
287                                 {\r
288                                         if(StartWith(buf[i].lifr_name, "lo") == false){\r
289                                                 Add(o, CopyStr(buf[i].lifr_name));\r
290                                         }\r
291                                 }\r
292                         }\r
293                         Free(buf);\r
294                 }\r
295                 closesocket(s);\r
296         }\r
297 \r
298         Sort(o);\r
299 \r
300         t = ZeroMalloc(sizeof(TOKEN_LIST));\r
301         t->NumTokens = LIST_NUM(o);\r
302         t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);\r
303 \r
304         for (i = 0;i < LIST_NUM(o);i++)\r
305         {\r
306                 char *name = LIST_DATA(o, i);\r
307                 t->Token[i] = name;\r
308         }\r
309 \r
310         ReleaseList(o);\r
311 \r
312         return t;\r
313 }\r
314 #endif  // UNIX_SOLARIS\r
315 \r
316 #ifdef  UNIX_LINUX\r
317 // アダプタ一覧を取得 (Linux)\r
318 TOKEN_LIST *GetEthListLinux()\r
319 {\r
320         struct ifreq ifr;\r
321         TOKEN_LIST *t;\r
322         UINT i, n;\r
323         int s;\r
324         LIST *o;\r
325         char name[MAX_SIZE];\r
326 \r
327         o = NewListFast(CompareStr);\r
328 \r
329         s = UnixEthOpenRawSocket();\r
330         if (s != INVALID_SOCKET)\r
331         {\r
332                 n = 0;\r
333                 for (i = 0;;i++)\r
334                 {\r
335                         Zero(&ifr, sizeof(ifr));\r
336                         ifr.ifr_ifindex = i;\r
337 \r
338                         if (ioctl(s, SIOCGIFNAME, &ifr) >= 0)\r
339                         {\r
340                                 n = 0;\r
341                                 StrCpy(name, sizeof(name), ifr.ifr_name);\r
342 \r
343                                 Zero(&ifr, sizeof(ifr));\r
344                                 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);\r
345                                 if (ioctl(s, SIOCGIFHWADDR, &ifr) >= 0)\r
346                                 {\r
347                                         UINT type = ifr.ifr_hwaddr.sa_family;\r
348                                         if (type == 1 || type == 2 || type == 6 || type == 800 || type == 801)\r
349                                         {\r
350                                                 if (IsInListStr(o, name) == false)\r
351                                                 {\r
352                                                         if (StartWith(name, "tap_") == false)\r
353                                                         {\r
354                                                                 Add(o, CopyStr(name));\r
355                                                         }\r
356                                                 }\r
357                                         }\r
358                                 }\r
359                         }\r
360                         else\r
361                         {\r
362                                 n++;\r
363                                 if (n >= 64)\r
364                                 {\r
365                                         break;\r
366                                 }\r
367                         }\r
368                 }\r
369                 closesocket(s);\r
370         }\r
371 \r
372         Sort(o);\r
373 \r
374         t = ZeroMalloc(sizeof(TOKEN_LIST));\r
375         t->NumTokens = LIST_NUM(o);\r
376         t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);\r
377 \r
378         for (i = 0;i < LIST_NUM(o);i++)\r
379         {\r
380                 char *name = LIST_DATA(o, i);\r
381                 t->Token[i] = name;\r
382         }\r
383 \r
384         ReleaseList(o);\r
385 \r
386         return t;\r
387 }\r
388 #endif  // UNIX_LINUX\r
389 \r
390 #ifdef BRIDGE_PCAP\r
391 // アダプタ一覧を取得 (Pcap)\r
392 TOKEN_LIST *GetEthListPcap()\r
393 {\r
394         pcap_if_t *alldevs;\r
395         char errbuf[PCAP_ERRBUF_SIZE];\r
396         LIST *o;\r
397         TOKEN_LIST *t;\r
398         int i;\r
399 \r
400         o = NewListFast(CompareStr);\r
401 \r
402         if( pcap_findalldevs(&alldevs,errbuf) != -1)\r
403         {\r
404                 pcap_if_t *dev = alldevs;\r
405                 while(dev != NULL)\r
406                 {\r
407                         pcap_t *p;\r
408                         // デバイスを開いてみないとデバイスの種類が分からない?\r
409                         p = pcap_open_live(dev->name, 0, false, 0, errbuf);\r
410                         if(p != NULL)\r
411                         {\r
412                                 int datalink = pcap_datalink(p);\r
413         //                      Debug("type:%s\n",pcap_datalink_val_to_name(datalink));\r
414                                 pcap_close(p);\r
415                                 if(datalink == DLT_EN10MB){\r
416                                         // イーサネットデバイスのみ列挙する\r
417                                         Add(o, CopyStr(dev->name));\r
418                                 }\r
419                         }\r
420                         dev = dev->next;\r
421                 }\r
422                 pcap_freealldevs(alldevs);\r
423         }\r
424         \r
425         Sort(o);\r
426         t = ZeroMalloc(sizeof(TOKEN_LIST));\r
427         t->NumTokens = LIST_NUM(o);\r
428         t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);\r
429         for (i = 0;i < LIST_NUM(o);i++)\r
430         {\r
431                 t->Token[i] = LIST_DATA(o, i);\r
432         }\r
433         ReleaseList(o);\r
434         return t;\r
435 }\r
436 #endif // BRIDGE_PCAP\r
437 \r
438 #ifdef BRIDGE_BPF\r
439 // アダプタ一覧を取得 (BPF)\r
440 TOKEN_LIST *GetEthListBpf()\r
441 {\r
442         struct ifaddrs *ifadrs;\r
443         struct sockaddr_dl *sockadr;\r
444         LIST *o;\r
445         TOKEN_LIST *t;\r
446         int i;\r
447 \r
448         o = NewListFast(CompareStr);\r
449 \r
450         // ネットワークデバイスの一覧を取得\r
451         if(getifaddrs( &ifadrs ) == 0)\r
452         {\r
453                 struct ifaddrs *ifadr = ifadrs;\r
454                 while(ifadr)\r
455                 {\r
456                         sockadr = (struct sockaddr_dl*)ifadr->ifa_addr;\r
457                         if(sockadr->sdl_family == AF_LINK && sockadr->sdl_type == IFT_ETHER)\r
458                         {\r
459                                 // Ethernet デバイスか?\r
460                                 if(!IsInListStr(o,ifadr->ifa_name))\r
461                                 {\r
462                                         // 既存でなければ追加(複数のMACアドレスを持つインターフェースへの対策)\r
463                                         Add(o, CopyStr(ifadr->ifa_name));\r
464                                 }\r
465                         }\r
466                         ifadr = ifadr -> ifa_next;\r
467                 }\r
468                 freeifaddrs(ifadrs);\r
469         }\r
470 \r
471         Sort(o);\r
472         t = ZeroMalloc(sizeof(TOKEN_LIST));\r
473         t->NumTokens = LIST_NUM(o);\r
474         t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);\r
475         for (i = 0;i < LIST_NUM(o);i++)\r
476         {\r
477                 t->Token[i] = LIST_DATA(o, i);\r
478         }\r
479         ReleaseList(o);\r
480         return t;\r
481 }\r
482 #endif // BRIDGE_BPF\r
483 \r
484 // アダプタ一覧を取得\r
485 TOKEN_LIST *GetEthList()\r
486 {\r
487         TOKEN_LIST *t = NULL;\r
488 \r
489 #if     defined(UNIX_LINUX)\r
490         t = GetEthListLinux();\r
491 #elif   defined(UNIX_SOLARIS)\r
492         t = GetEthListSolaris();\r
493 #elif   defined(BRIDGE_PCAP)\r
494         t = GetEthListPcap();\r
495 #elif   defined(BRIDGE_BPF)\r
496         t = GetEthListBpf();\r
497 #endif\r
498 \r
499         return t;\r
500 }\r
501 \r
502 #ifdef  UNIX_LINUX\r
503 // アダプタを開く (Linux)\r
504 ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)\r
505 {\r
506         ETH *e;\r
507         struct ifreq ifr;\r
508         struct sockaddr_ll addr;\r
509         int s;\r
510         int index;\r
511         CANCEL *c;\r
512         // 引数チェック\r
513         if (name == NULL)\r
514         {\r
515                 return NULL;\r
516         }\r
517 \r
518         if (tapmode)\r
519         {\r
520 #ifndef NO_VLAN\r
521                 // tap モードの場合\r
522                 VLAN *v = NewTap(name, tapaddr);\r
523                 if (v == NULL)\r
524                 {\r
525                         return NULL;\r
526                 }\r
527 \r
528                 e = ZeroMalloc(sizeof(ETH));\r
529                 e->Name = CopyStr(name);\r
530                 e->Title = CopyStr(name);\r
531                 e->Cancel = VLanGetCancel(v);\r
532                 e->IfIndex = 0;\r
533                 e->Socket = INVALID_SOCKET;\r
534                 e->Tap = v;\r
535 \r
536                 return e;\r
537 #else   // NO_VLAN\r
538                 return NULL;\r
539 #endif  // NO_VLAN\r
540         }\r
541 \r
542         s = UnixEthOpenRawSocket();\r
543         if (s == INVALID_SOCKET)\r
544         {\r
545                 return NULL;\r
546         }\r
547 \r
548         Zero(&ifr, sizeof(ifr));\r
549         StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);\r
550 \r
551         if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)\r
552         {\r
553                 closesocket(s);\r
554                 return NULL;\r
555         }\r
556 \r
557         index = ifr.ifr_ifindex;\r
558 \r
559         Zero(&addr, sizeof(addr));\r
560         addr.sll_family = PF_PACKET;\r
561         addr.sll_protocol = htons(ETH_P_ALL);\r
562         addr.sll_ifindex = index;\r
563 \r
564         if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)\r
565         {\r
566                 closesocket(s);\r
567                 return NULL;\r
568         }\r
569 \r
570         if (local == false)\r
571         {\r
572                 // プロミスキャスモードに設定する\r
573                 Zero(&ifr, sizeof(ifr));\r
574                 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);\r
575                 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)\r
576                 {\r
577                         // 失敗\r
578                         closesocket(s);\r
579                         return NULL;\r
580                 }\r
581 \r
582                 ifr.ifr_flags |= IFF_PROMISC;\r
583 \r
584                 if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)\r
585                 {\r
586                         // 失敗\r
587                         closesocket(s);\r
588                         return NULL;\r
589                 }\r
590         }\r
591 \r
592         e = ZeroMalloc(sizeof(ETH));\r
593         e->Name = CopyStr(name);\r
594         e->Title = CopyStr(name);\r
595         e->IfIndex = index;\r
596         e->Socket = s;\r
597 \r
598         c = NewCancel();\r
599         UnixDeletePipe(c->pipe_read, c->pipe_write);\r
600         c->pipe_read = c->pipe_write = -1;\r
601 \r
602         UnixSetSocketNonBlockingMode(s, true);\r
603 \r
604         c->SpecialFlag = true;\r
605         c->pipe_read = s;\r
606 \r
607         e->Cancel = c;\r
608 \r
609         // MTU の取得\r
610         e->InitialMtu = EthGetMtu(e);\r
611 \r
612         return e;\r
613 }\r
614 #endif  // UNIX_LINUX\r
615 \r
616 // MTU の値を取得\r
617 UINT EthGetMtu(ETH *e)\r
618 {\r
619 #if     defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
620         UINT ret = 0;\r
621 #ifdef  UNIX_SOLARIS\r
622         struct lifreq ifr;\r
623 #else   // UNIX_SOLARIS\r
624         struct ifreq ifr;\r
625 #endif  // UNIX_SOLARIS\r
626         int s;\r
627         // 引数チェック\r
628         if (e == NULL || e->Tap != NULL)\r
629         {\r
630                 return 0;\r
631         }\r
632 \r
633         if (e->CurrentMtu != 0)\r
634         {\r
635                 return e->CurrentMtu;\r
636         }\r
637 \r
638 #if     defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
639         s = e->SocketBsdIf;\r
640 #else   // defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
641         s = e->Socket;\r
642 #endif  // defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
643 \r
644         Zero(&ifr, sizeof(ifr));\r
645 \r
646 #ifdef  UNIX_SOLARIS\r
647         StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);\r
648 #else   // UNIX_SOLARIS\r
649         StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);\r
650 #endif  // UNIX_SOLARIS\r
651 \r
652 #ifdef  UNIX_SOLARIS\r
653         if (ioctl(s, SIOCGLIFMTU, &ifr) < 0)\r
654         {\r
655                 // 失敗\r
656                 return 0;\r
657         }\r
658 #else   // UNIX_SOLARIS\r
659         if (ioctl(s, SIOCGIFMTU, &ifr) < 0)\r
660         {\r
661                 // 失敗\r
662                 return 0;\r
663         }\r
664 #endif  // UNIX_SOLARIS\r
665 \r
666 #ifdef  UNIX_SOLARIS\r
667         ret = ifr.lifr_mtu + 14;\r
668 #else   // UNIX_SOLARIS\r
669         ret = ifr.ifr_mtu + 14;\r
670 #endif  // UNIX_SOLARIS\r
671 \r
672         e->CurrentMtu = ret;\r
673 \r
674         Debug("%s: GetMtu: %u\n", e->Name, ret);\r
675 \r
676         return ret;\r
677 #else   // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
678         return 0;\r
679 #endif  // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
680 }\r
681 \r
682 // MTU の値を設定\r
683 bool EthSetMtu(ETH *e, UINT mtu)\r
684 {\r
685 #if     defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
686         UINT ret = 0;\r
687 #ifdef  UNIX_SOLARIS\r
688         struct lifreq ifr;\r
689 #else   // UNIX_SOLARIS\r
690         struct ifreq ifr;\r
691 #endif  // UNIX_SOLARIS\r
692         int s;\r
693         // 引数チェック\r
694         if (e == NULL || e->Tap != NULL || (mtu > 1 && mtu < 1514))\r
695         {\r
696                 return false;\r
697         }\r
698         if (mtu == 0 && e->InitialMtu == 0)\r
699         {\r
700                 return false;\r
701         }\r
702 \r
703         if (mtu == 0)\r
704         {\r
705                 // mtu == 0 の場合は MTU の値を元に戻す\r
706                 mtu = e->InitialMtu;\r
707         }\r
708 \r
709 #if     defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
710         s = e->SocketBsdIf;\r
711 #else   // defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
712         s = e->Socket;\r
713 #endif  // defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
714 \r
715         if (e->CurrentMtu == mtu)\r
716         {\r
717                 // 変更の必要なし\r
718                 return true;\r
719         }\r
720 \r
721         Zero(&ifr, sizeof(ifr));\r
722 \r
723 #ifdef  UNIX_SOLARIS\r
724         StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);\r
725         ifr.lifr_mtu = mtu - 14;\r
726 #else   // UNIX_SOLARIS\r
727         StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);\r
728         ifr.ifr_mtu = mtu - 14;\r
729 #endif  // UNIX_SOLARIS\r
730 \r
731 #ifdef  UNIX_SOLARIS\r
732         if (ioctl(s, SIOCSLIFMTU, &ifr) < 0)\r
733         {\r
734                 // 失敗\r
735                 return false;\r
736         }\r
737 #else   // UNIX_SOLARIS\r
738         if (ioctl(s, SIOCSIFMTU, &ifr) < 0)\r
739         {\r
740                 // 失敗\r
741                 return false;\r
742         }\r
743 #endif  // UNIX_SOLARIS\r
744 \r
745         e->CurrentMtu = mtu;\r
746 \r
747         Debug("%s: SetMtu: %u\n", e->Name, mtu);\r
748 \r
749         return true;\r
750 #else   // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
751         return false;\r
752 #endif  // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
753 }\r
754 \r
755 // MTU の値の変更がサポートされているかどうか取得\r
756 bool EthIsChangeMtuSupported(ETH *e)\r
757 {\r
758 #if     defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
759         // 引数チェック\r
760         if (e == NULL || e->Tap != NULL)\r
761         {\r
762                 return false;\r
763         }\r
764 \r
765         return true;\r
766 #else   // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
767         return false;\r
768 #endif  // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)\r
769 }\r
770 \r
771 #ifdef  UNIX_SOLARIS\r
772 // アダプタを開く (Solaris)\r
773 ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr)\r
774 {\r
775         char devname[MAX_SIZE];\r
776         UINT devid;\r
777         int fd;\r
778         ETH *e;\r
779         CANCEL *c;\r
780         struct strioctl sioc;\r
781 \r
782         // 引数チェック\r
783         if (name == NULL || tapmode != false)\r
784         {\r
785                 return NULL;\r
786         }\r
787 \r
788         // デバイス名を解析\r
789         if (ParseUnixEthDeviceName(devname, sizeof(devname), &devid, name) == false)\r
790         {\r
791                 return NULL;\r
792         }\r
793 \r
794         // デバイスを開く\r
795         fd = open(devname, O_RDWR);\r
796         if (fd == -1)\r
797         {\r
798                 // 失敗\r
799                 return NULL;\r
800         }\r
801 \r
802         // デバイスにアタッチする\r
803         if (DlipAttatchRequest(fd, devid) == false)\r
804         {\r
805                 // 失敗\r
806                 close(fd);\r
807                 return NULL;\r
808         }\r
809 \r
810         // 確認\r
811         if (DlipReceiveAck(fd) == false)\r
812         {\r
813                 // 失敗\r
814                 close(fd);\r
815                 return NULL;\r
816         }\r
817 \r
818         // SAPにバインドする\r
819         if (DlipBindRequest(fd) == false)\r
820         {\r
821                 // 失敗\r
822                 close(fd);\r
823                 return NULL;\r
824         }\r
825 \r
826         // 確認\r
827         if (DlipReceiveAck(fd) == false)\r
828         {\r
829                 // 失敗\r
830                 close(fd);\r
831                 return NULL;\r
832         }\r
833 \r
834         // SAPに関わらず受信するモードにセットする\r
835         if (DlipPromiscuous(fd, DL_PROMISC_SAP) == false)\r
836         {\r
837                 // 失敗\r
838                 close(fd);\r
839                 return NULL;\r
840         }\r
841 \r
842         // 確認\r
843         if (DlipReceiveAck(fd) == false)\r
844         {\r
845                 // 失敗\r
846                 close(fd);\r
847                 return NULL;\r
848         }\r
849 \r
850         // 自分の送信するパケットも受信するモードにセットする\r
851         if (DlipPromiscuous(fd, DL_PROMISC_PHYS) == false)\r
852         {\r
853                 // 失敗\r
854                 close(fd);\r
855                 return NULL;\r
856         }\r
857 \r
858         // 確認\r
859         if (DlipReceiveAck(fd) == false)\r
860         {\r
861                 // 失敗\r
862                 close(fd);\r
863                 return NULL;\r
864         }\r
865 \r
866         // Raw モードに設定\r
867         sioc.ic_cmd = DLIOCRAW;\r
868         sioc.ic_timout = -1;\r
869         sioc.ic_len = 0;\r
870         sioc.ic_dp = NULL;\r
871         if (ioctl(fd, I_STR, &sioc) < 0)\r
872         {\r
873                 // 失敗\r
874                 close(fd);\r
875                 return NULL;\r
876         }\r
877 \r
878         if (ioctl(fd, I_FLUSH, FLUSHR) < 0)\r
879         {\r
880                 // 失敗\r
881                 close(fd);\r
882                 return NULL;\r
883         }\r
884 \r
885         e = ZeroMalloc(sizeof(ETH));\r
886         e->Name = CopyStr(name);\r
887         e->Title = CopyStr(name);\r
888 \r
889         c = NewCancel();\r
890         UnixDeletePipe(c->pipe_read, c->pipe_write);\r
891         c->pipe_read = c->pipe_write = -1;\r
892 \r
893         c->SpecialFlag = true;\r
894         c->pipe_read = fd;\r
895 \r
896         e->Cancel = c;\r
897 \r
898         e->IfIndex = -1;\r
899         e->Socket = fd;\r
900 \r
901         UnixSetSocketNonBlockingMode(fd, true);\r
902 \r
903         // 操作用 I/F の取得\r
904         e->SocketBsdIf = socket(AF_INET, SOCK_DGRAM, 0);\r
905 \r
906         // MTU の取得\r
907         e->InitialMtu = EthGetMtu(e);\r
908 \r
909         return e;\r
910 }\r
911 \r
912 // プロミスキャスモードにセットする\r
913 bool DlipPromiscuous(int fd, UINT level)\r
914 {\r
915         dl_promiscon_req_t req;\r
916         struct strbuf ctl;\r
917         int flags;\r
918         // 引数チェック\r
919         if (fd == -1)\r
920         {\r
921                 return false;\r
922         }\r
923 \r
924         Zero(&req, sizeof(req));\r
925         req.dl_primitive = DL_PROMISCON_REQ;\r
926         req.dl_level = level;\r
927 \r
928         Zero(&ctl, sizeof(ctl));\r
929         ctl.maxlen = 0;\r
930         ctl.len = sizeof(req);\r
931         ctl.buf = (char *)&req;\r
932 \r
933         flags = 0;\r
934 \r
935         if (putmsg(fd, &ctl, NULL, flags) < 0)\r
936         {\r
937                 return false;\r
938         }\r
939 \r
940         return true;\r
941 }\r
942 \r
943 // SAPにバインドする\r
944 bool DlipBindRequest(int fd)\r
945 {\r
946         dl_bind_req_t   req;\r
947         struct strbuf ctl;\r
948 \r
949         if (fd == -1)\r
950         {\r
951                 return false;\r
952         }\r
953 \r
954         Zero(&req, sizeof(req));\r
955         req.dl_primitive = DL_BIND_REQ;\r
956         req.dl_service_mode = DL_CLDLS;\r
957         req.dl_sap = 0;\r
958 \r
959         Zero(&ctl, sizeof(ctl));\r
960         ctl.maxlen = 0;\r
961         ctl.len = sizeof(req);\r
962         ctl.buf = (char *)&req;\r
963 \r
964         if (putmsg(fd, &ctl, NULL, 0) < 0)\r
965         {\r
966                 return false;\r
967         }\r
968         return true;\r
969 }\r
970 \r
971 // デバイスにアタッチする\r
972 bool DlipAttatchRequest(int fd, UINT devid)\r
973 {\r
974         dl_attach_req_t req;\r
975         struct strbuf ctl;\r
976         int flags;\r
977         // 引数チェック\r
978         if (fd == -1)\r
979         {\r
980                 return false;\r
981         }\r
982 \r
983         Zero(&req, sizeof(req));\r
984         req.dl_primitive = DL_ATTACH_REQ;\r
985         req.dl_ppa = devid;\r
986 \r
987         Zero(&ctl, sizeof(ctl));\r
988         ctl.maxlen = 0;\r
989         ctl.len = sizeof(req);\r
990         ctl.buf = (char *)&req;\r
991 \r
992         flags = 0;\r
993 \r
994         if (putmsg(fd, &ctl, NULL, flags) < 0)\r
995         {\r
996                 return false;\r
997         }\r
998 \r
999         return true;\r
1000 }\r
1001 \r
1002 // 確認応答を受信する\r
1003 bool DlipReceiveAck(int fd)\r
1004 {\r
1005         union DL_primitives *dlp;\r
1006         struct strbuf ctl;\r
1007         int flags = 0;\r
1008         char *buf;\r
1009         // 引数チェック\r
1010         if (fd == -1)\r
1011         {\r
1012                 return false;\r
1013         }\r
1014 \r
1015         buf = MallocFast(SOLARIS_MAXDLBUF);\r
1016 \r
1017         Zero(&ctl, sizeof(ctl));\r
1018         ctl.maxlen = SOLARIS_MAXDLBUF;\r
1019         ctl.len = 0;\r
1020         ctl.buf = buf;\r
1021 \r
1022         if (getmsg(fd, &ctl, NULL, &flags) < 0)\r
1023         {\r
1024                 return false;\r
1025         }\r
1026 \r
1027         dlp = (union DL_primitives *)ctl.buf;\r
1028         if (dlp->dl_primitive != (UINT)DL_OK_ACK && dlp->dl_primitive != (UINT)DL_BIND_ACK)\r
1029         {\r
1030                 Free(buf);\r
1031                 return false;\r
1032         }\r
1033 \r
1034         Free(buf);\r
1035 \r
1036         return true;\r
1037 }\r
1038 \r
1039 #endif  // UNIX_SOLARIS\r
1040 \r
1041 // UNIX のデバイス名文字列をデバイス名と番号に分ける\r
1042 bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, UINT *dst_devid, char *src_name)\r
1043 {\r
1044         UINT len, i, j;\r
1045 \r
1046         // 引数チェック\r
1047         if (dst_devname == NULL || dst_devid == NULL || src_name == NULL)\r
1048         {\r
1049                 return false;\r
1050         }\r
1051 \r
1052         len = strlen(src_name);\r
1053         // 文字列長チェック\r
1054         if(len == 0)\r
1055         {\r
1056                 return false;\r
1057         }\r
1058 \r
1059         for (i = len-1; i+1 != 0; i--)\r
1060         {\r
1061                 // 末尾からたどって最初に数字でない文字を検出\r
1062                 if (src_name[i] < '0' || '9' < src_name[i])\r
1063                 {\r
1064                         // 最後の文字が数字でなければエラー\r
1065                         if(src_name[i+1]==0)\r
1066                         {\r
1067                                 return false;\r
1068                         }\r
1069                         *dst_devid = ToInt(src_name + i + 1);\r
1070                         StrCpy(dst_devname, dst_devname_size, "/dev/");\r
1071                         for (j = 0; j<i+1 && j<dst_devname_size-6; j++)\r
1072                         {\r
1073                                 dst_devname[j+5] = src_name[j];\r
1074                         }\r
1075                         dst_devname[j+5]=0;\r
1076                         return true;\r
1077                 }\r
1078         }\r
1079         // 全て数字ならエラー\r
1080         return false;\r
1081 }\r
1082 \r
1083 #if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP)\r
1084 // キャプチャしたパケットデータ構造体の初期化\r
1085 struct CAPTUREBLOCK *NewCaptureBlock(UCHAR *data, UINT size){\r
1086         struct CAPTUREBLOCK *block = Malloc(sizeof(struct CAPTUREBLOCK));\r
1087         block->Buf = data;\r
1088         block->Size = size;\r
1089         return block;\r
1090 }\r
1091 \r
1092 // キャプチャしたパケットデータ構造体の開放\r
1093 void FreeCaptureBlock(struct CAPTUREBLOCK *block){\r
1094         Free(block);\r
1095 }\r
1096 #endif // BRIDGE_BPF || BRIDGE_PCAP\r
1097 \r
1098 #ifdef  BRIDGE_PCAP\r
1099 // パケット到着のコールバック関数\r
1100 void PcapHandler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)\r
1101 {\r
1102         ETH *e = (ETH*) user;\r
1103         struct CAPTUREBLOCK *block;\r
1104         UCHAR *data;\r
1105         \r
1106         data = Malloc(h->caplen);\r
1107         Copy(data, bytes, h->caplen);\r
1108         block = NewCaptureBlock(data, h->caplen);\r
1109         LockQueue(e->Queue);\r
1110         // キューのサイズが限界を超えたらパケットを破棄する。\r
1111         if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE){\r
1112                 InsertQueue(e->Queue, block);\r
1113                 e->QueueSize += h->caplen;\r
1114         }\r
1115         UnlockQueue(e->Queue);\r
1116         Cancel(e->Cancel);\r
1117         return;\r
1118 }\r
1119 \r
1120 \r
1121 // Pcap でのパケットキャプチャの中継用スレッド\r
1122 void PcapThread(THREAD *thread, void *param)\r
1123 {\r
1124         ETH *e = (ETH*)param;\r
1125         pcap_t *p = e->Pcap;\r
1126         int ret;\r
1127 \r
1128         // 初期化完了を通知\r
1129         NoticeThreadInit(thread);\r
1130 \r
1131         // 帰り値 -1:エラー -2:外部からの終了\r
1132         ret = pcap_loop(p, -1, PcapHandler, (u_char*) e);\r
1133         if(ret == -1){\r
1134                 e->Socket = INVALID_SOCKET;\r
1135                 pcap_perror(p, "capture");\r
1136         }\r
1137         return;\r
1138 }\r
1139 \r
1140 \r
1141 // アダプタを開く (Pcap)\r
1142 ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr)\r
1143 {\r
1144         char errbuf[PCAP_ERRBUF_SIZE];\r
1145         ETH *e;\r
1146         pcap_t *p;\r
1147         CANCEL *c;\r
1148 \r
1149         // 引数チェック\r
1150         if (name == NULL || tapmode != false)\r
1151         {\r
1152                 return NULL;\r
1153         }\r
1154         \r
1155         // エラーメッセージバッファの初期化\r
1156         errbuf[0] = 0;\r
1157 \r
1158         // キャプチャデバイスを開く\r
1159         p = pcap_open_live(name, 65535, (local == false), 1, errbuf);\r
1160         if(p==NULL)\r
1161         {\r
1162                 return NULL;\r
1163         }\r
1164 \r
1165         // ノンブロックモードに設定\r
1166         // BSD系OSでは、BPFのselectが正常に動作しないのでブロックさせないとビジーループになる\r
1167         /*\r
1168         if(pcap_setnonblock(p, true, errbuf) == -1)\r
1169         {\r
1170                 Debug("pcap_setnonblock:%s\n",errbuf);\r
1171                 pcap_close(p);\r
1172                 return NULL;\r
1173         }\r
1174         */\r
1175         \r
1176         e = ZeroMalloc(sizeof(ETH));\r
1177         e->Name = CopyStr(name);\r
1178         e->Title = CopyStr(name);\r
1179         e->Queue = NewQueue();\r
1180         e->QueueSize = 0;\r
1181         e->Cancel = NewCancel();\r
1182         e->IfIndex = -1;\r
1183         e->Socket = pcap_get_selectable_fd(p);\r
1184         e->Pcap = p;\r
1185         \r
1186         e->CaptureThread = NewThread(PcapThread, e);\r
1187         WaitThreadInit(e->CaptureThread);\r
1188 \r
1189         return e;\r
1190 }\r
1191 #endif // BRIDGE_PCAP\r
1192 \r
1193 #ifdef BRIDGE_BPF\r
1194 #ifdef BRIDGE_BPF_THREAD\r
1195 // BPF でのパケットキャプチャの中継用スレッド\r
1196 void BpfThread(THREAD *thread, void *param)\r
1197 {\r
1198         ETH *e = (ETH*)param;\r
1199         int fd = e->Socket;\r
1200         int len;\r
1201         int rest;       // バッファ中の残りバイト数\r
1202         UCHAR *next;    //バッファ中の次のパケットの先頭\r
1203         struct CAPTUREBLOCK *block;     // キューに追加するデータ\r
1204         UCHAR *data;\r
1205         struct bpf_hdr *hdr;\r
1206 \r
1207         // バッファを確保\r
1208         UCHAR *buf = Malloc(e->BufSize);\r
1209         \r
1210         // 初期化完了を通知\r
1211         NoticeThreadInit(thread);\r
1212 \r
1213         while(1){\r
1214                 // ループの脱出判定\r
1215                 if(e->Socket == INVALID_SOCKET){\r
1216                         break;\r
1217                 }\r
1218                 \r
1219                 rest = read(fd, buf, e->BufSize);\r
1220                 if(rest < 0 && errno != EAGAIN){\r
1221                         // エラー\r
1222                         close(fd);\r
1223                         e->Socket = INVALID_SOCKET;\r
1224                         Free(buf);\r
1225                         Cancel(e->Cancel);\r
1226                         return;\r
1227                 }\r
1228                 next = buf;\r
1229                 LockQueue(e->Queue);\r
1230                 while(rest>0){\r
1231                         // パケットの切り出し\r
1232                         hdr = (struct bpf_hdr*)next;\r
1233 \r
1234                         // Queue中のパケットサイズが限界を超えたらパケットを破棄する\r
1235                         if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE){\r
1236                                 data = Malloc(hdr->bh_caplen);\r
1237                                 Copy(data, next+(hdr->bh_hdrlen), hdr->bh_caplen);\r
1238                                 block = NewCaptureBlock(data, hdr->bh_caplen);\r
1239                                 InsertQueue(e->Queue, block);\r
1240                                 e->QueueSize += hdr->bh_caplen;\r
1241                         }\r
1242 \r
1243                         // 次のパケットの頭出し\r
1244                         rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);\r
1245                         next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);\r
1246                 }\r
1247                 UnlockQueue(e->Queue);\r
1248                 Cancel(e->Cancel);\r
1249         }\r
1250         Free(buf);\r
1251         Cancel(e->Cancel);\r
1252         return;\r
1253 }\r
1254 #endif // BRIDGE_BPF_THREAD\r
1255 \r
1256 // アダプタを開く (BPF)\r
1257 ETH *OpenEthBpf(char *name, bool local, bool tapmode, char *tapaddr)\r
1258 {\r
1259         ETH *e;\r
1260         CANCEL *c;\r
1261         char devname[MAX_SIZE];\r
1262         int n = 0;\r
1263         int fd;\r
1264         int ret;\r
1265         UINT bufsize;\r
1266         struct ifreq ifr;\r
1267         struct timeval to;\r
1268         \r
1269         // 未使用の bpf デバイスを探して開く\r
1270         do{\r
1271                 Format(devname, sizeof(devname), "/dev/bpf%d", n++);\r
1272                 fd = open (devname, O_RDWR);\r
1273                 if(fd<0){\r
1274                         perror("open");\r
1275                 }\r
1276         }while(fd < 0 && errno == EBUSY);\r
1277         \r
1278         // 開くことが出来るbpfデバイスが無ければエラー\r
1279         if(fd < 0){\r
1280                 Debug("BPF: No minor number are free.\n");\r
1281                 return NULL;\r
1282         }\r
1283         \r
1284         // バッファサイズを拡大\r
1285         n = 524288; // なんとなく(libpcapでは32768だった)\r
1286         while(true){\r
1287                 // バッファサイズを指定\r
1288                 ioctl(fd, BIOCSBLEN, &n);\r
1289 \r
1290                 // ネットワークをバインド\r
1291                 StrCpy(ifr.ifr_name, IFNAMSIZ, name);\r
1292                 ret = ioctl(fd, BIOCSETIF, &ifr);\r
1293                 if(ret < 0){\r
1294                         if(ret == ENOBUFS && n>1500){\r
1295                                 // バッファサイズが不適切\r
1296                                 // サイズを半分にしてリトライ\r
1297                                 // バッファサイズ1500バイト以下でエラーになるのは何かおかしい\r
1298                                 n /= 2;\r
1299                                 continue;\r
1300                         }\r
1301                         Debug("bpf: binding network failed.\n");\r
1302                         close(fd);\r
1303                         return NULL;\r
1304                 }else{\r
1305                         break;\r
1306                 }\r
1307         }\r
1308         bufsize = n;\r
1309 \r
1310         // プロミスキャスモードに設定\r
1311         if(local == false){\r
1312                 if (ioctl(fd, BIOCPROMISC, NULL) < 0){\r
1313                         printf("bpf: promisc mode failed.\n");\r
1314                         close(fd);\r
1315                         return NULL;\r
1316                 }\r
1317         }\r
1318 \r
1319         \r
1320         // 即時モードに設定(パケットを受信するとタイムアウトを待たず、すぐにreadがreturnする)\r
1321         n = 1;\r
1322         if (ioctl(fd, BIOCIMMEDIATE, &n) < 0){\r
1323                 Debug("BPF: non-block mode failed.\n");\r
1324                 close(fd);\r
1325                 return NULL;\r
1326         }\r
1327 \r
1328         // 自分が送信するパケットも受信する\r
1329         n = 1;\r
1330         if (ioctl(fd, BIOCGSEESENT, &n) < 0){\r
1331                 Debug("BPF: see sent mode failed.\n");\r
1332                 close(fd);\r
1333                 return NULL;\r
1334         }\r
1335 \r
1336 \r
1337         // ヘッダ完全モード(送信するパケットのヘッダも自分で生成する)\r
1338         n = 1;\r
1339         if (ioctl(fd, BIOCSHDRCMPLT, &n) < 0){\r
1340                 Debug("BPF: Header complete mode failed.\n");\r
1341                 close(fd);\r
1342                 return NULL;\r
1343         }\r
1344         \r
1345         // read のタイムアウト時間を設定(1秒)\r
1346         to.tv_sec = 1;\r
1347         to.tv_usec = 0;\r
1348         if (ioctl(fd, BIOCSRTIMEOUT, &to) < 0){\r
1349                 Debug("BPF: Read timeout setting failed.\n");\r
1350                 close(fd);\r
1351                 return NULL;\r
1352         }\r
1353         \r
1354         e = ZeroMalloc(sizeof(ETH));\r
1355         e->Name = CopyStr(name);\r
1356         e->Title = CopyStr(name);\r
1357         e->IfIndex = -1;\r
1358         e->Socket = fd;\r
1359         e->BufSize = bufsize;\r
1360 \r
1361 #ifdef BRIDGE_BPF_THREAD\r
1362         e->Queue = NewQueue();\r
1363         e->QueueSize = 0;\r
1364         e->Cancel = NewCancel();\r
1365 \r
1366         // キャプチャ用スレッドの開始\r
1367         e->CaptureThread = NewThread(BpfThread, e);\r
1368         WaitThreadInit(e->CaptureThread);\r
1369 \r
1370 #else // BRIDGE_BPF_THREAD\r
1371         c = NewCancel();\r
1372         UnixDeletePipe(c->pipe_read, c->pipe_write);\r
1373         c->pipe_read = c->pipe_write = -1;\r
1374         c->SpecialFlag = true;\r
1375         c->pipe_read = fd;\r
1376         e->Cancel = c;\r
1377         e->Buffer = Malloc(bufsize);\r
1378         e->Next = e->Buffer;\r
1379         e->Rest = 0;\r
1380 \r
1381         // ノンブロッキングモードに設定\r
1382         UnixSetSocketNonBlockingMode(fd, true);\r
1383 #endif // BRIDGE_BPF_THREAD\r
1384 \r
1385         // FreeBSD 用インターフェイス操作用ソケットを作成\r
1386         e->SocketBsdIf = socket(AF_LOCAL, SOCK_DGRAM, 0);\r
1387 \r
1388         // MTU の取得\r
1389         e->InitialMtu = EthGetMtu(e);\r
1390 \r
1391         return e;\r
1392 }\r
1393 #endif // BRIDGE_BPF\r
1394 \r
1395 // アダプタを開く\r
1396 ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)\r
1397 {\r
1398         ETH *ret = NULL;\r
1399 \r
1400 #if             defined(UNIX_LINUX)\r
1401         ret = OpenEthLinux(name, local, tapmode, tapaddr);\r
1402 #elif   defined(UNIX_SOLARIS)\r
1403         ret = OpenEthSolaris(name, local, tapmode, tapaddr);\r
1404 #elif   defined(BRIDGE_PCAP)\r
1405         ret = OpenEthPcap(name, local, tapmode, tapaddr);\r
1406 #elif   defined(BRIDGE_BPF)\r
1407         ret = OpenEthBpf(name, local, tapmode, tapaddr);\r
1408 #endif\r
1409 \r
1410         return ret;\r
1411 }\r
1412 \r
1413 typedef struct UNIXTHREAD\r
1414 {\r
1415         pthread_t thread;\r
1416         bool finished;\r
1417 } UNIXTHREAD;\r
1418 \r
1419 // アダプタを閉じる\r
1420 void CloseEth(ETH *e)\r
1421 {\r
1422         // 引数チェック\r
1423         if (e == NULL)\r
1424         {\r
1425                 return;\r
1426         }\r
1427 \r
1428         if (e->Tap != NULL)\r
1429         {\r
1430 #ifndef NO_VLAN\r
1431                 FreeTap(e->Tap);\r
1432 #endif  // NO_VLAN\r
1433         }\r
1434 \r
1435 #ifdef BRIDGE_PCAP\r
1436         {\r
1437                 struct CAPTUREBLOCK *block;\r
1438                 pcap_breakloop(e->Pcap);\r
1439                 WaitThread(e->CaptureThread, INFINITE);\r
1440                 ReleaseThread(e->CaptureThread);\r
1441                 pcap_close(e->Pcap);\r
1442                 while (block = GetNext(e->Queue)){\r
1443                         Free(block->Buf);\r
1444                         FreeCaptureBlock(block);\r
1445                 }\r
1446                 ReleaseQueue(e->Queue);\r
1447         }\r
1448 #endif // BRIDGE_PCAP\r
1449 \r
1450 #ifdef BRIDGE_BPF\r
1451 #ifdef BRIDGE_BPF_THREAD\r
1452         {\r
1453                 struct CAPTUREBLOCK *block;\r
1454                 int fd = e->Socket;\r
1455                 e->Socket = INVALID_SOCKET;\r
1456                 WaitThread(e->CaptureThread, INFINITE);\r
1457                 ReleaseThread(e->CaptureThread);\r
1458                 e->Socket = fd; // 後でcloseするために復帰\r
1459                 while (block = GetNext(e->Queue)){\r
1460                         Free(block->Buf);\r
1461                         FreeCaptureBlock(block);\r
1462                 }\r
1463                 ReleaseQueue(e->Queue);\r
1464         }\r
1465 #else // BRIDGE_BPF_THREAD\r
1466         Free(e->Buffer);\r
1467 #endif // BRIDGE_BPF_THREAD\r
1468 #endif // BRIDGE_BPF\r
1469 \r
1470         ReleaseCancel(e->Cancel);\r
1471         Free(e->Name);\r
1472         Free(e->Title);\r
1473 \r
1474         // MTU の値を元に戻す\r
1475         EthSetMtu(e, 0);\r
1476 \r
1477         if (e->Socket != INVALID_SOCKET)\r
1478         {\r
1479 #if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP) || defined(UNIX_SOLARIS)\r
1480                 close(e->Socket);\r
1481 #else // BRIDGE_PCAP\r
1482                 closesocket(e->Socket);\r
1483 #endif // BRIDGE_PCAP\r
1484 #if defined(BRIDGE_BPF) || defined(UNIX_SOLARIS)\r
1485                 if (e->SocketBsdIf != INVALID_SOCKET)\r
1486                 {\r
1487                         close(e->SocketBsdIf);\r
1488                 }\r
1489 #endif  // BRIDGE_BPF || UNIX_SOLARIS\r
1490         }\r
1491 \r
1492         Free(e);\r
1493 }\r
1494 \r
1495 // キャンセルオブジェクトの取得\r
1496 CANCEL *EthGetCancel(ETH *e)\r
1497 {\r
1498         CANCEL *c;\r
1499         // 引数チェック\r
1500         if (e == NULL)\r
1501         {\r
1502                 return NULL;\r
1503         }\r
1504 \r
1505         c = e->Cancel;\r
1506         AddRef(c->ref);\r
1507 \r
1508         return c;\r
1509 }\r
1510 \r
1511 // パケットの読み込み\r
1512 UINT EthGetPacket(ETH *e, void **data)\r
1513 {\r
1514         UINT ret = 0;\r
1515 \r
1516 #if             defined(UNIX_LINUX)\r
1517         ret = EthGetPacketLinux(e, data);\r
1518 #elif   defined(UNIX_SOLARIS)\r
1519         ret = EthGetPacketSolaris(e, data);\r
1520 #elif   defined(BRIDGE_PCAP)\r
1521         ret = EthGetPacketPcap(e, data);\r
1522 #elif   defined(BRIDGE_BPF)\r
1523         ret = EthGetPacketBpf(e, data);\r
1524 #endif\r
1525 \r
1526         return ret;\r
1527 }\r
1528 \r
1529 #ifdef  UNIX_LINUX\r
1530 UINT EthGetPacketLinux(ETH *e, void **data)\r
1531 {\r
1532         int s, ret;\r
1533         UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];\r
1534         // 引数チェック\r
1535         if (e == NULL || data == NULL)\r
1536         {\r
1537                 return INFINITE;\r
1538         }\r
1539 \r
1540         if (e->Tap != NULL)\r
1541         {\r
1542 #ifndef NO_VLAN\r
1543                 // tap モード\r
1544                 void *buf;\r
1545                 UINT size;\r
1546 \r
1547                 if (VLanGetNextPacket(e->Tap, &buf, &size) == false)\r
1548                 {\r
1549                         return INFINITE;\r
1550                 }\r
1551 \r
1552                 *data = buf;\r
1553                 return size;\r
1554 #else   // NO_VLAN\r
1555                 return INFINITE;\r
1556 #endif\r
1557         }\r
1558 \r
1559         s = e->Socket;\r
1560 \r
1561         if (s == INVALID_SOCKET)\r
1562         {\r
1563                 return INFINITE;\r
1564         }\r
1565 \r
1566         // 読み込み\r
1567         ret = read(s, tmp, sizeof(tmp));\r
1568         if (ret == 0 || (ret == -1 && errno == EAGAIN))\r
1569         {\r
1570                 // パケット無し\r
1571                 *data = NULL;\r
1572                 return 0;\r
1573         }\r
1574         else if (ret == -1 || ret > sizeof(tmp))\r
1575         {\r
1576                 // エラー\r
1577                 *data = NULL;\r
1578                 e->Socket = INVALID_SOCKET;\r
1579                 return INFINITE;\r
1580         }\r
1581         else\r
1582         {\r
1583                 // パケット読み込み成功\r
1584                 *data = MallocFast(ret);\r
1585                 Copy(*data, tmp, ret);\r
1586                 return ret;\r
1587         }\r
1588 \r
1589         return 0;\r
1590 }\r
1591 #endif  // UNIX_LINUX\r
1592 \r
1593 #ifdef  UNIX_SOLARIS\r
1594 UINT EthGetPacketSolaris(ETH *e, void **data)\r
1595 {\r
1596         UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];\r
1597         struct strbuf buf;\r
1598         int s;\r
1599         int flags = 0;\r
1600         int ret;\r
1601         // 引数チェック\r
1602         if (e == NULL || data == NULL)\r
1603         {\r
1604                 return INFINITE;\r
1605         }\r
1606 \r
1607         s = e->Socket;\r
1608         if (s == INVALID_SOCKET)\r
1609         {\r
1610                 return INFINITE;\r
1611         }\r
1612 \r
1613         Zero(&buf, sizeof(buf));\r
1614         buf.buf = tmp;\r
1615         buf.maxlen = sizeof(tmp);\r
1616 \r
1617         ret = getmsg(s, NULL, &buf, &flags);\r
1618 \r
1619         if (ret < 0 || ret > sizeof(tmp))\r
1620         {\r
1621                 if (errno == EAGAIN)\r
1622                 {\r
1623                         // パケット無し\r
1624                         *data = NULL;\r
1625                         return 0;\r
1626                 }\r
1627                 // エラー\r
1628                 *data = NULL;\r
1629                 return INFINITE;\r
1630         }\r
1631 \r
1632         ret = buf.len;\r
1633 \r
1634         *data = MallocFast(ret);\r
1635         Copy(*data, tmp, ret);\r
1636         return ret;\r
1637 }\r
1638 #endif  // UNIX_SOLARIS\r
1639 \r
1640 #ifdef  BRIDGE_PCAP\r
1641 UINT EthGetPacketPcap(ETH *e, void **data)\r
1642 {\r
1643         struct CAPTUREBLOCK *block;\r
1644         UINT size;\r
1645         \r
1646         LockQueue(e->Queue);\r
1647         block = GetNext(e->Queue);\r
1648         if(block != NULL){\r
1649                 e->QueueSize -= block->Size;\r
1650         }\r
1651         UnlockQueue(e->Queue);\r
1652         \r
1653         if(block == NULL){\r
1654                 *data = NULL;\r
1655                 if(e->Socket == INVALID_SOCKET){\r
1656                         return INFINITE;\r
1657                 }\r
1658                 return 0;\r
1659         }\r
1660         \r
1661         *data = block->Buf;\r
1662         size = block->Size;\r
1663         FreeCaptureBlock(block);\r
1664         \r
1665         return size;\r
1666 }\r
1667 #endif // BRIDGE_PCAP\r
1668 \r
1669 #ifdef  BRIDGE_BPF\r
1670 #ifdef BRIDGE_BPF_THREAD\r
1671 UINT EthGetPacketBpf(ETH *e, void **data)\r
1672 {\r
1673         struct CAPTUREBLOCK *block;\r
1674         UINT size;\r
1675         \r
1676         LockQueue(e->Queue);\r
1677         block = GetNext(e->Queue);\r
1678         if(block != NULL){\r
1679                 e->QueueSize -= block->Size;\r
1680         }\r
1681         UnlockQueue(e->Queue);\r
1682         \r
1683         if(block == NULL){\r
1684                 *data = NULL;\r
1685                 if(e->Socket == INVALID_SOCKET){\r
1686                         return INFINITE;\r
1687                 }\r
1688                 return 0;\r
1689         }\r
1690         \r
1691         *data = block->Buf;\r
1692         size = block->Size;\r
1693         FreeCaptureBlock(block);\r
1694         \r
1695         return size;\r
1696 }\r
1697 #else // BRIDGE_BPF_THREAD\r
1698 UINT EthGetPacketBpf(ETH *e, void **data)\r
1699 {\r
1700         struct bpf_hdr *hdr;\r
1701         \r
1702         if(e->Rest<=0){\r
1703                 e->Rest = read(e->Socket, e->Buffer, e->BufSize);\r
1704                 if(e->Rest < 0){\r
1705                         *data = NULL;\r
1706                         if(errno != EAGAIN){\r
1707                                 // エラー\r
1708                                 return INFINITE;\r
1709                         }\r
1710                         // データなし\r
1711                         return 0;\r
1712                 }\r
1713                 e->Next = e->Buffer;\r
1714         }\r
1715         // パケットの切り出し\r
1716         hdr = (struct bpf_hdr*)e->Next;\r
1717         *data = Malloc(hdr->bh_caplen);\r
1718         Copy(*data, e->Next+(hdr->bh_hdrlen), hdr->bh_caplen);\r
1719 \r
1720         // 次のパケットの頭出し\r
1721         e->Rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);\r
1722         e->Next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);\r
1723         \r
1724         return hdr->bh_caplen;\r
1725 }\r
1726 #endif // BRIDGE_BPF_THREAD\r
1727 #endif // BRIDGE_BPF\r
1728 \r
1729 \r
1730 // 複数のパケットの書き込み\r
1731 void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)\r
1732 {\r
1733         UINT i;\r
1734         // 引数チェック\r
1735         if (e == NULL || num == 0 || datas == NULL || sizes == NULL)\r
1736         {\r
1737                 return;\r
1738         }\r
1739 \r
1740         for (i = 0;i < num;i++)\r
1741         {\r
1742                 EthPutPacket(e, datas[i], sizes[i]);\r
1743         }\r
1744 }\r
1745 \r
1746 // パケットの書き込み\r
1747 void EthPutPacket(ETH *e, void *data, UINT size)\r
1748 {\r
1749         int s, ret;\r
1750         // 引数チェック\r
1751         if (e == NULL || data == NULL)\r
1752         {\r
1753                 return;\r
1754         }\r
1755         if (size < 14 || size > MAX_PACKET_SIZE)\r
1756         {\r
1757                 Free(data);\r
1758                 return;\r
1759         }\r
1760 \r
1761         if (e->Tap != NULL)\r
1762         {\r
1763 #ifndef NO_VLAN\r
1764                 // tap モード\r
1765                 VLanPutPacket(e->Tap, data, size);\r
1766 #endif  // NO_VLAN\r
1767                 return;\r
1768         }\r
1769 \r
1770         s = e->Socket;\r
1771 \r
1772         if (s == INVALID_SOCKET)\r
1773         {\r
1774                 Free(data);\r
1775                 return;\r
1776         }\r
1777 \r
1778         // 書き込み\r
1779 #ifdef BRIDGE_PCAP\r
1780         ret = pcap_inject(e->Pcap, data, size);\r
1781         if( ret == -1 ){\r
1782 #ifdef _DEBUG\r
1783                 pcap_perror(e->Pcap, "inject");\r
1784 #endif // _DEBUG\r
1785                 Debug("EthPutPacket: ret:%d size:%d\n", ret, size);\r
1786         }\r
1787 #else // BRIDGE_PCAP\r
1788         ret = write(s, data, size);\r
1789         if (ret<0)\r
1790         {\r
1791                 Debug("EthPutPacket: ret:%d errno:%d  size:%d\n", ret, errno, size);\r
1792         }\r
1793 #endif //BRIDGE_PCAP\r
1794         \r
1795         Free(data);\r
1796 }\r
1797 \r
1798 #endif  // BRIDGE_C\r
1799 \r
1800 \r