}
}
+/**
+ * Return true if addr_1 matches addr_2 in the first `netmask' bits.
+ */
+static int v4_addr_match(uint32_t addr_1, uint32_t addr_2, uint8_t netmask)
+{
+ uint32_t mask = ~0U;
+
+ if (netmask < 32)
+ mask <<= (32 - netmask);
+ return (htonl(addr_1) & mask) == (htonl(addr_2) & mask);
+}
+
static int host_in_access_perm_list(struct http_client *hc)
{
- struct sockaddr_storage ss;
- socklen_t sslen = sizeof(ss);
+ struct access_info *ai, *tmp;
+ struct sockaddr_storage ss;
+ socklen_t sslen = sizeof(ss);
+ struct in_addr v4_addr;
if (getpeername(hc->fd, (struct sockaddr *)&ss, &sslen) < 0) {
- PARA_ERROR_LOG("can not determine address family: %s\n", strerror(errno));
- } else if (ss.ss_family == AF_INET) {
- /* FIXME: access restriction is (currently) only supported for IPv4 */
- struct access_info *ai, *tmp;
- struct in_addr client_addr = ((struct sockaddr_in *)&ss)->sin_addr;
-
- list_for_each_entry_safe(ai, tmp, &access_perm_list, node) {
- unsigned mask = ((~0U) >> ai->netmask);
- if ((client_addr.s_addr & mask) == (ai->addr.s_addr & mask))
- return 1;
- }
+ PARA_ERROR_LOG("Can not determine peer address: %s\n", strerror(errno));
+ goto no_match;
}
+ v4_addr = extract_v4_addr(&ss);
+ if (!v4_addr.s_addr)
+ goto no_match;
+
+ list_for_each_entry_safe(ai, tmp, &access_perm_list, node)
+ if (v4_addr_match(v4_addr.s_addr, ai->addr.s_addr, ai->netmask))
+ return 1;
+no_match:
return 0;
}
return __get_sock_name(sockfd, getpeername);
}
+/**
+ * Extract IPv4 or IPv6-mapped-IPv4 address from sockaddr_storage.
+ * \param ss Container of IPv4/6 address
+ * \return Extracted IPv4 address (different from 0) or 0 if unsuccessful.
+ *
+ * \sa RFC 3493
+ */
+struct in_addr extract_v4_addr(const struct sockaddr_storage *ss)
+{
+ struct in_addr ia = { 0 };
+
+ if (ss->ss_family == AF_INET)
+ ia.s_addr = ((struct sockaddr_in *)ss)->sin_addr.s_addr;
+ if (ss->ss_family == AF_INET6) {
+ const struct in6_addr v6_addr = ((struct sockaddr_in6 *)ss)->sin6_addr;
+
+ if (IN6_IS_ADDR_V4MAPPED(&v6_addr))
+ memcpy(&ia.s_addr, &(v6_addr.s6_addr[12]), 4);
+ }
+ return ia;
+}
+
/*
* Send out a buffer, resend on short writes.
*
*/
extern int makesock(unsigned l3type, unsigned l4type, int passive,
const char *host, unsigned short port_number);
+extern struct in_addr extract_v4_addr(const struct sockaddr_storage *ss);
/**
* Functions to support listening sockets.