This commit is contained in:
Minecon724 2025-10-23 15:14:38 +02:00
commit 7664bd2092
Signed by untrusted user who does not match committer: m724
GPG key ID: A02E6E67AB961189
2 changed files with 79 additions and 12 deletions

View file

@ -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}")
}
}

View file

@ -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<BgpAttribute>
) {
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<BgpAttribute>()
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<BgpAttribute, Int> {
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 }
}
}
}
}
}