Skip to content

Commit

Permalink
Added ipv6 checksum tests and fixed ipv6 + transport layer checksums
Browse files Browse the repository at this point in the history
  • Loading branch information
compscidr committed Oct 15, 2024
1 parent 9b06c61 commit 35f9936
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.jasonernst.icmp_common.Checksum
import com.jasonernst.icmp_common.PacketHeaderException
import com.jasonernst.knet.network.ip.IpHeader
import com.jasonernst.knet.network.ip.v4.Ipv4Header
import com.jasonernst.knet.network.ip.v6.Ipv6Header
import com.jasonernst.knet.network.ip.v6.Ipv6Header.Companion.IP6_HEADER_SIZE
import com.jasonernst.knet.network.nextheader.NextHeader
import com.jasonernst.knet.transport.tcp.TcpHeader
Expand Down Expand Up @@ -48,9 +49,18 @@ interface TransportHeader : NextHeader {
pseudoHeader.put(0)
pseudoHeader.put(ipHeader.protocol.toByte())
pseudoHeader.putShort(ipHeader.getPayloadLength().toShort())
} else {
} else if (ipHeader is Ipv6Header) {
val extensionHeaderLength = ipHeader.extensionHeaders.sumOf { it.getExtensionLengthInBytes() }
val tcpLength = ipHeader.getPayloadLength().toInt() - extensionHeaderLength
// https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_checksum_for_IPv6
pseudoHeader = ByteBuffer.allocate(IP6_HEADER_SIZE.toInt())
pseudoHeader = ByteBuffer.allocate(IP6_HEADER_SIZE.toInt() + tcpLength)
pseudoHeader.put(ipHeader.sourceAddress.address)
pseudoHeader.put(ipHeader.destinationAddress.address)
pseudoHeader.putInt(tcpLength)
val nextHeader = (ipHeader.extensionHeaders.lastOrNull()?.nextHeader ?: ipHeader.protocol).toInt()
pseudoHeader.putInt(nextHeader)
} else {
throw IllegalArgumentException("Unknown IP header type")
}
val pseudoHeaderTransportStart = pseudoHeader.position()
pseudoHeader.put(toByteArray())
Expand Down
53 changes: 53 additions & 0 deletions knet/src/test/kotlin/com/jasonernst/knet/ChecksumTests.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.jasonernst.knet

import com.jasonernst.icmp_common.PacketHeaderException
import com.jasonernst.knet.datalink.EthernetHeader
import com.jasonernst.knet.network.ip.IpHeader
import com.jasonernst.knet.network.nextheader.NextHeader
import com.jasonernst.knet.transport.TransportHeader
Expand Down Expand Up @@ -117,4 +118,56 @@ class ChecksumTests {

udpHeader.computeChecksum(ipHeader, payload, true)
}

@Test fun ipv6TcpBadChecksum() {
val filename = "/test_packets/ipv6_tcp_badchecksum.dump"
val resource =
javaClass.getResource(filename)
?: throw FileNotFoundException("Could not find test dump: $filename")
val stream = TextFilePacketDumper.parseFile(resource.file, true)
logger.debug("Read buffer length: {}", stream.limit())

EthernetHeader.fromStream(stream)
val ipHeader = IpHeader.fromStream(stream)
logger.debug("IP Header: {}", ipHeader)
val nextHeader = NextHeader.fromStream(stream, ipHeader.protocol)
assertTrue(nextHeader is TransportHeader)
assertTrue(nextHeader is TcpHeader)
val tcpHeader = nextHeader as TcpHeader

// this may be a bad checksum because the length of the payload is truncated, so we'll
// do a min check to prevent buffer underflow
val remainingPayloadSize = min(stream.remaining(), ipHeader.getPayloadLength().toInt() - tcpHeader.getHeaderLength().toInt())
val payload = ByteArray(remainingPayloadSize)
stream.get(payload)

assertThrows<PacketHeaderException> {
tcpHeader.computeChecksum(ipHeader, payload, true)
}
}

@Test fun ipv6TcpGoodChecksum() {
val filename = "/test_packets/ipv6_tcp_goodchecksum.dump"
val resource =
javaClass.getResource(filename)
?: throw FileNotFoundException("Could not find test dump: $filename")
val stream = TextFilePacketDumper.parseFile(resource.file, true)
logger.debug("Read buffer length: {}", stream.limit())

EthernetHeader.fromStream(stream)
val ipHeader = IpHeader.fromStream(stream)
logger.debug("IP Header: {}", ipHeader)
val nextHeader = NextHeader.fromStream(stream, ipHeader.protocol)
assertTrue(nextHeader is TransportHeader)
assertTrue(nextHeader is TcpHeader)
val tcpHeader = nextHeader as TcpHeader

// this may be a bad checksum because the length of the payload is truncated, so we'll
// do a min check to prevent buffer underflow
val remainingPayloadSize = min(stream.remaining(), ipHeader.getPayloadLength().toInt() - tcpHeader.getHeaderLength().toInt())
val payload = ByteArray(remainingPayloadSize)
stream.get(payload)

tcpHeader.computeChecksum(ipHeader, payload, true)
}
}

0 comments on commit 35f9936

Please sign in to comment.