1 // SoftEther UT-VPN SourceCode
\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
8 // http://utvpn.tsukuba.ac.jp/
\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
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
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
23 // このファイルは GPL バージョン 2 ライセンスで公開されています。
\r
24 // 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
\r
25 // することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
\r
26 // を除去することはできません。改変した著作物を配布する場合は、改変実施者の
\r
27 // 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
\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
33 // 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
\r
34 // および、試験または研究のために利用が行われることを想定して配布
\r
36 // SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
\r
38 // 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
\r
39 // の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
\r
40 // いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
\r
41 // ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
\r
44 // GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
\r
45 // 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
\r
47 // 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
\r
48 // (SoftEther Corporation) およびその他の著作権保持者が保有しています。
\r
49 // ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
\r
50 // 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
\r
53 // お願い: どのような通信ソフトウェアにも通常は必ず未発見の
\r
54 // セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
\r
55 // UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
\r
56 // 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
\r
57 // および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
\r
58 // 公益保護にご協力いただきますようお願い申し上げます。
\r
60 // ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
\r
61 // 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
\r
64 // ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
\r
65 // 日本国内の脆弱性情報届出受付公的機関:
\r
67 // http://www.ipa.go.jp/security/vuln/report/
\r
69 // 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
\r
70 // 連絡先: http://www.softether.co.jp/jp/contact/
\r
72 // -----------------------------------------------
\r
75 // 新規リリース by SoftEther
\r
76 // -----------------------------------------------
\r
79 // Ethernet ブリッジプログラム (UNIX 版)
\r
81 //#define UNIX_LINUX
\r
92 #include <Mayaqua/Mayaqua.h>
\r
93 #include <Cedar/Cedar.h>
\r
96 #include <sys/sockio.h>
\r
101 #endif // BRIDGE_PCAP
\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
121 // Unix のデバイスの説明文字列の取得がサポートされているかどうか取得
\r
122 bool EthIsInterfaceDescriptionSupportedUnix()
\r
125 DIRLIST *d = EnumDir("/etc/sysconfig/networking/devices/");
\r
132 if (d->NumFiles >= 1)
\r
142 // Unix のデバイスの説明文字列を取得
\r
143 bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size)
\r
145 char tmp[MAX_SIZE];
\r
149 if (name == NULL || str == NULL)
\r
154 StrCpy(str, size, name);
\r
156 Format(tmp, sizeof(tmp), "/etc/sysconfig/networking/devices/ifcfg-%s", name);
\r
161 char *line = CfgReadNextLine(b);
\r
163 if (IsEmptyStr(line) == false)
\r
165 if (StartWith(line, "#"))
\r
167 char tmp[MAX_SIZE];
\r
169 StrCpy(tmp, sizeof(tmp), line + 1);
\r
174 StrCpy(str, size, tmp);
\r
189 int UnixEthOpenRawSocket()
\r
194 s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
\r
197 return INVALID_SOCKET;
\r
203 #else // UNIX_LINUX
\r
205 #endif // UNIX_LINUX
\r
208 // Ethernet 操作がサポートされているかどうか
\r
209 bool IsEthSupported()
\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
219 #elif defined(BRIDGE_BPF)
\r
226 bool IsEthSupportedLinux()
\r
231 s = UnixEthOpenRawSocket();
\r
232 if (s == INVALID_SOCKET)
\r
243 #endif // UNIX_LINUX
\r
245 #ifdef UNIX_SOLARIS
\r
246 bool IsEthSupportedSolaris()
\r
250 #endif // UNIX_SOLARIS
\r
252 #ifdef UNIX_SOLARIS
\r
253 // アダプタ一覧を取得 (Solaris)
\r
254 TOKEN_LIST *GetEthListSolaris()
\r
261 o = NewListFast(CompareStr);
\r
262 s = socket(AF_INET, SOCK_DGRAM, 0);
\r
263 if (s != INVALID_SOCKET)
\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
270 struct lifconf lifc;
\r
271 struct lifreq *buf;
\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
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
286 for (i = 0; i<numifs; i++)
\r
288 if(StartWith(buf[i].lifr_name, "lo") == false){
\r
289 Add(o, CopyStr(buf[i].lifr_name));
\r
300 t = ZeroMalloc(sizeof(TOKEN_LIST));
\r
301 t->NumTokens = LIST_NUM(o);
\r
302 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
\r
304 for (i = 0;i < LIST_NUM(o);i++)
\r
306 char *name = LIST_DATA(o, i);
\r
307 t->Token[i] = name;
\r
314 #endif // UNIX_SOLARIS
\r
317 // アダプタ一覧を取得 (Linux)
\r
318 TOKEN_LIST *GetEthListLinux()
\r
325 char name[MAX_SIZE];
\r
327 o = NewListFast(CompareStr);
\r
329 s = UnixEthOpenRawSocket();
\r
330 if (s != INVALID_SOCKET)
\r
335 Zero(&ifr, sizeof(ifr));
\r
336 ifr.ifr_ifindex = i;
\r
338 if (ioctl(s, SIOCGIFNAME, &ifr) >= 0)
\r
341 StrCpy(name, sizeof(name), ifr.ifr_name);
\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
347 UINT type = ifr.ifr_hwaddr.sa_family;
\r
348 if (type == 1 || type == 2 || type == 6 || type == 800 || type == 801)
\r
350 if (IsInListStr(o, name) == false)
\r
352 if (StartWith(name, "tap_") == false)
\r
354 Add(o, CopyStr(name));
\r
374 t = ZeroMalloc(sizeof(TOKEN_LIST));
\r
375 t->NumTokens = LIST_NUM(o);
\r
376 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
\r
378 for (i = 0;i < LIST_NUM(o);i++)
\r
380 char *name = LIST_DATA(o, i);
\r
381 t->Token[i] = name;
\r
388 #endif // UNIX_LINUX
\r
391 // アダプタ一覧を取得 (Pcap)
\r
392 TOKEN_LIST *GetEthListPcap()
\r
394 pcap_if_t *alldevs;
\r
395 char errbuf[PCAP_ERRBUF_SIZE];
\r
400 o = NewListFast(CompareStr);
\r
402 if( pcap_findalldevs(&alldevs,errbuf) != -1)
\r
404 pcap_if_t *dev = alldevs;
\r
408 // デバイスを開いてみないとデバイスの種類が分からない?
\r
409 p = pcap_open_live(dev->name, 0, false, 0, errbuf);
\r
412 int datalink = pcap_datalink(p);
\r
413 // Debug("type:%s\n",pcap_datalink_val_to_name(datalink));
\r
415 if(datalink == DLT_EN10MB){
\r
416 // イーサネットデバイスのみ列挙する
\r
417 Add(o, CopyStr(dev->name));
\r
422 pcap_freealldevs(alldevs);
\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
431 t->Token[i] = LIST_DATA(o, i);
\r
436 #endif // BRIDGE_PCAP
\r
440 TOKEN_LIST *GetEthListBpf()
\r
442 struct ifaddrs *ifadrs;
\r
443 struct sockaddr_dl *sockadr;
\r
448 o = NewListFast(CompareStr);
\r
450 // ネットワークデバイスの一覧を取得
\r
451 if(getifaddrs( &ifadrs ) == 0)
\r
453 struct ifaddrs *ifadr = ifadrs;
\r
456 sockadr = (struct sockaddr_dl*)ifadr->ifa_addr;
\r
457 if(sockadr->sdl_family == AF_LINK && sockadr->sdl_type == IFT_ETHER)
\r
460 if(!IsInListStr(o,ifadr->ifa_name))
\r
462 // 既存でなければ追加(複数のMACアドレスを持つインターフェースへの対策)
\r
463 Add(o, CopyStr(ifadr->ifa_name));
\r
466 ifadr = ifadr -> ifa_next;
\r
468 freeifaddrs(ifadrs);
\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
477 t->Token[i] = LIST_DATA(o, i);
\r
482 #endif // BRIDGE_BPF
\r
485 TOKEN_LIST *GetEthList()
\r
487 TOKEN_LIST *t = NULL;
\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
504 ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)
\r
508 struct sockaddr_ll addr;
\r
522 VLAN *v = NewTap(name, tapaddr);
\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
533 e->Socket = INVALID_SOCKET;
\r
542 s = UnixEthOpenRawSocket();
\r
543 if (s == INVALID_SOCKET)
\r
548 Zero(&ifr, sizeof(ifr));
\r
549 StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
\r
551 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
\r
557 index = ifr.ifr_ifindex;
\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
564 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
\r
570 if (local == false)
\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
582 ifr.ifr_flags |= IFF_PROMISC;
\r
584 if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
\r
592 e = ZeroMalloc(sizeof(ETH));
\r
593 e->Name = CopyStr(name);
\r
594 e->Title = CopyStr(name);
\r
595 e->IfIndex = index;
\r
599 UnixDeletePipe(c->pipe_read, c->pipe_write);
\r
600 c->pipe_read = c->pipe_write = -1;
\r
602 UnixSetSocketNonBlockingMode(s, true);
\r
604 c->SpecialFlag = true;
\r
610 e->InitialMtu = EthGetMtu(e);
\r
614 #endif // UNIX_LINUX
\r
617 UINT EthGetMtu(ETH *e)
\r
619 #if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
621 #ifdef UNIX_SOLARIS
\r
623 #else // UNIX_SOLARIS
\r
625 #endif // UNIX_SOLARIS
\r
628 if (e == NULL || e->Tap != NULL)
\r
633 if (e->CurrentMtu != 0)
\r
635 return e->CurrentMtu;
\r
638 #if defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
639 s = e->SocketBsdIf;
\r
640 #else // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
642 #endif // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
644 Zero(&ifr, sizeof(ifr));
\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
652 #ifdef UNIX_SOLARIS
\r
653 if (ioctl(s, SIOCGLIFMTU, &ifr) < 0)
\r
658 #else // UNIX_SOLARIS
\r
659 if (ioctl(s, SIOCGIFMTU, &ifr) < 0)
\r
664 #endif // UNIX_SOLARIS
\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
672 e->CurrentMtu = ret;
\r
674 Debug("%s: GetMtu: %u\n", e->Name, ret);
\r
677 #else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
679 #endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
683 bool EthSetMtu(ETH *e, UINT mtu)
\r
685 #if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
687 #ifdef UNIX_SOLARIS
\r
689 #else // UNIX_SOLARIS
\r
691 #endif // UNIX_SOLARIS
\r
694 if (e == NULL || e->Tap != NULL || (mtu > 1 && mtu < 1514))
\r
698 if (mtu == 0 && e->InitialMtu == 0)
\r
705 // mtu == 0 の場合は MTU の値を元に戻す
\r
706 mtu = e->InitialMtu;
\r
709 #if defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
710 s = e->SocketBsdIf;
\r
711 #else // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
713 #endif // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
715 if (e->CurrentMtu == mtu)
\r
721 Zero(&ifr, sizeof(ifr));
\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
731 #ifdef UNIX_SOLARIS
\r
732 if (ioctl(s, SIOCSLIFMTU, &ifr) < 0)
\r
737 #else // UNIX_SOLARIS
\r
738 if (ioctl(s, SIOCSIFMTU, &ifr) < 0)
\r
743 #endif // UNIX_SOLARIS
\r
745 e->CurrentMtu = mtu;
\r
747 Debug("%s: SetMtu: %u\n", e->Name, mtu);
\r
750 #else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
752 #endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
755 // MTU の値の変更がサポートされているかどうか取得
\r
756 bool EthIsChangeMtuSupported(ETH *e)
\r
758 #if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
760 if (e == NULL || e->Tap != NULL)
\r
766 #else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
768 #endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
\r
771 #ifdef UNIX_SOLARIS
\r
772 // アダプタを開く (Solaris)
\r
773 ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr)
\r
775 char devname[MAX_SIZE];
\r
780 struct strioctl sioc;
\r
783 if (name == NULL || tapmode != false)
\r
789 if (ParseUnixEthDeviceName(devname, sizeof(devname), &devid, name) == false)
\r
795 fd = open(devname, O_RDWR);
\r
803 if (DlipAttatchRequest(fd, devid) == false)
\r
811 if (DlipReceiveAck(fd) == false)
\r
819 if (DlipBindRequest(fd) == false)
\r
827 if (DlipReceiveAck(fd) == false)
\r
834 // SAPに関わらず受信するモードにセットする
\r
835 if (DlipPromiscuous(fd, DL_PROMISC_SAP) == false)
\r
843 if (DlipReceiveAck(fd) == false)
\r
850 // 自分の送信するパケットも受信するモードにセットする
\r
851 if (DlipPromiscuous(fd, DL_PROMISC_PHYS) == false)
\r
859 if (DlipReceiveAck(fd) == false)
\r
867 sioc.ic_cmd = DLIOCRAW;
\r
868 sioc.ic_timout = -1;
\r
871 if (ioctl(fd, I_STR, &sioc) < 0)
\r
878 if (ioctl(fd, I_FLUSH, FLUSHR) < 0)
\r
885 e = ZeroMalloc(sizeof(ETH));
\r
886 e->Name = CopyStr(name);
\r
887 e->Title = CopyStr(name);
\r
890 UnixDeletePipe(c->pipe_read, c->pipe_write);
\r
891 c->pipe_read = c->pipe_write = -1;
\r
893 c->SpecialFlag = true;
\r
901 UnixSetSocketNonBlockingMode(fd, true);
\r
904 e->SocketBsdIf = socket(AF_INET, SOCK_DGRAM, 0);
\r
907 e->InitialMtu = EthGetMtu(e);
\r
912 // プロミスキャスモードにセットする
\r
913 bool DlipPromiscuous(int fd, UINT level)
\r
915 dl_promiscon_req_t req;
\r
924 Zero(&req, sizeof(req));
\r
925 req.dl_primitive = DL_PROMISCON_REQ;
\r
926 req.dl_level = level;
\r
928 Zero(&ctl, sizeof(ctl));
\r
930 ctl.len = sizeof(req);
\r
931 ctl.buf = (char *)&req;
\r
935 if (putmsg(fd, &ctl, NULL, flags) < 0)
\r
944 bool DlipBindRequest(int fd)
\r
954 Zero(&req, sizeof(req));
\r
955 req.dl_primitive = DL_BIND_REQ;
\r
956 req.dl_service_mode = DL_CLDLS;
\r
959 Zero(&ctl, sizeof(ctl));
\r
961 ctl.len = sizeof(req);
\r
962 ctl.buf = (char *)&req;
\r
964 if (putmsg(fd, &ctl, NULL, 0) < 0)
\r
972 bool DlipAttatchRequest(int fd, UINT devid)
\r
974 dl_attach_req_t req;
\r
983 Zero(&req, sizeof(req));
\r
984 req.dl_primitive = DL_ATTACH_REQ;
\r
985 req.dl_ppa = devid;
\r
987 Zero(&ctl, sizeof(ctl));
\r
989 ctl.len = sizeof(req);
\r
990 ctl.buf = (char *)&req;
\r
994 if (putmsg(fd, &ctl, NULL, flags) < 0)
\r
1003 bool DlipReceiveAck(int fd)
\r
1005 union DL_primitives *dlp;
\r
1006 struct strbuf ctl;
\r
1015 buf = MallocFast(SOLARIS_MAXDLBUF);
\r
1017 Zero(&ctl, sizeof(ctl));
\r
1018 ctl.maxlen = SOLARIS_MAXDLBUF;
\r
1022 if (getmsg(fd, &ctl, NULL, &flags) < 0)
\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
1039 #endif // UNIX_SOLARIS
\r
1041 // UNIX のデバイス名文字列をデバイス名と番号に分ける
\r
1042 bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, UINT *dst_devid, char *src_name)
\r
1047 if (dst_devname == NULL || dst_devid == NULL || src_name == NULL)
\r
1052 len = strlen(src_name);
\r
1059 for (i = len-1; i+1 != 0; i--)
\r
1061 // 末尾からたどって最初に数字でない文字を検出
\r
1062 if (src_name[i] < '0' || '9' < src_name[i])
\r
1064 // 最後の文字が数字でなければエラー
\r
1065 if(src_name[i+1]==0)
\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
1073 dst_devname[j+5] = src_name[j];
\r
1075 dst_devname[j+5]=0;
\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
1092 // キャプチャしたパケットデータ構造体の開放
\r
1093 void FreeCaptureBlock(struct CAPTUREBLOCK *block){
\r
1096 #endif // BRIDGE_BPF || BRIDGE_PCAP
\r
1098 #ifdef BRIDGE_PCAP
\r
1099 // パケット到着のコールバック関数
\r
1100 void PcapHandler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
\r
1102 ETH *e = (ETH*) user;
\r
1103 struct CAPTUREBLOCK *block;
\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
1115 UnlockQueue(e->Queue);
\r
1116 Cancel(e->Cancel);
\r
1121 // Pcap でのパケットキャプチャの中継用スレッド
\r
1122 void PcapThread(THREAD *thread, void *param)
\r
1124 ETH *e = (ETH*)param;
\r
1125 pcap_t *p = e->Pcap;
\r
1129 NoticeThreadInit(thread);
\r
1131 // 帰り値 -1:エラー -2:外部からの終了
\r
1132 ret = pcap_loop(p, -1, PcapHandler, (u_char*) e);
\r
1134 e->Socket = INVALID_SOCKET;
\r
1135 pcap_perror(p, "capture");
\r
1142 ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr)
\r
1144 char errbuf[PCAP_ERRBUF_SIZE];
\r
1150 if (name == NULL || tapmode != false)
\r
1155 // エラーメッセージバッファの初期化
\r
1159 p = pcap_open_live(name, 65535, (local == false), 1, errbuf);
\r
1166 // BSD系OSでは、BPFのselectが正常に動作しないのでブロックさせないとビジーループになる
\r
1168 if(pcap_setnonblock(p, true, errbuf) == -1)
\r
1170 Debug("pcap_setnonblock:%s\n",errbuf);
\r
1176 e = ZeroMalloc(sizeof(ETH));
\r
1177 e->Name = CopyStr(name);
\r
1178 e->Title = CopyStr(name);
\r
1179 e->Queue = NewQueue();
\r
1181 e->Cancel = NewCancel();
\r
1183 e->Socket = pcap_get_selectable_fd(p);
\r
1186 e->CaptureThread = NewThread(PcapThread, e);
\r
1187 WaitThreadInit(e->CaptureThread);
\r
1191 #endif // BRIDGE_PCAP
\r
1194 #ifdef BRIDGE_BPF_THREAD
\r
1195 // BPF でのパケットキャプチャの中継用スレッド
\r
1196 void BpfThread(THREAD *thread, void *param)
\r
1198 ETH *e = (ETH*)param;
\r
1199 int fd = e->Socket;
\r
1201 int rest; // バッファ中の残りバイト数
\r
1202 UCHAR *next; //バッファ中の次のパケットの先頭
\r
1203 struct CAPTUREBLOCK *block; // キューに追加するデータ
\r
1205 struct bpf_hdr *hdr;
\r
1208 UCHAR *buf = Malloc(e->BufSize);
\r
1211 NoticeThreadInit(thread);
\r
1215 if(e->Socket == INVALID_SOCKET){
\r
1219 rest = read(fd, buf, e->BufSize);
\r
1220 if(rest < 0 && errno != EAGAIN){
\r
1223 e->Socket = INVALID_SOCKET;
\r
1225 Cancel(e->Cancel);
\r
1229 LockQueue(e->Queue);
\r
1232 hdr = (struct bpf_hdr*)next;
\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
1244 rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
\r
1245 next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
\r
1247 UnlockQueue(e->Queue);
\r
1248 Cancel(e->Cancel);
\r
1251 Cancel(e->Cancel);
\r
1254 #endif // BRIDGE_BPF_THREAD
\r
1257 ETH *OpenEthBpf(char *name, bool local, bool tapmode, char *tapaddr)
\r
1261 char devname[MAX_SIZE];
\r
1267 struct timeval to;
\r
1269 // 未使用の bpf デバイスを探して開く
\r
1271 Format(devname, sizeof(devname), "/dev/bpf%d", n++);
\r
1272 fd = open (devname, O_RDWR);
\r
1276 }while(fd < 0 && errno == EBUSY);
\r
1278 // 開くことが出来るbpfデバイスが無ければエラー
\r
1280 Debug("BPF: No minor number are free.\n");
\r
1285 n = 524288; // なんとなく(libpcapでは32768だった)
\r
1288 ioctl(fd, BIOCSBLEN, &n);
\r
1291 StrCpy(ifr.ifr_name, IFNAMSIZ, name);
\r
1292 ret = ioctl(fd, BIOCSETIF, &ifr);
\r
1294 if(ret == ENOBUFS && n>1500){
\r
1297 // バッファサイズ1500バイト以下でエラーになるのは何かおかしい
\r
1301 Debug("bpf: binding network failed.\n");
\r
1311 if(local == false){
\r
1312 if (ioctl(fd, BIOCPROMISC, NULL) < 0){
\r
1313 printf("bpf: promisc mode failed.\n");
\r
1320 // 即時モードに設定(パケットを受信するとタイムアウトを待たず、すぐにreadがreturnする)
\r
1322 if (ioctl(fd, BIOCIMMEDIATE, &n) < 0){
\r
1323 Debug("BPF: non-block mode failed.\n");
\r
1328 // 自分が送信するパケットも受信する
\r
1330 if (ioctl(fd, BIOCGSEESENT, &n) < 0){
\r
1331 Debug("BPF: see sent mode failed.\n");
\r
1337 // ヘッダ完全モード(送信するパケットのヘッダも自分で生成する)
\r
1339 if (ioctl(fd, BIOCSHDRCMPLT, &n) < 0){
\r
1340 Debug("BPF: Header complete mode failed.\n");
\r
1345 // read のタイムアウト時間を設定(1秒)
\r
1348 if (ioctl(fd, BIOCSRTIMEOUT, &to) < 0){
\r
1349 Debug("BPF: Read timeout setting failed.\n");
\r
1354 e = ZeroMalloc(sizeof(ETH));
\r
1355 e->Name = CopyStr(name);
\r
1356 e->Title = CopyStr(name);
\r
1359 e->BufSize = bufsize;
\r
1361 #ifdef BRIDGE_BPF_THREAD
\r
1362 e->Queue = NewQueue();
\r
1364 e->Cancel = NewCancel();
\r
1367 e->CaptureThread = NewThread(BpfThread, e);
\r
1368 WaitThreadInit(e->CaptureThread);
\r
1370 #else // BRIDGE_BPF_THREAD
\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
1377 e->Buffer = Malloc(bufsize);
\r
1378 e->Next = e->Buffer;
\r
1382 UnixSetSocketNonBlockingMode(fd, true);
\r
1383 #endif // BRIDGE_BPF_THREAD
\r
1385 // FreeBSD 用インターフェイス操作用ソケットを作成
\r
1386 e->SocketBsdIf = socket(AF_LOCAL, SOCK_DGRAM, 0);
\r
1389 e->InitialMtu = EthGetMtu(e);
\r
1393 #endif // BRIDGE_BPF
\r
1396 ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)
\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
1413 typedef struct UNIXTHREAD
\r
1420 void CloseEth(ETH *e)
\r
1428 if (e->Tap != NULL)
\r
1435 #ifdef BRIDGE_PCAP
\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
1444 FreeCaptureBlock(block);
\r
1446 ReleaseQueue(e->Queue);
\r
1448 #endif // BRIDGE_PCAP
\r
1451 #ifdef BRIDGE_BPF_THREAD
\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
1461 FreeCaptureBlock(block);
\r
1463 ReleaseQueue(e->Queue);
\r
1465 #else // BRIDGE_BPF_THREAD
\r
1467 #endif // BRIDGE_BPF_THREAD
\r
1468 #endif // BRIDGE_BPF
\r
1470 ReleaseCancel(e->Cancel);
\r
1477 if (e->Socket != INVALID_SOCKET)
\r
1479 #if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP) || defined(UNIX_SOLARIS)
\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
1487 close(e->SocketBsdIf);
\r
1489 #endif // BRIDGE_BPF || UNIX_SOLARIS
\r
1496 CANCEL *EthGetCancel(ETH *e)
\r
1512 UINT EthGetPacket(ETH *e, void **data)
\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
1530 UINT EthGetPacketLinux(ETH *e, void **data)
\r
1533 UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
\r
1535 if (e == NULL || data == NULL)
\r
1540 if (e->Tap != NULL)
\r
1547 if (VLanGetNextPacket(e->Tap, &buf, &size) == false)
\r
1561 if (s == INVALID_SOCKET)
\r
1567 ret = read(s, tmp, sizeof(tmp));
\r
1568 if (ret == 0 || (ret == -1 && errno == EAGAIN))
\r
1574 else if (ret == -1 || ret > sizeof(tmp))
\r
1578 e->Socket = INVALID_SOCKET;
\r
1584 *data = MallocFast(ret);
\r
1585 Copy(*data, tmp, ret);
\r
1591 #endif // UNIX_LINUX
\r
1593 #ifdef UNIX_SOLARIS
\r
1594 UINT EthGetPacketSolaris(ETH *e, void **data)
\r
1596 UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
\r
1597 struct strbuf buf;
\r
1602 if (e == NULL || data == NULL)
\r
1608 if (s == INVALID_SOCKET)
\r
1613 Zero(&buf, sizeof(buf));
\r
1615 buf.maxlen = sizeof(tmp);
\r
1617 ret = getmsg(s, NULL, &buf, &flags);
\r
1619 if (ret < 0 || ret > sizeof(tmp))
\r
1621 if (errno == EAGAIN)
\r
1634 *data = MallocFast(ret);
\r
1635 Copy(*data, tmp, ret);
\r
1638 #endif // UNIX_SOLARIS
\r
1640 #ifdef BRIDGE_PCAP
\r
1641 UINT EthGetPacketPcap(ETH *e, void **data)
\r
1643 struct CAPTUREBLOCK *block;
\r
1646 LockQueue(e->Queue);
\r
1647 block = GetNext(e->Queue);
\r
1648 if(block != NULL){
\r
1649 e->QueueSize -= block->Size;
\r
1651 UnlockQueue(e->Queue);
\r
1653 if(block == NULL){
\r
1655 if(e->Socket == INVALID_SOCKET){
\r
1661 *data = block->Buf;
\r
1662 size = block->Size;
\r
1663 FreeCaptureBlock(block);
\r
1667 #endif // BRIDGE_PCAP
\r
1670 #ifdef BRIDGE_BPF_THREAD
\r
1671 UINT EthGetPacketBpf(ETH *e, void **data)
\r
1673 struct CAPTUREBLOCK *block;
\r
1676 LockQueue(e->Queue);
\r
1677 block = GetNext(e->Queue);
\r
1678 if(block != NULL){
\r
1679 e->QueueSize -= block->Size;
\r
1681 UnlockQueue(e->Queue);
\r
1683 if(block == NULL){
\r
1685 if(e->Socket == INVALID_SOCKET){
\r
1691 *data = block->Buf;
\r
1692 size = block->Size;
\r
1693 FreeCaptureBlock(block);
\r
1697 #else // BRIDGE_BPF_THREAD
\r
1698 UINT EthGetPacketBpf(ETH *e, void **data)
\r
1700 struct bpf_hdr *hdr;
\r
1703 e->Rest = read(e->Socket, e->Buffer, e->BufSize);
\r
1706 if(errno != EAGAIN){
\r
1713 e->Next = e->Buffer;
\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
1721 e->Rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
\r
1722 e->Next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
\r
1724 return hdr->bh_caplen;
\r
1726 #endif // BRIDGE_BPF_THREAD
\r
1727 #endif // BRIDGE_BPF
\r
1731 void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)
\r
1735 if (e == NULL || num == 0 || datas == NULL || sizes == NULL)
\r
1740 for (i = 0;i < num;i++)
\r
1742 EthPutPacket(e, datas[i], sizes[i]);
\r
1747 void EthPutPacket(ETH *e, void *data, UINT size)
\r
1751 if (e == NULL || data == NULL)
\r
1755 if (size < 14 || size > MAX_PACKET_SIZE)
\r
1761 if (e->Tap != NULL)
\r
1765 VLanPutPacket(e->Tap, data, size);
\r
1772 if (s == INVALID_SOCKET)
\r
1779 #ifdef BRIDGE_PCAP
\r
1780 ret = pcap_inject(e->Pcap, data, size);
\r
1783 pcap_perror(e->Pcap, "inject");
\r
1785 Debug("EthPutPacket: ret:%d size:%d\n", ret, size);
\r
1787 #else // BRIDGE_PCAP
\r
1788 ret = write(s, data, size);
\r
1791 Debug("EthPutPacket: ret:%d errno:%d size:%d\n", ret, errno, size);
\r
1793 #endif //BRIDGE_PCAP
\r
1798 #endif // BRIDGE_C
\r