Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ipv6 extension headers #9

Merged
merged 23 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Kotlin user-space network stack. This can be used for:
- [ ] RFC 2474: https://datatracker.ietf.org/doc/html/rfc2474
- [x] IPv6:
- [X] WiP: RFC 8200: https://datatracker.ietf.org/doc/html/rfc8200
- [X] RFC 6564: https://www.rfc-editor.org/rfc/rfc6564
- [ ] RFC 7045: https://www.rfc-editor.org/rfc/rfc7045.html
- [ ] RFC: 4302: https://datatracker.ietf.org/doc/html/rfc4302
- [ ] RFC: 4303: https://datatracker.ietf.org/doc/html/rfc4303
- [x] ICMP (via https://github.com/compscidr/icmp)
- [] TCP
- [] UDP
- [ ] TCP
- [ ] UDP
12 changes: 11 additions & 1 deletion knet/src/main/kotlin/com/jasonernst/knet/ip/IpHeader.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.jasonernst.knet.ip

import com.jasonernst.knet.PacketTooShortException
import com.jasonernst.knet.ip.Ipv4Header.Companion.IP4_MIN_HEADER_LENGTH
import com.jasonernst.knet.ip.v4.Ipv4Header
import com.jasonernst.knet.ip.v4.Ipv4Header.Companion.IP4_MIN_HEADER_LENGTH
import com.jasonernst.knet.ip.v6.Ipv6Header
import org.slf4j.LoggerFactory
import java.net.Inet4Address
import java.net.Inet6Address
Expand All @@ -18,6 +20,14 @@ interface IpHeader {
const val IP4_VERSION: UByte = 4u
const val IP6_VERSION: UByte = 6u

/**
* Helper function so that we can ensure the payload length is a multiple of 8
*/
fun closestDivisibleBy(
initialValue: UInt,
divisor: UInt,
): UInt = (initialValue + divisor - 1u) / divisor * divisor

fun fromStream(stream: ByteBuffer): IpHeader {
val start = stream.position()
if (stream.remaining() < 1) {
Expand Down
75 changes: 0 additions & 75 deletions knet/src/main/kotlin/com/jasonernst/knet/ip/Ipv6ExtensionHeader.kt

This file was deleted.

121 changes: 0 additions & 121 deletions knet/src/main/kotlin/com/jasonernst/knet/ip/Ipv6Header.kt

This file was deleted.

31 changes: 0 additions & 31 deletions knet/src/main/kotlin/com/jasonernst/knet/ip/Ipv6HopByHopOption.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package com.jasonernst.knet.ip
package com.jasonernst.knet.ip.v4

import com.jasonernst.icmp_common.Checksum
import com.jasonernst.knet.PacketTooShortException
import com.jasonernst.knet.ip.IpHeader
import com.jasonernst.knet.ip.IpHeader.Companion.IP4_VERSION
import com.jasonernst.knet.ip.options.Ipv4Option
import com.jasonernst.knet.ip.options.Ipv4Option.Companion.parseOptions
import com.jasonernst.knet.ip.IpHeader.Companion.closestDivisibleBy
import com.jasonernst.knet.ip.IpType
import com.jasonernst.knet.ip.v4.options.Ipv4Option
import com.jasonernst.knet.ip.v4.options.Ipv4Option.Companion.parseOptions
import org.slf4j.LoggerFactory
import java.net.Inet4Address
import java.net.InetAddress
import java.nio.ByteBuffer
import java.nio.ByteOrder
import kotlin.experimental.or
import kotlin.math.ceil
import kotlin.math.min

/**
* Internet Protocol Version 4 Header Implementation.
Expand All @@ -26,8 +30,8 @@ data class Ipv4Header(
val dscp: UByte = 0u,
// 2-bits, explicit congestion notification.
val ecn: UByte = 0u,
// 16-bits, IP packet, including the header
private val totalLength: UShort = 0u,
// 16-bits, IP packet, including the header: default to a just the header with no payload
private val totalLength: UShort = IP4_MIN_HEADER_LENGTH.toUShort(),
// 16-bits, groups fragments of a single IPv4 datagram.
val id: UShort = 0u,
// if the packet is marked as don't fragment and we can't fit it in a single packet, drop it.
Expand Down Expand Up @@ -310,9 +314,12 @@ data class Ipv4Header(
*
*/
fun fragment(
maxSize: UInt,
maxSize: UInt, // max size includes the header size
payload: ByteArray,
): List<Pair<Ipv4Header, ByteArray>> {
if (maxSize.toInt() % 8 != 0) {
throw IllegalArgumentException("Fragment max size must be divisible by 8")
}
if (dontFragment) {
throw IllegalArgumentException("Cannot fragment packets marked as don't fragment")
}
Expand All @@ -325,11 +332,17 @@ data class Ipv4Header(
"The smallest fragment size is ${IP4_MIN_FRAGMENT_PAYLOAD.toInt()} bytes because it must align on a 64-bit boundary",
)
}
var payloadPerPacket = maxSize - getHeaderLength()
var lastFragment = false
var payloadPosition = 0u
var payloadPerPacket = min(payload.size - payloadPosition.toInt(), closestDivisibleBy(maxSize - getHeaderLength(), 8u).toInt())
logger.debug("PAYLOAD PER PACKET: $payloadPerPacket HEADERSIZE: ${getHeaderLength()}")
if (payloadPosition.toInt() + payloadPerPacket == payload.size) {
lastFragment = true
}

var isFirstFragment = true
while (payloadPosition < payload.size.toUInt()) {
logger.debug("$payloadPosition:${payloadPosition + payloadPerPacket}")
logger.debug("$payloadPosition:${payloadPosition + payloadPerPacket.toUInt()}")
val offsetIn64BitOctets = payloadPosition / 8u
var newOptions = options
var newIhl = ihl
Expand All @@ -353,10 +366,10 @@ data class Ipv4Header(
ihl = newIhl,
dscp = dscp,
ecn = ecn,
totalLength = (getHeaderLength() + payloadPerPacket).toUShort(),
totalLength = (getHeaderLength() + payloadPerPacket.toUInt()).toUShort(),
id = id,
dontFragment = false,
lastFragment = payloadPosition >= getHeaderLength(),
lastFragment = lastFragment,
fragmentOffset = offsetIn64BitOctets.toUShort(),
ttl = ttl,
protocol = protocol,
Expand All @@ -367,9 +380,10 @@ data class Ipv4Header(
logger.debug("payload len:${newHeader.getPayloadLength()}")
val newPayload = payload.copyOfRange(payloadPosition.toInt(), payloadPosition.toInt() + payloadPerPacket.toInt())
packetList.add(Pair(newHeader, newPayload))
payloadPosition += payloadPerPacket
if (payloadPosition + payloadPerPacket > payload.size.toUInt()) {
payloadPerPacket = payload.size.toUInt() - payloadPosition
payloadPosition += payloadPerPacket.toUInt()
if (payloadPosition + payloadPerPacket.toUInt() > payload.size.toUInt()) {
payloadPerPacket = (payload.size.toUInt() - payloadPosition).toInt()
lastFragment = true
}
}
return packetList
Expand Down
Loading