/* Define to 1 if you have the <unistd.h> header file. */
/* #undef HAVE_UNISTD_H */
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
/* Name of package */
#define PACKAGE "shibboleth"
AC_FUNC_STRFTIME
AC_FUNC_STRERROR_R
AC_CHECK_HEADERS([sys/utsname.h grp.h pwd.h])
+AC_CHECK_HEADERS([sys/socket.h], [AC_DEFINE([SHIBSP_HAVE_SYS_SOCKET_H],[1],[Define to 1 if you have the <sys/socket> header file.])], [])
AC_CHECK_FUNCS([strchr strdup strstr timegm gmtime_r strtok_r strcasecmp getpwnam getgrnam])
+AC_CHECK_TYPES([struct sockaddr_storage], [], [], [[#include <sys/socket.h>]])
# checks for pthreads
ACX_PTHREAD([enable_threads="pthread"],[enable_threads="no"])
utilinclude_HEADERS = \
util/CGIParser.h \
util/DOMPropertySet.h \
+ util/IPRange.h \
util/PropertySet.h \
util/SPConstants.h \
util/TemplateParameters.h
remoting/impl/UnixListener.cpp \
util/CGIParser.cpp \
util/DOMPropertySet.cpp \
+ util/IPRange.cpp \
util/SPConstants.cpp \
util/TemplateParameters.cpp
/* Define to 1 if XML-Security-C supports white/blacklisting algorithms. */
#undef SHIBSP_XMLSEC_WHITELISTING
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef SHIBSP_HAVE_SYS_SOCKET_H
#include "SPRequest.h"
#include "handler/AbstractHandler.h"
#include "handler/RemotedHandler.h"
+#include "util/IPRange.h"
#include "util/SPConstants.h"
#ifndef SHIBSP_LITE
private:
pair<bool,long> processMessage(const Application& application, HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
- set<string> m_acl;
+ vector<IPRange> m_acl;
};
#if defined (_MSC_VER)
AssertionLookup::AssertionLookup(const DOMElement* e, const char* appId)
: AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".AssertionLookup"), &g_Blocker)
{
- setAddress("run::AssertionLookup");
if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
pair<bool,const char*> acl = getString("exportACL");
- if (!acl.first) {
- m_acl.insert("127.0.0.1");
- return;
- }
- string aclbuf=acl.second;
- int j = 0;
- for (unsigned int i=0; i < aclbuf.length(); i++) {
- if (aclbuf.at(i)==' ') {
- m_acl.insert(aclbuf.substr(j, i-j));
- j = i+1;
+ if (acl.first) {
+ string aclbuf=acl.second;
+ int j = 0;
+ for (unsigned int i=0; i < aclbuf.length(); i++) {
+ if (aclbuf.at(i)==' ') {
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, i-j).c_str()));
+ }
+ catch (exception& ex) {
+ m_log.error("invalid CIDR block (%s): %s", aclbuf.substr(j, i-j).c_str(), ex.what());
+ }
+ j = i+1;
+ }
+ }
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, aclbuf.length()-j).c_str()));
+ }
+ catch (exception& ex) {
+ m_log.error("invalid CIDR block (%s): %s", aclbuf.substr(j, aclbuf.length()-j).c_str(), ex.what());
+ }
+
+ if (m_acl.empty()) {
+ m_log.warn("invalid CIDR range(s) in acl property, allowing 127.0.0.1 as a fall back");
+ m_acl.push_back(IPRange::parseCIDRBlock("127.0.0.1"));
}
}
- m_acl.insert(aclbuf.substr(j, aclbuf.length()-j));
+ else {
+ m_acl.push_back(IPRange::parseCIDRBlock("127.0.0.1"));
+ }
}
+
+ setAddress("run::AssertionLookup");
}
pair<bool,long> AssertionLookup::run(SPRequest& request, bool isHandler) const
{
- string relayState;
SPConfig& conf = SPConfig::getConfig();
- if (conf.isEnabled(SPConfig::InProcess)) {
- if (m_acl.count(request.getRemoteAddr()) == 0) {
+ if (conf.isEnabled(SPConfig::InProcess) && !m_acl.empty()) {
+ bool found = false;
+ for (vector<IPRange>::const_iterator acl = m_acl.begin(); !found && acl != m_acl.end(); ++acl) {
+ found = acl->contains(request.getRemoteAddr().c_str());
+ }
+ if (!found) {
m_log.error("request for assertion lookup blocked from invalid address (%s)", request.getRemoteAddr().c_str());
istringstream msg("Assertion Lookup Blocked");
return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN));
#include "SPRequest.h"
#include "handler/AbstractHandler.h"
#include "handler/RemotedHandler.h"
+#include "util/IPRange.h"
#ifndef SHIBSP_LITE
# include "attribute/resolver/AttributeExtractor.h"
HTTPResponse& httpResponse
) const;
- set<string> m_acl;
+ vector<IPRange> m_acl;
#ifndef SHIBSP_LITE
string m_salt;
short m_http,m_https;
string address(appId);
address += getString("Location").second;
setAddress(address.c_str());
+
if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
pair<bool,const char*> acl = getString("acl");
if (acl.first) {
string aclbuf=acl.second;
int j = 0;
- for (unsigned int i=0; i < aclbuf.length(); i++) {
+ for (unsigned int i=0; i < aclbuf.length(); ++i) {
if (aclbuf.at(i)==' ') {
- m_acl.insert(aclbuf.substr(j, i-j));
- j = i+1;
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, i-j).c_str()));
+ }
+ catch (exception& ex) {
+ m_log.error("invalid CIDR block (%s): %s", aclbuf.substr(j, i-j).c_str(), ex.what());
+ }
+ j = i + 1;
}
}
- m_acl.insert(aclbuf.substr(j, aclbuf.length()-j));
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, aclbuf.length()-j).c_str()));
+ }
+ catch (exception& ex) {
+ m_log.error("invalid CIDR block (%s): %s", aclbuf.substr(j, aclbuf.length()-j).c_str(), ex.what());
+ }
+
+ if (m_acl.empty()) {
+ m_log.warn("invalid CIDR range(s) in Metadata Generator acl property, allowing 127.0.0.1 as a fall back");
+ m_acl.push_back(IPRange::parseCIDRBlock("127.0.0.1"));
+ }
}
}
pair<bool,long> MetadataGenerator::run(SPRequest& request, bool isHandler) const
{
SPConfig& conf = SPConfig::getConfig();
- if (conf.isEnabled(SPConfig::InProcess)) {
- if (!m_acl.empty() && m_acl.count(request.getRemoteAddr()) == 0) {
+ if (conf.isEnabled(SPConfig::InProcess) && !m_acl.empty()) {
+ bool found = false;
+ for (vector<IPRange>::const_iterator acl = m_acl.begin(); !found && acl != m_acl.end(); ++acl) {
+ found = acl->contains(request.getRemoteAddr().c_str());
+ }
+ if (!found) {
m_log.error("request for metadata blocked from invalid address (%s)", request.getRemoteAddr().c_str());
istringstream msg("Metadata Request Blocked");
return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN));
#include "SPRequest.h"
#include "attribute/Attribute.h"
#include "handler/AbstractHandler.h"
+#include "util/IPRange.h"
#include <ctime>
private:
bool m_values;
- set<string> m_acl;
+ vector<IPRange> m_acl;
};
#if defined (_MSC_VER)
if (acl.first) {
string aclbuf=acl.second;
int j = 0;
- for (unsigned int i=0; i < aclbuf.length(); i++) {
+ for (unsigned int i=0; i < aclbuf.length(); ++i) {
if (aclbuf.at(i)==' ') {
- m_acl.insert(aclbuf.substr(j, i-j));
- j = i+1;
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, i-j).c_str()));
+ }
+ catch (exception& ex) {
+ m_log.error("invalid CIDR block (%s): %s", aclbuf.substr(j, i-j).c_str(), ex.what());
+ }
+ j = i + 1;
}
}
- m_acl.insert(aclbuf.substr(j, aclbuf.length()-j));
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, aclbuf.length()-j).c_str()));
+ }
+ catch (exception& ex) {
+ m_log.error("invalid CIDR block (%s): %s", aclbuf.substr(j, aclbuf.length()-j).c_str(), ex.what());
+ }
+
+ if (m_acl.empty()) {
+ m_log.warn("invalid CIDR range(s) in Session handler acl property, allowing 127.0.0.1 as a fall back");
+ m_acl.push_back(IPRange::parseCIDRBlock("127.0.0.1"));
+ }
}
pair<bool,bool> flag = getBool("showAttributeValues");
pair<bool,long> SessionHandler::run(SPRequest& request, bool isHandler) const
{
- if (!m_acl.empty() && m_acl.count(request.getRemoteAddr()) == 0) {
- m_log.error("session handler request blocked from invalid address (%s)", request.getRemoteAddr().c_str());
- istringstream msg("Session Handler Blocked");
- return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN));
+ if (!m_acl.empty()) {
+ bool found = false;
+ for (vector<IPRange>::const_iterator acl = m_acl.begin(); !found && acl != m_acl.end(); ++acl) {
+ found = acl->contains(request.getRemoteAddr().c_str());
+ }
+ if (!found) {
+ m_log.error("session handler request blocked from invalid address (%s)", request.getRemoteAddr().c_str());
+ istringstream msg("Session Handler Blocked");
+ return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN));
+ }
}
stringstream s;
#include "SPRequest.h"
#include "handler/AbstractHandler.h"
#include "handler/RemotedHandler.h"
+#include "util/IPRange.h"
#include "util/CGIParser.h"
#include <xmltooling/version.h>
pair<bool,long> processMessage(const Application& application, const HTTPRequest& httpRequest, HTTPResponse& httpResponse) const;
ostream& systemInfo(ostream& os) const;
- set<string> m_acl;
+ vector<IPRange> m_acl;
};
#if defined (_MSC_VER)
StatusHandler::StatusHandler(const DOMElement* e, const char* appId)
: AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".StatusHandler"), &g_Blocker)
{
- string address(appId);
- address += getString("Location").second;
- setAddress(address.c_str());
if (SPConfig::getConfig().isEnabled(SPConfig::InProcess)) {
pair<bool,const char*> acl = getString("acl");
if (acl.first) {
int j = 0;
for (unsigned int i=0; i < aclbuf.length(); i++) {
if (aclbuf.at(i)==' ') {
- m_acl.insert(aclbuf.substr(j, i-j));
- j = i+1;
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, i-j).c_str()));
+ }
+ catch (exception& ex) {
+ m_log.error("invalid CIDR block (%s): %s", aclbuf.substr(j, i-j).c_str(), ex.what());
+ }
+ j = i + 1;
}
}
- m_acl.insert(aclbuf.substr(j, aclbuf.length()-j));
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, aclbuf.length()-j).c_str()));
+ }
+ catch (exception& ex) {
+ m_log.error("invalid CIDR block (%s): %s", aclbuf.substr(j, aclbuf.length()-j).c_str(), ex.what());
+ }
+
+ if (m_acl.empty()) {
+ m_log.warn("invalid CIDR range(s) in Status handler acl property, allowing 127.0.0.1 as a fall back");
+ m_acl.push_back(IPRange::parseCIDRBlock("127.0.0.1"));
+ }
}
}
+
+ string address(appId);
+ address += getString("Location").second;
+ setAddress(address.c_str());
}
pair<bool,long> StatusHandler::run(SPRequest& request, bool isHandler) const
{
SPConfig& conf = SPConfig::getConfig();
- if (conf.isEnabled(SPConfig::InProcess)) {
- if (!m_acl.empty() && m_acl.count(request.getRemoteAddr()) == 0) {
+ if (conf.isEnabled(SPConfig::InProcess) && !m_acl.empty()) {
+ bool found = false;
+ for (vector<IPRange>::const_iterator acl = m_acl.begin(); !found && acl != m_acl.end(); ++acl) {
+ found = acl->contains(request.getRemoteAddr().c_str());
+ }
+ if (!found) {
m_log.error("status handler request blocked from invalid address (%s)", request.getRemoteAddr().c_str());
istringstream msg("Status Handler Blocked");
return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN));
return out;
}
-bool SocketListener::log_error() const
+bool SocketListener::log_error(const char* fn) const
{
+ if (!fn)
+ fn = "unknown";
#ifdef WIN32
int rc=WSAGetLastError();
#else
char buf[256];
memset(buf,0,sizeof(buf));
strerror_r(rc,buf,sizeof(buf));
- log->error("socket call resulted in error (%d): %s",rc,isprint(*buf) ? buf : "no message");
+ log->error("socket call (%s) resulted in error (%d): %s",fn, rc, isprint(*buf) ? buf : "no message");
#else
const char* buf=strerror(rc);
- log->error("socket call resulted in error (%d): %s",rc,isprint(*buf) ? buf : "no message");
+ log->error("socket call (%s) resulted in error (%d): %s", fn, rc, isprint(*buf) ? buf : "no message");
#endif
return false;
}
bool m_catchAll;
protected:
- bool log_error() const; // for OS-level errors
+ bool log_error(const char* fn=nullptr) const; // for OS-level errors
xmltooling::logging::Category* log;
/// @endcond
*/
#include "internal.h"
+#include "exceptions.h"
#include "remoting/impl/SocketListener.h"
+#include "util/IPRange.h"
#include <xercesc/util/XMLUniDefs.hpp>
#include <xmltooling/unicode.h>
#include <xmltooling/util/XMLHelper.h>
+#ifdef WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#endif
+
#ifdef HAVE_UNISTD_H
# include <sys/socket.h>
# include <sys/un.h>
+# include <netdb.h>
# include <unistd.h>
# include <arpa/inet.h>
# include <netinet/in.h>
}
private:
- void setup_tcp_sockaddr(struct sockaddr_in* addr) const;
+ bool setup_tcp_sockaddr();
string m_address;
unsigned short m_port;
- set<string> m_acl;
+ vector<IPRange> m_acl;
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+ struct sockaddr_storage m_sockaddr;
+#else
+ struct sockaddr_in m_sockaddr;
+#endif
};
ListenerService* SHIBSP_DLLLOCAL TCPListenerServiceFactory(const DOMElement* const & e)
}
int j = 0;
- string sockacl = XMLHelper::getAttrString(e, "127.0.0.1", acl);
- for (unsigned int i = 0; i < sockacl.length(); i++) {
- if (sockacl.at(i) == ' ') {
- m_acl.insert(sockacl.substr(j, i-j));
- j = i+1;
+ string aclbuf = XMLHelper::getAttrString(e, "127.0.0.1", acl);
+ for (unsigned int i = 0; i < aclbuf.length(); ++i) {
+ if (aclbuf.at(i) == ' ') {
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, i-j).c_str()));
+ }
+ catch (exception& ex) {
+ log->error("invalid CIDR block (%s): %s", aclbuf.substr(j, i-j).c_str(), ex.what());
+ }
+ j = i + 1;
}
}
- m_acl.insert(sockacl.substr(j, sockacl.length()-j));
+ try {
+ m_acl.push_back(IPRange::parseCIDRBlock(aclbuf.substr(j, aclbuf.length()-j).c_str()));
+ }
+ catch (exception& ex) {
+ log->error("invalid CIDR block (%s): %s", aclbuf.substr(j, aclbuf.length()-j).c_str(), ex.what());
+ }
+
+ if (m_acl.empty()) {
+ log->warn("invalid CIDR range(s) in acl property, allowing 127.0.0.1 as a fall back");
+ m_acl.push_back(IPRange::parseCIDRBlock("127.0.0.1"));
+ }
+
+ if (!setup_tcp_sockaddr()) {
+ throw ConfigurationException("Unable to use configured socket address property.");
+ }
}
-void TCPListener::setup_tcp_sockaddr(struct sockaddr_in* addr) const
+bool TCPListener::setup_tcp_sockaddr()
{
- // Split on host:port boundary. Default to port only.
- memset(addr,0,sizeof(struct sockaddr_in));
- addr->sin_family=AF_INET;
- addr->sin_port=htons(m_port);
- addr->sin_addr.s_addr=inet_addr(m_address.c_str());
+ struct addrinfo* ret = nullptr;
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = AF_UNSPEC;
+
+ if (getaddrinfo(m_address.c_str(), nullptr, &hints, &ret) != 0) {
+ log->error("unable to parse server address (%s)", m_address.c_str());
+ return false;
+ }
+
+ if (ret->ai_family == AF_INET) {
+ memcpy(&m_sockaddr, ret->ai_addr, ret->ai_addrlen);
+ freeaddrinfo(ret);
+ ((struct sockaddr_in*)&m_sockaddr)->sin_port=htons(m_port);
+ return true;
+ }
+#if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_STORAGE)
+ else if (ret->ai_family == AF_INET6) {
+ memcpy(&m_sockaddr, ret->ai_addr, ret->ai_addrlen);
+ freeaddrinfo(ret);
+ ((struct sockaddr_in6*)&m_sockaddr)->sin6_port=htons(m_port);
+ return true;
+ }
+#endif
+
+ log->error("unknown address type (%d)", ret->ai_family);
+ freeaddrinfo(ret);
+ return false;
}
bool TCPListener::create(ShibSocket& s) const
{
- s=socket(AF_INET,SOCK_STREAM,0);
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+ s = socket(m_sockaddr.ss_family, SOCK_STREAM, 0);
+#else
+ s = socket(m_sockaddr.sin_family, SOCK_STREAM, 0);
+#endif
#ifdef WIN32
- if(s==INVALID_SOCKET)
+ if(s == INVALID_SOCKET)
#else
if (s < 0)
#endif
- return log_error();
+ return log_error("socket");
return true;
}
bool TCPListener::bind(ShibSocket& s, bool force) const
{
- struct sockaddr_in addr;
- setup_tcp_sockaddr(&addr);
-
// XXX: Do we care about the return value from setsockopt?
int opt = 1;
::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
#ifdef WIN32
- if (SOCKET_ERROR==::bind(s,(struct sockaddr *)&addr,sizeof(addr)) || SOCKET_ERROR==::listen(s,3)) {
- log_error();
+ if (SOCKET_ERROR==::bind(s, (const struct sockaddr*)&m_sockaddr, m_sockaddr.ss_len) || SOCKET_ERROR==::listen(s, 3)) {
+ log_error("bind");
close(s);
return false;
}
#else
- if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
- log_error();
+# ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+ if (::bind(s, (const struct sockaddr*)&m_sockaddr, m_sockaddr.ss_len) < 0)
+# else
+ if (::bind(s, (const struct sockaddr*)&m_sockaddr, m_sockaddr.sin_len) < 0)
+# endif
+ {
+ log_error("bind");
close(s);
return false;
}
- ::listen(s,3);
+ ::listen(s, 3);
#endif
return true;
}
bool TCPListener::connect(ShibSocket& s) const
{
- struct sockaddr_in addr;
- setup_tcp_sockaddr(&addr);
#ifdef WIN32
- if(SOCKET_ERROR==::connect(s,(struct sockaddr *)&addr,sizeof(addr)))
- return log_error();
+ if(SOCKET_ERROR==::connect(s, (const struct sockaddr*)&m_sockaddr, m_sockaddr.ss_len))
+ return log_error("connect");
#else
- if (::connect(s, (struct sockaddr*)&addr, sizeof (addr)) < 0)
- return log_error();
+# ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+ if (::connect(s, (const struct sockaddr*)&m_sockaddr, m_sockaddr.ss_len) < 0)
+# else
+ if (::connect(s, (const struct sockaddr*)&m_sockaddr, m_sockaddr.sin_len) < 0)
+# endif
+ return log_error("connect");
#endif
return true;
}
bool TCPListener::accept(ShibSocket& listener, ShibSocket& s) const
{
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+ struct sockaddr_storage addr;
+#else
struct sockaddr_in addr;
+#endif
+ memset(&addr, 0, sizeof(addr));
#ifdef WIN32
int size=sizeof(addr);
- s=::accept(listener,(struct sockaddr*)&addr,&size);
+ s=::accept(listener, (struct sockaddr*)&addr, &size);
if(s==INVALID_SOCKET)
#else
socklen_t size=sizeof(addr);
- s=::accept(listener,(struct sockaddr*)&addr,&size);
+ s=::accept(listener, (struct sockaddr*)&addr, &size);
if (s < 0)
#endif
- return log_error();
- char* client=inet_ntoa(addr.sin_addr);
- if (m_acl.count(client) == 0) {
+ return log_error("accept");
+ bool found = false;
+ for (vector<IPRange>::const_iterator acl = m_acl.begin(); !found && acl != m_acl.end(); ++acl) {
+ found = acl->contains((const struct sockaddr*)&addr);
+ }
+ if (!found) {
close(s);
- s=-1;
- log->error("accept() rejected client at %s", client);
+ s = -1;
+ log->error("accept() rejected client with invalid address");
return false;
}
return true;
{
sock = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
- return log_error();
+ return log_error("socket");
return true;
}
unlink(m_address.c_str());
if (::bind(s, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
- log_error();
+ log_error("bind");
close(s);
return false;
}
// Make sure that only the creator can read -- we don't want just
// anyone connecting, do we?
if (chmod(m_address.c_str(),0777) < 0) {
- log_error();
+ log_error("chmod");
close(s);
unlink(m_address.c_str());
return false;
strncpy(addr.sun_path, m_address.c_str(), UNIX_PATH_MAX);
if (::connect(s, (struct sockaddr *)&addr, sizeof (addr)) < 0)
- return log_error();
+ return log_error("connect");
return true;
}
{
s=::accept(listener,nullptr,nullptr);
if (s < 0)
- return log_error();
+ return log_error("accept");
return true;
}
<ClCompile Include="SPConfig.cpp" />\r
<ClCompile Include="util\CGIParser.cpp" />\r
<ClCompile Include="util\DOMPropertySet.cpp" />\r
+ <ClCompile Include="util\IPRange.cpp" />\r
<ClCompile Include="util\SPConstants.cpp" />\r
<ClCompile Include="util\TemplateParameters.cpp" />\r
<ClCompile Include="remoting\impl\ddf.cpp" />\r
<ClInclude Include="version.h" />\r
<ClInclude Include="util\CGIParser.h" />\r
<ClInclude Include="util\DOMPropertySet.h" />\r
+ <ClInclude Include="util\IPRange.h" />\r
<ClInclude Include="util\PropertySet.h" />\r
<ClInclude Include="util\SPConstants.h" />\r
<ClInclude Include="util\TemplateParameters.h" />\r
<ClCompile Include="util\DOMPropertySet.cpp">\r
<Filter>Source Files\util</Filter>\r
</ClCompile>\r
+ <ClCompile Include="util\IPRange.cpp">\r
+ <Filter>Source Files\util</Filter>\r
+ </ClCompile>\r
<ClCompile Include="util\SPConstants.cpp">\r
<Filter>Source Files\util</Filter>\r
</ClCompile>\r
<ClInclude Include="util\DOMPropertySet.h">\r
<Filter>Header Files\util</Filter>\r
</ClInclude>\r
+ <ClInclude Include="util\IPRange.h">\r
+ <Filter>Header Files\util</Filter>\r
+ </ClInclude>\r
<ClInclude Include="util\PropertySet.h">\r
<Filter>Header Files\util</Filter>\r
</ClInclude>\r
<ClCompile Include="SPConfig.cpp" />\r
<ClCompile Include="util\CGIParser.cpp" />\r
<ClCompile Include="util\DOMPropertySet.cpp" />\r
+ <ClCompile Include="util\IPRange.cpp" />\r
<ClCompile Include="util\SPConstants.cpp" />\r
<ClCompile Include="util\TemplateParameters.cpp" />\r
<ClCompile Include="security\PKIXTrustEngine.cpp" />\r
<ClInclude Include="version.h" />\r
<ClInclude Include="util\CGIParser.h" />\r
<ClInclude Include="util\DOMPropertySet.h" />\r
+ <ClInclude Include="util\IPRange.h" />\r
<ClInclude Include="util\PropertySet.h" />\r
<ClInclude Include="util\SPConstants.h" />\r
<ClInclude Include="util\TemplateParameters.h" />\r
<ClCompile Include="util\DOMPropertySet.cpp">\r
<Filter>Source Files\util</Filter>\r
</ClCompile>\r
+ <ClCompile Include="util\IPRange.cpp">\r
+ <Filter>Source Files\util</Filter>\r
+ </ClCompile>\r
<ClCompile Include="util\SPConstants.cpp">\r
<Filter>Source Files\util</Filter>\r
</ClCompile>\r
<ClInclude Include="util\DOMPropertySet.h">\r
<Filter>Header Files\util</Filter>\r
</ClInclude>\r
+ <ClInclude Include="util\IPRange.h">\r
+ <Filter>Header Files\util</Filter>\r
+ </ClInclude>\r
<ClInclude Include="util\PropertySet.h">\r
<Filter>Header Files\util</Filter>\r
</ClInclude>\r
--- /dev/null
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you 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.
+ */
+
+/**
+ * @file IPRange.cpp
+ *
+ * Represents a range of IP addresses.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "util/IPRange.h"
+
+#include <xmltooling/logging.h>
+
+#ifdef WIN32
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#else
+# include <netdb.h>
+# include <netinet/in.h>
+#endif
+
+using namespace shibsp;
+using namespace xmltooling::logging;
+using namespace xmltooling;
+using namespace std;
+
+namespace {
+ // Gets the byte-level representation of a numeric IP address.
+ struct addrinfo* parseIPAddress(const char* s)
+ {
+ struct addrinfo* ret = nullptr;
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = AF_UNSPEC;
+
+ if (getaddrinfo(s, nullptr, &hints, &ret) != 0)
+ return nullptr;
+ if (ret) {
+ if (ret->ai_family != AF_INET
+#ifdef AF_INET6
+ && ret->ai_family != AF_INET6
+#endif
+ ) {
+ freeaddrinfo(ret);
+ return nullptr;
+ }
+ }
+ return ret;
+ }
+};
+
+IPRange::IPRange(const bitset<32>& address, int maskSize) : m_addressLength(32)
+{
+ if (maskSize < 0 || maskSize > m_addressLength)
+ throw ConfigurationException("CIDR prefix length out of range.");
+
+ for (int i = m_addressLength - maskSize; i < m_addressLength; ++i)
+ m_mask4.set(i, true);
+
+ m_network4 = address;
+ m_network4 &= m_mask4;
+}
+
+IPRange::IPRange(const bitset<128>& address, int maskSize) : m_addressLength(128)
+{
+ if (maskSize < 0 || maskSize > m_addressLength)
+ throw ConfigurationException("CIDR prefix length out of range.");
+
+ for (int i = m_addressLength - maskSize; i < m_addressLength; ++i)
+ m_mask6.set(i, true);
+
+ m_network6 = address;
+ m_network6 &= m_mask6;
+}
+
+bool IPRange::contains(const char* address) const
+{
+
+ struct addrinfo* parsed = parseIPAddress(address);
+ if (!parsed)
+ return false;
+ bool ret = contains(parsed->ai_addr);
+ freeaddrinfo(parsed);
+ return ret;
+}
+
+bool IPRange::contains(const struct sockaddr* address) const
+{
+
+ Category& log = Category::getInstance(SHIBSP_LOGCAT".IPRange");
+
+ if (address->sa_family == AF_INET) {
+ if (m_addressLength != 32)
+ return false;
+ unsigned long raw = 0;
+ memcpy(&raw, &((struct sockaddr_in*)address)->sin_addr, 4);
+ bitset<32> rawbits(ntohl(raw)); // the bitset loads from a host-order variable
+ if (log.isDebugEnabled()) {
+ log.debug(
+ "comparing address (%s) to network (%s) with mask (%s)",
+ rawbits.to_string().c_str(),
+ m_network4.to_string().c_str(),
+ m_mask4.to_string().c_str()
+ );
+ }
+ rawbits &= m_mask4;
+ return (rawbits == m_network4);
+ }
+#ifdef AF_INET6
+ else if (address->sa_family == AF_INET6) {
+ if (m_addressLength != 128)
+ return false;
+ unsigned char raw[16];
+ memcpy(raw, &((struct sockaddr_in6*)address)->sin6_addr, 16);
+ bitset<128> rawbits(raw[0]);
+ for (int i = 1; i < 16; ++i) {
+ rawbits <<= 8;
+ rawbits |= bitset<128>(raw[i]);
+ }
+ if (log.isDebugEnabled()) {
+ log.debug(
+ "comparing address (%s) to network (%s) with mask (%s)",
+ rawbits.to_string().c_str(),
+ m_network6.to_string().c_str(),
+ m_mask6.to_string().c_str()
+ );
+ }
+ rawbits &= m_mask6;
+ return (rawbits == m_network6);
+ }
+#endif
+ return false;
+}
+
+IPRange IPRange::parseCIDRBlock(const char* cidrBlock)
+{
+ string block = cidrBlock;
+ string::size_type sep = block.find("/");
+ if (sep == string::npos) {
+ if (block.find(":") == string::npos)
+ block += "/32";
+ else
+ block += "/128";
+ sep = block.find("/");
+ }
+ struct addrinfo* address = parseIPAddress(block.substr(0, sep).c_str());
+ if (!address)
+ throw ConfigurationException("Unable to parse address in CIDR block.");
+ int maskSize = atoi(block.substr(++sep).c_str());
+ if (address->ai_family == AF_INET) {
+ unsigned long raw = 0;
+ memcpy(&raw, &((struct sockaddr_in*)address->ai_addr)->sin_addr, 4);
+ freeaddrinfo(address);
+ bitset<32> rawbits(ntohl(raw)); // the bitset loads from a host-order variable
+ return IPRange(rawbits, maskSize);
+ }
+#ifdef AF_INET6
+ else if (address->ai_family == AF_INET6) {
+ unsigned char raw[16];
+ memcpy(raw, &((struct sockaddr_in6*)address->ai_addr)->sin6_addr, 16);
+ freeaddrinfo(address);
+ bitset<128> rawbits(raw[0]);
+ for (int i = 1; i < 16; ++i) {
+ rawbits <<= 8;
+ rawbits |= bitset<128>(raw[i]);
+ }
+ return IPRange(rawbits, maskSize);
+ }
+#endif
+ throw ConfigurationException("Unrecognized address type in CIDR block.");
+}
--- /dev/null
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you 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.
+ */
+
+/**
+ * @file shibsp/util/IPRange.h
+ *
+ * Represents a range of IP addresses.
+ */
+
+#ifndef __shibsp_iprange_h__
+#define __shibsp_iprange_h__
+
+#include <shibsp/base.h>
+
+#include <bitset>
+
+#ifdef WIN32
+# include <winsock.h>
+#elif defined(SHIBSP_HAVE_SYS_SOCKET_H)
+# include <sys/socket.h>
+#endif
+
+namespace shibsp {
+
+#if defined (_MSC_VER)
+ #pragma warning( push )
+ #pragma warning( disable : 4251 )
+#endif
+
+ /**
+ * Represents a range of IP addresses.
+ */
+ class SHIBSP_API IPRange
+ {
+ public:
+ /**
+ * Constructor.
+ *
+ * @param address address to base the range on; may be the network address or the
+ * address of a host within the network
+ * @param maskSize the number of bits in the netmask
+ */
+ IPRange(const std::bitset<32>& address, int maskSize);
+
+ /**
+ * Constructor.
+ *
+ * @param address address to base the range on; may be the network address or the
+ * address of a host within the network
+ * @param maskSize the number of bits in the netmask
+ */
+ IPRange(const std::bitset<128>& address, int maskSize);
+
+ /**
+ * Determines whether the given address is contained in the IP range.
+ *
+ * @param address the address to check
+ *
+ * @return true iff the address is in the range
+ */
+ bool contains(const char* address) const;
+
+ /**
+ * Determines whether the given address is contained in the IP range.
+ *
+ * @param address the address to check
+ *
+ * @return true iff the address is in the range
+ */
+ bool contains(const struct sockaddr* address) const;
+
+ /**
+ * Parses a CIDR block definition in to an IP range.
+ *
+ * @param cidrBlock the CIDR block definition
+ *
+ * @return the resultant IP range
+ */
+ static IPRange parseCIDRBlock(const char* cidrBlock);
+
+ private:
+ /** Number of bits within the address. 32 bits for IPv4 address, 128 bits for IPv6 addresses. */
+ int m_addressLength;
+
+ /** The IP network address for the range. */
+ std::bitset<32> m_network4;
+
+ /** The netmask for the range. */
+ std::bitset<32> m_mask4;
+
+ /** The IP network address for the range. */
+ std::bitset<128> m_network6;
+
+ /** The netmask for the range. */
+ std::bitset<128> m_mask6;
+ };
+
+#if defined (_MSC_VER)
+ #pragma warning( pop )
+#endif
+
+};
+
+#endif /* __shibsp_iprange_h__ */