Loading proguard.flags +4 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,10 @@ static final int EVENT_*; } -keepclassmembers public class * extends com.android.networkstack.util.Struct { public <init>(...); } # The lite proto runtime uses reflection to access fields based on the names in # the schema, keep all the fields. # This replicates the base proguard rule used by the build by default Loading src/com/android/networkstack/packets/NeighborAdvertisement.java 0 → 100644 +127 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed 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 com.android.networkstack.packets; import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_HEADER_MIN_LEN; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN; import android.net.MacAddress; import androidx.annotation.NonNull; import com.android.net.module.util.Ipv6Utils; import com.android.net.module.util.Struct; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Icmpv6Header; import com.android.net.module.util.structs.Ipv6Header; import com.android.net.module.util.structs.LlaOption; import com.android.net.module.util.structs.NaHeader; import java.net.Inet6Address; import java.nio.ByteBuffer; /** * Defines basic data and operations needed to build and parse Neighbor Advertisement packet. * * @hide */ public class NeighborAdvertisement { @NonNull public final EthernetHeader ethHdr; @NonNull public final Ipv6Header ipv6Hdr; @NonNull public final Icmpv6Header icmpv6Hdr; @NonNull public final NaHeader naHdr; @NonNull public final LlaOption tlla; public NeighborAdvertisement(@NonNull final EthernetHeader ethHdr, @NonNull final Ipv6Header ipv6Hdr, @NonNull final Icmpv6Header icmpv6Hdr, @NonNull final NaHeader naHdr, @NonNull final LlaOption tlla) { this.ethHdr = ethHdr; this.ipv6Hdr = ipv6Hdr; this.icmpv6Hdr = icmpv6Hdr; this.naHdr = naHdr; this.tlla = tlla; } /** * Convert a Neighbor Advertisement instance to ByteBuffer. */ public ByteBuffer toByteBuffer() { final int etherHeaderLen = Struct.getSize(EthernetHeader.class); final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class); final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class); final int naHeaderLen = Struct.getSize(NaHeader.class); final int tllaOptionLen = Struct.getSize(LlaOption.class); final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen + icmpv6HeaderLen + naHeaderLen + tllaOptionLen); ethHdr.writeToByteBuffer(packet); ipv6Hdr.writeToByteBuffer(packet); icmpv6Hdr.writeToByteBuffer(packet); naHdr.writeToByteBuffer(packet); tlla.writeToByteBuffer(packet); packet.flip(); return packet; } /** * Build a Neighbor Advertisement packet from the required specified parameters. */ public static ByteBuffer build(@NonNull final MacAddress srcMac, @NonNull final MacAddress dstMac, @NonNull final Inet6Address srcIp, @NonNull final Inet6Address dstIp, int flags, @NonNull final Inet6Address target) { final ByteBuffer tlla = LlaOption.build((byte) ICMPV6_ND_OPTION_TLLA, srcMac); return Ipv6Utils.buildNaPacket(srcMac, dstMac, srcIp, dstIp, flags, target, tlla); } /** * Parse a Neighbor Advertisement packet from ByteBuffer. */ public static NeighborAdvertisement parse(@NonNull final byte[] recvbuf, final int length) throws ParseException { if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_HEADER_MIN_LEN || recvbuf.length < length) { throw new ParseException("Invalid packet length: " + length); } final ByteBuffer packet = ByteBuffer.wrap(recvbuf, 0, length); // Parse each header and option in Neighbor Advertisement packet in order. final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, packet); final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, packet); final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, packet); final NaHeader naHdr = Struct.parse(NaHeader.class, packet); final LlaOption tlla = Struct.parse(LlaOption.class, packet); return new NeighborAdvertisement(ethHdr, ipv6Hdr, icmpv6Hdr, naHdr, tlla); } /** * Thrown when parsing Neighbor Advertisement packet failed. */ public static class ParseException extends Exception { ParseException(String message) { super(message); } } } tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java 0 → 100644 +210 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed 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 com.android.networkstack.packets; import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IPPROTO_ICMPV6; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.net.InetAddresses; import android.net.MacAddress; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import java.net.Inet6Address; import java.nio.ByteBuffer; @RunWith(AndroidJUnit4.class) @SmallTest public final class NeighborAdvertisementTest { private static final Inet6Address TEST_SRC_ADDR = (Inet6Address) InetAddresses.parseNumericAddress("fe80::dfd9:50a0:cc7b:7d6d"); private static final Inet6Address TEST_TARGET_ADDR = (Inet6Address) InetAddresses.parseNumericAddress("2001:db8:1:0:c928:250d:b90c:3178"); private static final byte[] TEST_SOURCE_MAC_ADDR = new byte[] { (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25 }; private static final byte[] TEST_DST_MAC_ADDR = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, }; private static final byte[] TEST_GRATUITOUS_NA = new byte[] { // dst mac address (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // src mac address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25, // ether type (byte) 0x86, (byte) 0xdd, // version, priority and flow label (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00, // length (byte) 0x00, (byte) 0x20, // next header (byte) 0x3a, // hop limit (byte) 0xff, // source address (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xdf, (byte) 0xd9, (byte) 0x50, (byte) 0xa0, (byte) 0xcc, (byte) 0x7b, (byte) 0x7d, (byte) 0x6d, // destination address (byte) 0xff, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, // ICMP type, code, checksum (byte) 0x88, (byte) 0x00, (byte) 0x3a, (byte) 0x3c, // flags (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // target address (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0xc9, (byte) 0x28, (byte) 0x25, (byte) 0x0d, (byte) 0xb9, (byte) 0x0c, (byte) 0x31, (byte) 0x78, // TLLA option (byte) 0x02, (byte) 0x01, // Link-Layer address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25, }; private static final byte[] TEST_GRATUITOUS_NA_LESS_LENGTH = new byte[] { // dst mac address (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // src mac address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25, // ether type (byte) 0x86, (byte) 0xdd, // version, priority and flow label (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00, // length (byte) 0x00, (byte) 0x20, // next header (byte) 0x3a, // hop limit (byte) 0xff, // source address (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xdf, (byte) 0xd9, (byte) 0x50, (byte) 0xa0, (byte) 0xcc, (byte) 0x7b, (byte) 0x7d, (byte) 0x6d, // destination address (byte) 0xff, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, }; private static final byte[] TEST_GRATUITOUS_NA_TRUNCATED = new byte[] { // dst mac address (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // src mac address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25, // ether type (byte) 0x86, (byte) 0xdd, // version, priority and flow label (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00, // length (byte) 0x00, (byte) 0x20, // next header (byte) 0x3a, // hop limit (byte) 0xff, // source address (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xdf, (byte) 0xd9, (byte) 0x50, (byte) 0xa0, (byte) 0xcc, (byte) 0x7b, (byte) 0x7d, (byte) 0x6d, // destination address (byte) 0xff, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, // ICMP type, code, checksum (byte) 0x88, (byte) 0x00, (byte) 0x3a, (byte) 0x3c, // flags (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // target address (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0xc9, (byte) 0x28, (byte) 0x25, (byte) 0x0d, (byte) 0xb9, (byte) 0x0c, (byte) 0x31, (byte) 0x78, // TLLA option (byte) 0x02, (byte) 0x01, // Link-Layer address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, }; @Test public void testGratuitousNa_build() throws Exception { final ByteBuffer na = NeighborAdvertisement.build( MacAddress.fromBytes(TEST_SOURCE_MAC_ADDR), MacAddress.fromBytes(TEST_DST_MAC_ADDR), TEST_SRC_ADDR, IPV6_ADDR_ALL_ROUTERS_MULTICAST, 0 /* flags */, TEST_TARGET_ADDR); assertArrayEquals(na.array(), TEST_GRATUITOUS_NA); } @Test public void testGratuitousNa_parse() throws Exception { final NeighborAdvertisement na = NeighborAdvertisement.parse(TEST_GRATUITOUS_NA, TEST_GRATUITOUS_NA.length); assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.ethHdr.srcMac.toByteArray()); assertArrayEquals(TEST_DST_MAC_ADDR, na.ethHdr.dstMac.toByteArray()); assertEquals(ETH_P_IPV6, na.ethHdr.etherType); assertEquals(IPPROTO_ICMPV6, na.ipv6Hdr.nextHeader); assertEquals(0xff, na.ipv6Hdr.hopLimit); assertEquals(IPV6_ADDR_ALL_ROUTERS_MULTICAST, na.ipv6Hdr.dstIp); assertEquals(TEST_SRC_ADDR, na.ipv6Hdr.srcIp); assertEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, na.icmpv6Hdr.type); assertEquals(0, na.icmpv6Hdr.code); assertEquals(0, na.naHdr.flags); assertEquals(TEST_TARGET_ADDR, na.naHdr.target); assertEquals(2, na.tlla.type); assertEquals(1, na.tlla.length); assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.tlla.linkLayerAddress.toByteArray()); assertArrayEquals(TEST_GRATUITOUS_NA, na.toByteBuffer().array()); } @Test public void testGratuitousNa_invalidByteBufferParameters() throws Exception { assertThrows(NeighborAdvertisement.ParseException.class, () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA, 0)); } @Test public void testGratuitousNa_lessPacketLength() throws Exception { assertThrows(NeighborAdvertisement.ParseException.class, () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_LESS_LENGTH, TEST_GRATUITOUS_NA_LESS_LENGTH.length)); } @Test public void testGratuitousNa_truncatedPacket() throws Exception { assertThrows(IllegalArgumentException.class, () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_TRUNCATED, TEST_GRATUITOUS_NA_TRUNCATED.length)); } } Loading
proguard.flags +4 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,10 @@ static final int EVENT_*; } -keepclassmembers public class * extends com.android.networkstack.util.Struct { public <init>(...); } # The lite proto runtime uses reflection to access fields based on the names in # the schema, keep all the fields. # This replicates the base proguard rule used by the build by default Loading
src/com/android/networkstack/packets/NeighborAdvertisement.java 0 → 100644 +127 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed 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 com.android.networkstack.packets; import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_HEADER_MIN_LEN; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN; import android.net.MacAddress; import androidx.annotation.NonNull; import com.android.net.module.util.Ipv6Utils; import com.android.net.module.util.Struct; import com.android.net.module.util.structs.EthernetHeader; import com.android.net.module.util.structs.Icmpv6Header; import com.android.net.module.util.structs.Ipv6Header; import com.android.net.module.util.structs.LlaOption; import com.android.net.module.util.structs.NaHeader; import java.net.Inet6Address; import java.nio.ByteBuffer; /** * Defines basic data and operations needed to build and parse Neighbor Advertisement packet. * * @hide */ public class NeighborAdvertisement { @NonNull public final EthernetHeader ethHdr; @NonNull public final Ipv6Header ipv6Hdr; @NonNull public final Icmpv6Header icmpv6Hdr; @NonNull public final NaHeader naHdr; @NonNull public final LlaOption tlla; public NeighborAdvertisement(@NonNull final EthernetHeader ethHdr, @NonNull final Ipv6Header ipv6Hdr, @NonNull final Icmpv6Header icmpv6Hdr, @NonNull final NaHeader naHdr, @NonNull final LlaOption tlla) { this.ethHdr = ethHdr; this.ipv6Hdr = ipv6Hdr; this.icmpv6Hdr = icmpv6Hdr; this.naHdr = naHdr; this.tlla = tlla; } /** * Convert a Neighbor Advertisement instance to ByteBuffer. */ public ByteBuffer toByteBuffer() { final int etherHeaderLen = Struct.getSize(EthernetHeader.class); final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class); final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class); final int naHeaderLen = Struct.getSize(NaHeader.class); final int tllaOptionLen = Struct.getSize(LlaOption.class); final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + ipv6HeaderLen + icmpv6HeaderLen + naHeaderLen + tllaOptionLen); ethHdr.writeToByteBuffer(packet); ipv6Hdr.writeToByteBuffer(packet); icmpv6Hdr.writeToByteBuffer(packet); naHdr.writeToByteBuffer(packet); tlla.writeToByteBuffer(packet); packet.flip(); return packet; } /** * Build a Neighbor Advertisement packet from the required specified parameters. */ public static ByteBuffer build(@NonNull final MacAddress srcMac, @NonNull final MacAddress dstMac, @NonNull final Inet6Address srcIp, @NonNull final Inet6Address dstIp, int flags, @NonNull final Inet6Address target) { final ByteBuffer tlla = LlaOption.build((byte) ICMPV6_ND_OPTION_TLLA, srcMac); return Ipv6Utils.buildNaPacket(srcMac, dstMac, srcIp, dstIp, flags, target, tlla); } /** * Parse a Neighbor Advertisement packet from ByteBuffer. */ public static NeighborAdvertisement parse(@NonNull final byte[] recvbuf, final int length) throws ParseException { if (length < ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_HEADER_MIN_LEN || recvbuf.length < length) { throw new ParseException("Invalid packet length: " + length); } final ByteBuffer packet = ByteBuffer.wrap(recvbuf, 0, length); // Parse each header and option in Neighbor Advertisement packet in order. final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, packet); final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, packet); final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, packet); final NaHeader naHdr = Struct.parse(NaHeader.class, packet); final LlaOption tlla = Struct.parse(LlaOption.class, packet); return new NeighborAdvertisement(ethHdr, ipv6Hdr, icmpv6Hdr, naHdr, tlla); } /** * Thrown when parsing Neighbor Advertisement packet failed. */ public static class ParseException extends Exception { ParseException(String message) { super(message); } } }
tests/unit/src/com/android/networkstack/packets/NeighborAdvertisementTest.java 0 → 100644 +210 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed 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 com.android.networkstack.packets; import static android.system.OsConstants.ETH_P_IPV6; import static android.system.OsConstants.IPPROTO_ICMPV6; import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.net.InetAddresses; import android.net.MacAddress; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import java.net.Inet6Address; import java.nio.ByteBuffer; @RunWith(AndroidJUnit4.class) @SmallTest public final class NeighborAdvertisementTest { private static final Inet6Address TEST_SRC_ADDR = (Inet6Address) InetAddresses.parseNumericAddress("fe80::dfd9:50a0:cc7b:7d6d"); private static final Inet6Address TEST_TARGET_ADDR = (Inet6Address) InetAddresses.parseNumericAddress("2001:db8:1:0:c928:250d:b90c:3178"); private static final byte[] TEST_SOURCE_MAC_ADDR = new byte[] { (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25 }; private static final byte[] TEST_DST_MAC_ADDR = new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, }; private static final byte[] TEST_GRATUITOUS_NA = new byte[] { // dst mac address (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // src mac address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25, // ether type (byte) 0x86, (byte) 0xdd, // version, priority and flow label (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00, // length (byte) 0x00, (byte) 0x20, // next header (byte) 0x3a, // hop limit (byte) 0xff, // source address (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xdf, (byte) 0xd9, (byte) 0x50, (byte) 0xa0, (byte) 0xcc, (byte) 0x7b, (byte) 0x7d, (byte) 0x6d, // destination address (byte) 0xff, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, // ICMP type, code, checksum (byte) 0x88, (byte) 0x00, (byte) 0x3a, (byte) 0x3c, // flags (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // target address (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0xc9, (byte) 0x28, (byte) 0x25, (byte) 0x0d, (byte) 0xb9, (byte) 0x0c, (byte) 0x31, (byte) 0x78, // TLLA option (byte) 0x02, (byte) 0x01, // Link-Layer address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25, }; private static final byte[] TEST_GRATUITOUS_NA_LESS_LENGTH = new byte[] { // dst mac address (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // src mac address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25, // ether type (byte) 0x86, (byte) 0xdd, // version, priority and flow label (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00, // length (byte) 0x00, (byte) 0x20, // next header (byte) 0x3a, // hop limit (byte) 0xff, // source address (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xdf, (byte) 0xd9, (byte) 0x50, (byte) 0xa0, (byte) 0xcc, (byte) 0x7b, (byte) 0x7d, (byte) 0x6d, // destination address (byte) 0xff, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, }; private static final byte[] TEST_GRATUITOUS_NA_TRUNCATED = new byte[] { // dst mac address (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, // src mac address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, (byte) 0xc1, (byte) 0x25, // ether type (byte) 0x86, (byte) 0xdd, // version, priority and flow label (byte) 0x60, (byte) 0x00, (byte) 0x00, (byte) 0x00, // length (byte) 0x00, (byte) 0x20, // next header (byte) 0x3a, // hop limit (byte) 0xff, // source address (byte) 0xfe, (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xdf, (byte) 0xd9, (byte) 0x50, (byte) 0xa0, (byte) 0xcc, (byte) 0x7b, (byte) 0x7d, (byte) 0x6d, // destination address (byte) 0xff, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, // ICMP type, code, checksum (byte) 0x88, (byte) 0x00, (byte) 0x3a, (byte) 0x3c, // flags (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // target address (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0xc9, (byte) 0x28, (byte) 0x25, (byte) 0x0d, (byte) 0xb9, (byte) 0x0c, (byte) 0x31, (byte) 0x78, // TLLA option (byte) 0x02, (byte) 0x01, // Link-Layer address (byte) 0xea, (byte) 0xbe, (byte) 0x11, (byte) 0x25, }; @Test public void testGratuitousNa_build() throws Exception { final ByteBuffer na = NeighborAdvertisement.build( MacAddress.fromBytes(TEST_SOURCE_MAC_ADDR), MacAddress.fromBytes(TEST_DST_MAC_ADDR), TEST_SRC_ADDR, IPV6_ADDR_ALL_ROUTERS_MULTICAST, 0 /* flags */, TEST_TARGET_ADDR); assertArrayEquals(na.array(), TEST_GRATUITOUS_NA); } @Test public void testGratuitousNa_parse() throws Exception { final NeighborAdvertisement na = NeighborAdvertisement.parse(TEST_GRATUITOUS_NA, TEST_GRATUITOUS_NA.length); assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.ethHdr.srcMac.toByteArray()); assertArrayEquals(TEST_DST_MAC_ADDR, na.ethHdr.dstMac.toByteArray()); assertEquals(ETH_P_IPV6, na.ethHdr.etherType); assertEquals(IPPROTO_ICMPV6, na.ipv6Hdr.nextHeader); assertEquals(0xff, na.ipv6Hdr.hopLimit); assertEquals(IPV6_ADDR_ALL_ROUTERS_MULTICAST, na.ipv6Hdr.dstIp); assertEquals(TEST_SRC_ADDR, na.ipv6Hdr.srcIp); assertEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, na.icmpv6Hdr.type); assertEquals(0, na.icmpv6Hdr.code); assertEquals(0, na.naHdr.flags); assertEquals(TEST_TARGET_ADDR, na.naHdr.target); assertEquals(2, na.tlla.type); assertEquals(1, na.tlla.length); assertArrayEquals(TEST_SOURCE_MAC_ADDR, na.tlla.linkLayerAddress.toByteArray()); assertArrayEquals(TEST_GRATUITOUS_NA, na.toByteBuffer().array()); } @Test public void testGratuitousNa_invalidByteBufferParameters() throws Exception { assertThrows(NeighborAdvertisement.ParseException.class, () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA, 0)); } @Test public void testGratuitousNa_lessPacketLength() throws Exception { assertThrows(NeighborAdvertisement.ParseException.class, () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_LESS_LENGTH, TEST_GRATUITOUS_NA_LESS_LENGTH.length)); } @Test public void testGratuitousNa_truncatedPacket() throws Exception { assertThrows(IllegalArgumentException.class, () -> NeighborAdvertisement.parse(TEST_GRATUITOUS_NA_TRUNCATED, TEST_GRATUITOUS_NA_TRUNCATED.length)); } }