From 7664bd20920f4089f1a9bcad4c9139c07bcf9eb8 Mon Sep 17 00:00:00 2001 From: Minecon724 Date: Thu, 23 Oct 2025 15:14:38 +0200 Subject: [PATCH] Commit --- src/main/kotlin/Main.kt | 3 +- src/main/kotlin/mrt/RoutingInformationBase.kt | 88 ++++++++++++++++--- 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 22bbe54..2cf533c 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -4,6 +4,7 @@ import mrt.MrtExport import mrt.PeerIndexTable import mrt.RoutingInformationBase import kotlin.io.path.Path +import kotlin.system.exitProcess fun main() { runBlocking { @@ -31,7 +32,7 @@ fun main() { println(" For ${export.message.prefix} (#${export.message.sequenceNumber}) (${export.message.entries.size} entries):") export.message.entries.forEach { entry -> - println(" #${entry.peerIndex} | Since ${entry.originatedTime} | ${entry.attributes}") + println(" #${entry.peerIndex} | Since ${entry.originatedTime} | ${entry.attributes.size}") } } diff --git a/src/main/kotlin/mrt/RoutingInformationBase.kt b/src/main/kotlin/mrt/RoutingInformationBase.kt index 7a021ef..5e8f05b 100644 --- a/src/main/kotlin/mrt/RoutingInformationBase.kt +++ b/src/main/kotlin/mrt/RoutingInformationBase.kt @@ -2,8 +2,6 @@ package mrt import InetPrefix import io.ktor.utils.io.ByteReadChannel -import io.ktor.utils.io.discard -import io.ktor.utils.io.discardExact import io.ktor.utils.io.readByte import io.ktor.utils.io.readByteArray import io.ktor.utils.io.readInt @@ -11,6 +9,7 @@ import io.ktor.utils.io.readShort import java.net.Inet6Address import java.time.Instant import kotlin.experimental.and +import kotlin.math.sign data class RoutingInformationBase( val sequenceNumber: Int, @@ -22,9 +21,9 @@ data class RoutingInformationBase( val sequenceNumber = channel.readInt() val prefixLength = channel.readByte() - // TODO do this immedialtyl check out prefix length if it pads - //channel.discardExact(3) - val address = Inet6Address.getByAddress(channel.readByteArray(if (ipv6) 16 else 4)) + // TODO trim bits if prefix length is not multiple of 8 + val addressBytes = channel.readByteArray(Math.ceilDiv(prefixLength.toInt(), 8)).copyOf(if (ipv6) 16 else 4) + val address = Inet6Address.getByAddress(addressBytes) val entryCount = channel.readShort() val entries = List(entryCount.toInt()) { _ -> Entry.read(channel) } @@ -40,26 +39,93 @@ data class RoutingInformationBase( data class Entry( val peerIndex: UShort, val originatedTime: Instant, - val attributes: ByteArray + val attributes: List ) { companion object { suspend fun read(channel: ByteReadChannel): Entry { val peerIndex = channel.readShort().toUShort() - channel.discardExact(2) + //channel.discardExact(2) val originatedTime = Instant.ofEpochSecond(channel.readInt().toLong()) - val attributesLength = channel.readShort() - channel.discardExact(2) + var attributesLength = channel.readShort().toInt() + //channel.discardExact(2) + + val attributes = mutableListOf() + + while (attributesLength > 0) { + val (attribute, bytesRead) = BgpAttribute.read(channel) + attributes.add(attribute) + attributesLength -= bytesRead + //println("Attribute length: $attributesLength (-$bytesRead)") + } - val attributes = channel.readByteArray(attributesLength.toInt()) return Entry( peerIndex = peerIndex, originatedTime = originatedTime, - attributes = attributes + attributes = attributes.toList() ) } } } + + data class BgpAttribute( + val optional: Boolean, + val transitive: Boolean, + val partial: Boolean, + val type: Type, + val value: ByteArray + ) { + companion object { + suspend fun read(channel: ByteReadChannel): Pair { + val flags = channel.readByte() + val optional = flags.rotateRight(7).and(0x1) == 1.toByte() + val transitive = flags.rotateRight(6).and(0x1) == 1.toByte() + val partial = flags.rotateRight(5).and(0x1) == 1.toByte() + val extendedLength = flags.rotateRight(4).and(0x1) == 1.toByte() + + //println("Flags: 0x${flags.toHexString()}") + + val typeCode = channel.readByte() + //println("Type: 0x${typeCode.toHexString()}") + val type = Type.fromCode(typeCode) + + //println("Ext length: $extendedLength") + val length = if (extendedLength) channel.readShort().toUShort().toInt() else channel.readByte().toUByte().toInt() + //println("Length: $length") + + val value = channel.readByteArray(length) + + return Pair(BgpAttribute( + optional = optional, + transitive = transitive, + partial = partial, + type = type, + value = value + ), 3 + (if (extendedLength) 1 else 0) + length) + } + } + + enum class Type(val code: Byte) { + Origin(1), + AsPath(2), + NextHop(3), + MultiExitDisc(4), + LocalPref(5), + AtomicAggregate(6), + Aggregator(7), + Community(8), + MpReachNlri(14), + ExtendedCommunity(16), + LargeCommunity(32), + OnlyToCustomer(35); + + companion object { + fun fromCode(code: Byte): Type { + return Type.entries.first { it.code == code } + } + } + } + } } \ No newline at end of file