ipacl.cxx
来自「pwlib源码库」· CXX 代码 · 共 621 行
CXX
621 行
/* * ipacl.cxx * * IP Access Control Lists * * Portable Windows Library * * Copyright (c) 2002 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Contributor(s): ______________________________________. * * $Log: ipacl.cxx,v $ * Revision 1.16 2005/01/26 05:37:58 csoutheren * Added ability to remove config file support * * Revision 1.15 2004/04/03 08:22:20 csoutheren * Remove pseudo-RTTI and replaced with real RTTI * * Revision 1.14 2002/11/06 22:47:25 robertj * Fixed header comment (copyright etc) * * Revision 1.13 2002/07/16 10:05:01 robertj * Fixed GNU warning * * Revision 1.12 2002/07/16 10:02:49 robertj * Fixed MSVC warning * * Revision 1.11 2002/07/16 09:58:51 robertj * Fixed compatibility with unix htonl(), use platform independent function! * Allow number of bits of 32 to be a full mask, ie a single host ip. * * Revision 1.10 2002/07/16 08:00:49 robertj * Fixed correct endian-ness of mask when specifed in bits. * * Revision 1.9 2002/06/19 04:03:21 robertj * Added default allowance boolean if ACL empty. * Added ability to override the creation of ACL entry objects with descendents * so an application can add information/functionality to each entry. * * Revision 1.8 2002/02/13 02:08:12 robertj * Added const to IsAllowed() function. * Added missing function that takes a socket. * * Revision 1.7 1999/02/25 13:01:11 robertj * Fixed subtle bug in GNU compiler not automatically casting IP address. * * Revision 1.6 1999/02/25 11:10:52 robertj * Fixed count of non-hidden entries in config file. * * Revision 1.5 1999/02/25 05:05:15 robertj * Added missing test for hidden entries not to be written to config file * * Revision 1.4 1999/02/08 08:05:39 robertj * Changed semantics of IP access control list for empty list. * * Revision 1.3 1999/01/31 10:14:07 robertj * Changed about dialog to be full company name * * Revision 1.2 1999/01/31 08:10:33 robertj * Fixed PConfig file save, out by one error in array subscript. * * Revision 1.1 1999/01/31 00:59:26 robertj * Added IP Access Control List class to PTLib Components * */#include <ptlib.h>#include <ptclib/ipacl.h>#define new PNEWPIpAccessControlEntry::PIpAccessControlEntry(PIPSocket::Address addr, PIPSocket::Address msk, BOOL allow) : address(addr), mask(msk){ allowed = allow; hidden = FALSE;}PIpAccessControlEntry::PIpAccessControlEntry(const PString & description) : address(0), mask(0xffffffff){ Parse(description);}PIpAccessControlEntry & PIpAccessControlEntry::operator=(const PString & description){ Parse(description); return *this;}PIpAccessControlEntry & PIpAccessControlEntry::operator=(const char * description){ Parse(description); return *this;}PObject::Comparison PIpAccessControlEntry::Compare(const PObject & obj) const{ PAssert(PIsDescendant(&obj, PIpAccessControlEntry), PInvalidCast); const PIpAccessControlEntry & other = (const PIpAccessControlEntry &)obj; // The larger the mask value, th more specific the range, so earlier in list if (mask > other.mask) return LessThan; if (mask < other.mask) return GreaterThan; if (!domain && !other.domain) return domain.Compare(other.domain); if (address > other.address) return LessThan; if (address < other.address) return GreaterThan; return EqualTo;}void PIpAccessControlEntry::PrintOn(ostream & strm) const{ if (!allowed) strm << '-'; if (hidden) strm << '@'; if (domain.IsEmpty()) strm << address; else if (domain[0] != '\xff') strm << domain; else { strm << "ALL"; return; } if (mask != 0 && mask != 0xffffffff) strm << '/' << mask;}void PIpAccessControlEntry::ReadFrom(istream & strm){ char buffer[200]; strm >> ws >> buffer; Parse(buffer);}BOOL PIpAccessControlEntry::Parse(const PString & description){ domain = PString(); address = 0; if (description.IsEmpty()) return FALSE; // Check for the allow/deny indication in first character of description BOOL offset = 1; if (description[0] == '-') allowed = FALSE; else { allowed = TRUE; if (description[0] != '+') offset = 0; } // Check for indication entry is from the hosts.allow/hosts.deny file hidden = FALSE; if (description[offset] == '@') { offset++; hidden = TRUE; } if (description.Mid(offset) *= "all") { domain = "\xff"; mask = 0; return TRUE; } PINDEX slash = description.Find('/', offset); PString preSlash = description(offset, slash-1); if (preSlash[0] == '.') { // If has a leading dot then assume a domain, ignore anything after slash domain = preSlash; mask = 0; return TRUE; } if (strspn(preSlash, "0123456789.") != (size_t)preSlash.GetLength()) { // If is not all numbers and dots can't be an IP number so assume hostname domain = preSlash; } else if (preSlash[preSlash.GetLength()-1] != '.') { // Must be explicit IP number if doesn't end in dot address = preSlash; } else { // Must be partial IP number, count the dots! PINDEX dot = preSlash.Find('.', preSlash.Find('.')+1); if (dot == P_MAX_INDEX) { // One dot preSlash += "0.0.0"; mask = "255.0.0.0"; } else if ((dot = preSlash.Find('.', dot+1)) == P_MAX_INDEX) { // has two dots preSlash += "0.0"; mask = "255.255.0.0"; } else if (preSlash.Find('.', dot+1) == P_MAX_INDEX) { // has three dots preSlash += "0"; mask = "255.255.255.0"; } else { // Has more than three dots! return FALSE; } address = preSlash; return TRUE; } if (slash == P_MAX_INDEX) { // No slash so assume a full mask mask = 0xffffffff; return TRUE; } PString postSlash = description.Mid(slash+1); if (strspn(postSlash, "0123456789.") != (size_t)postSlash.GetLength()) { domain = PString(); address = 0; return FALSE; } if (postSlash.Find('.') != P_MAX_INDEX) mask = postSlash; else { DWORD bits = postSlash.AsUnsigned(); if (bits > 32) mask = PSocket::Host2Net(bits); else mask = PSocket::Host2Net((DWORD)(0xffffffff << (32 - bits))); } if (mask == 0) domain = "\xff"; address = (DWORD)address & (DWORD)mask; return TRUE;}PString PIpAccessControlEntry::AsString() const{ PStringStream str; str << *this; return str;}BOOL PIpAccessControlEntry::IsValid(){ return address != 0 || !domain;}BOOL PIpAccessControlEntry::Match(PIPSocket::Address & addr){ switch (domain[0]) { case '\0' : // Must have address field set break; case '.' : // Are a domain name return PIPSocket::GetHostName(addr).Right(domain.GetLength()) *= domain; case '\xff' : // Match all return TRUE; default : // All else must be a hostname if (!PIPSocket::GetHostAddress(domain, address)) return FALSE; } return (address & mask) == (addr & mask);}///////////////////////////////////////////////////////////////////////////////PIpAccessControlList::PIpAccessControlList(BOOL defAllow) : defaultAllowance(defAllow){}static BOOL ReadConfigFileLine(PTextFile & file, PString & line){ line = PString(); do { if (!file.ReadLine(line)) return FALSE; } while (line.IsEmpty() || line[0] == '#'); PINDEX lastCharPos; while (line[lastCharPos = line.GetLength()-1] == '\\') { PString str; if (!file.ReadLine(str)) return FALSE; line[lastCharPos] = ' '; line += str; } return TRUE;}static void ParseConfigFileExcepts(const PString & str, PStringList & entries, PStringList & exceptions){ PStringArray terms = str.Tokenise(' ', FALSE); BOOL hadExcept = FALSE; PINDEX d; for (d = 0; d < terms.GetSize(); d++) { if (terms[d] == "EXCEPT") hadExcept = TRUE; else if (hadExcept) exceptions.AppendString(terms[d]); else entries.AppendString(terms[d]); }}static BOOL SplitConfigFileLine(const PString & line, PString & daemons, PString & clients){ PINDEX colon = line.Find(':'); if (colon == P_MAX_INDEX) return FALSE; daemons = line.Left(colon).Trim(); PINDEX other_colon = line.Find(':', ++colon); clients = line(colon, other_colon-1).Trim(); return TRUE;}static BOOL IsDaemonInConfigFileLine(const PString & daemon, const PString & daemons){ PStringList daemonsIn, daemonsOut; ParseConfigFileExcepts(daemons, daemonsIn, daemonsOut); for (PINDEX in = 0; in < daemonsIn.GetSize(); in++) { if (daemonsIn[in] == "ALL" || daemonsIn[in] == daemon) { PINDEX out; for (out = 0; out < daemonsOut.GetSize(); out++) { if (daemonsOut[out] == daemon) break; } if (out >= daemonsOut.GetSize()) return TRUE; } } return FALSE;}static BOOL ReadConfigFile(PTextFile & file, const PString & daemon, PStringList & clientsIn, PStringList & clientsOut){ PString line; while (ReadConfigFileLine(file, line)) { PString daemons, clients; if (SplitConfigFileLine(line, daemons, clients) && IsDaemonInConfigFileLine(daemon, daemons)) { ParseConfigFileExcepts(clients, clientsIn, clientsOut); return TRUE; } } return FALSE;}BOOL PIpAccessControlList::InternalLoadHostsAccess(const PString & daemonName, const char * filename, BOOL allowance){ PTextFile file; if (!file.Open(PProcess::GetOSConfigDir() + filename, PFile::ReadOnly)) return TRUE; BOOL ok = TRUE; PStringList clientsIn; PStringList clientsOut; while (ReadConfigFile(file, daemonName, clientsIn, clientsOut)) { PINDEX i; for (i = 0; i < clientsOut.GetSize(); i++) { if (!Add((allowance ? "-@" : "+@") + clientsOut[i])) ok = FALSE; } for (i = 0; i < clientsIn.GetSize(); i++) { if (!Add((allowance ? "+@" : "-@") + clientsIn[i])) ok = FALSE; } } return ok;}BOOL PIpAccessControlList::LoadHostsAccess(const char * daemonName){ PString daemon; if (daemonName != NULL) daemon = daemonName; else daemon = PProcess::Current().GetName(); return InternalLoadHostsAccess(daemon, "hosts.allow", TRUE) & // Really is a single & InternalLoadHostsAccess(daemon, "hosts.deny", FALSE);}#ifdef P_CONFIG_LISTstatic const char DefaultConfigName[] = "IP Access Control List";BOOL PIpAccessControlList::Load(PConfig & cfg){ return Load(cfg, DefaultConfigName);}BOOL PIpAccessControlList::Load(PConfig & cfg, const PString & baseName){ BOOL ok = TRUE; PINDEX count = cfg.GetInteger(baseName & "Array Size"); for (PINDEX i = 1; i <= count; i++) { if (!Add(cfg.GetString(baseName & PString(PString::Unsigned, i)))) ok = FALSE; } return ok;}void PIpAccessControlList::Save(PConfig & cfg){ Save(cfg, DefaultConfigName);}void PIpAccessControlList::Save(PConfig & cfg, const PString & baseName){ PINDEX count = 0; for (PINDEX i = 0; i < GetSize(); i++) { PIpAccessControlEntry & entry = operator[](i); if (!entry.IsHidden()) { count++; cfg.SetString(baseName & PString(PString::Unsigned, count), entry.AsString()); } } cfg.SetInteger(baseName & "Array Size", count);}#endif // P_CONFIG_LISTBOOL PIpAccessControlList::Add(PIpAccessControlEntry * entry){ if (!entry->IsValid()) { delete entry; return FALSE; } PINDEX idx = GetValuesIndex(*entry); if (idx == P_MAX_INDEX) { Append(entry); return TRUE; } // Return TRUE if the newly added entry is identical to an existing one PIpAccessControlEntry & existing = operator[](idx); BOOL ok = existing.IsClass(PIpAccessControlEntry::Class()) && entry->IsClass(PIpAccessControlEntry::Class()) && existing.IsAllowed() == entry->IsAllowed(); delete entry; return ok;}BOOL PIpAccessControlList::Add(const PString & description){ return Add(CreateControlEntry(description));}BOOL PIpAccessControlList::Add(PIPSocket::Address addr, PIPSocket::Address mask, BOOL allow){ PStringStream description; description << (allow ? '+' : '-') << addr << '/' << mask; return Add(description);}BOOL PIpAccessControlList::Remove(const PString & description){ PIpAccessControlEntry entry(description); if (!entry.IsValid()) return FALSE; return InternalRemoveEntry(entry);}BOOL PIpAccessControlList::Remove(PIPSocket::Address addr, PIPSocket::Address mask){ PIpAccessControlEntry entry(addr, mask, TRUE); return InternalRemoveEntry(entry);}BOOL PIpAccessControlList::InternalRemoveEntry(PIpAccessControlEntry & entry){ PINDEX idx = GetValuesIndex(entry); if (idx == P_MAX_INDEX) return FALSE; RemoveAt(idx); return TRUE;}PIpAccessControlEntry * PIpAccessControlList::CreateControlEntry(const PString & description){ return new PIpAccessControlEntry(description);}PIpAccessControlEntry * PIpAccessControlList::Find(PIPSocket::Address address) const{ PINDEX size = GetSize(); if (size == 0) return NULL; for (PINDEX i = 0; i < GetSize(); i++) { PIpAccessControlEntry & entry = operator[](i); if (entry.Match(address)) return &entry; } return NULL;}BOOL PIpAccessControlList::IsAllowed(PTCPSocket & socket) const{ if (IsEmpty()) return defaultAllowance; PIPSocket::Address address; if (socket.GetPeerAddress(address)) return IsAllowed(address); return FALSE;}BOOL PIpAccessControlList::IsAllowed(PIPSocket::Address address) const{ if (IsEmpty()) return defaultAllowance; PIpAccessControlEntry * entry = Find(address); if (entry == NULL) return FALSE; return entry->IsAllowed();}// End of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?