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
81 #include "CedarPch.h"
\r
83 static char *delete_targets[] =
\r
85 "backup.vpn_bridge.config",
\r
86 "backup.vpn_client.config",
\r
87 "backup.vpn_server.config",
\r
88 "backup.etherlogger.config",
\r
98 void SendSysLog(SLOG *g, wchar_t *str)
\r
103 if (g == NULL || str == NULL)
\r
108 buf_size = CalcUniToUtf8(str);
\r
109 buf = ZeroMalloc(buf_size);
\r
110 UniToUtf8(buf, buf_size, str);
\r
112 if (buf_size >= 1024)
\r
119 if (Tick64() >= g->NextPollIp)
\r
123 if (GetIP(&ip, g->HostName))
\r
125 g->NextPollIp = Tick64() + SYSLOG_POLL_IP_INTERVAL;
\r
126 Copy(&g->DestIp, &ip, sizeof(IP));
\r
130 g->NextPollIp = Tick64() + SYSLOG_POLL_IP_INTERVAL_NG;
\r
134 if (g->DestPort != 0 && IsZeroIp(&g->DestIp) == false)
\r
136 SendTo(g->Udp, &g->DestIp, g->DestPort, buf, buf_size);
\r
144 // syslog クライアントの解放
\r
145 void FreeSysLog(SLOG *g)
\r
153 DeleteLock(g->lock);
\r
154 ReleaseSock(g->Udp);
\r
158 // syslog クライアントの設定
\r
159 void SetSysLog(SLOG *g, char *hostname, UINT port)
\r
169 port = SYSLOG_PORT;
\r
172 if (hostname == NULL)
\r
177 Zero(&ip, sizeof(IP));
\r
178 GetIP(&ip, hostname);
\r
182 Copy(&g->DestIp, &ip, sizeof(IP));
\r
183 g->DestPort = port;
\r
184 StrCpy(g->HostName, sizeof(g->HostName), hostname);
\r
185 g->NextPollIp = Tick64() + IsZeroIp(&ip) ? SYSLOG_POLL_IP_INTERVAL_NG : SYSLOG_POLL_IP_INTERVAL;
\r
190 // syslog クライアントの作成
\r
191 SLOG *NewSysLog(char *hostname, UINT port)
\r
194 SLOG *g = ZeroMalloc(sizeof(SLOG));
\r
196 g->lock = NewLock();
\r
197 g->Udp = NewUDP(0);
\r
199 SetSysLog(g, hostname, port);
\r
204 // ディスクに十分な空き容量があるかチェックする
\r
205 bool CheckEraserDiskFreeSpace(ERASER *e)
\r
215 if (GetDiskFree(e->DirName, &s, NULL, NULL) == false)
\r
221 if (e->MinFreeSpace > s)
\r
223 // 空き容量が指定されたバイト数未満である
\r
231 // 削除対象ファイルリストを解放する
\r
232 void FreeEraseFileList(LIST *o)
\r
241 for (i = 0;i < LIST_NUM(o);i++)
\r
243 ERASE_FILE *f = LIST_DATA(o, i);
\r
251 // 削除対象ファイルリストを表示する
\r
252 void PrintEraseFileList(LIST *o)
\r
261 for (i = 0;i < LIST_NUM(o);i++)
\r
263 ERASE_FILE *f = LIST_DATA(o, i);
\r
264 Print("%I64u - %s\n", f->UpdateTime, f->FullPath);
\r
268 // 指定されたディレクトリの削除対象ファイルリストを生成する
\r
269 void EnumEraseFile(LIST *o, char *dirname)
\r
273 char tmp[MAX_PATH];
\r
275 if (o == NULL || dirname == NULL)
\r
281 dir = EnumDir(dirname);
\r
283 for (i = 0;i < dir->NumFiles;i++)
\r
285 DIRENT *e = dir->File[i];
\r
286 Format(tmp, sizeof(tmp), "%s/%s", dirname, e->FileName);
\r
287 NormalizePath(tmp, sizeof(tmp), tmp);
\r
289 if (e->Folder == false)
\r
294 if (EndWith(tmp, ".log") || EndWith(tmp, ".config"))
\r
296 // ログファイルと .config ファイルのみを対象とする
\r
297 f = ZeroMalloc(sizeof(ERASE_FILE));
\r
298 f->FullPath = CopyStr(tmp);
\r
299 f->UpdateTime = e->UpdateDate;
\r
307 EnumEraseFile(o, tmp);
\r
314 // 削除対象ファイルリストを生成する
\r
315 LIST *GenerateEraseFileList(ERASER *e)
\r
325 o = NewListFast(CompareEraseFile);
\r
328 for (i = 0;i < sizeof(delete_targets) / sizeof(delete_targets[0]);i++)
\r
330 char dirname[MAX_PATH];
\r
331 Format(dirname, sizeof(dirname), "%s/%s", e->DirName, delete_targets[i]);
\r
333 EnumEraseFile(o, dirname);
\r
343 void EraserMain(ERASER *e)
\r
356 if (CheckEraserDiskFreeSpace(e))
\r
362 ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
\r
365 o = GenerateEraseFileList(e);
\r
367 // ファイルを古い順に 1 つずつ削除してみる
\r
368 for (i = 0;i < LIST_NUM(o);i++)
\r
370 ERASE_FILE *f = LIST_DATA(o, i);
\r
373 if (FileDelete(f->FullPath))
\r
375 ELog(e, "LE_DELETE", bs, f->FullPath);
\r
378 // 削除したあと空き容量を確認してみる
\r
379 if (CheckEraserDiskFreeSpace(e))
\r
388 FreeEraseFileList(o);
\r
390 if (e->LastFailed == false && ok == false)
\r
392 // 空き容量が足りないがこれ以上ファイルを削除できない状態になってしまった
\r
393 ELog(e, "LE_NOT_ENOUGH_FREE", bs);
\r
396 e->LastFailed = ok ? false : true;
\r
400 int CompareEraseFile(void *p1, void *p2)
\r
402 ERASE_FILE *f1, *f2;
\r
403 if (p1 == NULL || p2 == NULL)
\r
407 f1 = *(ERASE_FILE **)p1;
\r
408 f2 = *(ERASE_FILE **)p2;
\r
409 if (f1 == NULL || f2 == NULL)
\r
413 if (f1->UpdateTime > f2->UpdateTime)
\r
417 else if (f1->UpdateTime == f2->UpdateTime)
\r
428 void EraserThread(THREAD *t, void *p)
\r
430 ERASER *e = (ERASER *)p;
\r
433 if (t == NULL || e == NULL)
\r
439 ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
\r
440 ELog(e, "LE_START", e->DirName, bs);
\r
442 while (e->Halt == false)
\r
444 // 一定間隔ごとにディスクの空き容量をチェックする
\r
447 Wait(e->HaltEvent, DISK_FREE_CHECK_INTERVAL);
\r
452 ERASER *NewEraser(LOG *log, UINT64 min_size)
\r
455 char dir[MAX_PATH];
\r
459 min_size = DISK_FREE_SPACE_DEFAULT;
\r
462 if (min_size < DISK_FREE_SPACE_MIN)
\r
464 min_size = DISK_FREE_SPACE_MIN;
\r
467 e = ZeroMalloc(sizeof(ERASER));
\r
469 GetExeDir(dir, sizeof(dir));
\r
472 e->MinFreeSpace = min_size;
\r
473 e->DirName = CopyStr(dir);
\r
474 e->HaltEvent = NewEvent();
\r
476 e->Thread = NewThread(EraserThread, e);
\r
482 void FreeEraser(ERASER *e)
\r
492 WaitThread(e->Thread, INFINITE);
\r
493 ReleaseThread(e->Thread);
\r
494 ReleaseEvent(e->HaltEvent);
\r
500 // デバッグログをとる (可変長引数)
\r
501 void DebugLog(CEDAR *c, char *fmt, ...)
\r
503 char buf[MAX_SIZE * 2];
\r
510 if (c->DebugLog == NULL)
\r
515 va_start(args, fmt);
\r
516 FormatArgs(buf, sizeof(buf), fmt, args);
\r
518 InsertStringRecord(c->DebugLog, buf);
\r
523 void ELog(ERASER *e, char *name, ...)
\r
525 wchar_t buf[MAX_SIZE * 2];
\r
533 va_start(args, name);
\r
534 UniFormatArgs(buf, sizeof(buf), _UU(name), args);
\r
536 InsertUnicodeRecord(e->Log, buf);
\r
540 UniPrint(L"LOG: %s\n", buf);
\r
546 void ServerLog(CEDAR *c, wchar_t *fmt, ...)
\r
548 wchar_t buf[MAX_SIZE * 2];
\r
556 va_start(args, fmt);
\r
557 UniFormatArgs(buf, sizeof(buf), fmt, args);
\r
559 WriteServerLog(c, buf);
\r
562 void SLog(CEDAR *c, char *name, ...)
\r
564 wchar_t buf[MAX_SIZE * 2];
\r
572 va_start(args, name);
\r
573 UniFormatArgs(buf, sizeof(buf), _UU(name), args);
\r
575 WriteServerLog(c, buf);
\r
580 void CLog(CLIENT *c, char *name, ...)
\r
582 wchar_t buf[MAX_SIZE * 2];
\r
590 if (c == NULL || c->NoSaveLog)
\r
595 va_start(args, name);
\r
596 UniFormatArgs(buf, sizeof(buf), _UU(name), args);
\r
598 WriteClientLog(c, buf);
\r
602 // HUB のセキュリティログをとる
\r
603 void HubLog(HUB *h, wchar_t *fmt, ...)
\r
605 wchar_t buf[MAX_SIZE * 2];
\r
613 va_start(args, fmt);
\r
614 UniFormatArgs(buf, sizeof(buf), fmt, args);
\r
616 WriteHubLog(h, buf);
\r
619 void ALog(ADMIN *a, HUB *h, char *name, ...)
\r
621 wchar_t buf[MAX_SIZE * 2];
\r
622 wchar_t tmp[MAX_SIZE * 2];
\r
626 if (a == NULL || name == NULL)
\r
633 va_start(args, name);
\r
634 UniFormatArgs(buf, sizeof(buf), _UU(name), args);
\r
638 UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_1"), r->Name);
\r
642 UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_2"), r->Name, h->Name);
\r
645 UniStrCat(tmp, sizeof(tmp), buf);
\r
649 WriteServerLog(((ADMIN *)r->Param)->Server->Cedar, tmp);
\r
653 WriteHubLog(h, tmp);
\r
657 void HLog(HUB *h, char *name, ...)
\r
659 wchar_t buf[MAX_SIZE * 2];
\r
667 va_start(args, name);
\r
668 UniFormatArgs(buf, sizeof(buf), _UU(name), args);
\r
670 WriteHubLog(h, buf);
\r
673 void NLog(VH *v, char *name, ...)
\r
675 wchar_t buf[MAX_SIZE * 2];
\r
676 static wchar_t snat_prefix[] = L"SecureNAT: ";
\r
679 if (name == NULL || v == NULL || v->nat == NULL || v->nat->SecureNAT == NULL)
\r
684 va_start(args, name);
\r
685 Copy(buf, snat_prefix, sizeof(snat_prefix));
\r
686 UniFormatArgs(&buf[11], sizeof(buf) - 12 * sizeof(wchar_t), _UU(name), args);
\r
688 WriteHubLog(v->nat->SecureNAT->Hub, buf);
\r
692 // HUB のセキュリティログを保存する
\r
693 void WriteHubLog(HUB *h, wchar_t *str)
\r
695 wchar_t buf[MAX_SIZE * 2];
\r
698 if (h == NULL || str == NULL)
\r
703 s = h->Cedar->Server;
\r
705 UniFormat(buf, sizeof(buf), L"[HUB \"%S\"] %s", h->Name, str);
\r
707 WriteServerLog(h->Cedar, buf);
\r
709 if (h->LogSetting.SaveSecurityLog == false)
\r
714 InsertUnicodeRecord(h->SecurityLogger, str);
\r
718 void WriteClientLog(CLIENT *c, wchar_t *str)
\r
726 InsertUnicodeRecord(c->Logger, str);
\r
729 // サーバーのセキュリティログを保存する
\r
730 void WriteServerLog(CEDAR *c, wchar_t *str)
\r
734 if (c == NULL || str == NULL)
\r
747 UniPrint(L"LOG: %s\n", str);
\r
750 InsertUnicodeRecord(s->Logger, str);
\r
754 void WriteMultiLineLog(LOG *g, BUF *b)
\r
757 if (g == NULL || b == NULL)
\r
766 char *s = CfgReadNextLine(b);
\r
772 if (IsEmptyStr(s) == false)
\r
774 InsertStringRecord(g, s);
\r
781 // セキュリティログをとる (可変長引数) ※ 廃止
\r
782 void SecLog(HUB *h, char *fmt, ...)
\r
784 char buf[MAX_SIZE * 2];
\r
792 if (h->LogSetting.SaveSecurityLog == false)
\r
797 va_start(args, fmt);
\r
798 FormatArgs(buf, sizeof(buf), fmt, args);
\r
800 WriteSecurityLog(h, buf);
\r
805 void WriteSecurityLog(HUB *h, char *str)
\r
808 if (h == NULL || str == NULL)
\r
813 InsertStringRecord(h->SecurityLogger, str);
\r
817 void PacketLog(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *packet)
\r
823 bool no_log = false;
\r
825 if (hub == NULL || src_session == NULL || packet == NULL)
\r
830 s = hub->Cedar->Server;
\r
832 if (hub->LogSetting.SavePacketLog == false)
\r
838 if (Cmp(hub->HubMacAddr, packet->MacAddressSrc, 6) == 0 ||
\r
839 Cmp(hub->HubMacAddr, packet->MacAddressDest, 6) == 0)
\r
845 level = CalcPacketLoggingLevel(hub, packet);
\r
846 if (level == PACKET_LOG_NONE)
\r
852 if (hub->Option != NULL)
\r
854 if (hub->Option->NoIPv4PacketLog && (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4))
\r
856 // IPv4 パケットログを一切保存しない
\r
860 if (hub->Option->NoIPv6PacketLog && packet->TypeL3 == L3_IPV6)
\r
862 // IPv6 パケットログを一切保存しない
\r
867 if (s->Cedar->Bridge == false)
\r
869 if (s->LicenseSystem != NULL && s->LicenseSystem->Status != NULL)
\r
871 if (s->LicenseSystem->Status->AllowEnterpriseFunction == false &&
\r
872 s->LicenseSystem->Status->Edition != 0)
\r
874 // VPN Server の製品エディションが低い場合はパケットログのうち一部
\r
882 p = ClonePacket(packet, level == PACKET_LOG_ALL ? true : false);
\r
885 pl = ZeroMalloc(sizeof(PACKET_LOG));
\r
886 pl->Cedar = hub->Cedar;
\r
888 pl->NoLog = no_log;
\r
889 if (src_session != NULL)
\r
891 pl->SrcSessionName = CopyStr(src_session->Name);
\r
895 pl->SrcSessionName = CopyStr("");
\r
897 if (dest_session != NULL)
\r
899 pl->DestSessionName = CopyStr(dest_session->Name);
\r
903 pl->DestSessionName = CopyStr("");
\r
906 if (src_session->LoggingRecordCount != NULL)
\r
909 while (src_session->LoggingRecordCount->c >= 30000)
\r
920 pl->SrcSession = src_session;
\r
921 AddRef(src_session->ref);
\r
923 Inc(src_session->LoggingRecordCount);
\r
926 InsertRecord(hub->PacketLogger, pl, PacketLogParseProc);
\r
929 // 指定されたパケットのロギングレベルを計算する
\r
930 UINT CalcPacketLoggingLevelEx(HUB_LOG *g, PKT *packet)
\r
934 if (g == NULL || packet == NULL)
\r
936 return PACKET_LOG_NONE;
\r
940 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ETHERNET]);
\r
942 switch (packet->TypeL3)
\r
946 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ARP]);
\r
951 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
\r
953 switch (packet->TypeL4)
\r
957 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
\r
962 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
\r
964 if (packet->L4.TCPHeader->Flag & TCP_SYN ||
\r
965 packet->L4.TCPHeader->Flag & TCP_RST ||
\r
966 packet->L4.TCPHeader->Flag & TCP_FIN)
\r
969 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
\r
976 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
\r
978 switch (packet->TypeL7)
\r
982 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_DHCP]);
\r
993 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
\r
995 switch (packet->TypeL4)
\r
999 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
\r
1004 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
\r
1006 if (packet->L4.TCPHeader->Flag & TCP_SYN ||
\r
1007 packet->L4.TCPHeader->Flag & TCP_RST ||
\r
1008 packet->L4.TCPHeader->Flag & TCP_FIN)
\r
1011 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
\r
1018 ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
\r
1028 UINT CalcPacketLoggingLevel(HUB *hub, PKT *packet)
\r
1031 if (hub == NULL || packet == NULL)
\r
1033 return PACKET_LOG_NONE;
\r
1036 return CalcPacketLoggingLevelEx(&hub->LogSetting, packet);
\r
1039 // パケットログエントリを文字列に変換するプロシージャ
\r
1040 char *PacketLogParseProc(RECORD *rec)
\r
1046 char tmp[MAX_SIZE];
\r
1053 pl = (PACKET_LOG *)rec->Data;
\r
1057 t = ZeroMalloc(sizeof(TOKEN_LIST));
\r
1058 t->NumTokens = 16;
\r
1059 t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
\r
1062 t->Token[0] = pl->SrcSessionName;
\r
1065 t->Token[1] = pl->DestSessionName;
\r
1068 BinToStr(tmp, sizeof(tmp), p->MacAddressSrc, 6);
\r
1070 t->Token[2] = CopyStr(tmp);
\r
1072 BinToStr(tmp, sizeof(tmp), p->MacAddressDest, 6);
\r
1074 t->Token[3] = CopyStr(tmp);
\r
1077 snprintf(tmp, sizeof(tmp), "0x%04X", Endian16(p->MacHeader->Protocol));
\r
1078 t->Token[4] = CopyStr(tmp);
\r
1081 ToStr(tmp, p->PacketSize);
\r
1082 t->Token[5] = CopyStr(tmp);
\r
1084 // パケットログ本体は実装されていない
\r
1085 t->Token[6] = CopyUniToUtf(_UU("LH_PACKET_LOG_NO_LOG"));
\r
1087 s = GenCsvLine(t);
\r
1091 if (pl->PurePacket == false)
\r
1093 FreeClonePacket(p);
\r
1097 Free(p->PacketData);
\r
1102 if (pl->SrcSession != NULL)
\r
1104 Dec(pl->SrcSession->LoggingRecordCount);
\r
1105 ReleaseSession(pl->SrcSession);
\r
1108 // PACKET_LOG を破棄する
\r
1115 char *TcpFlagStr(UCHAR flag)
\r
1117 char tmp[MAX_SIZE];
\r
1118 StrCpy(tmp, sizeof(tmp), "");
\r
1120 if (flag & TCP_FIN)
\r
1122 StrCat(tmp, sizeof(tmp), "FIN+");
\r
1125 if (flag & TCP_SYN)
\r
1127 StrCat(tmp, sizeof(tmp), "SYN+");
\r
1130 if (flag & TCP_RST)
\r
1132 StrCat(tmp, sizeof(tmp), "RST+");
\r
1135 if (flag & TCP_PSH)
\r
1137 StrCat(tmp, sizeof(tmp), "PSH+");
\r
1140 if (flag & TCP_ACK)
\r
1142 StrCat(tmp, sizeof(tmp), "ACK+");
\r
1145 if (flag & TCP_URG)
\r
1147 StrCat(tmp, sizeof(tmp), "URG+");
\r
1150 if (StrLen(tmp) >= 1)
\r
1152 if (tmp[StrLen(tmp) - 1] == '+')
\r
1154 tmp[StrLen(tmp) - 1] = 0;
\r
1158 return CopyStr(tmp);
\r
1162 char *PortStr(CEDAR *cedar, UINT port, bool udp)
\r
1164 char tmp[MAX_SIZE];
\r
1167 if (cedar == NULL)
\r
1172 name = GetSvcName(cedar, udp, port);
\r
1176 snprintf(tmp, sizeof(tmp), "%u", port);
\r
1180 snprintf(tmp, sizeof(tmp), "%s(%u)", name, port);
\r
1183 return CopyStr(tmp);
\r
1186 // カンマで区切られた文字列を生成する
\r
1187 char *GenCsvLine(TOKEN_LIST *t)
\r
1199 for (i = 0;i < t->NumTokens;i++)
\r
1201 if (t->Token[i] != NULL)
\r
1203 ReplaceForCsv(t->Token[i]);
\r
1204 if (StrLen(t->Token[i]) == 0)
\r
1206 WriteBuf(b, "-", 1);
\r
1210 WriteBuf(b, t->Token[i], StrLen(t->Token[i]));
\r
1215 WriteBuf(b, "-", 1);
\r
1217 if (i != (t->NumTokens - 1))
\r
1219 WriteBuf(b, ",", 1);
\r
1222 WriteBuf(b, "\0", 1);
\r
1224 ret = (char *)b->Buf;
\r
1231 // CSV の中に入る文字列を正しく置換する
\r
1232 void ReplaceForCsv(char *str)
\r
1243 len = StrLen(str);
\r
1245 for (i = 0;i < len;i++)
\r
1247 // カンマをアンダーバーに変換する
\r
1248 if (str[i] == ',')
\r
1256 void SetLogDirName(LOG *g, char *dir)
\r
1259 if (g == NULL || dir == NULL)
\r
1266 if (g->DirName != NULL)
\r
1270 g->DirName = CopyStr(dir);
\r
1276 void SetLogPrefix(LOG *g, char *prefix)
\r
1279 if (g == NULL || prefix == NULL)
\r
1286 if (g->DirName != NULL)
\r
1290 g->DirName = CopyStr(prefix);
\r
1296 void SetLogSwitchType(LOG *g, UINT switch_type)
\r
1306 g->SwitchType = switch_type;
\r
1312 char *StringRecordParseProc(RECORD *rec)
\r
1320 return (char *)rec->Data;
\r
1323 // ログに Unicode 文字列レコードを追加
\r
1324 void InsertUnicodeRecord(LOG *g, wchar_t *unistr)
\r
1329 if (g == NULL || unistr == NULL)
\r
1334 size = CalcUniToUtf8(unistr) + 32;
\r
1335 str = ZeroMalloc(size);
\r
1337 UniToUtf8((BYTE *)str, size, unistr);
\r
1338 InsertStringRecord(g, str);
\r
1343 void InsertStringRecord(LOG *g, char *str)
\r
1347 if (g == NULL || str == NULL)
\r
1352 str_copy = CopyStr(str);
\r
1354 InsertRecord(g, str_copy, StringRecordParseProc);
\r
1358 void InsertRecord(LOG *g, void *data, RECORD_PARSE_PROC *proc)
\r
1362 if (g == NULL || data == NULL || proc == NULL)
\r
1367 rec = ZeroMalloc(sizeof(RECORD));
\r
1368 rec->Tick = Tick64();
\r
1369 rec->ParseProc = proc;
\r
1372 LockQueue(g->RecordQueue);
\r
1374 InsertQueue(g->RecordQueue, rec);
\r
1376 UnlockQueue(g->RecordQueue);
\r
1382 void LockLog(LOG *g)
\r
1394 void UnlockLog(LOG *g)
\r
1405 // ログファイル名の文字列部分を時刻とスイッチ規則から生成する
\r
1406 void MakeLogFileNameStringFromTick(LOG *g, char *str, UINT size, UINT64 tick, UINT switch_type)
\r
1412 if (str == NULL || g == NULL)
\r
1419 if (g->LastTick == tick &&
\r
1420 g->LastSwitchType == switch_type)
\r
1422 StrCpy(str, size, g->LastStr);
\r
1427 time = TickToTime(tick);
\r
1428 UINT64ToSystem(&st, SystemToLocal64(time));
\r
1430 switch (switch_type)
\r
1432 case LOG_SWITCH_SECOND: // 1 秒単位
\r
1433 snprintf(str, size, "_%04u%02u%02u_%02u%02u%02u",
\r
1434 st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
\r
1437 case LOG_SWITCH_MINUTE: // 1 分単位
\r
1438 snprintf(str, size, "_%04u%02u%02u_%02u%02u",
\r
1439 st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);
\r
1442 case LOG_SWITCH_HOUR: // 1 時間単位
\r
1443 snprintf(str, size, "_%04u%02u%02u_%02u", st.wYear, st.wMonth, st.wDay, st.wHour);
\r
1446 case LOG_SWITCH_DAY: // 1 日単位
\r
1447 snprintf(str, size, "_%04u%02u%02u", st.wYear, st.wMonth, st.wDay);
\r
1450 case LOG_SWITCH_MONTH: // 1 ヶ月単位
\r
1451 snprintf(str, size, "_%04u%02u", st.wYear, st.wMonth);
\r
1454 default: // 切り替え無し
\r
1455 snprintf(str, size, "");
\r
1459 g->CacheFlag = true;
\r
1460 g->LastTick = tick;
\r
1461 g->LastSwitchType = switch_type;
\r
1462 StrCpy(g->LastStr, sizeof(g->LastStr), str);
\r
1466 bool MakeLogFileName(LOG *g, char *name, UINT size, char *dir, char *prefix, UINT64 tick, UINT switch_type, UINT num, char *old_datestr)
\r
1468 char tmp[MAX_SIZE];
\r
1472 if (g == NULL || name == NULL || prefix == NULL || old_datestr == NULL)
\r
1477 MakeLogFileNameStringFromTick(g, tmp, sizeof(tmp), tick, switch_type);
\r
1485 snprintf(tmp2, sizeof(tmp2), "~%02u", num);
\r
1488 if (strcmp(old_datestr, tmp) != 0)
\r
1491 strcpy(old_datestr, tmp);
\r
1494 snprintf(name, size, "%s%s%s%s%s.log", dir,
\r
1495 StrLen(dir) == 0 ? "" : "/",
\r
1502 // ログがフラッシュされるまで待機
\r
1503 void WaitLogFlush(LOG *g)
\r
1514 LockQueue(g->RecordQueue);
\r
1516 num = g->RecordQueue->num_item;
\r
1518 UnlockQueue(g->RecordQueue);
\r
1525 Wait(g->FlushEvent, 100);
\r
1530 void LogThread(THREAD *thread, void *param)
\r
1535 bool flag = false;
\r
1536 char current_file_name[MAX_SIZE];
\r
1537 char current_logfile_datename[MAX_SIZE];
\r
1538 bool last_priority_flag = false;
\r
1539 bool log_date_changed = false;
\r
1541 if (thread == NULL || param == NULL)
\r
1546 Zero(current_file_name, sizeof(current_file_name));
\r
1547 Zero(current_logfile_datename, sizeof(current_logfile_datename));
\r
1557 MsSetThreadPriorityIdle();
\r
1559 #endif // OS_WIN32
\r
1561 NoticeThreadInit(thread);
\r
1566 UINT64 s = Tick64();
\r
1570 char file_name[MAX_SIZE];
\r
1573 // キューの先頭からレコードを取得する
\r
1574 LockQueue(g->RecordQueue);
\r
1576 rec = GetNext(g->RecordQueue);
\r
1577 num = g->RecordQueue->num_item;
\r
1579 UnlockQueue(g->RecordQueue);
\r
1582 if (num >= LOG_ENGINE_SAVE_START_CACHE_COUNT)
\r
1585 if (last_priority_flag == false)
\r
1587 Debug("LOG_THREAD: MsSetThreadPriorityRealtime\n");
\r
1588 MsSetThreadPriorityRealtime();
\r
1589 last_priority_flag = true;
\r
1593 if (num < (LOG_ENGINE_SAVE_START_CACHE_COUNT / 2))
\r
1596 if (last_priority_flag)
\r
1598 Debug("LOG_THREAD: MsSetThreadPriorityIdle\n");
\r
1599 MsSetThreadPriorityIdle();
\r
1600 last_priority_flag = false;
\r
1603 #endif // OS_WIN32
\r
1605 if (b->Size > g->MaxLogFileSize)
\r
1607 // バッファのサイズが最大ログファイルサイズを超える場合は消去する
\r
1611 if (b->Size >= LOG_ENGINE_BUFFER_CACHE_SIZE_MAX)
\r
1613 // バッファの中身をファイルに書き出す
\r
1616 if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
\r
1618 if (g->log_number_incremented == false)
\r
1620 g->CurrentLogNumber++;
\r
1621 g->log_number_incremented = true;
\r
1626 if (FileWrite(io, b->Buf, b->Size) == false)
\r
1628 FileCloseEx(io, true);
\r
1629 // ファイルへの書き込みに失敗した場合は仕方が無い
\r
1636 g->CurrentFilePointer += (UINT64)b->Size;
\r
1647 // バッファの中身をファイルに書き出す
\r
1650 if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
\r
1652 if (g->log_number_incremented == false)
\r
1654 g->CurrentLogNumber++;
\r
1655 g->log_number_incremented = true;
\r
1660 if (FileWrite(io, b->Buf, b->Size) == false)
\r
1662 FileCloseEx(io, true);
\r
1663 // ファイルへの書き込みに失敗した場合は仕方が無い
\r
1670 g->CurrentFilePointer += (UINT64)b->Size;
\r
1677 Set(g->FlushEvent);
\r
1684 log_date_changed = MakeLogFileName(g, file_name, sizeof(file_name),
\r
1685 g->DirName, g->Prefix, rec->Tick, g->SwitchType, g->CurrentLogNumber, current_logfile_datename);
\r
1687 if (log_date_changed)
\r
1691 g->CurrentLogNumber = 0;
\r
1692 MakeLogFileName(g, file_name, sizeof(file_name),
\r
1693 g->DirName, g->Prefix, rec->Tick, g->SwitchType, 0, current_logfile_datename);
\r
1696 char tmp[MAX_SIZE];
\r
1697 MakeLogFileName(g, tmp, sizeof(tmp),
\r
1698 g->DirName, g->Prefix, rec->Tick, g->SwitchType, i, current_logfile_datename);
\r
1700 if (IsFileExists(tmp) == false)
\r
1704 StrCpy(file_name, sizeof(file_name), tmp);
\r
1705 g->CurrentLogNumber = i;
\r
1713 if (StrCmp(current_file_name, file_name) != 0)
\r
1715 // 現在ログファイルを開いていて今回別のログファイルへの書き込みが必要になった
\r
1716 // 場合はログファイルにバッファの内容を書き込んでからログファイルを閉じる
\r
1717 // バッファの中身をファイルに書き出す
\r
1720 if (log_date_changed)
\r
1722 if ((g->CurrentFilePointer + (UINT64)b->Size) <= g->MaxLogFileSize)
\r
1724 if (FileWrite(io, b->Buf, b->Size) == false)
\r
1726 FileCloseEx(io, true);
\r
1732 g->CurrentFilePointer += (UINT64)b->Size;
\r
1738 FileCloseEx(io, true);
\r
1741 g->log_number_incremented = false;
\r
1743 // 新しいログファイルを開くか作成する
\r
1744 StrCpy(current_file_name, sizeof(current_file_name), file_name);
\r
1745 io = FileOpen(file_name, true);
\r
1751 MakeDir(g->DirName);
\r
1754 Win32SetFolderCompress(g->DirName, true);
\r
1755 #endif // OS_WIN32
\r
1758 io = FileCreate(file_name);
\r
1759 g->CurrentFilePointer = 0;
\r
1764 g->CurrentFilePointer = FileSize64(io);
\r
1765 FileSeek(io, SEEK_END, 0);
\r
1771 // 新しいログファイルを開くか作成する
\r
1772 StrCpy(current_file_name, sizeof(current_file_name), file_name);
\r
1773 io = FileOpen(file_name, true);
\r
1779 MakeDir(g->DirName);
\r
1781 Win32SetFolderCompress(g->DirName, true);
\r
1782 #endif // OS_WIN32
\r
1785 io = FileCreate(file_name);
\r
1786 g->CurrentFilePointer = 0;
\r
1789 Debug("Logging.c: SleepThread(30);\n");
\r
1796 g->CurrentFilePointer = FileSize64(io);
\r
1797 FileSeek(io, SEEK_END, 0);
\r
1800 g->log_number_incremented = false;
\r
1803 // ログの内容をバッファに書き出す
\r
1804 WriteRecordToBuffer(b, rec);
\r
1818 // すべてのレコードを保存し終えるとブレイクする
\r
1821 if (flag == false)
\r
1824 MsSetThreadPriorityRealtime();
\r
1825 #endif // OS_WIN32
\r
1829 LockQueue(g->RecordQueue);
\r
1831 num = g->RecordQueue->num_item;
\r
1833 UnlockQueue(g->RecordQueue);
\r
1835 if (num == 0 || io == NULL)
\r
1842 Wait(g->Event, 9821);
\r
1848 FileCloseEx(io, true);
\r
1854 // ログの内容をバッファに書き出す
\r
1855 void WriteRecordToBuffer(BUF *b, RECORD *r)
\r
1858 char time_str[MAX_SIZE];
\r
1859 char date_str[MAX_SIZE];
\r
1862 if (b == NULL || r == NULL)
\r
1868 time = SystemToLocal64(TickToTime(r->Tick));
\r
1871 GetDateStr64(date_str, sizeof(date_str), time);
\r
1872 GetTimeStrMilli64(time_str, sizeof(time_str), time);
\r
1874 if (r->ParseProc != PacketLogParseProc)
\r
1877 WriteBuf(b, date_str, StrLen(date_str));
\r
1878 WriteBuf(b, " ", 1);
\r
1879 WriteBuf(b, time_str, StrLen(time_str));
\r
1880 WriteBuf(b, " ", 1);
\r
1885 WriteBuf(b, date_str, StrLen(date_str));
\r
1886 WriteBuf(b, ",", 1);
\r
1887 WriteBuf(b, time_str, StrLen(time_str));
\r
1888 WriteBuf(b, ",", 1);
\r
1892 s = r->ParseProc(r);
\r
1893 WriteBuf(b, s, StrLen(s));
\r
1896 WriteBuf(b, "\r\n", 2);
\r
1900 void FreeLog(LOG *g)
\r
1913 WaitThread(g->Thread, INFINITE);
\r
1914 ReleaseThread(g->Thread);
\r
1916 DeleteLock(g->lock);
\r
1920 // 未処理のレコードが残っている場合は解放する
\r
1921 // (本来はここでは残っていないはず)
\r
1922 while (rec = GetNext(g->RecordQueue))
\r
1924 char *s = rec->ParseProc(rec);
\r
1928 ReleaseQueue(g->RecordQueue);
\r
1930 ReleaseEvent(g->Event);
\r
1931 ReleaseEvent(g->FlushEvent);
\r
1937 LOG *NewLog(char *dir, char *prefix, UINT switch_type)
\r
1941 g = ZeroMalloc(sizeof(LOG));
\r
1942 g->lock = NewLock();
\r
1943 g->DirName = CopyStr(dir == NULL ? "" : dir);
\r
1944 g->Prefix = CopyStr(prefix == NULL ? "log" : prefix);
\r
1945 g->SwitchType = switch_type;
\r
1946 g->RecordQueue = NewQueue();
\r
1947 g->Event = NewEvent();
\r
1948 g->MaxLogFileSize = MAX_LOG_SIZE;
\r
1949 g->FlushEvent = NewEvent();
\r
1951 g->Thread = NewThread(LogThread, g);
\r
1953 WaitThreadInit(g->Thread);
\r