Merge changes Ic4b22e2c,Iaf4250da,I429b316a,I03cdb93f into main

* changes:
  Use Kotlin syntax for getters
  Return this from add*Option methods
  Add some documentation to RaPkt
  s/payload/data/ for brevity
This commit is contained in:
Maciej Żenczykowski 2025-04-02 19:35:47 -07:00 • committed by Android (Google) Code Review
commit 96e3faa6bc

View file

@ -105,13 +105,14 @@ class NaPkt(
}
/** Add Target Link-Layer Address Option */
fun addTllaOption(lla: MacAddress) {
fun addTllaOption(lla: MacAddress): NaPkt {
val llao = ByteBuffer.allocate(8)
llao.put(2) // Type = 2 (Target Link-layer Address)
llao.put(1) // Length in units of 8 octets
llao.put(lla.toByteArray())
llao.flip()
outputStream.write(llao.array())
return this
}
/**
@ -119,8 +120,8 @@ class NaPkt(
*
* @param lla Link-Layer Address as a String; e.g. {@code "0:0:5e:0:53:0"}
*/
fun addTllaOption(lla: String) {
addTllaOption(MacAddress.fromString(lla))
fun addTllaOption(lla: String): NaPkt {
return addTllaOption(MacAddress.fromString(lla))
}
override fun toByteArray() = outputStream.toByteArray()
@ -130,6 +131,11 @@ class NaPkt(
* Class that facilitates the creation of RA packets.
*
* Default argument values reflect the rfc4861 defaults where applicable.
*
* @param routerLft lifetime of the default router in seconds.
* @param reachableTime The time, in milliseconds, that a node assumes a neighbor is reachable.
* @param retransTimer The time, in milliseconds, between retransmitted NS messages.
* @param flags The Router Advertisement flags.
*/
class RaPkt(
private val routerLft: Short,
@ -137,6 +143,14 @@ class RaPkt(
private val retransTimer: Int,
private val flags: EnumSet<RaFlags>,
) : L4Packet {
/**
* Convenience constructor accepting flags parameter as String
*
* @param routerLft lifetime of the default router in seconds.
* @param reachableTime The time, in milliseconds, that a node assumes a neighbor is reachable.
* @param retransTimer The time, in milliseconds, between retransmitted NS messages.
* @param flags The Router Advertisement flags as a String; e.g. {@code "MO"}. Defaults to "".
*/
constructor(
routerLft: Short = 1800,
reachableTime: Int = 0,
@ -145,7 +159,9 @@ class RaPkt(
) : this(routerLft, reachableTime, retransTimer, enumSetOfFlags<RaFlags>(flags))
enum class RaFlags(override val value: Int) : Flags {
/** Managed address configuration: indicates addresses are available via DHCPv6. */
M(0x80),
/** Other configuration: indicates other configuration info is available via DHCPv6. */
O(0x40),
}
@ -169,42 +185,73 @@ class RaPkt(
}
enum class PioFlags(override val value: Int) : Flags {
/** On-Link: indicates that this prefix can be used for on-link determination. */
L(0x80),
/** Autonomous address-configuration: indicates that this prefix can be used for SLAAC. */
A(0x40),
/** Router Address: obsolete. */
R(0x20),
/** PD Preferred: indicates that the network prefers the use of DHCPv6-PD over SLAAC. */
P(0x10),
}
/**
* Add a Prefix Information Option
*
* @param prefix The prefix of an IPv6 address.
* @param validLft The time, in seconds, that the prefix is valid for on-link determination.
* @param preferredLft The time, in seconds, that SLAAC-generated addresses remain preferred.
* @param flags The Prefix Information Option flags.
*/
fun addPioOption(
prefix: IpPrefix,
validLft: Int,
preferredLft: Int,
flags: EnumSet<PioFlags>,
) {
): RaPkt {
if (!prefix.isIPv6()) throw IllegalArgumentException("Invalid prefix")
val pio = ByteBuffer.allocate(32)
pio.put(3) // Type = 3
pio.put(4) // Length = 4 (*8)
pio.put(prefix.getPrefixLength().toByte()) // Prefix Length
pio.put(prefix.prefixLength.toByte()) // Prefix Length
pio.put(flags.toByte()) // Flags
pio.putInt(validLft) // Valid Lifetime
pio.putInt(preferredLft) // Preferred Lifetime
pio.putInt(0) // Reserved2
pio.put(prefix.getRawAddress())
pio.put(prefix.rawAddress)
pio.flip()
outputStream.write(pio.array())
return this
}
/**
* Add a Prefix Information Option
*
* @param prefix The IPv6 prefix as a String; e.g. {@code "2001:db8::/64"}
* @param validLft The time, in seconds, that the prefix is valid for on-link determination.
* @param preferredLft The time, in seconds, that SLAAC-generated addresses remain preferred.
* @param flags The PIO flags as a String; e.g. {@code "LA"}
*/
fun addPioOption(
prefix: String,
validLft: Int = 2592000,
preferredLft: Int = 604800,
flags: String = "L",
) {
addPioOption(IpPrefix(prefix), validLft, preferredLft, enumSetOfFlags<PioFlags>(flags))
): RaPkt {
return addPioOption(
IpPrefix(prefix),
validLft,
preferredLft,
enumSetOfFlags<PioFlags>(flags)
)
}
fun addRdnssOption(dns: List<Inet6Address>, lft: Int) {
/** Add a Recursive DNS Server Option
*
* @param dns The list of DNS servers.
* @param lft The time, in seconds, over which the DNS servers may be used for resolution.
*/
fun addRdnssOption(dns: List<Inet6Address>, lft: Int): RaPkt {
val length = 1 + (dns.size * 2)
val rdnss = ByteBuffer.allocate(length * 8) // length is in units of 8 octets.
rdnss.put(25) // Type = 25
@ -216,14 +263,25 @@ class RaPkt(
}
rdnss.flip()
outputStream.write(rdnss.array())
return this
}
fun addRdnssOption(dns: String, lft: Int = 1800) {
/** Add a Recursive DNS Server Option
*
* @param dns The list of DNS servers as a String; e.g. {@code "2001:db8:1,2001:db8:2"}
* @param lft The time, in seconds, over which the DNS servers may be used for resolution.
*/
fun addRdnssOption(dns: String, lft: Int = 1800): RaPkt {
val dnsServers = dns.split(",").map { InetAddress.getByName(it) as Inet6Address }
addRdnssOption(dnsServers, lft)
return addRdnssOption(dnsServers, lft)
}
fun addRioOption(prefix: IpPrefix, lft: Int) {
/** Add a Route Information Option
*
* @param prefix The IPv6 prefix of the route.
* @param lft The lifetime of the route in seconds.
*/
fun addRioOption(prefix: IpPrefix, lft: Int): RaPkt {
val rio = ByteBuffer.allocate(24)
rio.put(24) // Type = 24
rio.put(3) // Length = 3 -- TODO: support variable prefix length
@ -234,13 +292,24 @@ class RaPkt(
rio.put(prefix.rawAddress)
rio.flip()
outputStream.write(rio.array())
return this
}
fun addRioOption(prefix: String, lft: Int = 1800) {
addRioOption(IpPrefix(prefix), lft)
/** Add a Route Information Option
*
* @param prefix The IPv6 prefix of the route as a String; e.g. {@code "2001:db8::/48"}
* @param lft The lifetime of the route in seconds.
*/
fun addRioOption(prefix: String, lft: Int = 1800): RaPkt {
return addRioOption(IpPrefix(prefix), lft)
}
fun addPref64Option(prefix: IpPrefix, lft: Int) {
/** Add a PREF64 Option
*
* @param prefix The PREF64 prefix.
* @param lft The lifetime of the PREF64 prefix in seconds.
*/
fun addPref64Option(prefix: IpPrefix, lft: Int): RaPkt {
val pref64 = ByteBuffer.allocate(16)
pref64.put(38) // Type = 38
pref64.put(2) // Length = 2 (*8)
@ -258,10 +327,16 @@ class RaPkt(
pref64.put(prefix.rawAddress, 0 /*offset*/, 12 /*length*/) // highest 96 bits of prefix.
pref64.flip()
outputStream.write(pref64.array())
return this
}
fun addPref64Option(prefix: String, lft: Int = 1800) {
addPref64Option(IpPrefix(prefix), lft)
/** Add a PREF64 Option
*
* @param prefix The PREF64 prefix as a String; e.g. {@code "2001:db8::/64"}
* @param lft The lifetime of the PREF64 prefix in seconds.
*/
fun addPref64Option(prefix: String, lft: Int = 1800): RaPkt {
return addPref64Option(IpPrefix(prefix), lft)
}
override fun toByteArray() = outputStream.toByteArray()
@ -271,12 +346,12 @@ class RaPkt(
class Ip6Pkt(
private val src: Inet6Address,
private val dst: Inet6Address,
private val payload: L4Packet,
private val data: L4Packet,
) : L3Packet {
constructor(src: String, dst: String, payload: L4Packet) : this(
constructor(src: String, dst: String, data: L4Packet) : this(
InetAddress.getByName(src) as Inet6Address,
InetAddress.getByName(dst) as Inet6Address,
payload,
data,
)
override val etherType = 0x86dd.toShort()
@ -290,16 +365,16 @@ class Ip6Pkt(
init {
val ipv6Header = ByteBuffer.allocate(40)
ipv6Header.putInt((6 shl 28) or (tc shl 20) or flowlabel)
ipv6Header.putShort(payload.size)
ipv6Header.put(payload.proto)
ipv6Header.putShort(data.size)
ipv6Header.put(data.proto)
ipv6Header.put(hlim)
ipv6Header.put(src.getAddress())
ipv6Header.put(dst.getAddress())
ipv6Header.put(src.address)
ipv6Header.put(dst.address)
ipv6Header.flip()
val outputStream = ByteArrayOutputStream()
outputStream.write(ipv6Header.array())
outputStream.write(payload.toByteArray())
outputStream.write(data.toByteArray())
bytes = outputStream.toByteArray()
}
@ -315,18 +390,18 @@ class Ip6Pkt(
* {@code
* val ra = RaPkt(routerLft = 50, reachableTime = 100, flags = "O")
* ra.addPioOption(prefix = "2001:db8::1/64", flags = "LA")
* val ipv6 = Ip6Pkt(src = "fe80::1", dst = "fe80::2", payload = ra)
* val ether = EtherPkt(src = "1:2:3:4:5:6", dst = "1:1:1:1:1:1", payload = ipv6)
* val ipv6 = Ip6Pkt(src = "fe80::1", dst = "fe80::2", data = ra)
* val ether = EtherPkt(src = "1:2:3:4:5:6", dst = "1:1:1:1:1:1", data = ipv6)
* }
* </pre>
**/
class EtherPkt(
dst: MacAddress,
src: MacAddress,
payload: L3Packet,
data: L3Packet,
) : Packet {
constructor(dst: String, src: String, payload: L3Packet) :
this(MacAddress.fromString(dst), MacAddress.fromString(src), payload)
constructor(dst: String, src: String, data: L3Packet) :
this(MacAddress.fromString(dst), MacAddress.fromString(src), data)
val bytes: ByteArray
@ -334,12 +409,12 @@ class EtherPkt(
val ethernetHeader = ByteBuffer.allocate(14)
ethernetHeader.put(dst.toByteArray())
ethernetHeader.put(src.toByteArray())
ethernetHeader.putShort(payload.etherType)
ethernetHeader.putShort(data.etherType)
ethernetHeader.flip()
val outputStream = ByteArrayOutputStream()
outputStream.write(ethernetHeader.array())
outputStream.write(payload.toByteArray())
outputStream.write(data.toByteArray())
bytes = outputStream.toByteArray()
}