Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2015 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.util;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 
     21 import android.support.test.runner.AndroidJUnit4;
     22 import android.support.test.filters.SmallTest;
     23 
     24 import java.nio.ByteBuffer;
     25 
     26 import org.junit.runner.RunWith;
     27 import org.junit.Test;
     28 
     29 @RunWith(AndroidJUnit4.class)
     30 @SmallTest
     31 public class IpUtilsTest {
     32 
     33     private static final int IPV4_HEADER_LENGTH = 20;
     34     private static final int IPV6_HEADER_LENGTH = 40;
     35     private static final int TCP_HEADER_LENGTH = 20;
     36     private static final int UDP_HEADER_LENGTH = 8;
     37     private static final int IP_CHECKSUM_OFFSET = 10;
     38     private static final int TCP_CHECKSUM_OFFSET = 16;
     39     private static final int UDP_CHECKSUM_OFFSET = 6;
     40 
     41     private int getUnsignedByte(ByteBuffer buf, int offset) {
     42         return buf.get(offset) & 0xff;
     43     }
     44 
     45     private int getChecksum(ByteBuffer buf, int offset) {
     46         return getUnsignedByte(buf, offset) * 256 + getUnsignedByte(buf, offset + 1);
     47     }
     48 
     49     private void assertChecksumEquals(int expected, short actual) {
     50         assertEquals(Integer.toHexString(expected), Integer.toHexString(actual & 0xffff));
     51     }
     52 
     53     // Generate test packets using Python code like this::
     54     //
     55     // from scapy import all as scapy
     56     //
     57     // def JavaPacketDefinition(bytes):
     58     //   out = "        ByteBuffer packet = ByteBuffer.wrap(new byte[] {\n            "
     59     //   for i in xrange(len(bytes)):
     60     //     out += "(byte) 0x%02x" % ord(bytes[i])
     61     //     if i < len(bytes) - 1:
     62     //       if i % 4 == 3:
     63     //         out += ",\n            "
     64     //       else:
     65     //         out += ", "
     66     //   out += "\n        });"
     67     //   return out
     68     //
     69     // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2") /
     70     //           scapy.UDP(sport=12345, dport=7) /
     71     //           "hello")
     72     // print JavaPacketDefinition(str(packet))
     73 
     74     @Test
     75     public void testIpv6TcpChecksum() throws Exception {
     76         // packet = (scapy.IPv6(src="2001:db8::1", dst="2001:db8::2", tc=0x80) /
     77         //           scapy.TCP(sport=12345, dport=7,
     78         //                     seq=1692871236, ack=128376451, flags=16,
     79         //                     window=32768) /
     80         //           "hello, world")
     81         ByteBuffer packet = ByteBuffer.wrap(new byte[] {
     82             (byte) 0x68, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     83             (byte) 0x00, (byte) 0x20, (byte) 0x06, (byte) 0x40,
     84             (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
     85             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     86             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     87             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
     88             (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
     89             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     90             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     91             (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02,
     92             (byte) 0x30, (byte) 0x39, (byte) 0x00, (byte) 0x07,
     93             (byte) 0x64, (byte) 0xe7, (byte) 0x2a, (byte) 0x44,
     94             (byte) 0x07, (byte) 0xa6, (byte) 0xde, (byte) 0x83,
     95             (byte) 0x50, (byte) 0x10, (byte) 0x80, (byte) 0x00,
     96             (byte) 0xee, (byte) 0x71, (byte) 0x00, (byte) 0x00,
     97             (byte) 0x68, (byte) 0x65, (byte) 0x6c, (byte) 0x6c,
     98             (byte) 0x6f, (byte) 0x2c, (byte) 0x20, (byte) 0x77,
     99             (byte) 0x6f, (byte) 0x72, (byte) 0x6c, (byte) 0x64
    100         });
    101 
    102         // Check that a valid packet has checksum 0.
    103         int transportLen = packet.limit() - IPV6_HEADER_LENGTH;
    104         assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
    105 
    106         // Check that we can calculate the checksum from scratch.
    107         int sumOffset = IPV6_HEADER_LENGTH + TCP_CHECKSUM_OFFSET;
    108         int sum = getUnsignedByte(packet, sumOffset) * 256 + getUnsignedByte(packet, sumOffset + 1);
    109         assertEquals(0xee71, sum);
    110 
    111         packet.put(sumOffset, (byte) 0);
    112         packet.put(sumOffset + 1, (byte) 0);
    113         assertChecksumEquals(sum, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
    114 
    115         // Check that writing the checksum back into the packet results in a valid packet.
    116         packet.putShort(
    117             sumOffset,
    118             IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
    119         assertEquals(0, IpUtils.tcpChecksum(packet, 0, IPV6_HEADER_LENGTH, transportLen));
    120     }
    121 
    122     @Test
    123     public void testIpv4UdpChecksum() {
    124         // packet = (scapy.IP(src="192.0.2.1", dst="192.0.2.2", tos=0x40) /
    125         //           scapy.UDP(sport=32012, dport=4500) /
    126         //           "\xff")
    127         ByteBuffer packet = ByteBuffer.wrap(new byte[] {
    128             (byte) 0x45, (byte) 0x40, (byte) 0x00, (byte) 0x1d,
    129             (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
    130             (byte) 0x40, (byte) 0x11, (byte) 0xf6, (byte) 0x8b,
    131             (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x01,
    132             (byte) 0xc0, (byte) 0x00, (byte) 0x02, (byte) 0x02,
    133             (byte) 0x7d, (byte) 0x0c, (byte) 0x11, (byte) 0x94,
    134             (byte) 0x00, (byte) 0x09, (byte) 0xee, (byte) 0x36,
    135             (byte) 0xff
    136         });
    137 
    138         // Check that a valid packet has IP checksum 0 and UDP checksum 0xffff (0 is not a valid
    139         // UDP checksum, so the udpChecksum rewrites 0 to 0xffff).
    140         assertEquals(0, IpUtils.ipChecksum(packet, 0));
    141         assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
    142 
    143         // Check that we can calculate the checksums from scratch.
    144         final int ipSumOffset = IP_CHECKSUM_OFFSET;
    145         final int ipSum = getChecksum(packet, ipSumOffset);
    146         assertEquals(0xf68b, ipSum);
    147 
    148         packet.put(ipSumOffset, (byte) 0);
    149         packet.put(ipSumOffset + 1, (byte) 0);
    150         assertChecksumEquals(ipSum, IpUtils.ipChecksum(packet, 0));
    151 
    152         final int udpSumOffset = IPV4_HEADER_LENGTH + UDP_CHECKSUM_OFFSET;
    153         final int udpSum = getChecksum(packet, udpSumOffset);
    154         assertEquals(0xee36, udpSum);
    155 
    156         packet.put(udpSumOffset, (byte) 0);
    157         packet.put(udpSumOffset + 1, (byte) 0);
    158         assertChecksumEquals(udpSum, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
    159 
    160         // Check that writing the checksums back into the packet results in a valid packet.
    161         packet.putShort(ipSumOffset, IpUtils.ipChecksum(packet, 0));
    162         packet.putShort(udpSumOffset, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
    163         assertEquals(0, IpUtils.ipChecksum(packet, 0));
    164         assertEquals((short) 0xffff, IpUtils.udpChecksum(packet, 0, IPV4_HEADER_LENGTH));
    165     }
    166 }
    167