Author: markt
Date: Wed May 23 14:23:01 2018
New Revision: 1832105
URL: http://svn.apache.org/viewvc?rev=1832105&view=rev
Log:
Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=51497
Add an option, ipv6Canonical, to the AccessLogValve that causes IPv6 addresses
to be output in canonical form defined by RFC 5952.
Based on a patch by ognjen.
Added:
tomcat/trunk/java/org/apache/tomcat/util/net/IPv6Utils.java (with props)
tomcat/trunk/test/org/apache/tomcat/util/net/IPv6UtilsTest.java (with
props)
Modified:
tomcat/trunk/java/org/apache/catalina/valves/AbstractAccessLogValve.java
tomcat/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/docs/config/valve.xml
Modified:
tomcat/trunk/java/org/apache/catalina/valves/AbstractAccessLogValve.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/AbstractAccessLogValve.java?rev=1832105&r1=1832104&r2=1832105&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/AbstractAccessLogValve.java
(original)
+++ tomcat/trunk/java/org/apache/catalina/valves/AbstractAccessLogValve.java
Wed May 23 14:23:01 2018
@@ -52,6 +52,7 @@ import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.collections.SynchronizedStack;
+import org.apache.tomcat.util.net.IPv6Utils;
/**
@@ -174,6 +175,11 @@ public abstract class AbstractAccessLogV
*/
protected boolean enabled = true;
+ /**
+ * Use IPv6 canonical representation format as defined by RFC 5952.
+ */
+ private boolean ipv6Canonical = false;
+
/**
* The pattern used to format our access log lines.
*/
@@ -480,6 +486,16 @@ public abstract class AbstractAccessLogV
// ------------------------------------------------------------- Properties
+ public boolean getIpv6Canonical() {
+ return ipv6Canonical;
+ }
+
+
+ public void setIpv6Canonical(boolean ipv6Canonical) {
+ this.ipv6Canonical = ipv6Canonical;
+ }
+
+
/**
* {@inheritDoc}
* Default is <code>false</code>.
@@ -489,6 +505,7 @@ public abstract class AbstractAccessLogV
this.requestAttributesEnabled = requestAttributesEnabled;
}
+
/**
* {@inheritDoc}
*/
@@ -792,11 +809,11 @@ public abstract class AbstractAccessLogV
/**
* write local IP address - %A
*/
- protected static class LocalAddrElement implements AccessLogElement {
+ protected class LocalAddrElement implements AccessLogElement {
- private static final String LOCAL_ADDR_VALUE;
+ private final String localAddrValue;
- static {
+ public LocalAddrElement(boolean ipv6Canonical) {
String init;
try {
init = InetAddress.getLocalHost().getHostAddress();
@@ -804,13 +821,18 @@ public abstract class AbstractAccessLogV
ExceptionUtils.handleThrowable(e);
init = "127.0.0.1";
}
- LOCAL_ADDR_VALUE = init;
+
+ if (ipv6Canonical) {
+ localAddrValue = IPv6Utils.canonize(init);
+ } else {
+ localAddrValue = init;
+ }
}
@Override
public void addElement(CharArrayWriter buf, Date date, Request request,
Response response, long time) {
- buf.append(LOCAL_ADDR_VALUE);
+ buf.append(localAddrValue);
}
}
@@ -821,16 +843,22 @@ public abstract class AbstractAccessLogV
@Override
public void addElement(CharArrayWriter buf, Date date, Request request,
Response response, long time) {
+ String value = null;
if (requestAttributesEnabled) {
Object addr = request.getAttribute(REMOTE_ADDR_ATTRIBUTE);
if (addr == null) {
- buf.append(request.getRemoteAddr());
+ value = request.getRemoteAddr();
} else {
- buf.append(addr.toString());
+ value = addr.toString();
}
} else {
- buf.append(request.getRemoteAddr());
+ value = request.getRemoteAddr();
+ }
+
+ if (ipv6Canonical) {
+ value = IPv6Utils.canonize(value);
}
+ buf.append(value);
}
}
@@ -854,6 +882,10 @@ public abstract class AbstractAccessLogV
if (value == null || value.length() == 0) {
value = "-";
}
+
+ if (ipv6Canonical) {
+ value = IPv6Utils.canonize(value);
+ }
buf.append(value);
}
}
@@ -1348,11 +1380,15 @@ public abstract class AbstractAccessLogV
/**
* write local server name - %v
*/
- protected static class LocalServerNameElement implements AccessLogElement {
+ protected class LocalServerNameElement implements AccessLogElement {
@Override
public void addElement(CharArrayWriter buf, Date date, Request request,
Response response, long time) {
- buf.append(request.getServerName());
+ if (ipv6Canonical) {
+ buf.append(IPv6Utils.canonize(request.getServerName()));
+ } else {
+ buf.append(request.getServerName());
+ }
}
}
@@ -1649,7 +1685,7 @@ public abstract class AbstractAccessLogV
case 'a':
return new RemoteAddrElement();
case 'A':
- return new LocalAddrElement();
+ return new LocalAddrElement(ipv6Canonical);
case 'b':
return new ByteSentElement(true);
case 'B':
Modified:
tomcat/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java?rev=1832105&r1=1832104&r2=1832105&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
(original)
+++ tomcat/trunk/java/org/apache/catalina/valves/ExtendedAccessLogValve.java
Wed May 23 14:23:01 2018
@@ -604,7 +604,7 @@ public class ExtendedAccessLogValve exte
} else if ("s".equals(token)) {
String nextToken = tokenizer.getToken();
if ("ip".equals(nextToken)) {
- return new LocalAddrElement();
+ return new LocalAddrElement(getIpv6Canonical());
} else if ("dns".equals(nextToken)) {
return new AccessLogElement() {
@Override
Added: tomcat/trunk/java/org/apache/tomcat/util/net/IPv6Utils.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/IPv6Utils.java?rev=1832105&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/IPv6Utils.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/IPv6Utils.java Wed May 23
14:23:01 2018
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+package org.apache.tomcat.util.net;
+
+/**
+ * <p>IPv6 utilities.
+ * <p>For the moment, it only contains function to canonicalize IPv6 address
+ * into RFC 5952 form.
+ */
+public class IPv6Utils {
+
+ private static final int MAX_NUMBER_OF_GROUPS = 8;
+ private static final int MAX_GROUP_LENGTH = 4;
+
+ /**
+ * <p>Convert IPv6 address into RFC 5952 form.
+ * E.g. 2001:db8:0:1:0:0:0:1 -> 2001:db8:0:1::1</p>
+ *
+ * <p>Method is null safe, and if IPv4 address or host name is passed to
the
+ * method it is returned without any processing.</p>
+ *
+ * <p>Method also supports IPv4 in IPv6 (e.g. 0:0:0:0:0:ffff:192.0.2.1 ->
+ * ::ffff:192.0.2.1), and zone ID (e.g. fe80:0:0:0:f0f0:c0c0:1919:1234%4
+ * -> fe80::f0f0:c0c0:1919:1234%4).</p>
+ *
+ * <p>The behaviour of this method is undefined if an invalid IPv6 address
+ * is passed in as input.</p>
+ *
+ * @param ipv6Address String representing valid IPv6 address.
+ * @return String representing IPv6 in canonical form.
+ * @throws IllegalArgumentException if IPv6 format is unacceptable.
+ */
+ public static String canonize(String ipv6Address) throws
IllegalArgumentException {
+
+ if (ipv6Address == null) {
+ return null;
+ }
+
+ // Definitely not an IPv6, return untouched input.
+ if (!mayBeIPv6Address(ipv6Address)) {
+ return ipv6Address;
+ }
+
+ // Length without zone ID (%zone) or IPv4 address
+ int ipv6AddressLength = ipv6Address.length();
+ if (ipv6Address.contains(".")) {
+ // IPv4 in IPv6
+ // e.g. 0:0:0:0:0:FFFF:127.0.0.1
+ int lastColonPos = ipv6Address.lastIndexOf(":");
+ int lastColonsPos = ipv6Address.lastIndexOf("::");
+ if (lastColonsPos >= 0 && lastColonPos == lastColonsPos + 1) {
+ /*
+ * IPv6 part ends with two consecutive colons,
+ * last colon is part of IPv6 format.
+ * e.g. ::127.0.0.1
+ */
+ ipv6AddressLength = lastColonPos + 1;
+ } else {
+ /*
+ * IPv6 part ends with only one colon,
+ * last colon is not part of IPv6 format.
+ * e.g. ::FFFF:127.0.0.1
+ */
+ ipv6AddressLength = lastColonPos;
+ }
+ } else if (ipv6Address.contains("%")) {
+ // Zone ID
+ // e.g. fe80:0:0:0:f0f0:c0c0:1919:1234%4
+ ipv6AddressLength = ipv6Address.lastIndexOf("%");
+ }
+
+ StringBuilder result = new StringBuilder();
+ char [][] groups = new char[MAX_NUMBER_OF_GROUPS][MAX_GROUP_LENGTH];
+ int groupCounter = 0;
+ int charInGroupCounter = 0;
+
+ // Index of the current zeroGroup, -1 means not found.
+ int zeroGroupIndex = -1;
+ int zeroGroupLength = 0;
+
+ // maximum length zero group, if there is more then one, then first one
+ int maxZeroGroupIndex = -1;
+ int maxZeroGroupLength = 0;
+
+ boolean isZero = true;
+ boolean groupStart = true;
+
+ /*
+ * Two consecutive colons, initial expansion.
+ * e.g. 2001:db8:0:0:1::1 -> 2001:db8:0:0:1:0:0:1
+ */
+
+ StringBuilder expanded = new StringBuilder(ipv6Address);
+ int colonsPos = ipv6Address.indexOf("::");
+ int length = ipv6AddressLength;
+ int change = 0;
+
+ if (colonsPos >= 0 && colonsPos < ipv6AddressLength - 2) {
+ int colonCounter = 0;
+ for (int i = 0; i < ipv6AddressLength; i++) {
+ if (ipv6Address.charAt(i) == ':') {
+ colonCounter++;
+ }
+ }
+
+ if (colonsPos == 0) {
+ expanded.insert(0, "0");
+ change = change + 1;
+ }
+
+ for (int i = 0; i < MAX_NUMBER_OF_GROUPS - colonCounter; i++) {
+ expanded.insert(colonsPos + 1, "0:");
+ change = change + 2;
+ }
+
+
+ if (colonsPos == ipv6AddressLength - 2) {
+ expanded.setCharAt(colonsPos + change + 1, '0');
+ } else {
+ expanded.deleteCharAt(colonsPos + change + 1);
+ change = change - 1;
+ }
+ length = length + change;
+ }
+
+
+ // Processing one char at the time
+ for (int charCounter = 0; charCounter < length; charCounter++) {
+ char c = expanded.charAt(charCounter);
+ if (c >= 'A' && c <= 'F') {
+ c = (char) (c + 32);
+ }
+ if (c != ':') {
+ groups[groupCounter][charInGroupCounter] = c;
+ if (!(groupStart && c == '0')) {
+ ++charInGroupCounter;
+ groupStart = false;
+ }
+ if (c != '0') {
+ isZero = false;
+ }
+ }
+ if (c == ':' || charCounter == (length - 1)) {
+ // We reached end of current group
+ if (isZero) {
+ ++zeroGroupLength;
+ if (zeroGroupIndex == -1) {
+ zeroGroupIndex = groupCounter;
+ }
+ }
+
+ if (!isZero || charCounter == (length - 1)) {
+ // We reached end of zero group
+ if (zeroGroupLength > maxZeroGroupLength) {
+ maxZeroGroupLength = zeroGroupLength;
+ maxZeroGroupIndex = zeroGroupIndex;
+ }
+ zeroGroupLength = 0;
+ zeroGroupIndex = -1;
+ }
+ ++groupCounter;
+ charInGroupCounter = 0;
+ isZero = true;
+ groupStart = true;
+ }
+ }
+
+ int numberOfGroups = groupCounter;
+
+ // Output results
+ for (groupCounter = 0; groupCounter < numberOfGroups; groupCounter++) {
+ if (maxZeroGroupLength <= 1 || groupCounter < maxZeroGroupIndex
+ || groupCounter >= maxZeroGroupIndex + maxZeroGroupLength)
{
+ for (int j = 0; j < MAX_GROUP_LENGTH; j++) {
+ if (groups[groupCounter][j] != 0) {
+ result.append(groups[groupCounter][j]);
+ }
+ }
+ if (groupCounter < (numberOfGroups - 1)
+ && (groupCounter != maxZeroGroupIndex - 1
+ || maxZeroGroupLength <= 1)) {
+ result.append(':');
+ }
+ } else if (groupCounter == maxZeroGroupIndex) {
+ result.append("::");
+ }
+ }
+
+ // Solve problem with three colons in IPv4 in IPv6 format
+ // e.g. 0:0:0:0:0:0:127.0.0.1 -> :::127.0.0.1 -> ::127.0.0.1
+ int resultLength = result.length();
+ if (result.charAt(resultLength - 1) == ':' && ipv6AddressLength <
ipv6Address.length()
+ && ipv6Address.charAt(ipv6AddressLength) == ':') {
+ result.delete(resultLength - 1, resultLength);
+ }
+
+ /*
+ * Append IPv4 from IPv4-in-IPv6 format or Zone ID
+ */
+ for (int i = ipv6AddressLength; i < ipv6Address.length(); i++) {
+ result.append(ipv6Address.charAt(i));
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Heuristic check if string might be an IPv6 address.
+ *
+ * @param address Any string or null
+ * @return true, if input string contains only hex digits and at least two
colons, before '.' or '%' character
+ */
+ static boolean mayBeIPv6Address(String input) {
+ if (input == null) {
+ return false;
+ }
+
+ int colonsCounter = 0;
+ int length = input.length();
+ for (int i = 0; i < length; i++) {
+ char c = input.charAt(i);
+ if (c == '.' || c == '%') {
+ // IPv4 in IPv6 or Zone ID detected, end of checking.
+ break;
+ }
+ if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F') || c == ':')) {
+ return false;
+ } else if (c == ':') {
+ colonsCounter++;
+ }
+ }
+ if (colonsCounter < 2) {
+ return false;
+ }
+ return true;
+ }
+}
Propchange: tomcat/trunk/java/org/apache/tomcat/util/net/IPv6Utils.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: tomcat/trunk/test/org/apache/tomcat/util/net/IPv6UtilsTest.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/net/IPv6UtilsTest.java?rev=1832105&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/util/net/IPv6UtilsTest.java (added)
+++ tomcat/trunk/test/org/apache/tomcat/util/net/IPv6UtilsTest.java Wed May 23
14:23:01 2018
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.
+ */
+package org.apache.tomcat.util.net;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+
+/**
+ * Mostly examples from RFC 5952
+ */
+public class IPv6UtilsTest {
+
+ @Test
+ public void testMayBeIPv6Address() {
+ Assert.assertFalse(IPv6Utils.mayBeIPv6Address(null));
+
+ Assert.assertTrue(IPv6Utils.mayBeIPv6Address("::1"));
+ Assert.assertTrue(IPv6Utils.mayBeIPv6Address("::"));
+ Assert.assertTrue(IPv6Utils.mayBeIPv6Address("2001:db8:0:0:1:0:0:1"));
+
+ Assert.assertFalse(IPv6Utils.mayBeIPv6Address(""));
+ Assert.assertFalse(IPv6Utils.mayBeIPv6Address(":1"));
+ Assert.assertFalse(IPv6Utils.mayBeIPv6Address("123.123.123.123"));
+
Assert.assertFalse(IPv6Utils.mayBeIPv6Address("tomcat.eu.apache.org:443"));
+ }
+
+ @Test
+ public void testCanonize() {
+ Assert.assertNull(IPv6Utils.canonize(null));
+ Assert.assertEquals("", IPv6Utils.canonize(""));
+
+ // IPv4-safe
+ Assert.assertEquals("123.123.123.123",
IPv6Utils.canonize("123.123.123.123"));
+ Assert.assertEquals("123.1.2.23", IPv6Utils.canonize("123.1.2.23"));
+
+ // Introductory RFC 5952 examples
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:db8:0:0:1:0:0:1"));
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:0db8:0:0:1:0:0:1"));
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:db8::1:0:0:1"));
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:db8::0:1:0:0:1"));
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:0db8::1:0:0:1"));
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:db8:0:0:1::1"));
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:db8:0000:0:1::1"));
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:DB8:0:0:1::1"));
+
+ // Strip leading zeros (2.1)
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:0001"));
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:001"));
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:01"));
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:1"));
+
+ // Zero compression (2.2)
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:0:1",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd::1"));
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:0:1",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:0:1"));
+
+ Assert.assertEquals("2001:db8::1",
IPv6Utils.canonize("2001:db8:0:0:0::1"));
+ Assert.assertEquals("2001:db8::1",
IPv6Utils.canonize("2001:db8:0:0::1"));
+ Assert.assertEquals("2001:db8::1",
IPv6Utils.canonize("2001:db8:0::1"));
+ Assert.assertEquals("2001:db8::1", IPv6Utils.canonize("2001:db8::1"));
+
+ Assert.assertEquals("2001:db8::aaaa:0:0:1",
IPv6Utils.canonize("2001:db8::aaaa:0:0:1"));
+ Assert.assertEquals("2001:db8::aaaa:0:0:1",
IPv6Utils.canonize("2001:db8:0:0:aaaa::1"));
+
+ // Uppercase or lowercase (2.3)
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa"));
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:AAAA"));
+ Assert.assertEquals("2001:db8:aaaa:bbbb:cccc:dddd:eeee:aaaa",
IPv6Utils.canonize("2001:db8:aaaa:bbbb:cccc:dddd:eeee:AaAa"));
+
+ // Some more zero compression for localhost addresses
+ Assert.assertEquals("::1", IPv6Utils.canonize("0:0:0:0:0:0:0:1"));
+ Assert.assertEquals("::1",
IPv6Utils.canonize("0000:0:0:0:0:0:0:0001"));
+ Assert.assertEquals("::1", IPv6Utils.canonize("00:00:0:0:00:00:0:01"));
+ Assert.assertEquals("::1", IPv6Utils.canonize("::0001"));
+ Assert.assertEquals("::1", IPv6Utils.canonize("::1"));
+
+ // IPv6 unspecified address
+ Assert.assertEquals("::", IPv6Utils.canonize("0:0:0:0:0:0:0:0"));
+ Assert.assertEquals("::", IPv6Utils.canonize("0000:0:0:0:0:0:0:0000"));
+ Assert.assertEquals("::", IPv6Utils.canonize("00:00:0:0:00:00:0:00"));
+ Assert.assertEquals("::", IPv6Utils.canonize("::0000"));
+ Assert.assertEquals("::", IPv6Utils.canonize("::0"));
+ Assert.assertEquals("::", IPv6Utils.canonize("::"));
+
+ // Leading zeros (4.1)
+ Assert.assertEquals("2001:db8::1",
IPv6Utils.canonize("2001:0db8::0001"));
+
+ // Shorten as much as possible (4.2.1)
+ Assert.assertEquals("2001:db8::2:1",
IPv6Utils.canonize("2001:db8:0:0:0:0:2:1"));
+ Assert.assertEquals("2001:db8::",
IPv6Utils.canonize("2001:db8:0:0:0:0:0:0"));
+
+ // Handling One 16-Bit 0 Field (4.2.2)
+ Assert.assertEquals("2001:db8:0:1:1:1:1:1",
IPv6Utils.canonize("2001:db8:0:1:1:1:1:1"));
+ Assert.assertEquals("2001:db8:0:1:1:1:1:1",
IPv6Utils.canonize("2001:db8::1:1:1:1:1"));
+
+ // Choice in Placement of "::" (4.2.3)
+ Assert.assertEquals("2001:0:0:1::1",
IPv6Utils.canonize("2001:0:0:1:0:0:0:1"));
+ Assert.assertEquals("2001:db8::1:0:0:1",
IPv6Utils.canonize("2001:db8:0:0:1:0:0:1"));
+
+ // IPv4 inside IPv6
+ Assert.assertEquals("::ffff:192.0.2.1",
IPv6Utils.canonize("::ffff:192.0.2.1"));
+ Assert.assertEquals("::ffff:192.0.2.1",
IPv6Utils.canonize("0:0:0:0:0:ffff:192.0.2.1"));
+ Assert.assertEquals("::192.0.2.1", IPv6Utils.canonize("::192.0.2.1"));
+ Assert.assertEquals("::192.0.2.1",
IPv6Utils.canonize("0:0:0:0:0:0:192.0.2.1"));
+
+ // Zone ID
+ Assert.assertEquals("fe80::f0f0:c0c0:1919:1234%4",
IPv6Utils.canonize("fe80::f0f0:c0c0:1919:1234%4"));
+ Assert.assertEquals("fe80::f0f0:c0c0:1919:1234%4",
IPv6Utils.canonize("fe80:0:0:0:f0f0:c0c0:1919:1234%4"));
+
+ Assert.assertEquals("::%4", IPv6Utils.canonize("::%4"));
+ Assert.assertEquals("::%4", IPv6Utils.canonize("::0%4"));
+ Assert.assertEquals("::%4", IPv6Utils.canonize("0:0::0%4"));
+ Assert.assertEquals("::%4", IPv6Utils.canonize("0:0:0:0:0:0:0:0%4"));
+
+ Assert.assertEquals("::1%4", IPv6Utils.canonize("::1%4"));
+ Assert.assertEquals("::1%4", IPv6Utils.canonize("0:0::1%4"));
+ Assert.assertEquals("::1%4", IPv6Utils.canonize("0:0:0:0:0:0:0:1%4"));
+
+ Assert.assertEquals("::1%eth0", IPv6Utils.canonize("::1%eth0"));
+ Assert.assertEquals("::1%eth0", IPv6Utils.canonize("0:0::1%eth0"));
+ Assert.assertEquals("::1%eth0",
IPv6Utils.canonize("0:0:0:0:0:0:0:1%eth0"));
+
+ // Hostname safety
+ Assert.assertEquals("www.apache.org",
IPv6Utils.canonize("www.apache.org"));
+ Assert.assertEquals("ipv6.google.com",
IPv6Utils.canonize("ipv6.google.com"));
+ }
+}
Propchange: tomcat/trunk/test/org/apache/tomcat/util/net/IPv6UtilsTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1832105&r1=1832104&r2=1832105&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Wed May 23 14:23:01 2018
@@ -92,6 +92,11 @@
usually performed during web application stop if that stop is triggered
by a JVM shutdown. (markt)
</fix>
+ <add>
+ <bug>51497</bug>: Add an option, <code>ipv6Canonical</code>, to the
+ <code>AccessLogValve</code> that causes IPv6 addresses to be output in
+ canonical form defined by RFC 5952. (ognjen/markt)
+ </add>
<fix>
<bug>62343</bug>: Make CORS filter defaults more secure. This is the
fix
for CVE-2018-8014. (markt)
Modified: tomcat/trunk/webapps/docs/config/valve.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/valve.xml?rev=1832105&r1=1832104&r2=1832105&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/valve.xml (original)
+++ tomcat/trunk/webapps/docs/config/valve.xml Wed May 23 14:23:01 2018
@@ -181,6 +181,16 @@
</p>
</attribute>
+ <attribute name="ipv6Canonical" required="false">
+ <p>Flag to determine if IPv6 addresses should be represented in
canonical
+ representation format as defined by RFC 5952. If set to
<code>true</code>,
+ then IPv6 addresses will be written in canonical format (e.g.
+ <code>2001:db8::1:0:0:1</code>, <code>::1</code>), otherwise it
will be
+ represented in full form (e.g. <code>2001:db8:0:0:1:0:0:1</code>,
+ <code>0:0:0:0:0:0:0:1</code>). Default value: <code>false</code>
+ </p>
+ </attribute>
+
<attribute name="locale" required="false">
<p>The locale used to format timestamps in the access log
lines. Any timestamps configured using an
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]