1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.netlink; 18 19 import static android.net.netlink.StructNdOptPref64.getScaledLifetimePlc; 20 import static android.net.netlink.StructNdOptPref64.plcToPrefixLength; 21 import static android.net.netlink.StructNdOptPref64.prefixLengthToPlc; 22 23 import static com.android.testutils.MiscAsserts.assertThrows; 24 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertNull; 27 28 import android.net.IpPrefix; 29 30 import androidx.test.filters.SmallTest; 31 import androidx.test.runner.AndroidJUnit4; 32 33 import libcore.util.HexEncoding; 34 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.net.InetAddress; 39 import java.nio.ByteBuffer; 40 41 @RunWith(AndroidJUnit4.class) 42 @SmallTest 43 public class StructNdOptPref64Test { 44 45 private static final String PREFIX1 = "64:ff9b::"; 46 private static final String PREFIX2 = "2001:db8:1:2:3:64::"; 47 prefixBytes(String addrString)48 private static byte[] prefixBytes(String addrString) throws Exception { 49 InetAddress addr = InetAddress.getByName(addrString); 50 byte[] prefixBytes = new byte[12]; 51 System.arraycopy(addr.getAddress(), 0, prefixBytes, 0, 12); 52 return prefixBytes; 53 } 54 prefix(String addrString, int prefixLength)55 private static IpPrefix prefix(String addrString, int prefixLength) throws Exception { 56 return new IpPrefix(InetAddress.getByName(addrString), prefixLength); 57 } 58 assertPref64OptMatches(int lifetime, IpPrefix prefix, StructNdOptPref64 opt)59 private void assertPref64OptMatches(int lifetime, IpPrefix prefix, StructNdOptPref64 opt) { 60 assertEquals(StructNdOptPref64.TYPE, opt.type); 61 assertEquals(2, opt.length); 62 assertEquals(lifetime, opt.lifetime); 63 assertEquals(prefix, opt.prefix); 64 } 65 assertToByteBufferMatches(StructNdOptPref64 opt, String expected)66 private void assertToByteBufferMatches(StructNdOptPref64 opt, String expected) { 67 String actual = HexEncoding.encodeToString(opt.toByteBuffer().array()); 68 assertEquals(expected, actual); 69 } 70 makeNdOptPref64(int lifetime, byte[] prefix, int prefixLengthCode)71 private ByteBuffer makeNdOptPref64(int lifetime, byte[] prefix, int prefixLengthCode) { 72 if (prefix.length != 12) throw new IllegalArgumentException("Prefix must be 12 bytes"); 73 74 ByteBuffer buf = ByteBuffer.allocate(16) 75 .put((byte) StructNdOptPref64.TYPE) 76 .put((byte) StructNdOptPref64.LENGTH) 77 .putShort(getScaledLifetimePlc(lifetime, prefixLengthCode)) 78 .put(prefix, 0, 12); 79 80 buf.flip(); 81 return buf; 82 } 83 84 @Test testParseCannedOption()85 public void testParseCannedOption() throws Exception { 86 String hexBytes = "2602" // type=38, len=2 (16 bytes) 87 + "0088" // lifetime=136, PLC=0 (/96) 88 + "20010DB80003000400050006"; // 2001:db8:3:4:5:6/96 89 byte[] rawBytes = HexEncoding.decode(hexBytes); 90 StructNdOptPref64 opt = StructNdOptPref64.parse(ByteBuffer.wrap(rawBytes)); 91 assertPref64OptMatches(136, prefix("2001:DB8:3:4:5:6::", 96), opt); 92 assertToByteBufferMatches(opt, hexBytes); 93 94 hexBytes = "2602" // type=38, len=2 (16 bytes) 95 + "2752" // lifetime=10064, PLC=2 (/56) 96 + "0064FF9B0000000000000000"; // 64:ff9b::/56 97 rawBytes = HexEncoding.decode(hexBytes); 98 opt = StructNdOptPref64.parse(ByteBuffer.wrap(rawBytes)); 99 assertPref64OptMatches(10064, prefix("64:FF9B::", 56), opt); 100 assertToByteBufferMatches(opt, hexBytes); 101 } 102 103 @Test testParsing()104 public void testParsing() throws Exception { 105 // Valid. 106 ByteBuffer buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 0); 107 StructNdOptPref64 opt = StructNdOptPref64.parse(buf); 108 assertPref64OptMatches(600, prefix(PREFIX1, 96), opt); 109 110 // Valid, zero lifetime, /64. 111 buf = makeNdOptPref64(0, prefixBytes(PREFIX1), 1); 112 opt = StructNdOptPref64.parse(buf); 113 assertPref64OptMatches(0, prefix(PREFIX1, 64), opt); 114 115 // Valid, low lifetime, /56. 116 buf = makeNdOptPref64(8, prefixBytes(PREFIX2), 2); 117 opt = StructNdOptPref64.parse(buf); 118 assertPref64OptMatches(8, prefix(PREFIX2, 56), opt); 119 assertEquals(new IpPrefix("2001:db8:1::/56"), opt.prefix); // Prefix is truncated. 120 121 // Valid, maximum lifetime, /32. 122 buf = makeNdOptPref64(65528, prefixBytes(PREFIX2), 5); 123 opt = StructNdOptPref64.parse(buf); 124 assertPref64OptMatches(65528, prefix(PREFIX2, 32), opt); 125 assertEquals(new IpPrefix("2001:db8::/32"), opt.prefix); // Prefix is truncated. 126 127 // Lifetime not divisible by 8. 128 buf = makeNdOptPref64(300, prefixBytes(PREFIX2), 0); 129 opt = StructNdOptPref64.parse(buf); 130 assertPref64OptMatches(296, prefix(PREFIX2, 96), opt); 131 132 // Invalid prefix length codes. 133 buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 6); 134 assertNull(StructNdOptPref64.parse(buf)); 135 buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 7); 136 assertNull(StructNdOptPref64.parse(buf)); 137 138 // Truncated to varying lengths... 139 buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 3); 140 final int len = buf.limit(); 141 for (int i = 0; i < buf.limit() - 1; i++) { 142 buf.flip(); 143 buf.limit(i); 144 assertNull("Option truncated to " + i + " bytes, should have returned null", 145 StructNdOptPref64.parse(buf)); 146 } 147 buf.flip(); 148 buf.limit(len); 149 // ... but otherwise OK. 150 opt = StructNdOptPref64.parse(buf); 151 assertPref64OptMatches(600, prefix(PREFIX1, 48), opt); 152 } 153 154 @Test testToString()155 public void testToString() throws Exception { 156 ByteBuffer buf = makeNdOptPref64(600, prefixBytes(PREFIX1), 4); 157 StructNdOptPref64 opt = StructNdOptPref64.parse(buf); 158 assertPref64OptMatches(600, prefix(PREFIX1, 40), opt); 159 assertEquals("NdOptPref64(64:ff9b::/40, 600)", opt.toString()); 160 } 161 assertInvalidPlc(int plc)162 private void assertInvalidPlc(int plc) { 163 assertThrows(IllegalArgumentException.class, () -> plcToPrefixLength(plc)); 164 } 165 166 @Test testPrefixLengthToPlc()167 public void testPrefixLengthToPlc() { 168 for (int i = 0; i < 6; i++) { 169 assertEquals(i, prefixLengthToPlc(plcToPrefixLength(i))); 170 } 171 assertInvalidPlc(-1); 172 assertInvalidPlc(6); 173 assertInvalidPlc(7); 174 assertEquals(0, prefixLengthToPlc(96)); 175 } 176 177 assertInvalidParameters(IpPrefix prefix, int lifetime)178 private void assertInvalidParameters(IpPrefix prefix, int lifetime) { 179 assertThrows(IllegalArgumentException.class, () -> new StructNdOptPref64(prefix, lifetime)); 180 } 181 182 @Test testToByteBuffer()183 public void testToByteBuffer() throws Exception { 184 final IpPrefix prefix1 = prefix(PREFIX1, 56); 185 final IpPrefix prefix2 = prefix(PREFIX2, 96); 186 187 StructNdOptPref64 opt = new StructNdOptPref64(prefix1, 600); 188 assertToByteBufferMatches(opt, "2602025A0064FF9B0000000000000000"); 189 assertEquals(new IpPrefix("64:ff9b::/56"), opt.prefix); 190 assertEquals(600, opt.lifetime); 191 192 opt = new StructNdOptPref64(prefix2, 65519); 193 assertToByteBufferMatches(opt, "2602FFE820010DB80001000200030064"); 194 assertEquals(new IpPrefix("2001:db8:1:2:3:64::/96"), opt.prefix); 195 assertEquals(65512, opt.lifetime); 196 197 assertInvalidParameters(prefix1, 65535); 198 assertInvalidParameters(prefix2, -1); 199 assertInvalidParameters(prefix("1.2.3.4", 32), 600); 200 } 201 } 202