2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
24 * Represents a range of IP addresses.
28 #include "exceptions.h"
29 #include "util/IPRange.h"
31 #include <xmltooling/logging.h>
34 # include <winsock2.h>
35 # include <ws2tcpip.h>
38 # include <netinet/in.h>
41 using namespace shibsp;
42 using namespace xmltooling::logging;
43 using namespace xmltooling;
47 // Gets the byte-level representation of a numeric IP address.
48 struct addrinfo* parseIPAddress(const char* s)
50 struct addrinfo* ret = nullptr;
51 struct addrinfo hints;
53 memset(&hints, 0, sizeof(hints));
54 hints.ai_flags = AI_NUMERICHOST;
55 hints.ai_family = AF_UNSPEC;
57 if (getaddrinfo(s, nullptr, &hints, &ret) != 0)
60 if (ret->ai_family != AF_INET
62 && ret->ai_family != AF_INET6
73 IPRange::IPRange(const bitset<32>& address, int maskSize) : m_addressLength(32)
75 if (maskSize < 0 || maskSize > m_addressLength)
76 throw ConfigurationException("CIDR prefix length out of range.");
78 for (int i = m_addressLength - maskSize; i < m_addressLength; ++i)
82 m_network4 &= m_mask4;
85 IPRange::IPRange(const bitset<128>& address, int maskSize) : m_addressLength(128)
87 if (maskSize < 0 || maskSize > m_addressLength)
88 throw ConfigurationException("CIDR prefix length out of range.");
90 for (int i = m_addressLength - maskSize; i < m_addressLength; ++i)
94 m_network6 &= m_mask6;
97 bool IPRange::contains(const char* address) const
100 struct addrinfo* parsed = parseIPAddress(address);
103 bool ret = contains(parsed->ai_addr);
104 freeaddrinfo(parsed);
108 bool IPRange::contains(const struct sockaddr* address) const
111 Category& log = Category::getInstance(SHIBSP_LOGCAT".IPRange");
113 if (address->sa_family == AF_INET) {
114 if (m_addressLength != 32)
116 unsigned long raw = 0;
117 memcpy(&raw, &((struct sockaddr_in*)address)->sin_addr, 4);
118 bitset<32> rawbits((int)ntohl(raw)); // the bitset loads from a host-order variable
119 if (log.isDebugEnabled()) {
121 "comparing address (%s) to network (%s) with mask (%s)",
122 rawbits.to_string< char, char_traits<char>, allocator<char> >().c_str(),
123 m_network4.to_string< char, char_traits<char>, allocator<char> >().c_str(),
124 m_mask4.to_string< char, char_traits<char>, allocator<char> >().c_str()
128 return (rawbits == m_network4);
131 else if (address->sa_family == AF_INET6) {
132 if (m_addressLength != 128)
134 unsigned char raw[16];
135 memcpy(raw, &((struct sockaddr_in6*)address)->sin6_addr, 16);
136 bitset<128> rawbits(raw[0]);
137 for (int i = 1; i < 16; ++i) {
139 rawbits |= bitset<128>(raw[i]);
141 if (log.isDebugEnabled()) {
143 "comparing address (%s) to network (%s) with mask (%s)",
144 rawbits.to_string< char, char_traits<char>, allocator<char> >().c_str(),
145 m_network6.to_string< char, char_traits<char>, allocator<char> >().c_str(),
146 m_mask6.to_string< char, char_traits<char>, allocator<char> >().c_str()
150 return (rawbits == m_network6);
156 IPRange IPRange::parseCIDRBlock(const char* cidrBlock)
158 string block = cidrBlock;
159 string::size_type sep = block.find("/");
160 if (sep == string::npos) {
161 if (block.find(":") == string::npos)
165 sep = block.find("/");
167 struct addrinfo* address = parseIPAddress(block.substr(0, sep).c_str());
169 throw ConfigurationException("Unable to parse address in CIDR block.");
170 int maskSize = atoi(block.substr(++sep).c_str());
171 if (address->ai_family == AF_INET) {
172 unsigned long raw = 0;
173 memcpy(&raw, &((struct sockaddr_in*)address->ai_addr)->sin_addr, 4);
174 freeaddrinfo(address);
175 bitset<32> rawbits((int)ntohl(raw)); // the bitset loads from a host-order variable
176 return IPRange(rawbits, maskSize);
179 else if (address->ai_family == AF_INET6) {
180 unsigned char raw[16];
181 memcpy(raw, &((struct sockaddr_in6*)address->ai_addr)->sin6_addr, 16);
182 freeaddrinfo(address);
183 bitset<128> rawbits(raw[0]);
184 for (int i = 1; i < 16; ++i) {
186 rawbits |= bitset<128>(raw[i]);
188 return IPRange(rawbits, maskSize);
191 throw ConfigurationException("Unrecognized address type in CIDR block.");