/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.network.protocols; import static jpcsp.network.protocols.InternetChecksum.computeInternetChecksum; import static jpcsp.network.protocols.NetPacket.getIpAddressString; import java.io.EOFException; import jpcsp.util.Utilities; public class IPv4 { // IPv4 packet format, see https://en.wikipedia.org/wiki/IPv4 public static final int IPv4_PROTOCOL_ICMP = 1; public static final int IPv4_PROTOCOL_TCP = 6; public static final int IPv4_PROTOCOL_UDP = 17; public int version; public int internetHeaderLength; public int differentiatedServicesCodePoint; public int explicitCongestionNotification; public int totalLength; public int identification; public int flags; public int fragmentOffset; public int timeToLive; public int protocol; public int headerChecksum; public byte[] sourceIPAddress; public byte[] destinationIPAddress; public byte[] options; public IPv4() { version = 4; internetHeaderLength = 5; timeToLive = 0x40; } public IPv4(IPv4 ipv4) { version = ipv4.version; internetHeaderLength = ipv4.internetHeaderLength; differentiatedServicesCodePoint = ipv4.differentiatedServicesCodePoint; explicitCongestionNotification = ipv4.explicitCongestionNotification; totalLength = ipv4.totalLength; identification = ipv4.identification; flags = ipv4.flags; fragmentOffset = ipv4.fragmentOffset; timeToLive = ipv4.timeToLive; protocol = ipv4.protocol; headerChecksum = ipv4.headerChecksum; sourceIPAddress = ipv4.sourceIPAddress; destinationIPAddress = ipv4.destinationIPAddress; options = ipv4.options; } private int getOptionsLength() { return Math.max((internetHeaderLength - 5) * 4, 0); } public void swapSourceAndDestination() { byte[] ip = sourceIPAddress; sourceIPAddress = destinationIPAddress; destinationIPAddress = ip; } public void computeChecksum() throws EOFException { // Computes the checksum with 0 at the headerChecksum field headerChecksum = 0; NetPacket checksumPacket = write(); headerChecksum = computeInternetChecksum(checksumPacket.getBuffer(), 0, checksumPacket.getOffset()); } public void read(NetPacket packet) throws EOFException { version = packet.readBits(4); internetHeaderLength = packet.readBits(4); differentiatedServicesCodePoint = packet.readBits(6); explicitCongestionNotification = packet.readBits(2); totalLength = packet.read16(); identification = packet.read16(); flags = packet.readBits(3); fragmentOffset = packet.readBits(13); timeToLive = packet.read8(); protocol = packet.read8(); headerChecksum = packet.read16(); sourceIPAddress = packet.readIpAddress(); destinationIPAddress = packet.readIpAddress(); options = packet.readBytes(getOptionsLength()); } public NetPacket write(NetPacket packet) throws EOFException { packet.writeBits(version, 4); packet.writeBits(internetHeaderLength, 4); packet.writeBits(differentiatedServicesCodePoint, 6); packet.writeBits(explicitCongestionNotification, 2); packet.write16(totalLength); packet.write16(identification); packet.writeBits(flags, 3); packet.writeBits(fragmentOffset, 13); packet.write8(timeToLive); packet.write8(protocol); packet.write16(headerChecksum); packet.writeIpAddress(sourceIPAddress); packet.writeIpAddress(destinationIPAddress); packet.writeBytes(options, 0, getOptionsLength()); return packet; } public NetPacket write() throws EOFException { return write(new NetPacket(sizeOf())); } public int sizeOf() { return internetHeaderLength * 4; } @Override public String toString() { return String.format("version=0x%X, internetHeaderLength=0x%X, differentiatedServicesCodePoint=0x%X, explicitCongestionNotification=0x%X, totalLength=0x%X, identification=0x%X, flags=0x%X, fragmentOffset=0x%X, timeToLive=0x%X, protocol=0x%X, headerChecksum=0x%04X, sourceIP=%s, destinationIP=%s, options=%s", version, internetHeaderLength, differentiatedServicesCodePoint, explicitCongestionNotification, totalLength, identification, flags, fragmentOffset, timeToLive, protocol, headerChecksum, getIpAddressString(sourceIPAddress), getIpAddressString(destinationIPAddress), Utilities.getMemoryDump(options, 0, getOptionsLength())); } }