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:
commit
96e3faa6bc
1 changed files with 107 additions and 32 deletions
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue