/* * * Copyright (c) 2014 The Apache Software Foundation * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "qpid/AclHost.h" #include "qpid/Exception.h" #include "qpid/Msg.h" #include "qpid/StringUtils.h" #include "qpid/log/Logger.h" #include "qpid/sys/SocketAddress.h" #include #include using namespace std; namespace qpid { AclHost::Invalid::Invalid(const string& s) : Exception(s) {} string AclHost::str() const { if (cache.empty()) { ostringstream os; os << *this; cache = os.str(); } return cache; } std::string undecorateIPv6Name(std::string& host) { std::string s(host); if (host.length() >= 3 && host.find("[") == 0 && host.rfind("]") == host.length()-1) s = host.substr(1, host.length()-2); return s; } ostream& operator<<(ostream& os, const AclHost& aclhost) { os << aclhost.comparisonDetails(); return os; } class AclHostParser { public: AclHostParser(AclHost& ah, const std::string& hSpec) : aclhost(ah), hostSpec(hSpec) {} bool parse() { // Convert given host spec into vector of host names // Blank host name means "all addresses. Create AclHost // with no SocketAddress objects if (hostSpec.compare("") == 0) { aclhost.allAddresses = true; return true; } std::vector hostList; split(hostList, hostSpec, ","); if (hostList.size() == 0 || hostList.size() > 2) { throw AclHost::Invalid( QPID_MSG("Invalid AclHost: hostlist must be one name or " "two names separated with a comma : " << hostSpec)); } // Create pairs of SocketAddress objects representing the host range if (hostList.size() == 1) { hostList[0] = undecorateIPv6Name(hostList[0]); aclhost.loSAptr = AclHost::SAptr(new sys::SocketAddress(hostList[0], "")); aclhost.hiSAptr = AclHost::SAptr(new sys::SocketAddress(hostList[0], "")); } else { hostList[0] = undecorateIPv6Name(hostList[0]); hostList[1] = undecorateIPv6Name(hostList[1]); aclhost.loSAptr = AclHost::SAptr(new sys::SocketAddress(hostList[0], "")); aclhost.hiSAptr = AclHost::SAptr(new sys::SocketAddress(hostList[1], "")); } // Make sure that this pair will work for run-time comparisons if (!aclhost.loSAptr->isComparable(*aclhost.hiSAptr)) { throw AclHost::Invalid( QPID_MSG("AclHost specifies hosts that cannot be compared : " << hostSpec)); } return true; } AclHost& aclhost; const std::string& hostSpec; }; void AclHost::parse(const std::string& hostSpec) { parseNoThrow(hostSpec); if (isEmpty() && !allAddresses) throw AclHost::Invalid(QPID_MSG("Invalid AclHost : " << hostSpec)); } void AclHost::parseNoThrow(const std::string& hostSpec) { clear(); try { if (!AclHostParser(*this, hostSpec).parse()) clear(); } catch (...) { clear(); } } std::istream& operator>>(std::istream& is, AclHost& aclhost) { std::string s; is >> s; aclhost.parse(s); return is; } /** * Given a connecting host's numeric IP address as a string * Return true if the host is in the range of any of our kept * SocketAddress's binary address ranges. */ bool AclHost::match(const std::string& hostIp) const { try { sys::SocketAddress sa1(hostIp, ""); return match(sa1); } catch (...) { return false; } } /** * Given a connecting host's SocketAddress * Return true if the host is in the range of any of our kept * SocketAddress's binary address ranges. */ bool AclHost::match(const sys::SocketAddress& peer) const { if (!loSAptr.get()) { // No kept socket address means "all addresses" return true; } bool result = peer.inRange(*loSAptr, *hiSAptr); return result; } } // namespace qpid