123 lines
3.9 KiB
Kotlin
123 lines
3.9 KiB
Kotlin
package tech.xvanturing.freeproxy.vpn.net
|
|
|
|
const val PROTO_ICMP = 1
|
|
const val PROTO_TCP = 6
|
|
const val PROTO_UDP = 17
|
|
|
|
/** IPv4 首部。选项字段不解析,但 [headerLength] 已把它算在内。 */
|
|
class Ipv4Header(
|
|
val headerLength: Int,
|
|
val totalLength: Int,
|
|
val protocol: Int,
|
|
val sourceIp: Int,
|
|
val destIp: Int,
|
|
) {
|
|
val payloadLength: Int get() = totalLength - headerLength
|
|
|
|
companion object {
|
|
const val MIN_SIZE = 20
|
|
|
|
/** 解析失败返回 null(畸形包直接丢弃,不抛异常 —— 转发热路径上异常代价太高)。 */
|
|
fun parse(buffer: ByteArray, length: Int): Ipv4Header? {
|
|
if (length < MIN_SIZE) return null
|
|
val versionAndIhl = buffer.u8(0)
|
|
if ((versionAndIhl ushr 4) != 4) return null
|
|
|
|
val headerLength = (versionAndIhl and 0x0F) * 4
|
|
if (headerLength < MIN_SIZE || headerLength > length) return null
|
|
|
|
val totalLength = buffer.u16(2)
|
|
if (totalLength < headerLength || totalLength > length) return null
|
|
|
|
// 本栈不做分片重组:MF 置位或分片偏移非零的包一律丢弃。
|
|
// TUN 的 MTU 由我们自己设定,正常流量不会走到这里。
|
|
val fragmentField = buffer.u16(6)
|
|
val moreFragments = (fragmentField and 0x2000) != 0
|
|
val fragmentOffset = fragmentField and 0x1FFF
|
|
if (moreFragments || fragmentOffset != 0) return null
|
|
|
|
return Ipv4Header(
|
|
headerLength = headerLength,
|
|
totalLength = totalLength,
|
|
protocol = buffer.u8(9),
|
|
sourceIp = buffer.ipv4(12),
|
|
destIp = buffer.ipv4(16),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/** TCP 首部。 */
|
|
class TcpHeader(
|
|
val sourcePort: Int,
|
|
val destPort: Int,
|
|
val sequence: Long,
|
|
val acknowledgment: Long,
|
|
val dataOffset: Int,
|
|
val flags: Int,
|
|
val window: Int,
|
|
) {
|
|
val isFin: Boolean get() = (flags and FIN) != 0
|
|
val isSyn: Boolean get() = (flags and SYN) != 0
|
|
val isRst: Boolean get() = (flags and RST) != 0
|
|
val isAck: Boolean get() = (flags and ACK) != 0
|
|
|
|
override fun toString(): String = buildString {
|
|
if (isSyn) append("SYN ")
|
|
if (isAck) append("ACK ")
|
|
if (isFin) append("FIN ")
|
|
if (isRst) append("RST ")
|
|
append("seq=").append(sequence).append(" ack=").append(acknowledgment)
|
|
}
|
|
|
|
companion object {
|
|
const val MIN_SIZE = 20
|
|
|
|
const val FIN = 0x01
|
|
const val SYN = 0x02
|
|
const val RST = 0x04
|
|
const val PSH = 0x08
|
|
const val ACK = 0x10
|
|
const val URG = 0x20
|
|
|
|
fun parse(buffer: ByteArray, offset: Int, length: Int): TcpHeader? {
|
|
if (length < MIN_SIZE) return null
|
|
val dataOffset = ((buffer.u8(offset + 12) ushr 4) and 0x0F) * 4
|
|
if (dataOffset < MIN_SIZE || dataOffset > length) return null
|
|
return TcpHeader(
|
|
sourcePort = buffer.u16(offset),
|
|
destPort = buffer.u16(offset + 2),
|
|
sequence = buffer.u32(offset + 4),
|
|
acknowledgment = buffer.u32(offset + 8),
|
|
dataOffset = dataOffset,
|
|
flags = buffer.u8(offset + 13),
|
|
window = buffer.u16(offset + 14),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/** UDP 首部。 */
|
|
class UdpHeader(
|
|
val sourcePort: Int,
|
|
val destPort: Int,
|
|
val length: Int,
|
|
) {
|
|
val payloadLength: Int get() = length - SIZE
|
|
|
|
companion object {
|
|
const val SIZE = 8
|
|
|
|
fun parse(buffer: ByteArray, offset: Int, available: Int): UdpHeader? {
|
|
if (available < SIZE) return null
|
|
val length = buffer.u16(offset + 4)
|
|
if (length < SIZE || length > available) return null
|
|
return UdpHeader(
|
|
sourcePort = buffer.u16(offset),
|
|
destPort = buffer.u16(offset + 2),
|
|
length = length,
|
|
)
|
|
}
|
|
}
|
|
}
|