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 // Layer-3 スイッチ モジュール
\r
81 #include "CedarPch.h"
\r
83 static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
\r
86 void L3PollingIpQueue(L3IF *f)
\r
95 // 別のセッションから来たパケットを処理する
\r
96 while (p = GetNext(f->IpPacketQueue))
\r
98 PKT *pkt = p->Packet;
\r
106 void L3RecvIp(L3IF *f, PKT *p, bool self)
\r
115 if (f == NULL || p == NULL)
\r
120 ip = p->L3.IPv4Header;
\r
121 header_size = IPV4_GET_HEADER_LEN(p->L3.IPv4Header) * 4;
\r
124 if (IpCheckChecksum(ip) == false)
\r
131 L3KnownArp(f, ip->SrcIP, p->MacAddressSrc);
\r
133 if (p->BroadcastPacket)
\r
135 // ブロードキャストパケットの場合はルーティングしない
\r
140 if (ip->TimeToLive >= 1)
\r
142 new_ttl = ip->TimeToLive - 1;
\r
151 if (ip->DstIP != f->IpAddress)
\r
153 UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);
\r
154 UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;
\r
157 ICMP_HEADER *icmpv4;
\r
160 UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);
\r
162 // TTL 切れが発生したことを知らせる ICMP メッセージを生成する
\r
163 buf = ZeroMalloc(icmp_packet_total_size);
\r
164 ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));
\r
165 icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));
\r
166 data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;
\r
168 IPV4_SET_VERSION(ipv4, 4);
\r
169 IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);
\r
170 ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));
\r
171 ipv4->TimeToLive = 0xff;
\r
172 ipv4->Protocol = IP_PROTO_ICMPV4;
\r
173 ipv4->SrcIP = f->IpAddress;
\r
174 ipv4->DstIP = ip->SrcIP;
\r
175 ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
\r
178 Copy(data, ip, data_size);
\r
179 icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);
\r
184 pkt = ParsePacket(buf, icmp_packet_total_size);
\r
191 L3RecvIp(f, pkt, true);
\r
194 // TTL が切れたパケット本体は破棄する
\r
200 p->L3.IPv4Header->TimeToLive = (UCHAR)new_ttl;
\r
202 // 宛先 IP アドレスに対するインターフェイスを取得する
\r
203 dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);
\r
205 if (dst == NULL && self == false)
\r
207 UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);
\r
208 UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;
\r
211 ICMP_HEADER *icmpv4;
\r
214 UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);
\r
216 // ルートが見つからない旨を ICMP で応答する
\r
217 buf = ZeroMalloc(icmp_packet_total_size);
\r
218 ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));
\r
219 icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));
\r
220 data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;
\r
222 IPV4_SET_VERSION(ipv4, 4);
\r
223 IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);
\r
224 ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));
\r
225 ipv4->TimeToLive = 0xff;
\r
226 ipv4->Protocol = IP_PROTO_ICMPV4;
\r
227 ipv4->SrcIP = f->IpAddress;
\r
228 ipv4->DstIP = ip->SrcIP;
\r
229 ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
\r
232 Copy(data, ip, data_size);
\r
233 icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);
\r
238 pkt = ParsePacket(buf, icmp_packet_total_size);
\r
245 L3RecvIp(f, pkt, true);
\r
248 // ルートが見つからないパケット本体は破棄する
\r
252 if (dst != NULL && ip->DstIP == dst->IpAddress)
\r
254 bool free_packet = true;
\r
255 // 自分宛の IP パケットが届いた
\r
256 if (p->TypeL4 == L4_ICMPV4)
\r
258 ICMP_HEADER *icmp = p->L4.ICMPHeader;
\r
259 if (icmp->Type == ICMP_TYPE_ECHO_REQUEST)
\r
261 // この IP パケットの宛先と送信元を書き換えて返信する
\r
262 UINT src_ip, dst_ip;
\r
263 src_ip = p->L3.IPv4Header->DstIP;
\r
264 dst_ip = p->L3.IPv4Header->SrcIP;
\r
266 p->L3.IPv4Header->DstIP = dst_ip;
\r
267 p->L3.IPv4Header->SrcIP = src_ip;
\r
269 ip->TimeToLive = 0xff;
\r
272 ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
\r
273 icmp->Checksum = 0;
\r
274 icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
\r
275 icmp->Checksum = IpChecksum(icmp, p->PacketSize - sizeof(MAC_HEADER) - header_size);
\r
277 dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);
\r
279 free_packet = false;
\r
297 ip->Checksum = IpChecksum(ip, header_size);
\r
299 // Layer-3 パケットとして処理する
\r
300 packet = ZeroMalloc(sizeof(L3PACKET));
\r
301 packet->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;
\r
302 packet->NextHopIp = next_hop;
\r
303 packet->Packet = p;
\r
306 L3StoreIpPacketToIf(f, dst, packet);
\r
312 Free(p->PacketData);
\r
318 void L3RecvL2(L3IF *f, PKT *p)
\r
321 if (f == NULL || p == NULL)
\r
326 // 自分が送信したパケットか、ユニキャストパケットで自分宛で無いパケット
\r
328 if (Cmp(p->MacAddressSrc, f->MacAddress, 6) == 0 ||
\r
329 (p->BroadcastPacket == false && Cmp(p->MacAddressDest, f->MacAddress, 6) != 0))
\r
332 Free(p->PacketData);
\r
337 if (p->TypeL3 == L3_ARPV4)
\r
343 Free(p->PacketData);
\r
346 else if (p->TypeL3 == L3_IPV4)
\r
349 L3RecvIp(f, p, false);
\r
354 Free(p->PacketData);
\r
359 // IP パケットを別のインターフェイスにストアする
\r
360 void L3StoreIpPacketToIf(L3IF *src_if, L3IF *dst_if, L3PACKET *p)
\r
363 if (src_if == NULL || p == NULL || dst_if == NULL)
\r
368 // ストア先セッションのキューに追加する
\r
369 InsertQueue(dst_if->IpPacketQueue, p);
\r
371 // ストア先セッションの Cancel オブジェクトを叩くことにする
\r
372 AddCancelList(src_if->CancelList, dst_if->Session->Cancel1);
\r
375 // パケットを書き込む (新しいパケットが届いたので処理する)
\r
376 void L3PutPacket(L3IF *f, void *data, UINT size)
\r
390 if (f->CancelList == NULL)
\r
392 f->CancelList = NewCancelList();
\r
396 p = ParsePacket(data, size);
\r
415 // すべてのパケットの処理が終わったらキャンセルリストをキャンセル処理する
\r
416 if (f->CancelList != NULL)
\r
418 CancelList(f->CancelList);
\r
419 ReleaseCancelList(f->CancelList);
\r
420 f->CancelList = NULL;
\r
425 // 待機している IP パケットのうち送信先 MAC アドレスが解決したものを送信する
\r
426 void L3SendWaitingIp(L3IF *f, UCHAR *mac, UINT ip, L3ARPENTRY *a)
\r
431 if (f == NULL || mac == NULL || a == NULL)
\r
436 for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
\r
438 L3PACKET *p = LIST_DATA(f->IpWaitList, i);
\r
440 if (p->NextHopIp == ip)
\r
444 o = NewListFast(NULL);
\r
452 for (i = 0;i < LIST_NUM(o);i++)
\r
454 L3PACKET *p = LIST_DATA(o, i);
\r
457 L3SendIpNow(f, a, p);
\r
459 Delete(f->IpWaitList, p);
\r
460 Free(p->Packet->PacketData);
\r
461 FreePacket(p->Packet);
\r
470 void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac)
\r
474 if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)
\r
479 Zero(&t, sizeof(t));
\r
482 a = Search(f->ArpTable, &t);
\r
486 // リストに登録されていないので登録する
\r
487 a = ZeroMalloc(sizeof(L3ARPENTRY));
\r
489 Copy(a->MacAddress, mac, 6);
\r
490 Insert(f->ArpTable, a);
\r
494 a->Expire = Tick64() + ARP_ENTRY_EXPIRES;
\r
496 // 待機している IP パケットを送信させる
\r
497 L3SendWaitingIp(f, mac, ip, a);
\r
500 // ARP テーブルを知ったときに呼ばれる関数
\r
501 void L3KnownArp(L3IF *f, UINT ip, UCHAR *mac)
\r
505 if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)
\r
510 // この IP アドレスへの ARP 問い合わせテーブルを削除する
\r
511 Zero(&t, sizeof(t));
\r
513 w = Search(f->IpWaitList, &t);
\r
516 Delete(f->IpWaitList, w);
\r
521 L3InsertArpTable(f, ip, mac);
\r
525 void L3SendArp(L3IF *f, UINT ip)
\r
529 if (f == NULL || ip == 0 || ip == 0xffffffff)
\r
534 // すでに登録されていないかどうか調べる
\r
535 Zero(&t, sizeof(t));
\r
537 w = Search(f->ArpWaitTable, &t);
\r
541 // すでに待機リストに登録されているので何もしない
\r
547 w = ZeroMalloc(sizeof(L3ARPWAIT));
\r
548 w->Expire = Tick64() + ARP_REQUEST_GIVEUP;
\r
550 Insert(f->ArpWaitTable, w);
\r
555 void L3RecvArpRequest(L3IF *f, PKT *p)
\r
559 if (f == NULL || p == NULL)
\r
564 a = p->L3.ARPv4Header;
\r
566 L3KnownArp(f, a->SrcIP, a->SrcAddress);
\r
568 if (a->TargetIP == f->IpAddress)
\r
570 // 自分宛の ARP パケットの場合のみ応答する
\r
571 L3SendArpResponseNow(f, a->SrcAddress, a->SrcIP, f->IpAddress);
\r
576 void L3RecvArpResponse(L3IF *f, PKT *p)
\r
580 if (f == NULL || p == NULL)
\r
585 a = p->L3.ARPv4Header;
\r
587 L3KnownArp(f, a->SrcIP, a->SrcAddress);
\r
591 void L3RecvArp(L3IF *f, PKT *p)
\r
595 if (f == NULL || p == NULL)
\r
600 a = p->L3.ARPv4Header;
\r
602 if (Endian16(a->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET ||
\r
603 Endian16(a->ProtocolType) != MAC_PROTO_IPV4 ||
\r
604 a->HardwareSize != 6 || a->ProtocolSize != 4)
\r
608 if (Cmp(a->SrcAddress, p->MacAddressSrc, 6) != 0)
\r
613 switch (Endian16(a->Operation))
\r
615 case ARP_OPERATION_REQUEST:
\r
617 L3RecvArpRequest(f, p);
\r
620 case ARP_OPERATION_RESPONSE:
\r
622 L3RecvArpResponse(f, p);
\r
628 void L3SendIp(L3IF *f, L3PACKET *p)
\r
630 L3ARPENTRY *a = NULL;
\r
631 bool broadcast = false;
\r
633 bool for_me = false;
\r
635 if (f == NULL || p == NULL)
\r
639 if (p->Packet->TypeL3 != L3_IPV4)
\r
644 ip = p->Packet->L3.IPv4Header;
\r
647 if (p->NextHopIp == 0xffffffff ||
\r
648 ((p->NextHopIp & f->SubnetMask) == (f->IpAddress & f->SubnetMask)) &&
\r
649 ((p->NextHopIp & (~f->SubnetMask)) == (~f->SubnetMask)))
\r
654 if (broadcast == false && ip->DstIP == f->IpAddress)
\r
658 else if (broadcast == false)
\r
660 // ユニキャストの場合 ARP エントリに入っているかどうか調べる
\r
661 a = L3SearchArpTable(f, p->NextHopIp);
\r
665 // ARP エントリに入っていないので、すぐに送信せずに
\r
667 p->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;
\r
669 Insert(f->IpWaitList, p);
\r
672 L3SendArp(f, p->NextHopIp);
\r
677 if (for_me == false)
\r
680 L3SendIpNow(f, a, p);
\r
684 Free(p->Packet->PacketData);
\r
685 FreePacket(p->Packet);
\r
690 void L3SendIpNow(L3IF *f, L3ARPENTRY *a, L3PACKET *p)
\r
693 if (f == NULL || p == NULL)
\r
698 L3SendL2Now(f, a != NULL ? a->MacAddress : broadcast, f->MacAddress, Endian16(p->Packet->MacHeader->Protocol),
\r
699 p->Packet->L3.PointerL3, p->Packet->PacketSize - sizeof(MAC_HEADER));
\r
703 L3ARPENTRY *L3SearchArpTable(L3IF *f, UINT ip)
\r
707 if (f == NULL || ip == 0 || ip == 0xffffffff)
\r
712 Zero(&t, sizeof(t));
\r
715 e = Search(f->ArpTable, &t);
\r
721 void L3SendArpRequestNow(L3IF *f, UINT dest_ip)
\r
731 arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
\r
732 arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
\r
733 arp.HardwareSize = 6;
\r
734 arp.ProtocolSize = 4;
\r
735 arp.Operation = Endian16(ARP_OPERATION_REQUEST);
\r
736 Copy(arp.SrcAddress, f->MacAddress, 6);
\r
737 arp.SrcIP = f->IpAddress;
\r
738 Zero(&arp.TargetAddress, 6);
\r
739 arp.TargetIP = dest_ip;
\r
742 L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
\r
746 void L3SendArpResponseNow(L3IF *f, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)
\r
750 if (f == NULL || dest_mac == NULL)
\r
756 arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
\r
757 arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
\r
758 arp.HardwareSize = 6;
\r
759 arp.ProtocolSize = 4;
\r
760 arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
\r
761 Copy(arp.SrcAddress, f->MacAddress, 6);
\r
762 Copy(arp.TargetAddress, dest_mac, 6);
\r
763 arp.SrcIP = src_ip;
\r
764 arp.TargetIP = dest_ip;
\r
767 L3SendL2Now(f, dest_mac, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
\r
770 // インターフェイスの MAC アドレスの生成
\r
771 void L3GenerateMacAddress(L3IF *f)
\r
774 UCHAR hash[SHA1_SIZE];
\r
782 WriteBuf(b, f->Switch->Name, StrLen(f->Switch->Name));
\r
783 WriteBuf(b, f->HubName, StrLen(f->HubName));
\r
784 WriteBuf(b, &f->IpAddress, sizeof(f->IpAddress));
\r
786 GenMacAddress(f->MacAddress);
\r
787 Hash(hash, b->Buf, b->Size, true);
\r
788 Copy(f->MacAddress + 2, hash, 4);
\r
789 f->MacAddress[1] = 0xA3;
\r
794 void L3SendL2Now(L3IF *f, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)
\r
797 MAC_HEADER *mac_header;
\r
800 if (f == NULL || dest_mac == NULL || src_mac == NULL || data == NULL)
\r
806 buf = Malloc(MAC_HEADER_SIZE + size);
\r
809 mac_header = (MAC_HEADER *)&buf[0];
\r
810 Copy(mac_header->DestAddress, dest_mac, 6);
\r
811 Copy(mac_header->SrcAddress, src_mac, 6);
\r
812 mac_header->Protocol = Endian16(protocol);
\r
815 Copy(&buf[sizeof(MAC_HEADER)], data, size);
\r
818 size += sizeof(MAC_HEADER);
\r
821 p = ZeroMalloc(sizeof(PKT));
\r
822 p->PacketData = buf;
\r
823 p->PacketSize = size;
\r
826 InsertQueue(f->SendQueue, p);
\r
829 // ARP 解決待ちリストのポーリング
\r
830 void L3PollingArpWaitTable(L3IF *f)
\r
840 for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)
\r
842 L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);
\r
844 if (w->Expire <= Tick64())
\r
846 // ARP 要求テーブルが期限切れである
\r
849 o = NewListFast(NULL);
\r
854 else if ((w->LastSentTime + ARP_REQUEST_TIMEOUT) <= Tick64())
\r
856 // 次の ARP 要求パケットを送信する
\r
857 w->LastSentTime = Tick64();
\r
859 L3SendArpRequestNow(f, w->IpAddress);
\r
865 for (i = 0;i < LIST_NUM(o);i++)
\r
867 L3ARPWAIT *w = LIST_DATA(o, i);
\r
869 Delete(f->ArpWaitTable, w);
\r
878 void L3DeleteOldArpTable(L3IF *f)
\r
888 if ((f->LastDeleteOldArpTable + ARP_ENTRY_POLLING_TIME) > Tick64())
\r
892 f->LastDeleteOldArpTable = Tick64();
\r
894 for (i = 0;i < LIST_NUM(f->ArpTable);i++)
\r
896 L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);
\r
898 if (a->Expire <= Tick64())
\r
903 o = NewListFast(NULL);
\r
912 for (i = 0;i < LIST_NUM(o);i++)
\r
914 L3ARPENTRY *a = LIST_DATA(o, i);
\r
916 Delete(f->ArpTable, a);
\r
925 void L3DeleteOldIpWaitList(L3IF *f)
\r
935 for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
\r
937 L3PACKET *p = LIST_DATA(f->IpWaitList, i);
\r
939 if (p->Expire <= Tick64())
\r
943 o = NewListFast(NULL);
\r
952 for (i = 0;i < LIST_NUM(o);i++)
\r
954 L3PACKET *p = LIST_DATA(o, i);
\r
956 Delete(f->IpWaitList, p);
\r
958 Free(p->Packet->PacketData);
\r
959 FreePacket(p->Packet);
\r
968 void L3PollingBeacon(L3IF *f)
\r
976 if (f->LastBeaconSent == 0 ||
\r
977 (f->LastBeaconSent + BEACON_SEND_INTERVAL) <= Tick64())
\r
985 static char beacon_str[] =
\r
986 "SoftEther UT-VPN Virtual Layer-3 Switch Beacon";
\r
989 dest_ip = (f->IpAddress & f->SubnetMask) | (~f->SubnetMask);
\r
990 udp_buf_size = sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + sizeof(beacon_str);
\r
991 udp_buf = ZeroMalloc(udp_buf_size);
\r
993 ip = (IPV4_HEADER *)udp_buf;
\r
994 udp = (UDP_HEADER *)(udp_buf + sizeof(IPV4_HEADER));
\r
995 udp->DstPort = Endian16(7);
\r
996 udp->SrcPort = Endian16(7);
\r
997 udp->PacketLength = Endian16(sizeof(UDP_HEADER) + sizeof(beacon_str));
\r
999 Copy(udp_buf + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER), beacon_str, sizeof(beacon_str));
\r
1001 udp->Checksum = IpChecksum(udp, sizeof(UDP_HEADER) + sizeof(beacon_str));
\r
1003 ip->DstIP = dest_ip;
\r
1004 IPV4_SET_VERSION(ip, 4);
\r
1005 IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
\r
1006 ip->TypeOfService = DEFAULT_IP_TOS;
\r
1007 ip->TotalLength = Endian16((USHORT)(udp_buf_size));
\r
1008 ip->TimeToLive = DEFAULT_IP_TTL;
\r
1009 ip->Protocol = IP_PROTO_UDP;
\r
1010 ip->SrcIP = f->IpAddress;
\r
1011 ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
\r
1013 L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_IPV4, udp_buf, udp_buf_size);
\r
1018 arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
\r
1019 arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
\r
1020 arp.HardwareSize = 6;
\r
1021 arp.ProtocolSize = 4;
\r
1022 arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
\r
1023 Copy(arp.SrcAddress, f->MacAddress, 6);
\r
1024 arp.SrcIP = f->IpAddress;
\r
1025 arp.TargetAddress[0] =
\r
1026 arp.TargetAddress[1] =
\r
1027 arp.TargetAddress[2] =
\r
1028 arp.TargetAddress[3] =
\r
1029 arp.TargetAddress[4] =
\r
1030 arp.TargetAddress[5] = 0xff;
\r
1031 arp.TargetIP = dest_ip;
\r
1034 L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
\r
1036 f->LastBeaconSent = Tick64();
\r
1041 void L3Polling(L3IF *f)
\r
1052 // ポーリング処理の途中ではスイッチ全体にロックをかける
\r
1056 L3PollingBeacon(f);
\r
1059 L3PollingIpQueue(f);
\r
1062 L3DeleteOldArpTable(f);
\r
1064 // ARP 解決待ちリストのポーリング
\r
1065 L3PollingArpWaitTable(f);
\r
1068 L3DeleteOldIpWaitList(f);
\r
1074 UINT L3GetNextPacket(L3IF *f, void **data)
\r
1078 if (f == NULL || data == NULL)
\r
1085 LockQueue(f->SendQueue);
\r
1087 PKT *p = GetNext(f->SendQueue);
\r
1092 ret = p->PacketSize;
\r
1093 *data = p->PacketData;
\r
1098 UnlockQueue(f->SendQueue);
\r
1105 // ポーリング処理の結果、新たにパケットがキューに入っていないか
\r
1107 if (f->SendQueue->num_item != 0)
\r
1109 // キューに入っていたら早速そのパケットを取得させる
\r
1117 // 指定した IP アドレス宛のパケットをどのインターフェイスに投げれば良いか決める
\r
1118 L3IF *L3GetNextIf(L3SW *s, UINT ip, UINT *next_hop)
\r
1122 UINT next_hop_ip = 0;
\r
1124 if (s == NULL || ip == 0 || ip == 0xffffffff)
\r
1131 // まず各インターフェイスの所属しているネットワークに指定した IP アドレスが
\r
1132 // 含まれるものが無いかどうか調べる
\r
1133 for (i = 0;i < LIST_NUM(s->IfList);i++)
\r
1135 L3IF *ff = LIST_DATA(s->IfList, i);
\r
1137 if ((ff->IpAddress & ff->SubnetMask) == (ip & ff->SubnetMask))
\r
1147 // 見つからなかったらルーティングテーブルを探す
\r
1148 L3TABLE *t = L3GetBestRoute(s, ip);
\r
1157 // 見つかったルートの NextHop のルータの IP アドレスを持つ
\r
1159 for (i = 0;i < LIST_NUM(s->IfList);i++)
\r
1161 L3IF *ff = LIST_DATA(s->IfList, i);
\r
1163 if ((ff->IpAddress & ff->SubnetMask) == (t->GatewayAddress & ff->SubnetMask))
\r
1166 next_hop_ip = t->GatewayAddress;
\r
1175 // 結局宛先インターフェイスが不明であった
\r
1179 if (next_hop != NULL)
\r
1181 *next_hop = next_hop_ip;
\r
1187 // 指定した IP アドレス宛の最適なルーティングテーブルエントリを取得する
\r
1188 L3TABLE *L3GetBestRoute(L3SW *s, UINT ip)
\r
1191 UINT max_mask = 0;
\r
1192 UINT min_metric = INFINITE;
\r
1193 L3TABLE *ret = NULL;
\r
1195 if (s == NULL || ip == 0)
\r
1200 // 第一条件: サブネットマスクが最も大きいものを選択
\r
1201 // 第二条件: メトリックが最も小さいものを選択
\r
1202 for (i = 0;i < LIST_NUM(s->TableList);i++)
\r
1204 L3TABLE *t = LIST_DATA(s->TableList, i);
\r
1206 if ((t->NetworkAddress & t->SubnetMask) == (ip & t->SubnetMask))
\r
1208 if (t->SubnetMask >= max_mask)
\r
1210 max_mask = t->SubnetMask;
\r
1211 if (min_metric >= t->Metric)
\r
1213 min_metric = t->Metric;
\r
1223 // Layer-3 インターフェイスの初期化
\r
1224 void L3InitInterface(L3IF *f)
\r
1233 L3GenerateMacAddress(f);
\r
1236 f->ArpTable = NewList(CmpL3ArpEntry);
\r
1237 f->ArpWaitTable = NewList(CmpL3ArpWaitTable);
\r
1238 f->IpPacketQueue = NewQueue();
\r
1239 f->IpWaitList = NewList(NULL);
\r
1240 f->SendQueue = NewQueue();
\r
1243 // Layer-3 インターフェイスの解放
\r
1244 void L3FreeInterface(L3IF *f)
\r
1255 for (i = 0;i < LIST_NUM(f->ArpTable);i++)
\r
1257 L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);
\r
1260 ReleaseList(f->ArpTable);
\r
1261 f->ArpTable = NULL;
\r
1263 for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)
\r
1265 L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);
\r
1268 ReleaseList(f->ArpWaitTable);
\r
1269 f->ArpWaitTable = NULL;
\r
1271 while (p = GetNext(f->IpPacketQueue))
\r
1273 Free(p->Packet->PacketData);
\r
1274 FreePacket(p->Packet);
\r
1277 ReleaseQueue(f->IpPacketQueue);
\r
1278 f->IpPacketQueue = NULL;
\r
1280 for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
\r
1282 L3PACKET *p = LIST_DATA(f->IpWaitList, i);
\r
1283 Free(p->Packet->PacketData);
\r
1284 FreePacket(p->Packet);
\r
1287 ReleaseList(f->IpWaitList);
\r
1288 f->IpWaitList = NULL;
\r
1290 while (pkt = GetNext(f->SendQueue))
\r
1292 Free(pkt->PacketData);
\r
1295 ReleaseQueue(f->SendQueue);
\r
1296 f->SendQueue = NULL;
\r
1299 // Layer-3 インターフェイスのスレッド
\r
1300 void L3IfThread(THREAD *t, void *param)
\r
1306 char tmp[MAX_SIZE];
\r
1307 char name[MAX_SIZE];
\r
1308 char username[MAX_SIZE];
\r
1310 if (t == NULL || param == NULL)
\r
1315 f = (L3IF *)param;
\r
1317 StrCpy(username, sizeof(username), L3_USERNAME);
\r
1318 if (f->Switch != NULL)
\r
1320 StrCat(username, sizeof(username), f->Switch->Name);
\r
1324 c = NewServerConnection(f->Switch->Cedar, NULL, t);
\r
1325 c->Protocol = CONNECTION_HUB_LAYER3;
\r
1328 policy = ClonePolicy(GetDefaultPolicy());
\r
1329 // ポリシーではブロードキャスト数を制限しない
\r
1330 policy->NoBroadcastLimiter = true;
\r
1331 s = NewServerSession(f->Switch->Cedar, c, f->Hub, username, policy);
\r
1334 ReleaseConnection(c);
\r
1337 GetMachineHostName(tmp, sizeof(tmp));
\r
1338 if (f->Switch->Cedar->Server->ServerType == SERVER_TYPE_STANDALONE)
\r
1340 Format(name, sizeof(name), "SID-L3-%s-%u", f->Switch->Name, Inc(f->Hub->SessionCounter));
\r
1344 Format(name, sizeof(name), "SID-L3-%s-%s-%u", tmp, f->Switch->Name, Inc(f->Hub->SessionCounter));
\r
1346 ConvertSafeFileName(name, sizeof(name), name);
\r
1350 s->Name = CopyStr(name);
\r
1352 s->L3SwitchMode = true;
\r
1355 if (s->Username != NULL)
\r
1357 Free(s->Username);
\r
1359 s->Username = CopyStr(username);
\r
1361 StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username);
\r
1367 NoticeThreadInit(t);
\r
1373 ReleaseSession(s);
\r
1376 // すべての Layer-3 インターフェイスの初期化をする
\r
1377 void L3InitAllInterfaces(L3SW *s)
\r
1386 for (i = 0;i < LIST_NUM(s->IfList);i++)
\r
1388 L3IF *f = LIST_DATA(s->IfList, i);
\r
1391 L3InitInterface(f);
\r
1393 f->Hub = GetHub(s->Cedar, f->HubName);
\r
1394 t = NewThread(L3IfThread, f);
\r
1395 WaitThreadInit(t);
\r
1400 // すべての Layer-3 インターフェイスの解放をする
\r
1401 void L3FreeAllInterfaces(L3SW *s)
\r
1410 for (i = 0;i < LIST_NUM(s->IfList);i++)
\r
1412 L3IF *f = LIST_DATA(s->IfList, i);
\r
1414 ReleaseHub(f->Hub);
\r
1416 ReleaseSession(f->Session);
\r
1417 f->Session = NULL;
\r
1419 L3FreeInterface(f);
\r
1424 void L3Test(SERVER *s)
\r
1426 L3SW *ss = L3AddSw(s->Cedar, "TEST");
\r
1427 L3AddIf(ss, "DEFAULT", 0x0101a8c0, 0x00ffffff);
\r
1428 L3AddIf(ss, "DEFAULT2", 0x0102a8c0, 0x00ffffff);
\r
1433 // Layer-3 スイッチスレッド
\r
1434 void L3SwThread(THREAD *t, void *param)
\r
1437 bool shutdown_now = false;
\r
1439 if (t == NULL || param == NULL)
\r
1444 s = (L3SW *)param;
\r
1448 NoticeThreadInit(t);
\r
1451 SLog(s->Cedar, "L3_SWITCH_START", s->Name);
\r
1453 while (s->Halt == false)
\r
1455 if (s->Online == false)
\r
1457 // 現在 L3 スイッチはオフラインなので、一定時間ごとにオンライン化
\r
1459 LockList(s->Cedar->HubList);
\r
1465 bool all_exists = true;
\r
1466 if (LIST_NUM(s->IfList) == 0)
\r
1468 // 1 つもインターフェイスが無い場合は動作しない
\r
1469 all_exists = false;
\r
1471 for (i = 0;i < LIST_NUM(s->IfList);i++)
\r
1473 L3IF *f = LIST_DATA(s->IfList, i);
\r
1474 HUB *h = GetHub(s->Cedar, f->HubName);
\r
1478 if (h->Offline || h->Type == HUB_TYPE_FARM_DYNAMIC)
\r
1480 all_exists = false;
\r
1490 all_exists = false;
\r
1494 if (all_exists && n >= 1)
\r
1496 // すべてのインターフェイスの仮想 HUB が有効になったので
\r
1498 SLog(s->Cedar, "L3_SWITCH_ONLINE", s->Name);
\r
1499 L3InitAllInterfaces(s);
\r
1505 UnlockList(s->Cedar->HubList);
\r
1509 // 一定時間ごとにすべてのセッションが終了していないかどうか調査する
\r
1511 bool any_halted = false;
\r
1518 for (i = 0;i < LIST_NUM(s->IfList);i++)
\r
1520 L3IF *f = LIST_DATA(s->IfList, i);
\r
1521 if (f->Session->Halt || f->Hub->Offline != false)
\r
1523 any_halted = true;
\r
1530 any_halted = true;
\r
1535 SLog(s->Cedar, "L3_SWITCH_OFFLINE", s->Name);
\r
1536 o = NewListFast(NULL);
\r
1537 // 1 つでも終了したセッションがあれば、すべてのセッションを終了する
\r
1538 for (i = 0;i < LIST_NUM(s->IfList);i++)
\r
1540 L3IF *f = LIST_DATA(s->IfList, i);
\r
1541 Insert(o, f->Session);
\r
1545 s->Online = false;
\r
1553 for (i = 0;i < LIST_NUM(o);i++)
\r
1555 SESSION *s = LIST_DATA(o, i);
\r
1558 L3FreeAllInterfaces(s);
\r
1567 if (s->Online != false)
\r
1569 shutdown_now = true;
\r
1574 SLog(s->Cedar, "L3_SWITCH_STOP", s->Name);
\r
1577 // Layer-3 スイッチを開始する
\r
1578 void L3SwStart(L3SW *s)
\r
1588 if (s->Active == false)
\r
1590 // 登録されている IF 数が 1 以上でないと開始しない
\r
1591 if (LIST_NUM(s->IfList) >= 1)
\r
1596 s->Thread = NewThread(L3SwThread, s);
\r
1597 WaitThreadInit(s->Thread);
\r
1604 // Layer-3 スイッチを停止する
\r
1605 void L3SwStop(L3SW *s)
\r
1616 if (s->Active == false)
\r
1626 s->Active = false;
\r
1630 WaitThread(t, INFINITE);
\r
1634 // Layer-3 スイッチを追加する
\r
1635 L3SW *L3AddSw(CEDAR *c, char *name)
\r
1639 if (c == NULL || name == NULL)
\r
1644 LockList(c->L3SwList);
\r
1646 s = L3GetSw(c, name);
\r
1650 s = NewL3Sw(c, name);
\r
1652 Insert(c->L3SwList, s);
\r
1662 UnlockList(c->L3SwList);
\r
1667 // Layer-3 スイッチを削除する
\r
1668 bool L3DelSw(CEDAR *c, char *name)
\r
1673 if (c == NULL || name == NULL)
\r
1678 LockList(c->L3SwList);
\r
1680 s = L3GetSw(c, name);
\r
1686 Delete(c->L3SwList, s);
\r
1693 UnlockList(c->L3SwList);
\r
1700 bool L3DelTable(L3SW *s, L3TABLE *tbl)
\r
1704 if (s == NULL || tbl == NULL)
\r
1711 if (s->Active == false)
\r
1713 L3TABLE *t = Search(s->TableList, tbl);
\r
1717 Delete(s->TableList, t);
\r
1730 bool L3AddTable(L3SW *s, L3TABLE *tbl)
\r
1734 if (s == NULL || tbl == NULL)
\r
1739 if (tbl->Metric == 0 || tbl->GatewayAddress == 0 || tbl->GatewayAddress == 0xffffffff)
\r
1746 if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_table"))
\r
1753 if (s->Active == false)
\r
1755 if (Search(s->TableList, tbl) == NULL)
\r
1757 L3TABLE *t = ZeroMalloc(sizeof(L3TABLE));
\r
1759 Copy(t, tbl, sizeof(L3TABLE));
\r
1761 Insert(s->TableList, t);
\r
1774 L3SW *L3GetSw(CEDAR *c, char *name)
\r
1778 if (c == NULL || name == NULL)
\r
1783 Zero(&t, sizeof(t));
\r
1784 StrCpy(t.Name, sizeof(t.Name), name);
\r
1786 LockList(c->L3SwList);
\r
1788 s = Search(c->L3SwList, &t);
\r
1790 UnlockList(c->L3SwList);
\r
1800 // L3 スイッチから指定した仮想 HUB に接続されているインターフェイスを取得する
\r
1801 L3IF *L3SearchIf(L3SW *s, char *hubname)
\r
1805 if (s == NULL || hubname == NULL)
\r
1810 Zero(&t, sizeof(t));
\r
1811 StrCpy(t.HubName, sizeof(t.HubName), hubname);
\r
1813 f = Search(s->IfList, &t);
\r
1819 bool L3DelIf(L3SW *s, char *hubname)
\r
1824 if (s == NULL || hubname == NULL)
\r
1831 if (s->Active == false)
\r
1833 f = L3SearchIf(s, hubname);
\r
1838 Delete(s->IfList, f);
\r
1851 bool L3AddIf(L3SW *s, char *hubname, UINT ip, UINT subnet)
\r
1856 if (s == NULL || hubname == NULL || IsSafeStr(hubname) == false ||
\r
1857 ip == 0 || ip == 0xffffffff)
\r
1864 if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_if"))
\r
1870 if (s->Active == false)
\r
1872 // 同じ仮想 HUB にすでにインターフェイスが入っていないかどうか調べる
\r
1873 if (L3SearchIf(s, hubname) == NULL)
\r
1876 f = ZeroMalloc(sizeof(L3IF));
\r
1879 StrCpy(f->HubName, sizeof(f->HubName), hubname);
\r
1880 f->IpAddress = ip;
\r
1881 f->SubnetMask = subnet;
\r
1883 Insert(s->IfList, f);
\r
1895 // L3 スイッチのクリーンアップ
\r
1896 void CleanupL3Sw(L3SW *s)
\r
1905 for (i = 0;i < LIST_NUM(s->IfList);i++)
\r
1907 L3IF *f = LIST_DATA(s->IfList, i);
\r
1910 ReleaseList(s->IfList);
\r
1912 for (i = 0;i < LIST_NUM(s->TableList);i++)
\r
1914 L3TABLE *t = LIST_DATA(s->TableList, i);
\r
1917 ReleaseList(s->TableList);
\r
1919 DeleteLock(s->lock);
\r
1924 void ReleaseL3Sw(L3SW *s)
\r
1932 if (Release(s->ref) == 0)
\r
1938 // 新しい L3 スイッチを作成する
\r
1939 L3SW *NewL3Sw(CEDAR *c, char *name)
\r
1943 if (c == NULL || name == NULL)
\r
1948 o = ZeroMalloc(sizeof(L3SW));
\r
1950 StrCpy(o->Name, sizeof(o->Name), name);
\r
1952 o->lock = NewLock();
\r
1953 o->ref = NewRef();
\r
1955 o->Active = false;
\r
1957 o->IfList = NewList(CmpL3If);
\r
1958 o->TableList = NewList(CmpL3Table);
\r
1963 // Cedar にあるすべての L3 スイッチを停止する
\r
1964 void L3FreeAllSw(CEDAR *c)
\r
1974 o = NewListFast(NULL);
\r
1976 LockList(c->L3SwList);
\r
1978 for (i = 0;i < LIST_NUM(c->L3SwList);i++)
\r
1980 L3SW *s = LIST_DATA(c->L3SwList, i);
\r
1981 Insert(o, CopyStr(s->Name));
\r
1984 for (i = 0;i < LIST_NUM(o);i++)
\r
1986 char *name = LIST_DATA(o, i);
\r
1995 UnlockList(c->L3SwList);
\r
1998 // Cedar の L3 スイッチ機能を停止する
\r
1999 void FreeCedarLayer3(CEDAR *c)
\r
2007 ReleaseList(c->L3SwList);
\r
2008 c->L3SwList = NULL;
\r
2011 // Cedar の L3 スイッチ機能を開始する
\r
2012 void InitCedarLayer3(CEDAR *c)
\r
2020 c->L3SwList = NewList(CmpL3Sw);
\r
2024 int CmpL3If(void *p1, void *p2)
\r
2027 if (p1 == NULL || p2 == NULL)
\r
2031 f1 = *(L3IF **)p1;
\r
2032 f2 = *(L3IF **)p2;
\r
2033 if (f1 == NULL || f2 == NULL)
\r
2038 return StrCmpi(f1->HubName, f2->HubName);
\r
2042 int CmpL3Table(void *p1, void *p2)
\r
2045 if (p1 == NULL || p2 == NULL)
\r
2049 t1 = *(L3TABLE **)p1;
\r
2050 t2 = *(L3TABLE **)p2;
\r
2051 if (t1 == NULL || t2 == NULL)
\r
2056 if (t1->NetworkAddress > t2->NetworkAddress)
\r
2060 else if (t1->NetworkAddress < t2->NetworkAddress)
\r
2064 else if (t1->SubnetMask > t2->SubnetMask)
\r
2068 else if (t1->SubnetMask < t2->SubnetMask)
\r
2072 else if (t1->GatewayAddress > t2->GatewayAddress)
\r
2076 else if (t1->GatewayAddress < t2->GatewayAddress)
\r
2080 else if (t1->Metric > t2->Metric)
\r
2084 else if (t1->Metric < t2->Metric)
\r
2095 int CmpL3Sw(void *p1, void *p2)
\r
2098 if (p1 == NULL || p2 == NULL)
\r
2102 s1 = *(L3SW **)p1;
\r
2103 s2 = *(L3SW **)p2;
\r
2104 if (s1 == NULL || s2 == NULL)
\r
2109 return StrCmpi(s1->Name, s2->Name);
\r
2113 int CmpL3ArpWaitTable(void *p1, void *p2)
\r
2115 L3ARPWAIT *w1, *w2;
\r
2116 if (p1 == NULL || p2 == NULL)
\r
2120 w1 = *(L3ARPWAIT **)p1;
\r
2121 w2 = *(L3ARPWAIT **)p2;
\r
2122 if (w1 == NULL || w2 == NULL)
\r
2126 if (w1->IpAddress > w2->IpAddress)
\r
2130 else if (w1->IpAddress < w2->IpAddress)
\r
2141 int CmpL3ArpEntry(void *p1, void *p2)
\r
2143 L3ARPENTRY *e1, *e2;
\r
2144 if (p1 == NULL || p2 == NULL)
\r
2148 e1 = *(L3ARPENTRY **)p1;
\r
2149 e2 = *(L3ARPENTRY **)p2;
\r
2150 if (e1 == NULL || e2 == NULL)
\r
2154 if (e1->IpAddress > e2->IpAddress)
\r
2158 else if (e1->IpAddress < e2->IpAddress)
\r