Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion notifications/core-spi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ dependencies {
implementation "com.amazonaws:aws-java-sdk-ses:${aws_version}"
implementation "org.apache.httpcomponents.core5:httpcore5:${versions.httpcore5}"
implementation "org.apache.httpcomponents.client5:httpclient5:${versions.httpclient5}"
implementation "com.github.seancfoley:ipaddress:5.3.3"
implementation "com.github.seancfoley:ipaddress:5.5.0"
implementation "commons-validator:commons-validator:1.7"

testImplementation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

package org.opensearch.notifications.spi.utils

import inet.ipaddr.HostName
import inet.ipaddr.IPAddressString
import org.apache.commons.validator.routines.DomainValidator
import org.apache.hc.client5.http.classic.methods.HttpPatch
Expand All @@ -14,7 +13,6 @@ import org.apache.hc.client5.http.classic.methods.HttpPut
import org.apache.logging.log4j.LogManager
import org.opensearch.core.common.Strings
import org.opensearch.notifications.spi.utils.ValidationHelpers.FQDN_REGEX
import java.lang.Exception
import java.net.InetAddress
import java.net.URL

Expand Down Expand Up @@ -65,26 +63,34 @@ fun getResolvedIps(host: String): List<IPAddressString> {

fun isHostInDenylist(urlString: String, hostDenyList: List<String>): Boolean {
val url = URL(urlString)
if (url.host != null) {
val resolvedIpStrings = getResolvedIps(url.host)
val hostStr = HostName(url.host)

for (network in hostDenyList) {
val denyIpStr = IPAddressString(network)
val denyHostStr = HostName(network)
val hostInDenyList = denyHostStr.equals(hostStr)
var ipInDenyList = false

for (ipStr in resolvedIpStrings) {
if (denyIpStr.contains(ipStr)) {
ipInDenyList = true
break
}
}
val host = url.host ?: return false
val resolvedIps = getResolvedIps(host)
if (resolvedIps.isEmpty()) return false

// Parse deny list into IPAddress objects
val denyNetworks = hostDenyList.map { IPAddressString(it).address }

if (hostInDenyList || ipInDenyList) {
LogManager.getLogger().error("${url.host} is denied")
return true
for (ip in resolvedIps) {
val candidates = mutableListOf(ip)

if (ip.isIPv4) {
val ipv6Mapped = IPAddressString("::ffff:${ip.toNormalizedString()}").address
candidates.add(ipv6Mapped)
}

// IPv6 -> extract IPv4 if compatible (::ffff:a.b.c.d)
if (ip.isIPv6 && ip.isIPv4Compatible) {
val ipv4 = ip.toIPv4()
candidates.add(ipv4)
}

for (candidate in candidates) {
for (deny in denyNetworks) {
// Unspecified addresses match each other
if ((candidate.isZero && deny.isZero) || deny.contains(candidate)) {
LogManager.getLogger().error("$host is denied by rule $deny (matched $candidate)")
return true
}
}
}
}
Expand Down
Loading