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 // ユーザーモード仮想ホストプログラム
\r
81 // Q. このプログラムには大変多くの TCP/IP 関係の奥の深い処理が入っていて
\r
82 // さらに TCP スタックの簡易的な実装まで完結しているように見えるが
\r
83 // なぜこのように気合の入ったコードを書いたのか?
\r
84 // A. 作者の所属していた筑波大学第三学群情報学類という学科では、
\r
85 // 「情報特別演習」という授業がある。なんとこれは専門基礎単位を取得
\r
86 // することができる貴重なコマである。専門基礎単位を取得するための他の
\r
87 // 方法としては、解析学Ⅲなどという授業等がある。しかし、作者は受験勉強
\r
88 // のような数学のテスト勉強は嫌いであるし、また、SoftEther に関する打ち合わせ
\r
89 // のために大学の某所に駐車したときにその解析学Ⅲの当時の担当教員の車のミラー
\r
90 // をこすってしまって少し怒られたのでその単位の取得は難しくなった (?) のである。
\r
91 // だが、専門基礎の単位を取得しなければ、卒業することができない。
\r
92 // そこで代わりに「情報特別演習」で単位をとることにしたのだが、この授業は、
\r
93 // 何か面白いコンピュータの作品を作ってプレゼンテーションすれば 2 単位がくる
\r
94 // という名目なのであった。しかし、実際のところ、ろくな作品を 1 年間で
\r
95 // 作ってプレゼンする人はとても少なく、たいていが「無線 LAN の実験」とか
\r
96 // そういうほとんどクリエイティブな作業を必要とせずにできるいいかげんな
\r
97 // 「実習」を行ったと言って結果を報告すれば 2 単位来るという程度の難易度
\r
99 // 作者は大変真面目なので、部類としてはかなり難しい難易度に入る TCP/IP
\r
100 // スタックの開発を実習としてやってみようと思い、数週間かけていろいろ
\r
101 // プログラムを書いた。その成果の一部がこの Virtual.c というコードである。
\r
102 // 逆にいうと、大学の授業の実習程度で開発することができるくらいの簡単な
\r
103 // プログラムなので、実装は簡易的であり、効率が悪く、メンテナンス性にも欠け
\r
104 // ている。結構場当たり的なプログラミングを行ったためである。
\r
105 // それでも 2004 年末に本プログラムをインターネットで配布してから今まで
\r
106 // 一応は深刻な不具合は発生していない。ただし探せば深刻な障害が潜んでいる
\r
110 #include "CedarPch.h"
\r
112 static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
\r
114 // Virtual Host のログをとる
\r
115 void VLog(VH *v, char *str)
\r
121 // NAT が使用可能かどうかチェック
\r
122 bool CanCreateNewNatEntry(VH *v)
\r
130 if (v->UseNat == false)
\r
136 if (v->NatTable->num_item > NAT_MAX_SESSIONS)
\r
145 // NAT 処理スレッドのメイン関数
\r
146 void NatThreadMain(VH *v)
\r
155 v->TmpBuf = Malloc(NAT_TMPBUF_SIZE);
\r
159 // 次のイベントがセットされるまで待機する
\r
160 WaitSockEvent(v->SockEvent, SELECT_TIME);
\r
166 // すべての NAT セッションに対して処理を行う
\r
170 v->NatDoCancelFlag = false;
\r
172 LIST_ELEMENT_DELETED:
\r
173 num = LIST_NUM(v->NatTable);
\r
174 for (i = 0;i < num;i++)
\r
176 NAT_ENTRY *n = LIST_DATA(v->NatTable, i);
\r
178 switch (n->Protocol)
\r
180 case NAT_TCP: // TCP
\r
181 if (NatTransactTcp(v, n) == false)
\r
183 goto LIST_ELEMENT_DELETED;
\r
187 case NAT_UDP: // UDP
\r
188 if (NatTransactUdp(v, n) == false)
\r
190 goto LIST_ELEMENT_DELETED;
\r
194 case NAT_DNS: // DNS
\r
195 if (NatTransactDns(v, n) == false)
\r
197 goto LIST_ELEMENT_DELETED;
\r
203 if (v->NatDoCancelFlag)
\r
205 // 親スレッドの Cancel を叩く
\r
219 // すべてのエントリを強制切断してからスレッドを終了する
\r
222 UINT num = LIST_NUM(v->NatTable);
\r
223 NAT_ENTRY **nn = ToArray(v->NatTable);
\r
226 for (i = 0;i < num;i++)
\r
228 NAT_ENTRY *n = nn[i];
\r
229 n->DisconnectNow = true;
\r
231 switch (n->Protocol)
\r
233 case NAT_TCP: // TCP
\r
234 NatTransactTcp(v, n);
\r
237 case NAT_UDP: // UDP
\r
238 NatTransactUdp(v, n);
\r
241 case NAT_DNS: // DNS
\r
242 NatTransactDns(v, n);
\r
257 // DNS: IP アドレスを取得するスレッド
\r
258 void NatGetIPThread(THREAD *t, void *param)
\r
262 if (t == NULL || param == NULL)
\r
267 q = (NAT_DNS_QUERY *)param;
\r
270 q->Ok = GetIP(&q->Ip, q->Hostname);
\r
274 if (Release(q->ref) == 0)
\r
280 // DNS: ホスト名から IP アドレスを取得する
\r
281 bool NatGetIP(IP *ip, char *hostname)
\r
286 if (ip == NULL || hostname == NULL)
\r
291 t = ParseToken(hostname, ".");
\r
296 if (t->NumTokens == 0)
\r
302 if (t->NumTokens == 1)
\r
304 ret = GetIP(ip, hostname);
\r
308 char *hostname2 = t->Token[0];
\r
309 NAT_DNS_QUERY *q1, *q2;
\r
312 q1 = ZeroMalloc(sizeof(NAT_DNS_QUERY));
\r
313 q2 = ZeroMalloc(sizeof(NAT_DNS_QUERY));
\r
314 q1->ref = NewRef();
\r
315 q2->ref = NewRef();
\r
318 StrCpy(q1->Hostname, sizeof(q1->Hostname), hostname);
\r
319 StrCpy(q2->Hostname, sizeof(q2->Hostname), hostname2);
\r
321 t1 = NewThread(NatGetIPThread, q1);
\r
322 t2 = NewThread(NatGetIPThread, q2);
\r
324 WaitThread(t1, NAT_DNS_QUERY_TIMEOUT);
\r
329 Copy(ip, &q1->Ip, sizeof(IP));
\r
333 WaitThread(t2, NAT_DNS_QUERY_TIMEOUT);
\r
337 Copy(ip, &q1->Ip, sizeof(IP));
\r
342 Copy(ip, &q2->Ip, sizeof(IP));
\r
349 if (Release(q1->ref) == 0)
\r
353 if (Release(q2->ref) == 0)
\r
365 void NatDnsThread(THREAD *t, void *param)
\r
370 if (t == NULL || param == NULL)
\r
374 n = (NAT_ENTRY *)param;
\r
377 NoticeThreadInit(t);
\r
380 if (EndWith(n->DnsTargetHostName, ".in-addr.arpa") == false)
\r
383 if (NatGetIP(&ip, n->DnsTargetHostName))
\r
386 Copy(&n->DnsResponseIp, &ip, sizeof(IP));
\r
394 n->DnsGetIpFromHost = true; // 逆引きフラグを設定
\r
395 // *.in-addr.arpa 文字列を IP アドレスに変換してもらう
\r
396 if (ArpaToIP(&ip, n->DnsTargetHostName))
\r
400 if (GetHostName(tmp, sizeof(tmp), &ip))
\r
403 n->DnsResponseHostName = CopyStr(tmp);
\r
410 n->DnsFinished = true;
\r
412 SetSockEvent(n->v->SockEvent);
\r
415 // 逆引き用アドレスを IP アドレスに変換する
\r
416 bool ArpaToIP(IP *ip, char *str)
\r
421 if (ip == NULL || str == NULL)
\r
427 token = ParseToken(str, ".");
\r
428 if (token->NumTokens == 6)
\r
430 // token[0, 1, 2, 3] を IP に変換
\r
432 Zero(ip, sizeof(IP));
\r
433 for (i = 0;i < 4;i++)
\r
435 ip->addr[i] = (UCHAR)ToInt(token->Token[3 - i]);
\r
442 if (IPToUINT(ip) == 0)
\r
451 bool NatTransactDns(VH *v, NAT_ENTRY *n)
\r
454 if (v == NULL || n == NULL)
\r
459 if (n->DisconnectNow)
\r
464 if (n->DnsThread == NULL && n->DnsFinished == false)
\r
467 THREAD *t = NewThread(NatDnsThread, (void *)n);
\r
474 if (n->DnsFinished)
\r
477 WaitThread(n->DnsThread, INFINITE);
\r
478 ReleaseThread(n->DnsThread);
\r
479 n->DnsThread = NULL;
\r
481 v->NatDoCancelFlag = true;
\r
490 if (n->DnsThread != NULL)
\r
492 WaitThread(n->DnsThread, INFINITE);
\r
493 ReleaseThread(n->DnsThread);
\r
494 n->DnsThread = NULL;
\r
497 if (n->DnsTargetHostName != NULL)
\r
499 Free(n->DnsTargetHostName);
\r
500 n->DnsTargetHostName = NULL;
\r
503 if (n->DnsResponseHostName != NULL)
\r
505 Free(n->DnsResponseHostName);
\r
506 n->DnsResponseHostName = NULL;
\r
509 DeleteLock(n->lock);
\r
510 Delete(v->NatTable, n);
\r
517 bool NatTransactUdp(VH *v, NAT_ENTRY *n)
\r
522 UINT dest_port = n->DestPort;
\r
525 if (v == NULL || n == NULL)
\r
530 if (n->DisconnectNow)
\r
535 if (n->UdpSocketCreated == false)
\r
538 n->Sock = NewUDP(0);
\r
539 if (n->Sock == NULL)
\r
546 n->PublicIp = IPToUINT(&n->Sock->LocalIP);
\r
547 n->PublicPort = n->Sock->LocalPort;
\r
549 JoinSockToSockEvent(n->Sock, v->SockEvent);
\r
550 n->UdpSocketCreated = true;
\r
555 if (n->ProxyDns == false)
\r
557 UINTToIP(&dest_ip, n->DestIp);
\r
561 UINTToIP(&dest_ip, n->DestIpProxy);
\r
564 // UDP ソケットからデータを受信してみる
\r
569 recv_size = RecvFrom(n->Sock, &src_ip, &src_port, buf, 65536);
\r
571 if (recv_size == SOCK_LATER)
\r
576 else if (recv_size == 0)
\r
579 if (n->Sock->IgnoreRecvErr == false)
\r
587 // パケットが届いた。送信元 IP をチェック
\r
588 if (IPToUINT(&src_ip) == n->DestIp || (IPToUINT(&src_ip) == n->DestIpProxy && n->ProxyDns) && src_port == n->DestPort)
\r
591 void *data = Malloc(recv_size);
\r
592 Copy(data, buf, recv_size);
\r
593 block = NewBlock(data, recv_size, 0);
\r
594 InsertQueue(n->UdpRecvQueue, block);
\r
595 v->NatDoCancelFlag = true;
\r
596 n->LastCommTime = v->Now;
\r
601 // UDP ソケットにデータを送信してみる
\r
602 while (block = GetNext(n->UdpSendQueue))
\r
604 UINT send_size = SendTo(n->Sock, &dest_ip, dest_port, block->Buf, block->Size);
\r
607 if (send_size == 0)
\r
610 if (n->Sock->IgnoreSendErr == false)
\r
618 n->LastCommTime = v->Now;
\r
622 // このセッションがタイムアウトになっていないかどうか調べる
\r
623 if ((n->LastCommTime + (UINT64)v->NatUdpTimeout) < v->Now || n->LastCommTime > v->Now)
\r
633 if (n->UdpSocketCreated)
\r
636 Disconnect(n->Sock);
\r
637 ReleaseSock(n->Sock);
\r
642 DeleteNatUdp(v, n);
\r
647 // TCP ホストへの接続処理を行うためのスレッド
\r
648 void NatTcpConnectThread(THREAD *t, void *p)
\r
650 NAT_ENTRY *n = (NAT_ENTRY *)p;
\r
652 char hostname[MAX_SIZE];
\r
657 if (n == NULL || t == NULL)
\r
662 UINTToIP(&ip, n->DestIp);
\r
663 IPToStr(hostname, sizeof(hostname), &ip);
\r
664 port_number = n->DestPort;
\r
665 e = n->v->SockEvent;
\r
669 NoticeThreadInit(t);
\r
672 Debug("NatTcpConnect Connecting to %s:%u\n", hostname, port_number);
\r
673 sock = Connect(hostname, port_number);
\r
677 n->TcpMakeConnectionFailed = true;
\r
682 n->TcpMakeConnectionSucceed = true;
\r
685 JoinSockToSockEvent(sock, e);
\r
688 ReleaseSockEvent(e);
\r
691 // TCP ホストに接続するためのスレッドを作成する
\r
692 void CreateNatTcpConnectThread(VH *v, NAT_ENTRY *n)
\r
695 if (v == NULL || n == NULL)
\r
701 n->NatTcpConnectThread = NewThread(NatTcpConnectThread, (void *)n);
\r
704 WaitThreadInit(n->NatTcpConnectThread);
\r
708 bool NatTransactTcp(VH *v, NAT_ENTRY *n)
\r
710 char str[MAX_SIZE];
\r
712 if (v == NULL || n == NULL)
\r
717 if (n->DisconnectNow)
\r
723 switch (n->TcpStatus)
\r
725 case NAT_TCP_CONNECTING: // 接続待機中
\r
726 if (n->NatTcpConnectThread == NULL)
\r
728 // 接続スレッドを作成し接続を開始する
\r
729 CreateNatTcpConnectThread(v, n);
\r
733 // すでに開始されている接続スレッドの結果を待機
\r
734 if (n->TcpMakeConnectionFailed || n->TcpMakeConnectionSucceed)
\r
736 // スレッドの動作はすでに完了しているので結果を使用する
\r
737 WaitThread(n->NatTcpConnectThread, INFINITE);
\r
738 ReleaseThread(n->NatTcpConnectThread);
\r
739 n->NatTcpConnectThread = NULL;
\r
741 if (n->TcpMakeConnectionSucceed)
\r
743 // 接続は成功し Sock が作成された
\r
744 n->TcpStatus = NAT_TCP_CONNECTED;
\r
745 IPToStr32(str, sizeof(str), n->DestIp);
\r
746 NLog(v, "LH_NAT_TCP_SUCCEED", n->Id, n->Sock->RemoteHostname, str, n->DestPort);
\r
751 n->TcpStatus = NAT_TCP_SEND_RESET;
\r
752 IPToStr32(str, sizeof(str), n->DestIp);
\r
753 NLog(v, "LH_NAT_TCP_FAILED", n->Id, str, n->DestPort);
\r
755 v->NatDoCancelFlag = true;
\r
760 case NAT_TCP_CONNECTED: // TCP ソケット接続完了 クライアントホストとの間で交渉中
\r
763 case NAT_TCP_SEND_RESET: // TCP 通信切断 クライアントホストへ RST を送信
\r
766 case NAT_TCP_ESTABLISHED: // TCP 接続確立済み
\r
768 // 受信バッファにデータがあればソケットに対して送信する
\r
769 while (n->RecvFifo->size > 0)
\r
771 UINT sent_size = Send(n->Sock, ((UCHAR *)n->RecvFifo->p) + n->RecvFifo->pos,
\r
772 n->RecvFifo->size, false);
\r
773 if (sent_size == 0)
\r
776 n->TcpFinished = true;
\r
777 v->NatDoCancelFlag = true;
\r
780 else if (sent_size == SOCK_LATER)
\r
788 ReadFifo(n->RecvFifo, NULL, sent_size);
\r
789 n->SendAckNext = true;
\r
792 // ソケットからデータを取得して送信バッファに書き込む
\r
795 void *buf = (void *)v->TmpBuf;
\r
796 UINT want_to_recv_size = 0;
\r
799 if (n->SendFifo->size < NAT_SEND_BUF_SIZE)
\r
802 want_to_recv_size = MIN(NAT_SEND_BUF_SIZE - n->SendFifo->size, NAT_TMPBUF_SIZE);
\r
804 if (want_to_recv_size == 0)
\r
808 recv_size = Recv(n->Sock, buf, want_to_recv_size, false);
\r
809 if (recv_size == 0)
\r
812 n->TcpFinished = true;
\r
813 v->NatDoCancelFlag = true;
\r
816 else if (recv_size == SOCK_LATER)
\r
824 WriteFifo(n->SendFifo, buf, recv_size);
\r
825 v->NatDoCancelFlag = true;
\r
834 if ((n->LastCommTime + (UINT64)v->NatTcpTimeout) < v->Now || n->LastCommTime > v->Now)
\r
836 // タイムアウトが発生、セッション切断
\r
837 n->TcpStatus = NAT_TCP_SEND_RESET;
\r
838 v->NatDoCancelFlag = true;
\r
843 DISCONNECT: // 切断とセッション廃棄処理
\r
844 DeleteNatTcp(v, n);
\r
850 void DeleteNatTcp(VH *v, NAT_ENTRY *n)
\r
853 if (v == NULL || n == NULL)
\r
858 NLog(v, "LH_NAT_TCP_DELETED", n->Id);
\r
861 if (n->NatTcpConnectThread != NULL)
\r
863 WaitThread(n->NatTcpConnectThread, INFINITE);
\r
864 ReleaseThread(n->NatTcpConnectThread);
\r
865 n->NatTcpConnectThread = NULL;
\r
867 if (n->Sock != NULL)
\r
870 Disconnect(n->Sock);
\r
871 ReleaseSock(n->Sock);
\r
876 if (n->TcpRecvWindow != NULL)
\r
878 ReleaseFifo(n->TcpRecvWindow);
\r
879 n->TcpRecvWindow = NULL;
\r
883 if (n->TcpRecvList != NULL)
\r
886 for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
\r
888 IP_PART *p = LIST_DATA(n->TcpRecvList, i);
\r
891 ReleaseList(n->TcpRecvList);
\r
892 n->TcpRecvList = NULL;
\r
896 ReleaseFifo(n->SendFifo);
\r
897 ReleaseFifo(n->RecvFifo);
\r
900 Delete(v->NatTable, n);
\r
902 DeleteLock(n->lock);
\r
907 Debug("NAT_ENTRY: DeleteNatTcp\n");
\r
911 void NatThread(THREAD *t, void *param)
\r
914 if (t == NULL || param == NULL)
\r
920 NoticeThreadInit(t);
\r
922 NatThreadMain((VH *)param);
\r
926 void SendBeacon(VH *v)
\r
930 static char beacon_str[] =
\r
931 "SecureNAT Virtual TCP/IP Stack Beacon";
\r
939 dest_ip = (v->HostIP & v->HostMask) | (~v->HostMask);
\r
940 SendUdp(v, dest_ip, 7, v->HostIP, 7, beacon_str, sizeof(beacon_str));
\r
943 arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
\r
944 arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
\r
945 arp.HardwareSize = 6;
\r
946 arp.ProtocolSize = 4;
\r
947 arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
\r
948 Copy(arp.SrcAddress, v->MacAddress, 6);
\r
949 arp.SrcIP = v->HostIP;
\r
950 arp.TargetAddress[0] =
\r
951 arp.TargetAddress[1] =
\r
952 arp.TargetAddress[2] =
\r
953 arp.TargetAddress[3] =
\r
954 arp.TargetAddress[4] =
\r
955 arp.TargetAddress[5] = 0xff;
\r
956 arp.TargetIP = dest_ip;
\r
959 VirtualLayer2Send(v, broadcast, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
\r
963 void SendTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss, void *data, UINT size)
\r
965 static UCHAR tcp_mss_option[] = {0x02, 0x04, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00};
\r
966 TCPV4_PSEUDO_HEADER *vh;
\r
968 UINT header_size = TCP_HEADER_SIZE;
\r
971 if (v == NULL || (size != 0 && data == NULL))
\r
977 vh = Malloc(sizeof(TCPV4_PSEUDO_HEADER) + TCP_HEADER_SIZE + size + 32);
\r
978 tcp = (TCP_HEADER *)(((UCHAR *)vh) + sizeof(TCPV4_PSEUDO_HEADER));
\r
983 mss_size = (USHORT *)(&tcp_mss_option[2]);
\r
984 *mss_size = Endian16((USHORT)mss);
\r
985 header_size += sizeof(tcp_mss_option);
\r
988 total_size = header_size + size;
\r
989 if (total_size > 65536)
\r
997 vh->SrcIP = src_ip;
\r
998 vh->DstIP = dest_ip;
\r
1000 vh->Protocol = IP_PROTO_TCP;
\r
1001 vh->PacketLength = Endian16((USHORT)total_size);
\r
1004 tcp->SrcPort = Endian16((USHORT)src_port);
\r
1005 tcp->DstPort = Endian16((USHORT)dest_port);
\r
1006 tcp->SeqNumber = Endian32(seq);
\r
1007 tcp->AckNumber = Endian32(ack);
\r
1008 tcp->HeaderSizeAndReserved = 0;
\r
1009 TCP_SET_HEADER_SIZE(tcp, (UCHAR)(header_size / 4));
\r
1010 tcp->Flag = (UCHAR)flag;
\r
1011 tcp->WindowSize = Endian16((USHORT)window_size);
\r
1012 tcp->Checksum = 0;
\r
1013 tcp->UrgentPointer = 0;
\r
1018 Copy(((UCHAR *)tcp) + TCP_HEADER_SIZE, tcp_mss_option, sizeof(tcp_mss_option));
\r
1022 Copy(((UCHAR *)tcp) + header_size, data, size);
\r
1025 tcp->Checksum = IpChecksum(vh, total_size + 12);
\r
1028 SendIp(v, dest_ip, src_ip, IP_PROTO_TCP, tcp, total_size);
\r
1035 void PollingNatTcp(VH *v, NAT_ENTRY *n)
\r
1038 if (v == NULL || n == NULL)
\r
1043 switch (n->TcpStatus)
\r
1045 case NAT_TCP_CONNECTING: // ソケット接続中: 何もしない
\r
1048 case NAT_TCP_CONNECTED: // ソケット接続が完了した SYN+ACK, ACK 処理
\r
1049 if ((n->LastSynAckSentTime > v->Now) || n->LastSynAckSentTime == 0 || ((n->LastSynAckSentTime + (UINT64)(NAT_TCP_SYNACK_SEND_TIMEOUT * (UINT64)(n->SynAckSentCount + 1)) <= v->Now)))
\r
1051 n->LastSynAckSentTime = v->Now;
\r
1053 SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
\r
1054 (UINT)(n->SendSeqInit + n->SendSeq),
\r
1055 (UINT)(n->RecvSeqInit + n->RecvSeq),
\r
1056 TCP_SYN | TCP_ACK, n->TcpRecvWindowSize,
\r
1057 v->TcpMss, NULL, 0);
\r
1058 n->SynAckSentCount++;
\r
1062 case NAT_TCP_SEND_RESET: // コネクションのリセット
\r
1064 if (n->TcpFinished == false)
\r
1066 SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
\r
1067 (UINT)(n->SendSeq + n->SendSeqInit),
\r
1068 (UINT)(n->SendSeq + n->SendSeqInit),
\r
1072 n->TcpStatus = NAT_TCP_WAIT_DISCONNECT;
\r
1073 n->DisconnectNow = true;
\r
1077 // 合計 NAT_FIN_SEND_MAX_COUNT 回の FIN を送信する
\r
1078 if (n->FinSentTime == 0 || (n->FinSentTime > v->Now) || (n->FinSentTime + NAT_FIN_SEND_INTERVAL * (n->FinSentCount + 1)) < v->Now)
\r
1080 SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
\r
1081 (UINT)(n->SendSeq + n->SendSeqInit),
\r
1082 (UINT)(n->RecvSeq + n->RecvSeqInit),
\r
1083 TCP_ACK | TCP_FIN, 0,
\r
1085 n->FinSentTime = v->Now;
\r
1086 n->FinSentCount++;
\r
1087 if (n->FinSentCount >= NAT_FIN_SEND_MAX_COUNT)
\r
1089 n->TcpFinished = false;
\r
1095 case NAT_TCP_ESTABLISHED: // 接続確立済み
\r
1097 UINT send_data_size;
\r
1098 UINT current_pointer;
\r
1099 UINT notice_window_size_value = 0;
\r
1100 UINT buf_free_bytes = 0;
\r
1101 // 通知するウインドウサイズの値を決定する
\r
1102 if (FifoSize(n->RecvFifo) < NAT_RECV_BUF_SIZE)
\r
1104 buf_free_bytes = NAT_RECV_BUF_SIZE - FifoSize(n->RecvFifo);
\r
1106 notice_window_size_value = MIN(n->TcpRecvWindowSize, buf_free_bytes);
\r
1107 if (n->LastSentKeepAliveTime == 0 ||
\r
1108 (n->LastSentKeepAliveTime + (UINT64)NAT_ACK_KEEPALIVE_SPAN) < v->Now ||
\r
1109 (n->LastSentKeepAliveTime > v->Now))
\r
1111 if (n->LastSentKeepAliveTime != 0)
\r
1113 // Keep-Alive 用 ACK パケットの送信
\r
1114 SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
\r
1115 (UINT)(n->SendSeqInit + n->SendSeq),
\r
1116 (UINT)(n->RecvSeqInit + n->RecvSeq) - 1,
\r
1118 notice_window_size_value,
\r
1123 n->LastSentKeepAliveTime = v->Now;
\r
1125 if (n->TcpLastSentTime == 0 ||
\r
1126 (n->TcpLastSentTime > v->Now) ||
\r
1127 ((n->TcpLastSentTime + (UINT64)n->TcpSendTimeoutSpan) < v->Now) ||
\r
1130 // 送信すべきデータがある場合は送信する
\r
1131 // 送信すべきセグメントサイズを計算する
\r
1132 send_data_size = n->TcpSendWindowSize;
\r
1133 if (send_data_size > (n->TcpSendCWnd * n->TcpSendMaxSegmentSize))
\r
1136 send_data_size = n->TcpSendCWnd * n->TcpSendMaxSegmentSize;
\r
1138 if (send_data_size > n->SendFifo->size)
\r
1140 // 現在保有しているデータ以上は送れない
\r
1141 send_data_size = n->SendFifo->size;
\r
1143 if (send_data_size >= 1)
\r
1146 current_pointer = 0;
\r
1147 while (send_data_size > 0)
\r
1149 UINT send_segment_size = MIN(n->TcpSendMaxSegmentSize, send_data_size);
\r
1150 void *send_segment = (void *)(((UCHAR *)n->SendFifo->p) + n->SendFifo->pos + current_pointer);
\r
1151 SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
\r
1152 (UINT)(n->SendSeqInit + n->SendSeq + (UINT64)current_pointer),
\r
1153 (UINT)(n->RecvSeqInit + n->RecvSeq),
\r
1154 TCP_ACK | TCP_PSH,
\r
1155 notice_window_size_value,
\r
1158 send_segment_size);
\r
1159 current_pointer += send_segment_size;
\r
1160 send_data_size -= send_segment_size;
\r
1163 n->TcpLastSentTime = v->Now;
\r
1164 // 今回送信するストリームサイズを記録する
\r
1165 n->SendMissionSize = current_pointer;
\r
1166 n->CurrentSendingMission = true;
\r
1168 if (n->CalcRTTStartTime == 0)
\r
1170 n->CalcRTTStartTime = v->Now;
\r
1171 n->CalcRTTStartValue = n->SendSeq + current_pointer - 1;
\r
1173 if (n->RetransmissionUsedFlag == false)
\r
1175 n->RetransmissionUsedFlag = true;
\r
1180 if (n->TcpSendCWnd > 2)
\r
1186 else if (n->SendAckNext)
\r
1189 SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
\r
1190 (UINT)(n->SendSeqInit + n->SendSeq),
\r
1191 (UINT)(n->RecvSeqInit + n->RecvSeq),
\r
1193 notice_window_size_value,
\r
1198 n->SendAckNext = false;
\r
1200 if (n->TcpFinished)
\r
1202 // すべてのデータ送信が完了していたら切断する
\r
1203 if (n->SendFifo->size == 0)
\r
1205 n->TcpStatus = NAT_TCP_SEND_RESET;
\r
1213 // インターネットへ向かう TCP パケットの受信処理
\r
1214 void TcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *tcp, void *data, UINT size)
\r
1218 UINT64 seq64 = 0, ack64 = 0;
\r
1220 if (v == NULL || tcp == NULL || data == NULL)
\r
1225 // このパケットに関するセッションを NAT テーブルから検索
\r
1226 SetNat(&t, NAT_TCP, src_ip, src_port, dest_ip, dest_port, 0, 0);
\r
1227 n = SearchNat(v, &t);
\r
1232 // SYN パケットのみ通過を許可する
\r
1233 if ((tcp->Flag & TCP_SYN) && ((tcp->Flag & TCP_ACK) == false))
\r
1237 n = CreateNatTcp(v, src_ip, src_port, dest_ip, dest_port);
\r
1244 ParseTcpOption(&o, ((UCHAR *)tcp) + TCP_HEADER_SIZE, TCP_GET_HEADER_SIZE(tcp) * 4 - TCP_HEADER_SIZE);
\r
1245 if (o.MaxSegmentSize == 0)
\r
1247 o.MaxSegmentSize = v->TcpMss;
\r
1250 Debug("TCP SYN: MSS=%u, WS=%u\n", o.MaxSegmentSize, o.WindowScaling);
\r
1253 n->RecvSeqInit = (UINT64)Endian32(tcp->SeqNumber);
\r
1256 n->TcpSendMaxSegmentSize = o.MaxSegmentSize;
\r
1257 n->TcpRecvWindowSize = NAT_TCP_RECV_WINDOW_SIZE;
\r
1258 n->TcpSendWindowSize = (UINT)Endian16(tcp->WindowSize);
\r
1259 if (o.WindowScaling != 0)
\r
1261 if (o.WindowScaling > 14)
\r
1263 o.WindowScaling = 14;
\r
1265 n->TcpSendWindowSize = (n->TcpSendWindowSize << o.WindowScaling);
\r
1270 seq = Endian32(tcp->SeqNumber);
\r
1271 ack = Endian32(tcp->AckNumber);
\r
1275 // NAT エントリに登録されていないパケットが届いたので RST を返す
\r
1276 SendTcp(v, dest_ip, dest_port, src_ip, src_port,
\r
1277 ack, ack, TCP_RST, 0, 0, NULL, 0);
\r
1281 switch (n->TcpStatus)
\r
1283 case NAT_TCP_SEND_RESET: // リセットを送信してコネクションを切断
\r
1286 case NAT_TCP_CONNECTED: // ソケット接続完了 SYN+ACK, ACK 処理
\r
1287 if ((tcp->Flag & TCP_ACK) && ((tcp->Flag & TCP_SYN) == false))
\r
1289 if (seq == (UINT)(n->RecvSeqInit + n->RecvSeq) &&
\r
1290 ack == (UINT)(n->SendSeqInit + n->SendSeq + 1))
\r
1292 // ACK パケットが戻ってきたのでハンドシェイク完了
\r
1293 n->SendSeq++; // SYN パケットは seq を 1 消費する
\r
1294 Debug("TCP Connection Established.\n");
\r
1295 n->TcpStatus = NAT_TCP_ESTABLISHED;
\r
1297 n->TcpSendCWnd = 1;
\r
1298 n->LastCommTime = v->Now;
\r
1305 else if (tcp->Flag & TCP_RST)
\r
1309 Debug("TCP Connection Reseted.\n");
\r
1310 n->TcpStatus = NAT_TCP_SEND_RESET;
\r
1314 case NAT_TCP_ESTABLISHED: // 接続確立済み
\r
1315 if (tcp->Flag & TCP_FIN)
\r
1318 n->TcpFinished = true;
\r
1320 if (tcp->Flag & TCP_RST)
\r
1325 else if (tcp->Flag & TCP_ACK)
\r
1328 n->LastCommTime = v->Now;
\r
1329 // ウインドウサイズなどのオプションの取得
\r
1330 n->TcpSendWindowSize = Endian16(tcp->WindowSize);
\r
1331 ParseTcpOption(&opt, ((UCHAR *)tcp) + TCP_HEADER_SIZE, TCP_GET_HEADER_SIZE(tcp) * 4 - TCP_HEADER_SIZE);
\r
1332 if (opt.WindowScaling != 0)
\r
1334 if (opt.WindowScaling > 14)
\r
1336 opt.WindowScaling = 14;
\r
1338 n->TcpSendWindowSize = (n->TcpSendWindowSize << opt.WindowScaling);
\r
1340 // まず受信した ACK の処理を行う
\r
1341 // ack64 に応答確認を受けたストリームの終端位置を格納する
\r
1342 ack64 = n->SendSeq + (UINT64)ack - (n->SendSeqInit + n->SendSeq) % X32;
\r
1343 if ((n->SendSeqInit + n->SendSeq) % X32 > ack)
\r
1345 if (((n->SendSeqInit + n->SendSeq) % X32 - ack) >= 0x80000000)
\r
1347 ack64 = n->SendSeq + (UINT64)ack + X32 - (n->SendSeqInit + n->SendSeq) % X32;
\r
1350 if (ack64 > n->SendSeq)
\r
1352 // クライアントによって 1 バイト以上の受信が完了したらしい
\r
1353 UINT slide_offset = (UINT)(ack64 - n->SendSeq); // ウインドウのスライド量
\r
1354 if (slide_offset == 0 || slide_offset > n->TcpSendWindowSize || slide_offset > n->SendFifo->size)
\r
1356 // 確認応答のオフセット値がこれまでに送信したはずのサイズ
\r
1362 if (n->CalcRTTStartTime != 0)
\r
1364 if (n->CalcRTTStartValue < ack64)
\r
1367 if (v->Now > n->CalcRTTStartTime)
\r
1369 time_span = (UINT)(v->Now - n->CalcRTTStartTime);
\r
1375 n->CalcRTTStartTime = 0;
\r
1381 ((UINT64)n->CurrentRTT * (UINT64)9 +
\r
1382 (UINT64)time_span * (UINT64)1) / (UINT64)10
\r
1384 n->TcpSendTimeoutSpan = n->CurrentRTT * 2;
\r
1388 n->SendMissionSize -= slide_offset;
\r
1389 if (n->SendMissionSize == 0)
\r
1391 // 今回送信する予定であったすべてのセグメントの送受信が完了した
\r
1392 // より送信セグメントサイズを大きくしてみる
\r
1393 if (n->TcpSendCWnd < 65536)
\r
1397 n->CurrentSendingMission = false;
\r
1398 n->TcpLastSentTime = 0;
\r
1399 n->RetransmissionUsedFlag = false;
\r
1402 n->SendSeq += slide_offset;
\r
1403 ReadFifo(n->SendFifo, NULL, slide_offset);
\r
1404 // 今回 ACK によって送信完了が確認できたサイズだけ、さらに送信を実行する
\r
1405 if (n->SendMissionSize != 0 && false)
\r
1407 UINT notice_window_size_value = 0;
\r
1408 UINT send_data_size;
\r
1409 UINT buf_free_bytes;
\r
1410 UINT send_offset = n->SendMissionSize;
\r
1411 // 通知するウインドウサイズの値を決定する
\r
1412 if (FifoSize(n->RecvFifo) < NAT_RECV_BUF_SIZE)
\r
1414 buf_free_bytes = NAT_RECV_BUF_SIZE - FifoSize(n->RecvFifo);
\r
1416 notice_window_size_value = MIN(n->TcpRecvWindowSize, buf_free_bytes);
\r
1417 // 送信すべきセグメントサイズを計算する
\r
1418 send_data_size = n->TcpSendWindowSize;
\r
1419 if (send_data_size > (n->TcpSendCWnd * n->TcpSendMaxSegmentSize))
\r
1422 send_data_size = n->TcpSendCWnd * n->TcpSendMaxSegmentSize;
\r
1424 if (n->SendFifo->size > send_offset)
\r
1426 send_data_size = MIN(send_data_size, n->SendFifo->size - send_offset);
\r
1427 send_data_size = MIN(send_data_size, slide_offset);
\r
1431 send_data_size = 0;
\r
1433 if (send_data_size >= 1)
\r
1436 UINT current_pointer = 0;
\r
1437 while (send_data_size > 0)
\r
1439 UINT send_segment_size = MIN(n->TcpSendMaxSegmentSize, send_data_size);
\r
1440 void *send_segment = (void *)((
\r
1441 (UCHAR *)n->SendFifo->p) + n->SendFifo->pos +
\r
1442 current_pointer + send_offset);
\r
1444 SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
\r
1445 (UINT)(n->SendSeqInit + n->SendSeq + (UINT64)current_pointer
\r
1446 + (UINT)send_offset),
\r
1447 (UINT)(n->RecvSeqInit + n->RecvSeq),
\r
1448 TCP_ACK | TCP_PSH,
\r
1449 notice_window_size_value,
\r
1452 send_segment_size);
\r
1453 current_pointer += send_segment_size;
\r
1454 send_data_size -= send_segment_size;
\r
1456 n->SendMissionSize += current_pointer;
\r
1457 n->CurrentSendingMission = true;
\r
1458 n->TcpLastSentTime = v->Now;
\r
1460 if (n->CalcRTTStartTime == 0)
\r
1462 n->CalcRTTStartTime = v->Now;
\r
1463 n->CalcRTTStartValue = n->SendSeq + current_pointer - 1;
\r
1468 SetSockEvent(v->SockEvent);
\r
1472 seq64 = n->RecvSeq + (UINT64)seq - (n->RecvSeqInit + n->RecvSeq) % X32;
\r
1473 if ((n->RecvSeqInit + n->RecvSeq) % X32 > seq)
\r
1475 if (((n->RecvSeqInit + n->RecvSeq) % X32 - ack) >= 0x80000000)
\r
1477 seq64 = n->RecvSeq + (UINT64)seq + X32 - (n->RecvSeqInit + n->RecvSeq) % X32;
\r
1480 // この時点で seq64 にはクライアントからのデータ開始点の位置が入っている
\r
1481 if (seq64 >= n->RecvSeq && (seq64 + size) <= (n->RecvSeq + n->TcpRecvWindowSize))
\r
1485 // 受信ウインドウの範囲内に 1 バイト以上のデータが届いた
\r
1486 UINT offset = (UINT)(seq64 - n->RecvSeq);
\r
1489 if (n->TcpRecvWindow == NULL)
\r
1491 n->TcpRecvWindow = NewFifo();
\r
1493 if (n->TcpRecvList == NULL)
\r
1495 n->TcpRecvList = NewListFast(NULL);
\r
1497 // 届いたパケットをバッファに上書きしリストに追加する
\r
1498 if (FifoSize(n->TcpRecvWindow) < (offset + size))
\r
1501 WriteFifo(n->TcpRecvWindow, NULL, offset + size - FifoSize(n->TcpRecvWindow));
\r
1503 Copy(((UCHAR *)n->TcpRecvWindow->p) + n->TcpRecvWindow->pos +
\r
1504 offset, data, size);
\r
1505 me = ZeroMalloc(sizeof(IP_PART));
\r
1506 me->Offset = offset;
\r
1508 for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
\r
1510 IP_PART *p = LIST_DATA(n->TcpRecvList, i);
\r
1511 // 重なる領域があれば重なっている部分があれば除去する
\r
1514 if (me->Offset <= p->Offset && (me->Offset + me->Size) >= (p->Offset + p->Size))
\r
1516 // このパケットが既存パケットを完全に上書きする
\r
1519 else if (me->Offset >= p->Offset && (me->Offset + me->Size) <= (p->Offset + p->Size))
\r
1521 // 既存パケットがこのパケットを完全に上書きする
\r
1524 else if (me->Offset > p->Offset && me->Offset < (p->Offset + p->Size) &&
\r
1525 (me->Offset + me->Size) > (p->Offset + p->Size))
\r
1528 p->Size -= p->Offset + p->Size - me->Offset;
\r
1530 else if (me->Offset < p->Offset && (me->Offset + size) > p->Offset && (me->Offset + size) < (p->Offset + p->Size))
\r
1533 me->Size -= me->Offset + me->Size - p->Offset;
\r
1537 if (me->Size == 0)
\r
1543 Add(n->TcpRecvList, me);
\r
1546 // 受信リストから中身が空白のものをすべて削除する
\r
1547 for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
\r
1549 IP_PART *p = LIST_DATA(n->TcpRecvList, i);
\r
1552 Delete(n->TcpRecvList, p);
\r
1554 goto KILL_NULL_FIRST;
\r
1558 // 受信リストのうちオフセット 0 から始まるものがあれば抽出する
\r
1559 for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
\r
1561 IP_PART *p = LIST_DATA(n->TcpRecvList, i);
\r
1563 if (p->Offset == 0)
\r
1565 // 0 から始まるデータブロックを発見したので
\r
1566 // この分だけ左側にスライドさせてデータを抜き出す
\r
1567 // バッファを FIFO に書き出す
\r
1569 WriteFifo(n->RecvFifo, ((UCHAR *)n->TcpRecvWindow->p) + n->TcpRecvWindow->pos, sz);
\r
1571 Delete(n->TcpRecvList, p);
\r
1573 ReadFifo(n->TcpRecvWindow, NULL, sz);
\r
1574 // すべての項目を左側にスライドする
\r
1575 for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
\r
1577 p = LIST_DATA(n->TcpRecvList, i);
\r
1581 n->RecvSeq += (UINT64)sz;
\r
1582 SetSockEvent(v->SockEvent);
\r
1583 n->SendAckNext = true;
\r
1594 SetSockEvent(v->SockEvent);
\r
1598 void ParseTcpOption(TCP_OPTION *o, void *data, UINT size)
\r
1600 UCHAR *buf = (UCHAR *)data;
\r
1602 UINT value_size = 0;
\r
1603 UINT value_id = 0;
\r
1606 if (o == NULL || data == NULL)
\r
1611 Zero(o, sizeof(TCP_OPTION));
\r
1613 for (i = 0;i < size;i++)
\r
1621 value_id = buf[i];
\r
1627 value_size = buf[i];
\r
1628 if (value_size <= 1 || value_size > sizeof(value))
\r
1638 Copy(value, &buf[i], value_size);
\r
1647 if (value_size == 2)
\r
1649 USHORT *mss = (USHORT *)value;
\r
1650 o->MaxSegmentSize = Endian16(*mss);
\r
1655 if (value_size == 1)
\r
1657 UCHAR *wss = (UCHAR *)value;
\r
1658 o->WindowScaling = Endian16(*wss);
\r
1668 // 新しい NAT TCP セッションの作成
\r
1669 NAT_ENTRY *CreateNatTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port)
\r
1678 if (CanCreateNewNatEntry(v) == false)
\r
1684 n = ZeroMalloc(sizeof(NAT_ENTRY));
\r
1685 n->Id = Inc(v->Counter);
\r
1687 n->lock = NewLock();
\r
1688 n->Protocol = NAT_TCP;
\r
1689 n->SrcIp = src_ip;
\r
1690 n->SrcPort = src_port;
\r
1691 n->DestIp = dest_ip;
\r
1692 n->DestPort = dest_port;
\r
1693 n->CreatedTime = n->LastCommTime = v->Now;
\r
1695 n->DisconnectNow = false;
\r
1696 n->TcpSendMaxSegmentSize = n->TcpRecvMaxSegmentSize = v->TcpMss;
\r
1698 n->SendFifo = NewFifo();
\r
1699 n->RecvFifo = NewFifo();
\r
1701 n->TcpStatus = NAT_TCP_CONNECTING;
\r
1703 n->SendSeqInit = Rand32();
\r
1704 n->CurrentRTT = NAT_INITIAL_RTT_VALUE;
\r
1705 n->TcpSendTimeoutSpan = n->CurrentRTT * 2;
\r
1708 Add(v->NatTable, n);
\r
1714 char s1[MAX_SIZE], s2[MAX_SIZE];
\r
1715 UINTToIP(&ip1, src_ip);
\r
1716 UINTToIP(&ip2, dest_ip);
\r
1717 IPToStr(s1, 0, &ip1);
\r
1718 IPToStr(s2, 0, &ip2);
\r
1719 Debug("NAT_ENTRY: CreateNatTcp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
\r
1721 NLog(v, "LH_NAT_TCP_CREATED", n->Id, s1, src_port, s2, dest_port);
\r
1728 // TCP パケットを仮想ネットワークから受信した
\r
1729 void VirtualTcpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size)
\r
1732 UINT src_port, dest_port;
\r
1733 UINT header_size, buf_size;
\r
1737 if (v == NULL || data == NULL)
\r
1743 if (size < TCP_HEADER_SIZE)
\r
1748 tcp = (TCP_HEADER *)data;
\r
1749 src_port = Endian16(tcp->SrcPort);
\r
1750 dest_port = Endian16(tcp->DstPort);
\r
1751 if (src_port == 0 || dest_port == 0)
\r
1756 if (src_ip == dest_ip || src_ip == 0 || src_ip == 0xffffffff || dest_ip == 0 || dest_ip == 0xffffffff)
\r
1761 UINTToIP(&ip1, src_ip);
\r
1762 UINTToIP(&ip2, dest_ip);
\r
1763 if (ip1.addr[0] == 127 || ip2.addr[0] == 127)
\r
1765 // ループバック IP アドレスは指定できない
\r
1768 if (IsInNetwork(dest_ip, v->HostIP, v->HostMask))
\r
1770 // 仮想 LAN 側のネットワーク向けのパケットは無視する
\r
1774 header_size = TCP_GET_HEADER_SIZE(tcp) * 4;
\r
1775 if (size < header_size)
\r
1780 // バッファのサイズとアドレスを取得
\r
1781 buf_size = size - header_size;
\r
1782 buf = (void *)(((UCHAR *)data) + header_size);
\r
1784 TcpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, tcp, buf, buf_size);
\r
1788 void PoolingNatUdp(VH *v, NAT_ENTRY *n)
\r
1791 if (v == NULL || n == NULL)
\r
1796 // 受信キューにパケットが 1 つ以上あれば処理する
\r
1797 if (n->UdpRecvQueue->num_item != 0)
\r
1801 // すべての UDP パケットを仮想ネットワークに送信する
\r
1802 while (block = GetNext(n->UdpRecvQueue))
\r
1804 SendUdp(v, n->SrcIp, n->SrcPort, n->DestIp, n->DestPort,
\r
1805 block->Buf, block->Size);
\r
1813 void PoolingNat(VH *v)
\r
1822 // すべての NAT エントリを走査し処理を行う
\r
1823 for (i = 0;i < LIST_NUM(v->NatTable);i++)
\r
1825 NAT_ENTRY *n = LIST_DATA(v->NatTable, i);
\r
1827 switch (n->Protocol)
\r
1830 PollingNatTcp(v, n);
\r
1834 PoolingNatUdp(v, n);
\r
1838 PollingNatDns(v, n);
\r
1845 int CompareNat(void *p1, void *p2)
\r
1847 NAT_ENTRY *n1, *n2;
\r
1848 if (p1 == NULL || p2 == NULL)
\r
1852 n1 = *(NAT_ENTRY **)p1;
\r
1853 n2 = *(NAT_ENTRY **)p2;
\r
1859 if (n1->SrcIp > n2->SrcIp) return 1;
\r
1860 else if (n1->SrcIp < n2->SrcIp) return -1;
\r
1861 else if (n1->DestIp > n2->DestIp) return 1;
\r
1862 else if (n1->DestIp < n2->DestIp) return -1;
\r
1863 else if (n1->SrcPort > n2->SrcPort) return 1;
\r
1864 else if (n1->SrcPort < n2->SrcPort) return -1;
\r
1865 else if (n1->DestPort > n2->DestPort) return 1;
\r
1866 else if (n1->DestPort < n2->DestPort) return -1;
\r
1867 else if (n1->Protocol > n2->Protocol) return 1;
\r
1868 else if (n1->Protocol < n2->Protocol) return -1;
\r
1873 void SetNat(NAT_ENTRY *n, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT public_ip, UINT public_port)
\r
1881 n->Protocol = protocol;
\r
1882 n->SrcIp = src_ip;
\r
1883 n->SrcPort = src_port;
\r
1884 n->DestIp = dest_ip;
\r
1885 n->DestPort = dest_port;
\r
1886 n->PublicIp = public_ip;
\r
1887 n->PublicPort = public_port;
\r
1891 void InitNat(VH *v)
\r
1900 v->NatTable = NewList(CompareNat);
\r
1903 v->SockEvent = NewSockEvent();
\r
1906 v->HaltNat = false;
\r
1907 v->NatThread = NewThread(NatThread, (void *)v);
\r
1908 WaitThreadInit(v->NatThread);
\r
1912 void FreeNat(VH *v)
\r
1921 v->HaltNat = true;
\r
1922 SetSockEvent(v->SockEvent);
\r
1923 WaitThread(v->NatThread, INFINITE);
\r
1924 ReleaseThread(v->NatThread);
\r
1925 v->NatThread = NULL;
\r
1926 ReleaseSockEvent(v->SockEvent);
\r
1927 v->SockEvent = NULL;
\r
1930 ReleaseList(v->NatTable);
\r
1934 NAT_ENTRY *SearchNat(VH *v, NAT_ENTRY *target)
\r
1938 if (v == NULL || target == NULL)
\r
1944 n = (NAT_ENTRY *)Search(v->NatTable, target);
\r
1949 // UDP NAT エントリの削除
\r
1950 void DeleteNatUdp(VH *v, NAT_ENTRY *n)
\r
1954 if (v == NULL || n == NULL)
\r
1959 NLog(v, "LH_NAT_UDP_DELETED", n->Id);
\r
1962 while (block = GetNext(n->UdpRecvQueue))
\r
1966 ReleaseQueue(n->UdpRecvQueue);
\r
1967 while (block = GetNext(n->UdpSendQueue))
\r
1971 ReleaseQueue(n->UdpSendQueue);
\r
1974 if (n->Sock != NULL)
\r
1976 Disconnect(n->Sock);
\r
1977 ReleaseSock(n->Sock);
\r
1981 DeleteLock(n->lock);
\r
1984 Delete(v->NatTable, n);
\r
1989 Debug("NAT: DeleteNatUdp\n");
\r
1993 // NAT UDP エントリを作成
\r
1994 NAT_ENTRY *CreateNatUdp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT dns_proxy_ip)
\r
2003 if (CanCreateNewNatEntry(v) == false)
\r
2008 n = ZeroMalloc(sizeof(NAT_ENTRY));
\r
2009 n->Id = Inc(v->Counter);
\r
2011 n->lock = NewLock();
\r
2012 n->Protocol = NAT_UDP;
\r
2013 n->SrcIp = src_ip;
\r
2014 n->SrcPort = src_port;
\r
2015 n->DestIp = dest_ip;
\r
2016 n->DestPort = dest_port;
\r
2018 if (dns_proxy_ip != 0)
\r
2020 n->ProxyDns = true;
\r
2021 n->DestIpProxy = dns_proxy_ip;
\r
2024 n->CreatedTime = n->LastCommTime = v->Now;
\r
2026 n->UdpSendQueue = NewQueue();
\r
2027 n->UdpRecvQueue = NewQueue();
\r
2029 n->UdpSocketCreated = false;
\r
2031 SetSockEvent(v->SockEvent);
\r
2036 char s1[MAX_SIZE], s2[MAX_SIZE];
\r
2037 UINTToIP(&ip1, src_ip);
\r
2038 UINTToIP(&ip2, dest_ip);
\r
2039 IPToStr(s1, 0, &ip1);
\r
2040 IPToStr(s2, 0, &ip2);
\r
2041 Debug("NAT_ENTRY: CreateNatUdp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
\r
2043 NLog(v, "LH_NAT_UDP_CREATED", n->Id, s1, src_port, s2, dest_port);
\r
2047 Add(v->NatTable, n);
\r
2052 // インターネットへの UDP パケットの処理
\r
2053 void UdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy)
\r
2060 if (data == NULL || v == NULL)
\r
2067 // プロキシ接続先の DNS サーバーを取得する
\r
2069 char tmp[MAX_SIZE];
\r
2070 if (GetDefaultDns(&ip) == false)
\r
2073 Debug("Failed to GetDefaultDns()\n");
\r
2076 dns_ip = IPToUINT(&ip);
\r
2077 IPToStr(tmp, sizeof(tmp), &ip);
\r
2078 Debug("Redirect to DNS Server %s\n", tmp);
\r
2081 // このパケットに関する NAT エントリがすでに作成されているかどうかを調べる
\r
2082 SetNat(&t, NAT_UDP, src_ip, src_port, dest_ip, dest_port, 0, 0);
\r
2083 n = SearchNat(v, &t);
\r
2087 // 最初のパケットなので NAT エントリを作成する
\r
2088 n = CreateNatUdp(v, src_ip, src_port, dest_ip, dest_port, dns_proxy ? dns_ip : 0);
\r
2097 n->ProxyDns = true;
\r
2098 n->DestIpProxy = dns_ip;
\r
2102 // キューにパケットを挿入してイベントを呼び出す
\r
2103 buf = Malloc(size);
\r
2104 Copy(buf, data, size);
\r
2105 block = NewBlock(buf, size, 0);
\r
2106 InsertQueue(n->UdpSendQueue, block);
\r
2108 SetSockEvent(v->SockEvent);
\r
2111 // DNS パケットの解釈を試行する
\r
2112 bool ParseDnsPacket(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
\r
2114 DNSV4_HEADER *dns;
\r
2116 UINT transaction_id;
\r
2118 UINT query_data_size;
\r
2119 char hostname[256];
\r
2121 if (v == NULL || data == NULL || size == 0)
\r
2127 if (size < sizeof(DNSV4_HEADER))
\r
2134 dns = (DNSV4_HEADER *)data;
\r
2135 transaction_id = Endian16(dns->TransactionId);
\r
2136 if ((dns->Flag1 & 78) != 0 || (dns->Flag1 & 0x80) != 0)
\r
2141 if (Endian16(dns->NumQuery) != 1)
\r
2147 query_data = ((UCHAR *)dns) + sizeof(DNSV4_HEADER);
\r
2148 query_data_size = size - sizeof(DNSV4_HEADER);
\r
2151 if (ParseDnsQuery(hostname, sizeof(hostname), query_data, query_data_size) == false)
\r
2158 nat = CreateNatDns(v, src_ip, src_port, dest_ip, dest_port, transaction_id,
\r
2169 // NAT DNS 応答パケットの送信
\r
2170 void SendNatDnsResponse(VH *v, NAT_ENTRY *n)
\r
2173 UINT dns_header_size;
\r
2174 DNSV4_HEADER *dns;
\r
2176 if (n == NULL || v == NULL)
\r
2185 if (n->DnsGetIpFromHost == false)
\r
2187 BuildDnsQueryPacket(b, n->DnsTargetHostName, false);
\r
2191 BuildDnsQueryPacket(b, n->DnsTargetHostName, true);
\r
2197 if (n->DnsGetIpFromHost == false)
\r
2199 BuildDnsResponsePacketA(b, &n->DnsResponseIp);
\r
2203 BuildDnsResponsePacketPtr(b, n->DnsResponseHostName);
\r
2208 dns_header_size = sizeof(DNSV4_HEADER) + b->Size;
\r
2210 dns = ZeroMalloc(dns_header_size);
\r
2211 dns->TransactionId = Endian16((USHORT)n->DnsTransactionId);
\r
2216 dns->Flag1 = 0x85;
\r
2217 dns->Flag2 = 0x80;
\r
2221 dns->Flag1 = 0x85;
\r
2222 dns->Flag2 = 0x83;
\r
2225 dns->NumQuery = Endian16(1);
\r
2226 dns->AnswerRRs = Endian16(n->DnsOk != false ? 1 : 0);
\r
2227 dns->AuthorityRRs = 0;
\r
2228 dns->AdditionalRRs = 0;
\r
2231 Copy(((UCHAR *)dns) + sizeof(DNSV4_HEADER), b->Buf, b->Size);
\r
2234 SendUdp(v, n->SrcIp, n->SrcPort, n->DestIp, n->DestPort, dns, dns_header_size);
\r
2241 // DNS 応答パケット (ホスト名) の生成
\r
2242 void BuildDnsResponsePacketPtr(BUF *b, char *hostname)
\r
2245 USHORT type, clas;
\r
2250 if (b == NULL || hostname == NULL)
\r
2255 magic = Endian16(0xc00c);
\r
2256 type = Endian16(0x000c);
\r
2257 clas = Endian16(0x0001);
\r
2258 ttl = Endian32(NAT_DNS_RESPONSE_TTL);
\r
2260 c = BuildDnsHostName(hostname);
\r
2265 len = Endian16((USHORT)c->Size);
\r
2267 WriteBuf(b, &magic, 2);
\r
2268 WriteBuf(b, &type, 2);
\r
2269 WriteBuf(b, &clas, 2);
\r
2270 WriteBuf(b, &ttl, 4);
\r
2271 WriteBuf(b, &len, 2);
\r
2272 WriteBuf(b, c->Buf, c->Size);
\r
2276 // DNS 応答パケット (ホスト IP アドレス) の生成
\r
2277 void BuildDnsResponsePacketA(BUF *b, IP *ip)
\r
2281 USHORT type, clas;
\r
2285 if (b == NULL || ip == NULL)
\r
2290 ip_addr = IPToUINT(ip);
\r
2291 magic = Endian16(0xc00c);
\r
2292 type = Endian16(0x0001);
\r
2293 clas = Endian16(0x0001);
\r
2294 ttl = Endian32(NAT_DNS_RESPONSE_TTL);
\r
2295 len = Endian16((USHORT)sizeof(ttl));
\r
2297 WriteBuf(b, &magic, sizeof(magic));
\r
2298 WriteBuf(b, &type, sizeof(type));
\r
2299 WriteBuf(b, &clas, sizeof(clas));
\r
2300 WriteBuf(b, &ttl, sizeof(ttl));
\r
2301 WriteBuf(b, &len, sizeof(len));
\r
2302 WriteBuf(b, &ip_addr, sizeof(ip_addr));
\r
2305 // DNS クエリデータパケットの生成
\r
2306 void BuildDnsQueryPacket(BUF *b, char *hostname, bool ptr)
\r
2311 if (b == NULL || hostname == NULL)
\r
2317 c = BuildDnsHostName(hostname);
\r
2323 WriteBuf(b, c->Buf, c->Size);
\r
2329 val = Endian16(0x0001);
\r
2333 val = Endian16(0x000c);
\r
2335 WriteBuf(b, &val, 2);
\r
2337 val = Endian16(0x0001);
\r
2338 WriteBuf(b, &val, 2);
\r
2341 // DNS ホスト名バッファの生成
\r
2342 BUF *BuildDnsHostName(char *hostname)
\r
2346 TOKEN_LIST *token;
\r
2349 if (hostname == NULL)
\r
2355 token = ParseToken(hostname, ".");
\r
2356 if (token == NULL)
\r
2364 for (i = 0;i < token->NumTokens;i++)
\r
2366 size = (UCHAR)StrLen(token->Token[i]);
\r
2367 WriteBuf(b, &size, 1);
\r
2368 WriteBuf(b, token->Token[i], size);
\r
2373 WriteBuf(b, &size, 1);
\r
2382 // NAT DNS エントリの処理
\r
2383 void PollingNatDns(VH *v, NAT_ENTRY *n)
\r
2386 if (v == NULL || n == NULL)
\r
2391 if (n->DnsFinished)
\r
2393 if (n->DnsPollingFlag == false)
\r
2395 n->DnsPollingFlag = true;
\r
2397 SendNatDnsResponse(v, n);
\r
2400 n->DisconnectNow = true;
\r
2405 // NAT DNS エントリの作成
\r
2406 NAT_ENTRY *CreateNatDns(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port,
\r
2407 UINT transaction_id, bool dns_get_ip_from_host, char *dns_target_host_name)
\r
2411 if (v == NULL || dns_target_host_name == NULL)
\r
2416 if (CanCreateNewNatEntry(v) == false)
\r
2421 n = ZeroMalloc(sizeof(NAT_ENTRY));
\r
2422 n->Id = Inc(v->Counter);
\r
2424 n->lock = NewLock();
\r
2425 n->Protocol = NAT_DNS;
\r
2426 n->SrcIp = src_ip;
\r
2427 n->SrcPort = src_port;
\r
2428 n->DestIp = dest_ip;
\r
2429 n->DestPort = dest_port;
\r
2430 n->DnsTransactionId = transaction_id;
\r
2431 n->CreatedTime = n->LastCommTime = v->Now;
\r
2432 n->DisconnectNow = false;
\r
2434 n->DnsGetIpFromHost = false;
\r
2435 n->DnsTargetHostName = CopyStr(dns_target_host_name);
\r
2437 Add(v->NatTable, n);
\r
2442 char s1[MAX_SIZE], s2[MAX_SIZE];
\r
2443 UINTToIP(&ip1, src_ip);
\r
2444 UINTToIP(&ip2, dest_ip);
\r
2445 IPToStr(s1, 0, &ip1);
\r
2446 IPToStr(s2, 0, &ip2);
\r
2447 Debug("NAT_ENTRY: CreateNatDns %s %u -> %s %u\n", s1, src_port, s2, dest_port);
\r
2456 UCHAR GetNextByte(BUF *b)
\r
2465 if (ReadBuf(b, &c, 1) != 1)
\r
2474 bool ParseDnsQuery(char *name, UINT name_size, void *data, UINT data_size)
\r
2481 if (name == NULL || data == NULL || data_size == 0)
\r
2485 StrCpy(name, name_size, "");
\r
2488 WriteBuf(b, data, data_size);
\r
2493 UINT next_len = (UINT)GetNextByte(b);
\r
2497 Zero(tmp, sizeof(tmp));
\r
2498 if (ReadBuf(b, tmp, next_len) != next_len)
\r
2504 if (StrLen(name) != 0)
\r
2506 StrCat(name, name_size, ".");
\r
2508 StrCat(name, name_size, tmp);
\r
2517 if (ReadBuf(b, &val, sizeof(val)) != sizeof(val))
\r
2523 if (Endian16(val) != 0x01 && Endian16(val) != 0x0c)
\r
2529 if (ReadBuf(b, &val, sizeof(val)) != sizeof(val))
\r
2535 if (Endian16(val) != 0x01)
\r
2543 if (ok == false || StrLen(name) == 0)
\r
2553 // DNS プロキシとして動作する
\r
2554 void DnsProxy(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
\r
2557 if (v == NULL || data == NULL || size == 0)
\r
2562 // まず DNS クエリを解釈することができるかどうか試してみる
\r
2563 //if (ParseDnsPacket(v, src_ip, src_port, dest_ip, dest_port, data, size) == false)
\r
2565 // うまくいかない場合は要求をそのまま投げる
\r
2566 UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, data, size, true);
\r
2570 // 仮想ホストへの UDP パケットの処理
\r
2571 void UdpRecvForMe(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
\r
2574 if (data == NULL || v == NULL)
\r
2579 if (dest_port == NAT_DNS_PROXY_PORT)
\r
2582 DnsProxy(v, src_ip, src_port, dest_ip, dest_port, data, size);
\r
2586 // ブロードキャスト UDP パケットの処理
\r
2587 void UdpRecvForBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
\r
2590 if (data == NULL || v == NULL)
\r
2597 void VirtualUdpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, bool mac_broadcast)
\r
2600 UINT packet_length;
\r
2603 UINT src_port, dest_port;
\r
2605 if (v == NULL || data == NULL)
\r
2611 udp = (UDP_HEADER *)data;
\r
2612 if (size < UDP_HEADER_SIZE)
\r
2616 packet_length = Endian16(udp->PacketLength);
\r
2617 if (packet_length != size)
\r
2621 buf = ((UCHAR *)data) + UDP_HEADER_SIZE;
\r
2622 buf_size = size - UDP_HEADER_SIZE;
\r
2623 src_port = Endian16(udp->SrcPort);
\r
2624 dest_port = Endian16(udp->DstPort);
\r
2626 if (dest_port == 0)
\r
2632 // 自分宛のパケットまたはブロードキャストパケットかどうか判別する
\r
2633 if (dest_ip == v->HostIP)
\r
2636 UdpRecvForMe(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
\r
2638 else if (mac_broadcast || dest_ip == 0xffffffff || dest_ip == GetBroadcastAddress(v->HostIP, v->HostMask))
\r
2640 // ブロードキャストパケットが届いた
\r
2641 UdpRecvForBroadcast(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
\r
2643 else if (IsInNetwork(dest_ip, v->HostIP, v->HostMask) == false)
\r
2645 // ローカルアドレス以外 (つまりインターネット上) へのパケットが届いた
\r
2646 UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size, false);
\r
2650 // ローカルアドレスが届いた。無視
\r
2654 // 指定した IP アドレスの属するサブネットのネットワークアドレスを求める
\r
2655 UINT GetNetworkAddress(UINT addr, UINT mask)
\r
2657 return (addr & mask);
\r
2660 // 指定した IP アドレスの属するサブネットのブロードキャストアドレスを求める
\r
2661 UINT GetBroadcastAddress(UINT addr, UINT mask)
\r
2663 return ((addr & mask) | (~mask));
\r
2666 // 指定した IP アドレスが別の指定したアドレスとサブネットマスクによって表現される
\r
2667 // サブネットワークに所属しているかどうか判別する
\r
2668 bool IsInNetwork(UINT uni_addr, UINT network_addr, UINT mask)
\r
2670 if (GetNetworkAddress(uni_addr, mask) == GetNetworkAddress(network_addr, mask))
\r
2678 void SendUdp(VH *v, UINT dest_ip, UINT dest_port, UINT src_ip, UINT src_port, void *data, UINT size)
\r
2680 UDPV4_PSEUDO_HEADER *vh;
\r
2682 UINT udp_packet_length = UDP_HEADER_SIZE + size;
\r
2685 if (v == NULL || data == NULL)
\r
2689 if (udp_packet_length > 65536)
\r
2695 vh = Malloc(sizeof(UDPV4_PSEUDO_HEADER) + size);
\r
2696 udp = (UDP_HEADER *)(((UCHAR *)vh) + 12);
\r
2698 vh->SrcIP = src_ip;
\r
2699 vh->DstIP = dest_ip;
\r
2701 vh->Protocol = IP_PROTO_UDP;
\r
2702 vh->PacketLength1 = Endian16((USHORT)udp_packet_length);
\r
2703 udp->SrcPort = Endian16((USHORT)src_port);
\r
2704 udp->DstPort = Endian16((USHORT)dest_port);
\r
2705 udp->PacketLength = Endian16((USHORT)udp_packet_length);
\r
2706 udp->Checksum = 0;
\r
2709 Copy(((UCHAR *)udp) + UDP_HEADER_SIZE, data, size);
\r
2712 checksum = IpChecksum(vh, udp_packet_length + 12);
\r
2713 if (checksum == 0x0000)
\r
2715 checksum = 0xffff;
\r
2717 udp->Checksum = checksum;
\r
2720 SendIp(v, dest_ip, src_ip, IP_PROTO_UDP, udp, udp_packet_length);
\r
2726 // IP 結合オブジェクトのポーリング
\r
2727 void PollingIpCombine(VH *v)
\r
2737 // 古い結合オブジェクトを破棄する
\r
2739 for (i = 0;i < LIST_NUM(v->IpCombine);i++)
\r
2741 IP_COMBINE *c = LIST_DATA(v->IpCombine, i);
\r
2743 if (c->Expire < v->Now)
\r
2747 o = NewListFast(NULL);
\r
2755 for (i = 0;i < LIST_NUM(o);i++)
\r
2757 IP_COMBINE *c = LIST_DATA(o, i);
\r
2760 Delete(v->IpCombine, c);
\r
2763 FreeIpCombine(v, c);
\r
2770 void VirtualIcmpSend(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size)
\r
2772 ICMP_HEADER *icmp;
\r
2775 if (v == NULL || data == NULL)
\r
2781 icmp = ZeroMalloc(sizeof(ICMP_HEADER) + size);
\r
2783 data_buf = ((UCHAR *)icmp) + sizeof(ICMP_HEADER);
\r
2784 Copy(data_buf, data, size);
\r
2786 icmp->Checksum = 0;
\r
2788 icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
\r
2790 icmp->Checksum = IpChecksum(icmp, sizeof(ICMP_HEADER) + size);
\r
2793 SendIp(v, dst_ip, src_ip, IP_PROTO_ICMPV4, icmp, sizeof(ICMP_HEADER) + size);
\r
2799 // ICMP Echo Response パケットを送信する
\r
2800 void VirtualIcmpEchoSendResponse(VH *v, UINT src_ip, UINT dst_ip, USHORT id, USHORT seq_no, void *data, UINT size)
\r
2804 if (v == NULL || data == NULL)
\r
2810 e = ZeroMalloc(sizeof(ICMP_ECHO) + size);
\r
2811 e->Identifier = Endian16(id);
\r
2812 e->SeqNo = Endian16(seq_no);
\r
2815 Copy(((UCHAR *)e) + sizeof(ICMP_ECHO), data, size);
\r
2818 VirtualIcmpSend(v, src_ip, dst_ip, e, sizeof(ICMP_ECHO) + size);
\r
2824 // ICMP Echo Request パケットを受信した
\r
2825 void VirtualIcmpEchoRequestReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size)
\r
2830 USHORT id, seq_no;
\r
2832 if (v == NULL || data == NULL)
\r
2837 echo = (ICMP_ECHO *)data;
\r
2840 if (size < sizeof(ICMP_ECHO))
\r
2846 id = Endian16(echo->Identifier);
\r
2847 seq_no = Endian16(echo->SeqNo);
\r
2850 data_size = size - sizeof(ICMP_ECHO);
\r
2853 data_buf = ((UCHAR *)data) + sizeof(ICMP_ECHO);
\r
2855 // ICMP Echo Response を返す
\r
2856 VirtualIcmpEchoSendResponse(v, dst_ip, src_ip, id, seq_no, data_buf, data_size);
\r
2860 void VirtualIcmpReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size)
\r
2862 ICMP_HEADER *icmp;
\r
2864 USHORT checksum_calc, checksum_original;
\r
2866 if (v == NULL || data == NULL)
\r
2872 if (size < sizeof(ICMP_HEADER))
\r
2878 icmp = (ICMP_HEADER *)data;
\r
2880 // ICMP メッセージサイズの取得
\r
2881 msg_size = size - sizeof(ICMP_HEADER);
\r
2883 // ICMP ヘッダのチェックサムをチェックする
\r
2884 checksum_original = icmp->Checksum;
\r
2885 icmp->Checksum = 0;
\r
2886 checksum_calc = IpChecksum(data, size);
\r
2887 icmp->Checksum = checksum_original;
\r
2889 if (checksum_calc != checksum_original)
\r
2892 Debug("ICMP CheckSum Failed.\n");
\r
2897 switch (icmp->Type)
\r
2899 case ICMP_TYPE_ECHO_REQUEST: // ICMP Echo 要求
\r
2900 VirtualIcmpEchoRequestReceived(v, src_ip, dst_ip, ((UCHAR *)data) + sizeof(ICMP_HEADER), msg_size);
\r
2903 case ICMP_TYPE_ECHO_RESPONSE: // ICMP Echo 応答
\r
2910 void IpReceived(VH *v, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size, bool mac_broadcast)
\r
2913 if (v == NULL || data == NULL)
\r
2918 // サポートされている上位プロトコルにデータを渡す
\r
2921 case IP_PROTO_ICMPV4: // ICMPv4
\r
2922 VirtualIcmpReceived(v, src_ip, dest_ip, data, size);
\r
2925 case IP_PROTO_TCP: // TCP
\r
2926 if (mac_broadcast == false)
\r
2928 VirtualTcpReceived(v, src_ip, dest_ip, data, size);
\r
2932 case IP_PROTO_UDP: // UDP
\r
2933 VirtualUdpReceived(v, src_ip, dest_ip, data, size, mac_broadcast);
\r
2938 // IP ヘッダのチェックサムを確認する
\r
2939 bool IpCheckChecksum(IPV4_HEADER *ip)
\r
2942 USHORT checksum_original, checksum_calc;
\r
2949 header_size = IPV4_GET_HEADER_LEN(ip) * 4;
\r
2950 checksum_original = ip->Checksum;
\r
2952 checksum_calc = IpChecksum(ip, header_size);
\r
2953 ip->Checksum = checksum_original;
\r
2955 if (checksum_original == checksum_calc)
\r
2966 USHORT IpChecksum(void *buf, UINT size)
\r
2969 USHORT *addr = (USHORT *)buf;
\r
2970 int len = (int)size;
\r
2973 USHORT answer = 0;
\r
2983 *(UCHAR *)(&answer) = *(UCHAR *)w;
\r
2987 sum = (sum >> 16) + (sum & 0xffff);
\r
2988 sum += (sum >> 16);
\r
2995 // IP 結合オブジェクトに新しく受信した IP パケットを結合する
\r
2996 void CombineIp(VH *v, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet)
\r
3001 UINT data_size_delta;
\r
3003 if (c == NULL || data == NULL)
\r
3009 if ((offset + size) > 65535)
\r
3011 // 64Kbytes を超えるパケットは処理しない
\r
3015 if (last_packet == false && c->Size != 0)
\r
3017 if ((offset + size) > c->Size)
\r
3019 // パケットサイズより大きいパケットは処理しない
\r
3024 need_size = offset + size;
\r
3025 data_size_delta = c->DataReserved;
\r
3026 // バッファが不足している場合は十分確保する
\r
3027 while (c->DataReserved < need_size)
\r
3029 c->DataReserved = c->DataReserved * 4;
\r
3030 c->Data = ReAlloc(c->Data, c->DataReserved);
\r
3032 data_size_delta = c->DataReserved - data_size_delta;
\r
3033 v->CurrentIpQuota += data_size_delta;
\r
3036 Copy(((UCHAR *)c->Data) + offset, data, size);
\r
3040 // No More Flagment パケットが届いた場合、このデータグラムのサイズが確定する
\r
3041 c->Size = offset + size;
\r
3044 // オフセットとサイズによって表現されている領域と既存の受信済みリストの
\r
3045 // オフセットとサイズによって表現されている領域との間の重複をチェックする
\r
3046 for (i = 0;i < LIST_NUM(c->IpParts);i++)
\r
3049 IP_PART *p = LIST_DATA(c->IpParts, i);
\r
3051 // 先頭領域と既存領域との重複をチェック
\r
3052 if ((p->Offset <= offset) && ((p->Offset + p->Size) > offset))
\r
3054 // このパケットと既存パケットとの間で先頭部分に重複が見つかったので
\r
3055 // このパケットのオフセットを後方に圧縮する
\r
3057 if ((offset + size) <= (p->Offset + p->Size))
\r
3059 // このパケットは既存のパケットの中に埋もれている
\r
3065 moving_size = p->Offset + p->Size - offset;
\r
3066 offset += moving_size;
\r
3067 size -= moving_size;
\r
3070 if ((p->Offset < (offset + size)) && ((p->Offset + p->Size) >= (offset + size)))
\r
3072 // このパケットと既存パケットとの間で後方部分に重複が見つかったので
\r
3073 // このパケットのサイズを前方に圧縮する
\r
3075 moving_size = p->Offset + p->Size - offset - size;
\r
3076 size -= moving_size;
\r
3079 if ((p->Offset >= offset) && ((p->Offset + p->Size) <= (offset + size)))
\r
3081 // このパケットが既存のパケットを完全に覆いかぶさるように上書きされた
\r
3089 p = ZeroMalloc(sizeof(IP_PART));
\r
3091 p->Offset = offset;
\r
3094 Add(c->IpParts, p);
\r
3099 // すでに受信したデータ部分リストの合計サイズを取得する
\r
3100 UINT total_size = 0;
\r
3103 for (i = 0;i < LIST_NUM(c->IpParts);i++)
\r
3105 IP_PART *p = LIST_DATA(c->IpParts, i);
\r
3107 total_size += p->Size;
\r
3110 if (total_size == c->Size)
\r
3112 // IP パケットをすべて受信した
\r
3113 IpReceived(v, c->SrcIP, c->DestIP, c->Protocol, c->Data, c->Size, c->MacBroadcast);
\r
3116 FreeIpCombine(v, c);
\r
3118 // 結合オブジェクトをリストから削除
\r
3119 Delete(v->IpCombine, c);
\r
3125 void FreeIpCombine(VH *v, IP_COMBINE *c)
\r
3135 v->CurrentIpQuota -= c->DataReserved;
\r
3139 for (i = 0;i < LIST_NUM(c->IpParts);i++)
\r
3141 IP_PART *p = LIST_DATA(c->IpParts, i);
\r
3146 ReleaseList(c->IpParts);
\r
3151 IP_COMBINE *SearchIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol)
\r
3160 t.DestIP = dest_ip;
\r
3163 t.Protocol = protocol;
\r
3165 c = Search(v->IpCombine, &t);
\r
3170 // IP 結合リストに新しいオブジェクトを作成して挿入
\r
3171 IP_COMBINE *InsertIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast)
\r
3181 if ((v->CurrentIpQuota + IP_COMBINE_INITIAL_BUF_SIZE) > IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA)
\r
3183 // これ以上 IP パケットを格納できない
\r
3187 c = ZeroMalloc(sizeof(IP_COMBINE));
\r
3188 c->DestIP = dest_ip;
\r
3189 c->SrcIP = src_ip;
\r
3191 c->Expire = v->Now + (UINT64)IP_COMBINE_TIMEOUT;
\r
3193 c->IpParts = NewList(NULL);
\r
3194 c->Protocol = protocol;
\r
3195 c->MacBroadcast = mac_broadcast;
\r
3198 c->DataReserved = IP_COMBINE_INITIAL_BUF_SIZE;
\r
3199 c->Data = Malloc(c->DataReserved);
\r
3200 v->CurrentIpQuota += c->DataReserved;
\r
3202 Insert(v->IpCombine, c);
\r
3208 void InitIpCombineList(VH *v)
\r
3216 v->IpCombine = NewList(CompareIpCombine);
\r
3220 void FreeIpCombineList(VH *v)
\r
3229 for (i = 0;i < LIST_NUM(v->IpCombine);i++)
\r
3231 IP_COMBINE *c = LIST_DATA(v->IpCombine, i);
\r
3233 FreeIpCombine(v, c);
\r
3236 ReleaseList(v->IpCombine);
\r
3240 int CompareIpCombine(void *p1, void *p2)
\r
3242 IP_COMBINE *c1, *c2;
\r
3243 if (p1 == NULL || p2 == NULL)
\r
3247 c1 = *(IP_COMBINE **)p1;
\r
3248 c2 = *(IP_COMBINE **)p2;
\r
3249 if (c1 == NULL || c2 == NULL)
\r
3253 if (c1->Id > c2->Id)
\r
3257 else if (c1->Id < c2->Id)
\r
3261 else if (c1->DestIP > c2->DestIP)
\r
3265 else if (c1->DestIP < c2->DestIP)
\r
3269 else if (c1->SrcIP > c2->SrcIP)
\r
3273 else if (c1->SrcIP < c2->SrcIP)
\r
3277 else if (c1->Protocol > c2->Protocol)
\r
3281 else if (c1->Protocol < c2->Protocol)
\r
3289 void VirtualIpReceived(VH *v, PKT *packet)
\r
3293 UINT data_size_recved;
\r
3295 UINT ipv4_header_size;
\r
3298 if (v == NULL || packet == NULL)
\r
3303 ip = packet->L3.IPv4Header;
\r
3305 // IPv4 ヘッダのサイズを取得する
\r
3306 ipv4_header_size = IPV4_GET_HEADER_LEN(packet->L3.IPv4Header) * 4;
\r
3308 // IPv4 ヘッダのチェックサムを計算する
\r
3309 if (IpCheckChecksum(ip) == false)
\r
3315 data = ((UCHAR *)packet->L3.PointerL3) + ipv4_header_size;
\r
3317 // ARP テーブルに登録しておく
\r
3318 ArpIpWasKnown(v, packet->L3.IPv4Header->SrcIP, packet->MacAddressSrc);
\r
3321 size = Endian16(ip->TotalLength);
\r
3322 if (size <= ipv4_header_size)
\r
3327 size -= ipv4_header_size;
\r
3329 // 実際に受信したデータサイズを取得する
\r
3330 data_size_recved = packet->PacketSize - (ipv4_header_size + MAC_HEADER_SIZE);
\r
3331 if (data_size_recved < size)
\r
3333 // データが足りない (途中で欠落しているかも知れない)
\r
3337 if (IPV4_GET_OFFSET(ip) == 0 && (IPV4_GET_FLAGS(ip) & 0x01) == 0)
\r
3339 // このパケットは分割されていないので直ちに上位層に渡すことができる
\r
3340 IpReceived(v, ip->SrcIP, ip->DstIP, ip->Protocol, data, size, packet->BroadcastPacket);
\r
3344 // このパケットは分割されているので結合する必要がある
\r
3346 UINT offset = IPV4_GET_OFFSET(ip) * 8;
\r
3347 IP_COMBINE *c = SearchIpCombine(v, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol);
\r
3349 last_packet = ((IPV4_GET_FLAGS(ip) & 0x01) == 0 ? true : false);
\r
3354 CombineIp(v, c, offset, data, size, last_packet);
\r
3358 // 最初のパケットなので結合オブジェクトを作成する
\r
3359 c = InsertIpCombine(
\r
3360 v, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol, packet->BroadcastPacket);
\r
3363 CombineIp(v, c, offset, data, size, last_packet);
\r
3369 // 待機している IP パケットのうち指定した IP アドレスからのものを送信する
\r
3370 void SendWaitingIp(VH *v, UCHAR *mac, UINT dest_ip)
\r
3375 if (v == NULL || mac == NULL)
\r
3381 for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
\r
3383 IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
\r
3385 if (w->DestIP == dest_ip)
\r
3389 o = NewListFast(NULL);
\r
3395 // 対象となったパケットを一気に送信する
\r
3398 for (i = 0;i < LIST_NUM(o);i++)
\r
3400 IP_WAIT *w = LIST_DATA(o, i);
\r
3403 VirtualIpSend(v, mac, w->Data, w->Size);
\r
3406 Delete(v->IpWaitTable, w);
\r
3417 // 古い IP 待ちテーブルを削除する
\r
3418 void DeleteOldIpWaitTable(VH *v)
\r
3429 for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
\r
3431 IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
\r
3433 if (w->Expire < v->Now)
\r
3437 o = NewListFast(NULL);
\r
3446 for (i = 0;i < LIST_NUM(o);i++)
\r
3448 IP_WAIT *w = LIST_DATA(o, i);
\r
3451 Delete(v->IpWaitTable, w);
\r
3461 // IP 待ちテーブルのポーリング
\r
3462 void PollingIpWaitTable(VH *v)
\r
3465 DeleteOldIpWaitTable(v);
\r
3468 // IP 待ちテーブルに IP パケットを挿入する
\r
3469 void InsertIpWaitTable(VH *v, UINT dest_ip, UINT src_ip, void *data, UINT size)
\r
3473 if (v == NULL || data == NULL || size == 0)
\r
3478 w = ZeroMalloc(sizeof(IP_WAIT));
\r
3481 w->SrcIP = src_ip;
\r
3482 w->DestIP = dest_ip;
\r
3483 w->Expire = v->Now + (UINT64)IP_WAIT_FOR_ARP_TIMEOUT;
\r
3485 Add(v->IpWaitTable, w);
\r
3488 // IP 待ちテーブルを初期化する
\r
3489 void InitIpWaitTable(VH *v)
\r
3497 v->IpWaitTable = NewList(NULL);
\r
3501 void FreeIpWaitTable(VH *v)
\r
3510 for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
\r
3512 IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
\r
3518 ReleaseList(v->IpWaitTable);
\r
3521 // ARP Response が到着するなどして IP アドレスに対する MAC アドレスが判明した
\r
3522 void ArpIpWasKnown(VH *v, UINT ip, UCHAR *mac)
\r
3525 if (v == NULL || mac == NULL)
\r
3530 // ARP 待ち行列にこの IP アドレスに対する問い合わせがあった場合は削除する
\r
3531 DeleteArpWaitTable(v, ip);
\r
3533 // ARP テーブルに登録または更新する
\r
3534 InsertArpTable(v, mac, ip);
\r
3536 // IP 待機リストで待機している IP パケットを送信する
\r
3537 SendWaitingIp(v, mac, ip);
\r
3540 // ARP 待ちリストをチェックし適時 ARP を再発行する
\r
3541 void PollingArpWaitTable(VH *v)
\r
3554 // すべての ARP 待ちリストを走査
\r
3555 for (i = 0;i < LIST_NUM(v->ArpWaitTable);i++)
\r
3557 ARP_WAIT *w = LIST_DATA(v->ArpWaitTable, i);
\r
3559 if (w->GiveupTime < v->Now || (w->GiveupTime - 100 * 1000) > v->Now)
\r
3564 o = NewListFast(NULL);
\r
3570 if (w->TimeoutTime < v->Now)
\r
3573 VirtualArpSendRequest(v, w->IpAddress);
\r
3576 w->TimeoutTime = v->Now + (UINT64)w->NextTimeoutTimeValue;
\r
3577 // 2 回目以降の ARP 送信間隔は増やしていく
\r
3578 w->NextTimeoutTimeValue = w->NextTimeoutTimeValue + ARP_REQUEST_TIMEOUT;
\r
3583 // 削除対象の ARP 待ちレコードがある場合は削除する
\r
3586 for (i = 0;i < LIST_NUM(o);i++)
\r
3588 ARP_WAIT *w = LIST_DATA(o, i);
\r
3590 DeleteArpWaitTable(v, w->IpAddress);
\r
3597 void SendArp(VH *v, UINT ip)
\r
3606 // まず ARP 待ちリストに宛先 IP アドレスが登録されているかどうか調べる
\r
3607 w = SearchArpWaitTable(v, ip);
\r
3610 // すでに登録されているので何もしない
\r
3614 // まず ARP パケットを送信する
\r
3615 VirtualArpSendRequest(v, ip);
\r
3618 w = ZeroMalloc(sizeof(ARP_WAIT));
\r
3619 w->GiveupTime = v->Now + (UINT64)ARP_REQUEST_GIVEUP;
\r
3620 w->TimeoutTime = v->Now + (UINT64)ARP_REQUEST_TIMEOUT;
\r
3621 w->NextTimeoutTimeValue = ARP_REQUEST_TIMEOUT;
\r
3622 w->IpAddress = ip;
\r
3624 InsertArpWaitTable(v, w);
\r
3628 void DeleteArpWaitTable(VH *v, UINT ip)
\r
3637 w = SearchArpWaitTable(v, ip);
\r
3642 Delete(v->ArpWaitTable, w);
\r
3648 ARP_WAIT *SearchArpWaitTable(VH *v, UINT ip)
\r
3658 w = Search(v->ArpWaitTable, &t);
\r
3664 void InsertArpWaitTable(VH *v, ARP_WAIT *w)
\r
3667 if (v == NULL || w == NULL)
\r
3672 Add(v->ArpWaitTable, w);
\r
3676 void InitArpWaitTable(VH *v)
\r
3684 v->ArpWaitTable = NewList(CompareArpWaitTable);
\r
3688 void FreeArpWaitTable(VH *v)
\r
3697 for (i = 0;i < LIST_NUM(v->ArpWaitTable);i++)
\r
3699 ARP_WAIT *w = LIST_DATA(v->ArpWaitTable, i);
\r
3704 ReleaseList(v->ArpWaitTable);
\r
3707 // MAC アドレスが不正かどうかチェック
\r
3708 bool IsMacInvalid(UCHAR *mac)
\r
3717 for (i = 0;i < 6;i++)
\r
3719 if (mac[i] != 0x00)
\r
3727 // MAC アドレスがブロードキャストアドレスかどうかチェック
\r
3728 bool IsMacBroadcast(UCHAR *mac)
\r
3737 for (i = 0;i < 6;i++)
\r
3739 if (mac[i] != 0xff)
\r
3747 // ARP テーブルにエントリを挿入する
\r
3748 void InsertArpTable(VH *v, UCHAR *mac, UINT ip)
\r
3752 if (v == NULL || mac == NULL || ip == 0 || ip == 0xffffffff || IsMacBroadcast(mac) || IsMacInvalid(mac))
\r
3757 // すでに同じ IP アドレスが登録されていないかどうかチェック
\r
3759 e = Search(v->ArpTable, &t);
\r
3762 // 登録されていたのでこれを上書きするだけ
\r
3763 if (Cmp(e->MacAddress, mac, 6) != 0)
\r
3765 e->Created = v->Now;
\r
3766 Copy(e->MacAddress, mac, 6);
\r
3768 e->Expire = v->Now + (UINT64)ARP_ENTRY_EXPIRES;
\r
3773 e = ZeroMalloc(sizeof(ARP_ENTRY));
\r
3775 e->Created = v->Now;
\r
3776 e->Expire = v->Now + (UINT64)ARP_ENTRY_EXPIRES;
\r
3777 Copy(e->MacAddress, mac, 6);
\r
3778 e->IpAddress = ip;
\r
3780 Add(v->ArpTable, e);
\r
3785 void PollingArpTable(VH *v)
\r
3793 if (v->Now > v->NextArpTablePolling)
\r
3795 v->NextArpTablePolling = v->Now + (UINT64)ARP_ENTRY_POLLING_TIME;
\r
3796 RefreshArpTable(v);
\r
3800 // 古い ARP エントリを削除する
\r
3801 void RefreshArpTable(VH *v)
\r
3811 o = NewListFast(NULL);
\r
3812 for (i = 0;i < LIST_NUM(v->ArpTable);i++)
\r
3814 ARP_ENTRY *e = LIST_DATA(v->ArpTable, i);
\r
3817 if (e->Expire < v->Now)
\r
3824 // 有効期限が切れているものを一括して削除する
\r
3825 for (i = 0;i < LIST_NUM(o);i++)
\r
3827 ARP_ENTRY *e = LIST_DATA(o, i);
\r
3829 Delete(v->ArpTable, e);
\r
3837 ARP_ENTRY *SearchArpTable(VH *v, UINT ip)
\r
3847 e = Search(v->ArpTable, &t);
\r
3853 void InitArpTable(VH *v)
\r
3861 v->ArpTable = NewList(CompareArpTable);
\r
3865 void FreeArpTable(VH *v)
\r
3875 for (i = 0;i < LIST_NUM(v->ArpTable);i++)
\r
3877 ARP_ENTRY *e = LIST_DATA(v->ArpTable, i);
\r
3880 ReleaseList(v->ArpTable);
\r
3884 int CompareArpWaitTable(void *p1, void *p2)
\r
3886 ARP_WAIT *e1, *e2;
\r
3887 if (p1 == NULL || p2 == NULL)
\r
3891 e1 = *(ARP_WAIT **)p1;
\r
3892 e2 = *(ARP_WAIT **)p2;
\r
3893 if (e1 == NULL || e2 == NULL)
\r
3898 if (e1->IpAddress > e2->IpAddress)
\r
3902 else if (e1->IpAddress < e2->IpAddress)
\r
3910 int CompareArpTable(void *p1, void *p2)
\r
3912 ARP_ENTRY *e1, *e2;
\r
3913 if (p1 == NULL || p2 == NULL)
\r
3917 e1 = *(ARP_ENTRY **)p1;
\r
3918 e2 = *(ARP_ENTRY **)p2;
\r
3919 if (e1 == NULL || e2 == NULL)
\r
3924 if (e1->IpAddress > e2->IpAddress)
\r
3928 else if (e1->IpAddress < e2->IpAddress)
\r
3936 bool VirtualInit(VH *v)
\r
3944 v->Cancel = NewCancel();
\r
3945 v->SendQueue = NewQueue();
\r
3950 v->Counter->c = 0;
\r
3957 InitArpWaitTable(v);
\r
3960 InitIpWaitTable(v);
\r
3963 InitIpCombineList(v);
\r
3969 InitDhcpServer(v);
\r
3973 v->NextArpTablePolling = Tick64() + (UINT64)ARP_ENTRY_POLLING_TIME;
\r
3974 v->CurrentIpQuota = 0;
\r
3979 bool VirtualPaInit(SESSION *s)
\r
3983 if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
\r
3988 return VirtualInit(v);
\r
3991 // 仮想ホストのキャンセルオブジェクトを取得
\r
3992 CANCEL *VirtualPaGetCancel(SESSION *s)
\r
3996 if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
\r
4001 AddRef(v->Cancel->ref);
\r
4005 // 仮想ホストから次のパケットを取得
\r
4006 UINT VirtualGetNextPacket(VH *v, void **data)
\r
4012 LockQueue(v->SendQueue);
\r
4014 BLOCK *block = GetNext(v->SendQueue);
\r
4016 if (block != NULL)
\r
4019 ret = block->Size;
\r
4020 *data = block->Buf;
\r
4025 UnlockQueue(v->SendQueue);
\r
4031 v->Now = Tick64();
\r
4033 VirtualPolling(v);
\r
4036 if (v->SendQueue->num_item != 0)
\r
4044 UINT VirtualPaGetNextPacket(SESSION *s, void **data)
\r
4048 if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
\r
4053 return VirtualGetNextPacket(v, data);
\r
4056 // ポーリング処理 (SessionMain ループ中に 1 回必ず呼ばれる)
\r
4057 void VirtualPolling(VH *v)
\r
4066 PollingDhcpServer(v);
\r
4072 PollingArpTable(v);
\r
4074 // ARP 待ちリストのポーリング
\r
4075 PollingArpWaitTable(v);
\r
4078 PollingIpWaitTable(v);
\r
4081 PollingIpCombine(v);
\r
4088 void PollingBeacon(VH *v)
\r
4096 if (v->LastSendBeacon == 0 ||
\r
4097 ((v->LastSendBeacon + BEACON_SEND_INTERVAL) <= Tick64()))
\r
4099 v->LastSendBeacon = Tick64();
\r
4105 // Layer-2 パケットを送信する
\r
4106 void VirtualLayer2Send(VH *v, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)
\r
4108 MAC_HEADER *mac_header;
\r
4112 if (v == NULL || dest_mac == NULL || src_mac == NULL || data == NULL || size > (MAX_PACKET_SIZE - sizeof(MAC_HEADER)))
\r
4118 buf = Malloc(MAC_HEADER_SIZE + size);
\r
4121 mac_header = (MAC_HEADER *)&buf[0];
\r
4122 Copy(mac_header->DestAddress, dest_mac, 6);
\r
4123 Copy(mac_header->SrcAddress, src_mac, 6);
\r
4124 mac_header->Protocol = Endian16(protocol);
\r
4127 Copy(&buf[sizeof(MAC_HEADER)], data, size);
\r
4130 size += sizeof(MAC_HEADER);
\r
4133 block = NewBlock(buf, size, 0);
\r
4136 LockQueue(v->SendQueue);
\r
4138 InsertQueue(v->SendQueue, block);
\r
4140 UnlockQueue(v->SendQueue);
\r
4143 Cancel(v->Cancel);
\r
4146 // IP パケットを送信する (自動的に分割処理を行う)
\r
4147 void SendIp(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size)
\r
4153 USHORT total_size;
\r
4154 UINT size_of_this_packet;
\r
4156 if (v == NULL || data == NULL || size == 0 || size > MAX_IP_DATA_SIZE_TOTAL)
\r
4165 buf = (UCHAR *)data;
\r
4168 id = (v->NextId++);
\r
4171 total_size = (USHORT)size;
\r
4178 bool last_packet = false;
\r
4180 size_of_this_packet = MIN((USHORT)mss, (total_size - offset));
\r
4181 if ((offset + (USHORT)size_of_this_packet) == total_size)
\r
4183 last_packet = true;
\r
4187 SendFragmentedIp(v, dest_ip, src_ip, id,
\r
4188 total_size, offset, protocol, buf + offset, size_of_this_packet, NULL);
\r
4194 offset += (USHORT)size_of_this_packet;
\r
4198 // 分割済みの IP パケットを送信予約する
\r
4199 void SendFragmentedIp(VH *v, UINT dest_ip, UINT src_ip, USHORT id, USHORT total_size, USHORT offset, UCHAR protocol, void *data, UINT size, UCHAR *dest_mac)
\r
4205 if (v == NULL || data == NULL || size == 0)
\r
4211 buf = Malloc(size + IP_HEADER_SIZE);
\r
4212 ip = (IPV4_HEADER *)&buf[0];
\r
4215 ip->VersionAndHeaderLength = 0;
\r
4216 IPV4_SET_VERSION(ip, 4);
\r
4217 IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
\r
4218 ip->TypeOfService = DEFAULT_IP_TOS;
\r
4219 ip->TotalLength = Endian16((USHORT)(size + IP_HEADER_SIZE));
\r
4220 ip->Identification = Endian16(id);
\r
4221 ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
\r
4222 IPV4_SET_OFFSET(ip, (offset / 8));
\r
4223 if ((offset + size) >= total_size)
\r
4225 IPV4_SET_FLAGS(ip, 0x00);
\r
4229 IPV4_SET_FLAGS(ip, 0x01);
\r
4231 ip->TimeToLive = DEFAULT_IP_TTL;
\r
4232 ip->Protocol = protocol;
\r
4234 ip->SrcIP = src_ip;
\r
4235 ip->DstIP = dest_ip;
\r
4238 ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
\r
4241 Copy(buf + IP_HEADER_SIZE, data, size);
\r
4243 if (dest_mac == NULL)
\r
4245 if (ip->DstIP == 0xffffffff ||
\r
4246 (IsInNetwork(ip->DstIP, v->HostIP, v->HostMask) && (ip->DstIP & (~v->HostMask)) == (~v->HostMask)))
\r
4249 dest_mac = broadcast;
\r
4253 // 宛先 MAC アドレスが不明な場合は ARP 問い合わせ
\r
4254 arp = SearchArpTable(v, dest_ip);
\r
4257 dest_mac = arp->MacAddress;
\r
4261 if (dest_mac != NULL)
\r
4264 VirtualIpSend(v, dest_mac, buf, size + IP_HEADER_SIZE);
\r
4271 // このパケットはまだ転送できないので IP 待ちテーブルに追加する
\r
4272 InsertIpWaitTable(v, dest_ip, src_ip, buf, size + IP_HEADER_SIZE);
\r
4275 SendArp(v, dest_ip);
\r
4279 // IP パケット (分割済み) を送信する
\r
4280 void VirtualIpSend(VH *v, UCHAR *dest_mac, void *data, UINT size)
\r
4283 if (v == NULL || dest_mac == NULL || data == NULL || size == 0)
\r
4289 VirtualLayer2Send(v, dest_mac, v->MacAddress, MAC_PROTO_IPV4, data, size);
\r
4292 // ARP リクエストパケットを送信する
\r
4293 void VirtualArpSendRequest(VH *v, UINT dest_ip)
\r
4303 arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
\r
4304 arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
\r
4305 arp.HardwareSize = 6;
\r
4306 arp.ProtocolSize = 4;
\r
4307 arp.Operation = Endian16(ARP_OPERATION_REQUEST);
\r
4308 Copy(arp.SrcAddress, v->MacAddress, 6);
\r
4309 arp.SrcIP = v->HostIP;
\r
4310 Zero(&arp.TargetAddress, 6);
\r
4311 arp.TargetIP = dest_ip;
\r
4314 VirtualLayer2Send(v, broadcast, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
\r
4317 // ARP レスポンスパケットを送信する
\r
4318 void VirtualArpSendResponse(VH *v, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)
\r
4322 if (v == NULL || dest_mac == NULL)
\r
4328 arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
\r
4329 arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
\r
4330 arp.HardwareSize = 6;
\r
4331 arp.ProtocolSize = 4;
\r
4332 arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
\r
4333 Copy(arp.SrcAddress, v->MacAddress, 6);
\r
4334 Copy(arp.TargetAddress, dest_mac, 6);
\r
4335 arp.SrcIP = src_ip;
\r
4336 arp.TargetIP = dest_ip;
\r
4339 VirtualLayer2Send(v, dest_mac, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(ARPV4_HEADER));
\r
4342 // ARP リクエストパケットを受信した
\r
4343 void VirtualArpResponseRequest(VH *v, PKT *packet)
\r
4345 ARPV4_HEADER *arp;
\r
4347 if (v == NULL || packet == NULL)
\r
4352 arp = packet->L3.ARPv4Header;
\r
4354 // 相手のホスト IP アドレスと MAC アドレスを既知の情報とする
\r
4355 ArpIpWasKnown(v, arp->SrcIP, arp->SrcAddress);
\r
4357 // 自分のホスト IP アドレスと一致するかどうか検索
\r
4358 if (v->HostIP == arp->TargetIP)
\r
4361 VirtualArpSendResponse(v, arp->SrcAddress, arp->SrcIP, v->HostIP);
\r
4367 // ARP レスポンスパケットを受信した
\r
4368 void VirtualArpResponseReceived(VH *v, PKT *packet)
\r
4370 ARPV4_HEADER *arp;
\r
4372 if (v == NULL || packet == NULL)
\r
4377 arp = packet->L3.ARPv4Header;
\r
4380 ArpIpWasKnown(v, arp->SrcIP, arp->SrcAddress);
\r
4384 void VirtualArpReceived(VH *v, PKT *packet)
\r
4386 ARPV4_HEADER *arp;
\r
4388 if (v == NULL || packet == NULL)
\r
4393 arp = packet->L3.ARPv4Header;
\r
4395 if (Endian16(arp->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET)
\r
4397 // ハードウェア種類が Ethernet 以外の場合は無視
\r
4400 if (Endian16(arp->ProtocolType) != MAC_PROTO_IPV4)
\r
4402 // プロトコル種類が IPv4 以外の場合は無視
\r
4405 if (arp->HardwareSize != 6 || arp->ProtocolSize != 4)
\r
4407 // ハードウェアアドレスまたはプロトコルアドレスのサイズが不正なので無視
\r
4410 // 送信元 MAC アドレスをチェック
\r
4411 if (Cmp(arp->SrcAddress, packet->MacAddressSrc, 6) != 0)
\r
4413 // ARP パケットの MAC アドレスと MAC ヘッダの MAC アドレスが異なる
\r
4417 switch (Endian16(arp->Operation))
\r
4419 case ARP_OPERATION_REQUEST: // ARP リクエスト
\r
4420 VirtualArpResponseRequest(v, packet);
\r
4423 case ARP_OPERATION_RESPONSE: // ARP レスポンス
\r
4424 VirtualArpResponseReceived(v, packet);
\r
4430 void FreeDhcpServer(VH *v)
\r
4439 // すべてのリースエントリを削除する
\r
4440 for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
\r
4442 DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
\r
4446 ReleaseList(v->DhcpLeaseList);
\r
4447 v->DhcpLeaseList = NULL;
\r
4451 void InitDhcpServer(VH *v)
\r
4460 v->DhcpLeaseList = NewList(CompareDhcpLeaseList);
\r
4463 // DHCP リース項目を IP アドレスで検索
\r
4464 DHCP_LEASE *SearchDhcpLeaseByIp(VH *v, UINT ip)
\r
4473 for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
\r
4475 DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
\r
4476 if (d->IpAddress == ip)
\r
4485 // DHCP リース項目を MAC アドレスで検索
\r
4486 DHCP_LEASE *SearchDhcpLeaseByMac(VH *v, UCHAR *mac)
\r
4490 if (v == NULL || mac == NULL)
\r
4495 Copy(&t.MacAddress, mac, 6);
\r
4496 d = Search(v->DhcpLeaseList, &t);
\r
4502 void FreeDhcpLease(DHCP_LEASE *d)
\r
4510 Free(d->Hostname);
\r
4515 DHCP_LEASE *NewDhcpLease(UINT expire, UCHAR *mac_address, UINT ip, UINT mask, char *hostname)
\r
4519 if (mac_address == NULL || hostname == NULL)
\r
4524 d = ZeroMalloc(sizeof(DHCP_LEASE));
\r
4525 d->LeasedTime = (UINT64)Tick64();
\r
4526 if (expire == INFINITE)
\r
4528 d->ExpireTime = INFINITE;
\r
4532 d->ExpireTime = d->LeasedTime + (UINT64)expire;
\r
4534 d->IpAddress = ip;
\r
4536 d->Hostname = CopyStr(hostname);
\r
4537 Copy(d->MacAddress, mac_address, 6);
\r
4544 int CompareDhcpLeaseList(void *p1, void *p2)
\r
4546 DHCP_LEASE *d1, *d2;
\r
4548 if (p1 == NULL || p2 == NULL)
\r
4552 d1 = *(DHCP_LEASE **)p1;
\r
4553 d2 = *(DHCP_LEASE **)p2;
\r
4554 if (d1 == NULL || d2 == NULL)
\r
4559 return Cmp(d1->MacAddress, d2->MacAddress, 6);
\r
4562 // DHCP サーバーのポーリング
\r
4563 void PollingDhcpServer(VH *v)
\r
4572 if (v->LastDhcpPolling != 0)
\r
4574 if ((v->LastDhcpPolling + (UINT64)DHCP_POLLING_INTERVAL) < v->Now ||
\r
4575 v->LastDhcpPolling > v->Now)
\r
4580 v->LastDhcpPolling = v->Now;
\r
4582 // 有効期限の切れたエントリを削除
\r
4584 for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
\r
4586 DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
\r
4588 if (d->ExpireTime < v->Now)
\r
4591 Delete(v->DhcpLeaseList, d);
\r
4597 // DHCP REQUEST に対応する
\r
4598 UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip)
\r
4602 if (v == NULL || mac == NULL)
\r
4607 ret = ServeDhcpDiscover(v, mac, request_ip);
\r
4608 if (ret != request_ip)
\r
4610 if (request_ip != 0)
\r
4612 // 要求されている IP アドレスを割り当てることができない場合はエラー
\r
4620 // DHCP DISCOVER に対応する
\r
4621 UINT ServeDhcpDiscover(VH *v, UCHAR *mac, UINT request_ip)
\r
4625 if (v == NULL || mac == NULL)
\r
4630 if (request_ip != 0)
\r
4632 // IP アドレスが指定されている
\r
4633 DHCP_LEASE *d = SearchDhcpLeaseByIp(v, request_ip);
\r
4636 // 同じ IP アドレスのエントリがすでに存在している場合は
\r
4637 // 同じ MAC アドレスからの要求であることを調べる
\r
4638 if (Cmp(mac, d->MacAddress, 6) == 0)
\r
4640 // 指定された IP アドレスが割り当て範囲内にあるかどうか調べる
\r
4641 if (Endian32(v->DhcpIpStart) <= Endian32(request_ip) &&
\r
4642 Endian32(request_ip) <= Endian32(v->DhcpIpEnd))
\r
4651 // 指定された IP アドレスが割り当て範囲内にあるかどうか調べる
\r
4652 if (Endian32(v->DhcpIpStart) <= Endian32(request_ip) &&
\r
4653 Endian32(request_ip) <= Endian32(v->DhcpIpEnd))
\r
4660 // 範囲外であるが Discover なので範囲内の IP を 1 つ提案する
\r
4667 // すでに登録されているエントリで同じ MAC アドレスのものがあれば
\r
4669 DHCP_LEASE *d = SearchDhcpLeaseByMac(v, mac);
\r
4672 // 見つかった IP アドレスが割り当て範囲内にあるかどうか調べる
\r
4673 if (Endian32(v->DhcpIpStart) <= Endian32(d->IpAddress) &&
\r
4674 Endian32(d->IpAddress) <= Endian32(v->DhcpIpEnd))
\r
4676 // 範囲内にあるなら見つかったIPアドレスを使用する
\r
4677 ret = d->IpAddress;
\r
4684 // 新しく割り当てることが可能な IP アドレスを適当に取る
\r
4685 ret = GetFreeDhcpIpAddress(v);
\r
4691 // 新しく割り当てることが可能な IP アドレスを適当に 1 つ取る
\r
4692 UINT GetFreeDhcpIpAddress(VH *v)
\r
4694 UINT ip_start, ip_end;
\r
4702 ip_start = Endian32(v->DhcpIpStart);
\r
4703 ip_end = Endian32(v->DhcpIpEnd);
\r
4705 for (i = ip_start; i <= ip_end;i++)
\r
4707 UINT ip = Endian32(i);
\r
4708 if (SearchDhcpLeaseByIp(v, ip) == NULL)
\r
4710 // 空き IP アドレスを発見した
\r
4720 void VirtualDhcpServer(VH *v, PKT *p)
\r
4722 DHCPV4_HEADER *dhcp;
\r
4725 UINT dhcp_header_size;
\r
4726 UINT dhcp_data_offset;
\r
4728 UINT magic_cookie = Endian32(DHCP_MAGIC_COOKIE);
\r
4730 DHCP_OPTION_LIST *opt;
\r
4732 if (v == NULL || p == NULL)
\r
4737 dhcp = p->L7.DHCPv4Header;
\r
4739 tran_id = Endian32(dhcp->TransactionId);
\r
4741 // DHCP データとサイズを取得する
\r
4742 dhcp_header_size = sizeof(DHCPV4_HEADER);
\r
4743 dhcp_data_offset = (UINT)(((UCHAR *)p->L7.DHCPv4Header) - ((UCHAR *)p->MacHeader) + dhcp_header_size);
\r
4744 data = ((UCHAR *)dhcp) + dhcp_header_size;
\r
4745 size = p->PacketSize - dhcp_data_offset;
\r
4746 if (dhcp_header_size < 5)
\r
4752 // Magic Cookie を検索する
\r
4756 if (Cmp(data, &magic_cookie, sizeof(magic_cookie)) == 0)
\r
4774 // DHCP オプションリストのパース
\r
4775 opt = ParseDhcpOptionList(data, size);
\r
4782 if (dhcp->OpCode == 1 && (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST))
\r
4786 if (opt->RequestedIp == 0)
\r
4788 opt->RequestedIp = p->L3.IPv4Header->SrcIP;
\r
4790 if (opt->Opcode == DHCP_DISCOVER)
\r
4792 // 利用できる IP アドレスを 1 つ返す
\r
4793 ip = ServeDhcpDiscover(v, p->MacAddressSrc, opt->RequestedIp);
\r
4798 ip = ServeDhcpRequest(v, p->MacAddressSrc, opt->RequestedIp);
\r
4802 // 提供可能な IP アドレスがある場合は応答してやる
\r
4804 if (opt->Opcode == DHCP_REQUEST)
\r
4807 char mac[MAX_SIZE];
\r
4808 char str[MAX_SIZE];
\r
4809 // 同じ IP アドレスで古いレコードがあれば削除する
\r
4810 d = SearchDhcpLeaseByIp(v, ip);
\r
4814 Delete(v->DhcpLeaseList, d);
\r
4818 d = NewDhcpLease(v->DhcpExpire, p->MacAddressSrc,
\r
4821 d->Id = ++v->DhcpId;
\r
4822 Add(v->DhcpLeaseList, d);
\r
4823 MacToStr(mac, sizeof(mac), d->MacAddress);
\r
4825 IPToStr32(str, sizeof(str), d->IpAddress);
\r
4827 NLog(v, "LH_NAT_DHCP_CREATED", d->Id, mac, str, d->Hostname, v->DhcpExpire / 1000);
\r
4833 DHCP_OPTION_LIST ret;
\r
4835 Zero(&ret, sizeof(ret));
\r
4837 ret.Opcode = (opt->Opcode == DHCP_DISCOVER ? DHCP_OFFER : DHCP_ACK);
\r
4838 ret.ServerAddress = v->HostIP;
\r
4839 if (v->DhcpExpire == INFINITE)
\r
4841 ret.LeaseTime = INFINITE;
\r
4845 ret.LeaseTime = Endian32(v->DhcpExpire / 1000);
\r
4847 StrCpy(ret.DomainName, sizeof(ret.DomainName), v->DhcpDomain);
\r
4848 ret.SubnetMask = v->DhcpMask;
\r
4849 ret.DnsServer = v->DhcpDns;
\r
4850 ret.Gateway = v->DhcpGateway;
\r
4854 char client_mac[MAX_SIZE];
\r
4855 char client_ip[64];
\r
4857 BinToStr(client_mac, sizeof(client_mac), p->MacAddressSrc, 6);
\r
4858 UINTToIP(&ips, ip);
\r
4859 IPToStr(client_ip, sizeof(client_ip), &ips);
\r
4860 Debug("DHCP %s : %s given %s\n",
\r
4861 ret.Opcode == DHCP_OFFER ? "DHCP_OFFER" : "DHCP_ACK",
\r
4862 client_mac, client_ip);
\r
4866 o = BuildDhcpOption(&ret);
\r
4869 BUF *b = BuildDhcpOptionsBuf(o);
\r
4872 UINT dest_ip = p->L3.IPv4Header->SrcIP;
\r
4875 dest_ip = 0xffffffff;
\r
4878 VirtualDhcpSend(v, tran_id, dest_ip, Endian16(p->L4.UDPHeader->SrcPort),
\r
4879 ip, dhcp->ClientMacAddress, b);
\r
4884 FreeDhcpOptions(o);
\r
4890 // 提供できる IP アドレスが無い
\r
4891 DHCP_OPTION_LIST ret;
\r
4893 Zero(&ret, sizeof(ret));
\r
4895 ret.Opcode = DHCP_NACK;
\r
4896 ret.ServerAddress = v->HostIP;
\r
4897 StrCpy(ret.DomainName, sizeof(ret.DomainName), v->DhcpDomain);
\r
4898 ret.SubnetMask = v->DhcpMask;
\r
4901 o = BuildDhcpOption(&ret);
\r
4904 BUF *b = BuildDhcpOptionsBuf(o);
\r
4907 UINT dest_ip = p->L3.IPv4Header->SrcIP;
\r
4910 dest_ip = 0xffffffff;
\r
4913 VirtualDhcpSend(v, tran_id, dest_ip, Endian16(p->L4.UDPHeader->SrcPort),
\r
4914 ip, dhcp->ClientMacAddress, b);
\r
4919 FreeDhcpOptions(o);
\r
4929 void VirtualDhcpSend(VH *v, UINT tran_id, UINT dest_ip, UINT dest_port,
\r
4930 UINT new_ip, UCHAR *client_mac, BUF *b)
\r
4932 UINT blank_size = 128 + 64;
\r
4933 UINT dhcp_packet_size;
\r
4934 UINT magic = Endian32(DHCP_MAGIC_COOKIE);
\r
4935 DHCPV4_HEADER *dhcp;
\r
4936 void *magic_cookie_addr;
\r
4937 void *buffer_addr;
\r
4939 if (v == NULL || b == NULL)
\r
4944 // DHCP パケットサイズを求める
\r
4945 dhcp_packet_size = blank_size + sizeof(DHCPV4_HEADER) + sizeof(magic) + b->Size;
\r
4948 dhcp = ZeroMalloc(dhcp_packet_size);
\r
4951 dhcp->HardwareType = 1;
\r
4952 dhcp->HardwareAddressSize = 6;
\r
4954 dhcp->TransactionId = Endian32(tran_id);
\r
4955 dhcp->Seconds = 0;
\r
4957 dhcp->YourIP = new_ip;
\r
4958 dhcp->ServerIP = v->HostIP;
\r
4959 Copy(dhcp->ClientMacAddress, client_mac, 6);
\r
4962 magic_cookie_addr = (((UCHAR *)dhcp) + sizeof(DHCPV4_HEADER) + blank_size);
\r
4963 buffer_addr = ((UCHAR *)magic_cookie_addr) + sizeof(magic);
\r
4966 Copy(magic_cookie_addr, &magic, sizeof(magic));
\r
4969 Copy(buffer_addr, b->Buf, b->Size);
\r
4972 SendUdp(v, dest_ip, dest_port, v->HostIP, NAT_DHCP_SERVER_PORT, dhcp, dhcp_packet_size);
\r
4977 // DHCP オプション リストをバッファに変換する
\r
4978 BUF *BuildDhcpOptionsBuf(LIST *o)
\r
4991 for (i = 0;i < LIST_NUM(o);i++)
\r
4993 DHCP_OPTION *d = LIST_DATA(o, i);
\r
4994 id = (UCHAR)d->Id;
\r
4995 sz = (UCHAR)d->Size;
\r
4996 WriteBuf(b, &id, 1);
\r
4997 WriteBuf(b, &sz, 1);
\r
4998 WriteBuf(b, d->Data, d->Size);
\r
5002 WriteBuf(b, &id, 1);
\r
5007 // DHCP オプション リストを DHCP オプションに変換する
\r
5008 LIST *BuildDhcpOption(DHCP_OPTION_LIST *opt)
\r
5018 o = NewListFast(NULL);
\r
5021 opcode = (UCHAR)opt->Opcode;
\r
5022 Add(o, NewDhcpOption(DHCP_ID_MESSAGE_TYPE, &opcode, sizeof(opcode)));
\r
5023 Add(o, NewDhcpOption(DHCP_ID_SERVER_ADDRESS, &opt->ServerAddress, sizeof(opt->ServerAddress)));
\r
5024 Add(o, NewDhcpOption(DHCP_ID_LEASE_TIME, &opt->LeaseTime, sizeof(opt->LeaseTime)));
\r
5025 if (StrLen(opt->DomainName) != 0 && opt->DnsServer != 0)
\r
5027 Add(o, NewDhcpOption(DHCP_ID_DOMAIN_NAME, opt->DomainName, StrLen(opt->DomainName)));
\r
5029 if (opt->SubnetMask != 0)
\r
5031 Add(o, NewDhcpOption(DHCP_ID_SUBNET_MASK, &opt->SubnetMask, sizeof(opt->SubnetMask)));
\r
5033 if (opt->Gateway != 0)
\r
5035 Add(o, NewDhcpOption(DHCP_ID_GATEWAY_ADDR, &opt->Gateway, sizeof(opt->Gateway)));
\r
5037 if (opt->DnsServer != 0)
\r
5039 Add(o, NewDhcpOption(DHCP_ID_DNS_ADDR, &opt->DnsServer, sizeof(opt->DnsServer)));
\r
5045 // 新しい DHCP オプション項目の作成
\r
5046 DHCP_OPTION *NewDhcpOption(UINT id, void *data, UINT size)
\r
5049 if (size != 0 && data == NULL)
\r
5054 ret = ZeroMalloc(sizeof(DHCP_OPTION));
\r
5055 ret->Data = ZeroMalloc(size);
\r
5056 Copy(ret->Data, data, size);
\r
5057 ret->Size = (UCHAR)size;
\r
5058 ret->Id = (UCHAR)id;
\r
5063 // DHCP オプションリストのパース
\r
5064 DHCP_OPTION_LIST *ParseDhcpOptionList(void *data, UINT size)
\r
5066 DHCP_OPTION_LIST *ret;
\r
5076 o = ParseDhcpOptions(data, size);
\r
5082 ret = ZeroMalloc(sizeof(DHCP_OPTION_LIST));
\r
5085 a = GetDhcpOption(o, DHCP_ID_MESSAGE_TYPE);
\r
5090 ret->Opcode = *((UCHAR *)a->Data);
\r
5094 switch (ret->Opcode)
\r
5096 case DHCP_DISCOVER:
\r
5097 case DHCP_REQUEST:
\r
5098 // クライアント要求なのでより細かくパースする
\r
5100 a = GetDhcpOption(o, DHCP_ID_REQUEST_IP_ADDRESS);
\r
5101 if (a != NULL && a->Size == 4)
\r
5103 Copy(&ret->RequestedIp, a->Data, 4);
\r
5106 a = GetDhcpOption(o, DHCP_ID_HOST_NAME);
\r
5111 Copy(ret->Hostname, a->Data, MIN(a->Size, sizeof(ret->Hostname) - 1));
\r
5118 // 今のところこの 2 つのオプションをパースする必要は無い
\r
5123 FreeDhcpOptions(o);
\r
5129 DHCP_OPTION *GetDhcpOption(LIST *o, UINT id)
\r
5132 DHCP_OPTION *ret = NULL;
\r
5139 for (i = 0;i < LIST_NUM(o);i++)
\r
5141 DHCP_OPTION *opt = LIST_DATA(o, i);
\r
5142 if (opt->Id == id)
\r
5152 void FreeDhcpOptions(LIST *o)
\r
5161 for (i = 0;i < LIST_NUM(o);i++)
\r
5163 DHCP_OPTION *opt = LIST_DATA(o, i);
\r
5172 LIST *ParseDhcpOptions(void *data, UINT size)
\r
5183 WriteBuf(b, data, size);
\r
5186 o = NewListFast(NULL);
\r
5193 if (ReadBuf(b, &c, 1) != 1)
\r
5201 if (ReadBuf(b, &sz, 1) != 1)
\r
5206 opt = ZeroMalloc(sizeof(DHCP_OPTION));
\r
5207 opt->Id = (UINT)c;
\r
5208 opt->Size = (UINT)sz;
\r
5209 opt->Data = ZeroMalloc((UINT)sz);
\r
5210 ReadBuf(b, opt->Data, sz);
\r
5219 // 仮想ホスト - Layer2 の処理
\r
5220 void VirtualLayer2(VH *v, PKT *packet)
\r
5224 if (packet == NULL || v == NULL)
\r
5230 if (VirtualLayer2Filter(v, packet) == false)
\r
5237 if (packet->TypeL3 == L3_IPV4 && packet->TypeL4 == L4_UDP && packet->TypeL7 == L7_DHCPV4)
\r
5241 // DHCP パケットに関する特殊な処理
\r
5242 if (packet->BroadcastPacket || Cmp(packet->MacAddressDest, v->MacAddress, 6) == 0)
\r
5245 VirtualDhcpServer(v, packet);
\r
5253 // サポートしているプロトコルごとに処理
\r
5254 switch (packet->TypeL3)
\r
5256 case L3_ARPV4: // ARPv4
\r
5257 VirtualArpReceived(v, packet);
\r
5260 case L3_IPV4: // IPv4
\r
5261 VirtualIpReceived(v, packet);
\r
5267 // パケットフィルタ (自分以外へのパケットを遮断)
\r
5268 bool VirtualLayer2Filter(VH *v, PKT *packet)
\r
5271 if (v == NULL || packet == NULL)
\r
5276 // ブロードキャストパケットなら通過
\r
5277 if (packet->BroadcastPacket)
\r
5282 // 送信元が自分のパケットなら無視
\r
5283 if (Cmp(packet->MacAddressSrc, v->MacAddress, 6) == 0)
\r
5288 if (Cmp(packet->MacAddressDest, v->MacAddress, 6) == 0)
\r
5297 // 仮想ホストにパケットを受信させる
\r
5298 bool VirtualPutPacket(VH *v, void *data, UINT size)
\r
5308 PKT *packet = ParsePacket(data, size);
\r
5310 if (v->flag1 == false)
\r
5313 v->Now = Tick64();
\r
5316 // ここの中は仮想マシン全体をロックする
\r
5319 if (packet != NULL)
\r
5322 VirtualLayer2(v, packet);
\r
5325 FreePacket(packet);
\r
5335 bool VirtualPaPutPacket(SESSION *s, void *data, UINT size)
\r
5339 if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
\r
5344 return VirtualPutPacket(v, data, size);
\r
5347 // 仮想ホストのオプションを取得する
\r
5348 void GetVirtualHostOption(VH *v, VH_OPTION *o)
\r
5358 Zero(o, sizeof(VH_OPTION));
\r
5361 Copy(o->MacAddress, v->MacAddress, 6);
\r
5364 UINTToIP(&o->Ip, v->HostIP);
\r
5365 UINTToIP(&o->Mask, v->HostMask);
\r
5370 o->NatTcpTimeout = v->NatTcpTimeout / 1000;
\r
5371 o->NatUdpTimeout = v->NatUdpTimeout / 1000;
\r
5374 o->UseNat = v->UseNat;
\r
5377 o->UseDhcp = v->UseDhcp;
\r
5379 // DHCP 配布 IP アドレス範囲
\r
5380 UINTToIP(&o->DhcpLeaseIPStart, v->DhcpIpStart);
\r
5381 UINTToIP(&o->DhcpLeaseIPEnd, v->DhcpIpEnd);
\r
5384 UINTToIP(&o->DhcpSubnetMask, v->DhcpMask);
\r
5387 if (v->DhcpExpire != INFINITE)
\r
5389 o->DhcpExpireTimeSpan = v->DhcpExpire / 1000;
\r
5393 o->DhcpExpireTimeSpan = INFINITE;
\r
5397 UINTToIP(&o->DhcpGatewayAddress, v->DhcpGateway);
\r
5400 UINTToIP(&o->DhcpDnsServerAddress, v->DhcpDns);
\r
5403 StrCpy(o->DhcpDomainName, sizeof(o->DhcpDomainName), v->DhcpDomain);
\r
5406 o->SaveLog = v->SaveLog;
\r
5411 // 仮想ホストにオプションを設定する
\r
5412 void SetVirtualHostOption(VH *v, VH_OPTION *vo)
\r
5416 if (v == NULL || vo == NULL)
\r
5424 for (i = 0;i < 6;i++)
\r
5426 if (vo->MacAddress[i] != 0)
\r
5428 Copy(v->MacAddress, vo->MacAddress, 6);
\r
5434 v->HostIP = IPToUINT(&vo->Ip);
\r
5435 v->HostMask = IPToUINT(&vo->Mask);
\r
5438 v->Mtu = MIN(vo->Mtu, MAX_L3_DATA_SIZE);
\r
5441 v->Mtu = MAX_L3_DATA_SIZE;
\r
5443 v->Mtu = MAX(v->Mtu, TCP_HEADER_SIZE + IP_HEADER_SIZE + MAC_HEADER_SIZE + 8);
\r
5444 v->IpMss = ((v->Mtu - IP_HEADER_SIZE) / 8) * 8;
\r
5445 v->TcpMss = ((v->IpMss - TCP_HEADER_SIZE) / 8) * 8;
\r
5446 v->UdpMss = ((v->IpMss - UDP_HEADER_SIZE) / 8) * 8;
\r
5448 if (vo->NatTcpTimeout != 0)
\r
5450 v->NatTcpTimeout = MIN(vo->NatTcpTimeout, 4000000) * 1000;
\r
5452 if (vo->NatUdpTimeout != 0)
\r
5454 v->NatUdpTimeout = MIN(vo->NatUdpTimeout, 4000000) * 1000;
\r
5456 v->NatTcpTimeout = MAKESURE(v->NatTcpTimeout, NAT_TCP_MIN_TIMEOUT, NAT_TCP_MAX_TIMEOUT);
\r
5457 v->NatUdpTimeout = MAKESURE(v->NatUdpTimeout, NAT_UDP_MIN_TIMEOUT, NAT_UDP_MAX_TIMEOUT);
\r
5458 Debug("Timeout: %d , %d\n", v->NatTcpTimeout, v->NatUdpTimeout);
\r
5461 v->UseNat = vo->UseNat;
\r
5464 v->UseDhcp = vo->UseDhcp;
\r
5467 if (vo->DhcpExpireTimeSpan == 0 || vo->DhcpExpireTimeSpan == INFINITE)
\r
5469 v->DhcpExpire = INFINITE;
\r
5473 v->DhcpExpire = MAKESURE(DHCP_MIN_EXPIRE_TIMESPAN,
\r
5474 MIN(vo->DhcpExpireTimeSpan * 1000, 2000000000),
\r
5479 v->DhcpIpStart = IPToUINT(&vo->DhcpLeaseIPStart);
\r
5480 v->DhcpIpEnd = IPToUINT(&vo->DhcpLeaseIPEnd);
\r
5481 if (Endian32(v->DhcpIpEnd) < Endian32(v->DhcpIpStart))
\r
5483 v->DhcpIpEnd = v->DhcpIpStart;
\r
5487 v->DhcpMask = IPToUINT(&vo->DhcpSubnetMask);
\r
5490 v->DhcpGateway = IPToUINT(&vo->DhcpGatewayAddress);
\r
5493 v->DhcpDns = IPToUINT(&vo->DhcpDnsServerAddress);
\r
5496 StrCpy(v->DhcpDomain, sizeof(v->DhcpDomain), vo->DhcpDomainName);
\r
5499 v->SaveLog = vo->SaveLog;
\r
5505 void Virtual_Free(VH *v)
\r
5508 FreeDhcpServer(v);
\r
5516 FreeIpCombineList(v);
\r
5519 FreeIpWaitTable(v);
\r
5522 FreeArpWaitTable(v);
\r
5528 LockQueue(v->SendQueue);
\r
5533 while (block = GetNext(v->SendQueue))
\r
5538 UnlockQueue(v->SendQueue);
\r
5539 ReleaseQueue(v->SendQueue);
\r
5540 v->SendQueue = NULL;
\r
5543 ReleaseCancel(v->Cancel);
\r
5545 v->Active = false;
\r
5550 FreeLog(v->Logger);
\r
5552 void VirtualPaFree(SESSION *s)
\r
5556 if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
\r
5565 void ReleaseVirtual(VH *v)
\r
5573 if (Release(v->ref) == 0)
\r
5575 CleanupVirtual(v);
\r
5580 void LockVirtual(VH *v)
\r
5592 void UnlockVirtual(VH *v)
\r
5604 void CleanupVirtual(VH *v)
\r
5612 if (v->Session != NULL)
\r
5614 ReleaseSession(v->Session);
\r
5617 DeleteCounter(v->Counter);
\r
5618 DeleteLock(v->lock);
\r
5624 void StopVirtualHost(VH *v)
\r
5633 // 仮想ホストに対応したセッションの取得
\r
5646 // すでにこのセッションは停止している
\r
5653 ReleaseSession(s);
\r
5657 VH *NewVirtualHost(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option)
\r
5659 return NewVirtualHostEx(cedar, option, auth, vh_option, NULL);
\r
5661 VH *NewVirtualHostEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option, NAT *nat)
\r
5665 if (vh_option == NULL)
\r
5671 v = ZeroMalloc(sizeof(VH));
\r
5672 v->ref = NewRef();
\r
5673 v->lock = NewLock();
\r
5674 v->Counter = NewCounter();
\r
5679 SetVirtualHostOption(v, vh_option);
\r
5684 // ランダムな MAC アドレスを生成する
\r
5685 void GenMacAddress(UCHAR *mac)
\r
5687 UCHAR rand_data[32];
\r
5690 UCHAR hash[SHA1_SIZE];
\r
5698 now = SystemTime64();
\r
5701 Rand(rand_data, sizeof(rand_data));
\r
5705 WriteBuf(b, &now, sizeof(now));
\r
5706 WriteBuf(b, rand_data, sizeof(rand_data));
\r
5709 Hash(hash, b->Buf, b->Size, true);
\r
5713 mac[1] = 0xAC; // AC 万歳
\r
5722 // 仮想ホストのパケットアダプタを取得
\r
5723 PACKET_ADAPTER *VirtualGetPacketAdapter()
\r
5725 return NewPacketAdapter(VirtualPaInit, VirtualPaGetCancel,
\r
5726 VirtualPaGetNextPacket, VirtualPaPutPacket, VirtualPaFree);
\r