blob: 1581d3b46a87e9fdda1d13fd32b67fbebc107ff2 [file] [log] [blame]
/*
*
* 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 <vector>
#include <string>
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<string> 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