1 /* 2 * Copyright (C) 2016 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 com.android.cts.vpnfirewall; 18 19 import java.io.ByteArrayOutputStream; 20 import java.io.DataInputStream; 21 import java.io.DataOutputStream; 22 import java.io.IOException; 23 import java.net.Inet4Address; 24 import java.util.Arrays; 25 26 public class Ipv4Packet { 27 private static final int HEADER_MIN_LENGTH = 20; 28 29 int version; 30 int headerLength; 31 int type; 32 int totalLength; 33 int identification; 34 int flagsAndOffset; 35 int timeToLive; 36 int protocol; 37 Inet4Address sourceAddress; 38 Inet4Address destinationAddress; 39 byte[] options; 40 byte[] data; 41 Ipv4Packet(DataInputStream stream)42 public Ipv4Packet(DataInputStream stream) throws IOException { 43 int versionIhl = stream.readUnsignedByte(); 44 version = (versionIhl & 0xF0) >> 4; 45 headerLength = (versionIhl & 0x0F) * 4; 46 47 type = stream.readUnsignedByte(); 48 totalLength = stream.readUnsignedShort(); 49 identification = stream.readUnsignedShort(); 50 flagsAndOffset = stream.readUnsignedShort(); 51 timeToLive = stream.readUnsignedByte(); 52 protocol = stream.readUnsignedByte(); 53 int checksum = stream.readUnsignedShort(); 54 55 byte[] address = new byte[4]; 56 57 stream.read(address, 0, address.length); 58 sourceAddress = (Inet4Address) Inet4Address.getByAddress(address); 59 60 stream.read(address, 0, address.length); 61 destinationAddress = (Inet4Address) Inet4Address.getByAddress(address); 62 63 if (headerLength < HEADER_MIN_LENGTH) { 64 throw new IllegalArgumentException("Header length = " + headerLength 65 + " is less than HEADER_MIN_LENGTH = " + HEADER_MIN_LENGTH); 66 } 67 options = new byte[headerLength - HEADER_MIN_LENGTH]; 68 stream.read(options, 0, options.length); 69 70 if (totalLength < headerLength) { 71 throw new IllegalArgumentException("Total length = " + totalLength 72 + " is less than header length = " + headerLength); 73 } 74 data = new byte[totalLength - headerLength]; 75 stream.read(data, 0, data.length); 76 77 byte[] original = new byte[totalLength]; 78 stream.reset(); 79 stream.readFully(original); 80 if (!Arrays.equals(original, getEncoded())) { 81 throw new IOException("Corrupted message. Checksum: " + checksum); 82 } 83 } 84 setOptions(byte[] newOptions)85 public void setOptions(byte[] newOptions) { 86 options = newOptions; 87 headerLength = HEADER_MIN_LENGTH + options.length; 88 } 89 setData(byte[] newData)90 public void setData(byte[] newData) { 91 data = newData; 92 totalLength = headerLength + data.length; 93 } 94 getEncoded()95 public byte[] getEncoded() throws IOException { 96 ByteArrayOutputStream output = new ByteArrayOutputStream(); 97 DataOutputStream stream = new DataOutputStream(output); 98 99 stream.writeByte((version << 4) | (headerLength / 4)); 100 stream.writeByte(type); 101 stream.writeShort(totalLength); 102 stream.writeShort(identification); 103 stream.writeShort(flagsAndOffset); 104 stream.writeByte(timeToLive); 105 stream.writeByte(protocol); 106 107 int checksumPosition = stream.size(); 108 stream.writeShort(/* checksum */ 0); 109 stream.write(sourceAddress.getAddress(), 0, 4); 110 stream.write(destinationAddress.getAddress(), 0, 4); 111 stream.write(options, 0, options.length); 112 stream.write(data, 0, data.length); 113 stream.close(); 114 115 byte[] result = output.toByteArray(); 116 int checksum = Rfc1071.checksum(result, headerLength); 117 result[checksumPosition + 0] = (byte) ((checksum & 0xFF00) >> 8); 118 result[checksumPosition + 1] = (byte) ((checksum & 0x00FF)); 119 return result; 120 } 121 122 @Override toString()123 public String toString() { 124 StringBuilder out = new StringBuilder(256); 125 126 out.append("IPv4 Packet {"); 127 out.append("\n Version: ").append(version); 128 out.append("\n Header length: ").append(headerLength); 129 out.append("\n Type: ").append(type); 130 out.append("\n Total length: ").append(totalLength); 131 out.append("\n Identification: ").append(identification); 132 out.append("\n Flags + offset: ").append(flagsAndOffset); 133 out.append("\n Time to live: ").append(timeToLive); 134 out.append("\n Protocol: ").append(protocol); 135 out.append("\n Source: ").append(sourceAddress.getHostAddress()); 136 out.append("\n Destination: ").append(destinationAddress.getHostAddress()); 137 out.append("\n Options: ["); 138 for (int i = 0 ; i < options.length; i++) { 139 if (i % 16 == 0) { 140 out.append(String.format("\n%4s", "")); 141 } 142 out.append(String.format(" %02X", options[i] & 0xFF)); 143 } 144 out.append("\n ]"); 145 out.append("\n Data: ["); 146 for (int i = 0 ; i < data.length; i++) { 147 if (i % 16 == 0) { 148 out.append(String.format("\n%4s", "")); 149 } 150 out.append(String.format(" %02X", data[i] & 0xFF)); 151 } 152 out.append("\n ]"); 153 out.append("\n}"); 154 return out.toString(); 155 } 156 } 157