Skip to content

Commit

Permalink
Add a config option to redact remote IP addresses in logs. (#283)
Browse files Browse the repository at this point in the history
* Add a config option to redact remote IP addresses in logs.

And other human-readable text.

* Don't redact relayed candidates; do redact relAddrs.
  • Loading branch information
JonathanLennox authored Jul 9, 2024
1 parent b2c8f4d commit 1572b4f
Show file tree
Hide file tree
Showing 12 changed files with 257 additions and 44 deletions.
132 changes: 130 additions & 2 deletions src/main/java/org/ice4j/TransportAddress.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,42 @@ public byte[] getAddressBytes()
*/
public String toString()
{
String hostAddress = getHostAddress();
return toString(false);
}

public String toRedactedString()
{
return toString(true);
}

private String toString(boolean redact)
{
String hostAddress;
if (redact)
{
hostAddress = getRedactedAddress();
if (hostAddress == null)
{
String hostName = getHostName();
if (hostName != null)
{
/* The transport address is an unresolved hostname. Redact the hostname. */
hostAddress = "xxxx.xxx";
}
}
}
else
{
hostAddress = getHostAddress();
if (hostAddress == null)
{
hostAddress = getHostName();
}
}
if (hostAddress == null)
{
hostAddress = getHostName();
// The address has neither a hostName nor a hostAddress. Shouldn't happen, but don't NPE if it does. */
hostAddress = "null";
}

StringBuilder bldr = new StringBuilder(hostAddress);
Expand Down Expand Up @@ -181,6 +213,27 @@ public String getHostAddress()
return addressStr;
}

/* Return the host address, redacted if address redaction is enabled. */
public String getRedactedAddress()
{
if (AgentConfig.config.getRedactRemoteAddresses())
{
InetAddress addr = getAddress();
if (addr != null)
{
return toRedactedString(addr);
}
else
{
return null;
}
}
else
{
return getHostAddress();
}
}

/**
* The transport that this transport address is suggesting.
*
Expand Down Expand Up @@ -288,4 +341,79 @@ public boolean canReach(TransportAddress dst)

return true;
}

public static String redact(InetAddress addr)
{
if (AgentConfig.config.getRedactRemoteAddresses())
{
return toRedactedString(addr);
}
else
{
return addr.getHostAddress();
}
}

public static String redact(SocketAddress addr)
{
if (addr instanceof InetSocketAddress && AgentConfig.config.getRedactRemoteAddresses())
{
InetSocketAddress iaddr = (InetSocketAddress)addr;
return toRedactedString(iaddr.getAddress()) + ":" + iaddr.getPort();
}
else if (addr == null)
{
return null;
}
else
{
return addr.toString();
}
}

/**
* Return a redacted form of an InetAddress, in a form preserving its IP address family
* and (for IPv6) its highest-level bytes.
*/
public static String toRedactedString(InetAddress addr)
{
if (addr == null)
{
return null;
}
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress())
{
return addr.getHostAddress();
}
if (addr instanceof Inet6Address)
{
StringBuilder sb = new StringBuilder();
byte[] addrBytes = addr.getAddress();
if ((addrBytes[0] & 0xe0) == 0x20)
{
/* Globally-routable IPv6 address; the second nybble can indicate the
* RIR that allocated the address, so don't print it.
*/
sb.append("2xxx");
}
else if (addrBytes[0] != 0 || addrBytes[1] != 0)
{
/* Other IPv6 address; most common will be fc00:: unique-local and fe80:: link-local address where the
* first 16 bits don't leak anything but the type; all others indicate something unexpected.
*/
sb.append(Integer.toHexString(((addrBytes[0]<<8) & 0xff00)
| (addrBytes[1] & 0xff)));
}
sb.append("::xxx");
return sb.toString();
}
else if (addr instanceof Inet4Address)
{
return "xx.xx.xx.xx";
}
else
{
return addr.getHostAddress();
}
}
}
6 changes: 3 additions & 3 deletions src/main/java/org/ice4j/ice/Agent.java
Original file line number Diff line number Diff line change
Expand Up @@ -1613,7 +1613,7 @@ protected void incomingCheckReceived(TransportAddress remoteAddress,
= createCandidatePair(localCandidate, remoteCandidate);

logger.debug(() -> "set use-candidate " + useCandidate + " for pair " +
triggeredPair.toShortString());
triggeredPair.toRedactedShortString());
if (useCandidate)
{
triggeredPair.setUseCandidateReceived();
Expand All @@ -1635,7 +1635,7 @@ else if (state == IceProcessingState.FAILED)
else //Running, Connected or Terminated.
{
logger.debug(() -> "Received check from "
+ triggeredPair.toShortString() + " triggered a check.");
+ triggeredPair.toRedactedShortString() + " triggered a check.");

// We have been started, and have not failed (yet). If this is
// a new pair, handle it (even if we have already completed).
Expand Down Expand Up @@ -1725,7 +1725,7 @@ private void triggerCheck(CandidatePair triggerPair)
//
if (triggerPair.getParentComponent().getSelectedPair() == null)
logger.info("Add peer CandidatePair with new reflexive " +
"address to checkList: " + triggerPair);
"address to checkList: " + triggerPair.toRedactedString());
parentStream.addToCheckList(triggerPair);
}

Expand Down
46 changes: 43 additions & 3 deletions src/main/java/org/ice4j/ice/Candidate.java
Original file line number Diff line number Diff line change
Expand Up @@ -756,23 +756,54 @@ public TransportAddress getRelatedAddress()
* @return a <tt>String</tt> representation of this <tt>Candidate</tt>.
*/
@Override
public String toString()
public String toString() {
return toString(false);
}

/**
* Returns a <tt>String</tt> representation of this <tt>Candidate</tt>
* containing its <tt>TransportAddress</tt>, base, foundation, priority and
* whatever other properties may be relevant, but with its IP address redacted if
* redaction is enabled.
*
* @return a redacted <tt>String</tt> representation of this <tt>Candidate</tt>.
*/
public String toRedactedString() {
return toString(true);
}

private String toString(boolean redacted)
{
StringBuilder buff = new StringBuilder("candidate:");

buff.append(getFoundation());
buff.append(" ").append(getParentComponent().getComponentID());
buff.append(" ").append(getTransport());
buff.append(" ").append(getPriority());
buff.append(" ").append(getTransportAddress().getHostAddress());
if (redacted && getType() != CandidateType.RELAYED_CANDIDATE)
{
buff.append(" ").append(getTransportAddress().getRedactedAddress());
}
else
{
buff.append(" ").append(getTransportAddress().getHostAddress());
}
buff.append(" ").append(getTransportAddress().getPort());
buff.append(" typ ").append(getType());

TransportAddress relAddr = getRelatedAddress();

if (relAddr != null)
{
buff.append(" raddr ").append(relAddr.getHostAddress());
buff.append(" raddr ");
if (redacted)
{
buff.append(relAddr.getRedactedAddress());
}
else
{
buff.append(relAddr.getHostAddress());
}
buff.append(" rport ").append(relAddr.getPort());
}

Expand All @@ -788,6 +819,15 @@ public String toShortString()
return getTransportAddress() + "/" + getType();
}

public String toRedactedShortString()
{
if (getType() == CandidateType.RELAYED_CANDIDATE)
{
return toShortString();
}
return getTransportAddress().toRedactedString() + "/" + getType();
}

/**
* Returns an integer indicating the preference that this <tt>Candidate</tt>
* should be considered with for becoming a default candidate.
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/org/ice4j/ice/CandidatePair.java
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,20 @@ public String toString()
+ "\n\tRemoteCandidate=" + getRemoteCandidate();
}

/**
* Returns a String representation of this <tt>CandidatePair</tt>, with the remote
* candidate IP address redacted if redaction is enabled.
*
* @return a String representation of the object.
*/
public String toRedactedString()
{
return
"CandidatePair (State=" + getState() + " Priority=" + getPriority()
+ "):\n\tLocalCandidate=" + getLocalCandidate()
+ "\n\tRemoteCandidate=" + getRemoteCandidate().toRedactedString();
}

/**
* Returns a short String representation of this <tt>CandidatePair</tt>.
*
Expand All @@ -496,6 +510,19 @@ public String toShortString()
+ " (" + getParentComponent().toShortString() + ")";
}

/**
* Returns a short String representation of this <tt>CandidatePair</tt>,
* with the remote candidate IP address redacted if redaction is enabled.
*
* @return a redacted short String representation of the object.
*/
public String toRedactedShortString()
{
return getLocalCandidate().toShortString()
+ " -> " + getRemoteCandidate().toRedactedShortString()
+ " (" + getParentComponent().toShortString() + ")";
}

/**
* A <tt>Comparator</tt> using the <tt>compareTo</tt> method of the
* <tt>CandidatePair</tt>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/ice4j/ice/CheckList.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ protected synchronized void handleNominationConfirmed(

logger.info(
"Selected pair for stream " + cmp.toShortString() + ": "
+ nominatedPair.toShortString());
+ nominatedPair.toRedactedShortString());

cmp.setSelectedPair(nominatedPair);

Expand Down
23 changes: 16 additions & 7 deletions src/main/java/org/ice4j/ice/Component.java
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ public int getLocalCandidateCount()
public void addRemoteCandidate(RemoteCandidate candidate)
{
logger.info("Add remote candidate for " + toShortString()
+ ": " + candidate.toShortString());
+ ": " + candidate.toRedactedShortString());

synchronized(remoteCandidates)
{
Expand Down Expand Up @@ -471,15 +471,15 @@ public void updateRemoteCandidates()
if (existingPair != null)
{
logger.info("existing Pair updated: " +
existingPair.toShortString() +
" to " + pair.toShortString() + ".");
existingPair.toRedactedShortString() +
" to " + pair.toRedactedShortString() + ".");
existingPair.setRemoteCandidate(pair.getRemoteCandidate());
existingPair.computePriority();
}
else
{
streamCheckList.add(pair);
logger.info("new Pair added: " + pair.toShortString()
logger.info("new Pair added: " + pair.toRedactedShortString()
+ ".");
}
}
Expand Down Expand Up @@ -599,13 +599,22 @@ public String toString()
buff.append("\n")
.append(remoteCandidatesCount)
.append(" Remote candidates:");
buff.append("\ndefault remote candidate: ")
.append(getDefaultRemoteCandidate());
Candidate<?> defaultRemoteCandidate = getDefaultRemoteCandidate();
buff.append("\ndefault remote candidate: ");
if (defaultRemoteCandidate != null)
{
buff.append(defaultRemoteCandidate.toRedactedString());
}
else
{
buff.append("null");
}

synchronized(remoteCandidates)
{
for (RemoteCandidate cand : remoteCandidates)
{
buff.append("\n").append(cand);
buff.append("\n").append(cand.toRedactedString());
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/ice4j/ice/ComponentSocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private void addAuthorizedAddress(SocketAddress address)
return;
}

logger.info("Adding allowed address: " + address);
logger.info("Adding allowed address: " + TransportAddress.redact(address));

Set<SocketAddress> newSet = new HashSet<>();
newSet.addAll(authorizedAddresses);
Expand Down
Loading

0 comments on commit 1572b4f

Please sign in to comment.