1403 lines
45 KiB
Java
1403 lines
45 KiB
Java
package org.kne.cloud.network.ipv6;
|
|
|
|
import java.io.EOFException;
|
|
import java.io.IOException;
|
|
import java.io.StreamCorruptedException;
|
|
import java.net.Inet6Address;
|
|
import java.net.UnknownHostException;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.channels.ReadableByteChannel;
|
|
import java.nio.channels.WritableByteChannel;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
import org.kne.cloud.network.NetworkPacket;
|
|
import org.kne.cloud.network.klalb.KLALBPacket;
|
|
import org.kne.cloud.network.kltp.KLTPPacket;
|
|
import org.kne.cloud.network.srv6.IPv6SegmentRoutingTLV;
|
|
import org.kne.cloud.network.tcp.UDPPacket;
|
|
import org.kne.io.KNEChannels;
|
|
|
|
/**
|
|
* IPv6数据包类,继承自NetworkPacket,用于处理IPv6网络数据包
|
|
*/
|
|
public class IPv6Packet extends NetworkPacket {
|
|
|
|
private static final boolean debug=false;
|
|
|
|
// ==================== IPv6扩展头类型 ====================
|
|
|
|
/** 逐跳选项头 - RFC 8200 */
|
|
public static final int HOP_BY_HOP_OPTIONS = 0;
|
|
|
|
/** ICMPv4 - RFC 792 */
|
|
public static final int ICMPv4 = 1;
|
|
|
|
/** IGMP - RFC 1112 */
|
|
public static final int IGMP = 2;
|
|
|
|
/** IPv4封装 - RFC 2003 */
|
|
public static final int IPv4 = 4;
|
|
|
|
/** TCP - RFC 793 */
|
|
public static final int TCP = 6;
|
|
|
|
/** EGP - RFC 888 */
|
|
public static final int EGP = 8;
|
|
|
|
/** IGP - RFC 891 */
|
|
public static final int IGP = 9;
|
|
|
|
/** UDP - RFC 768 */
|
|
public static final int UDP = 17;
|
|
|
|
/** IPv6封装 - RFC 2473 */
|
|
public static final int IPv6 = 41;
|
|
|
|
/** 路由头 - RFC 8200 */
|
|
public static final int ROUTING = 43;
|
|
|
|
/** 分片头 - RFC 8200 */
|
|
public static final int FRAGMENT = 44;
|
|
|
|
/** RSVP - RFC 2205 */
|
|
public static final int RSVP = 46;
|
|
|
|
/** GRE - RFC 2784 */
|
|
public static final int GRE = 47;
|
|
|
|
/** 封装安全载荷 - RFC 4303 */
|
|
public static final int ESP = 50;
|
|
|
|
/** 认证头 - RFC 4302 */
|
|
public static final int AH = 51;
|
|
|
|
/** ICMPv6 - RFC 4443 */
|
|
public static final int ICMPv6 = 58;
|
|
|
|
/** 无下一个头 - RFC 8200 */
|
|
public static final int NO_NEXT_HEADER = 59;
|
|
|
|
/** 目的选项头 - RFC 8200 */
|
|
public static final int DESTINATION_OPTIONS = 60;
|
|
|
|
/** 移动IPv6 - RFC 6275 */
|
|
public static final int MOBILITY = 135;
|
|
|
|
/** Shim6 - RFC 5533 */
|
|
public static final int SHIM6 = 140;
|
|
|
|
/** 实验性和测试用途 - RFC 3692 */
|
|
public static final int EXPERIMENTAL_1 = 253;
|
|
|
|
/** 实验性和测试用途 - RFC 3692 */
|
|
public static final int EXPERIMENTAL_2 = 254;
|
|
|
|
/** 保留 - RFC 8200 */
|
|
public static final int RESERVED = 255;
|
|
|
|
// ==================== 上层协议类型 ====================
|
|
|
|
/** OSPF - RFC 2328 */
|
|
public static final int OSPF = 89;
|
|
|
|
/** SCTP - RFC 4960 */
|
|
public static final int SCTP = 132;
|
|
|
|
/** MPLS in IP - RFC 4023 */
|
|
public static final int MPLS_IN_IP = 137;
|
|
|
|
/** MANET协议 - RFC 5498 */
|
|
public static final int MANET = 138;
|
|
|
|
// ==================== 特殊用途 ====================
|
|
|
|
/** IPv6选项 - RFC 8200 */
|
|
public static final int IPv6_OPTIONS = 0;
|
|
|
|
/** 主机身份协议HIP(HOST_IDENTITY_PROTOCOL) - RFC 5201 */
|
|
public static final int HIP = 139;
|
|
|
|
/** 无线接入网协议 - RFC 5845 */
|
|
public static final int WARP = 142;
|
|
|
|
// ==================== SRv6相关常量 ====================
|
|
|
|
/** SRv6路由类型 */
|
|
public static final int SRV6_ROUTING_TYPE = 4;
|
|
|
|
// ==================== 地址相关常量 ====================
|
|
|
|
/** IPv6地址长度(字节) */
|
|
public static final int IPV6_ADDRESS_LENGTH = 16;
|
|
|
|
/** IPv6地址长整型部分数量 */
|
|
public static final int IPV6_ADDRESS_LONGS = 2;
|
|
|
|
// ==================== 位操作相关常量 ====================
|
|
|
|
public static final int BIT_MASK_LOW_4_BITS = 0b00001111;
|
|
public static final int BIT_MASK_HIGH_4_BITS = 0b11110000;
|
|
public static final int BIT_MASK_LOW_8_BITS = 0xFF;
|
|
public static final int BIT_MASK_LOW_16_BITS = 0xFFFF;
|
|
public static final int BIT_MASK_LOW_32_BITS = 0xFFFFFFFF;
|
|
|
|
// ==================== 扩展头对齐常量 ====================
|
|
|
|
public static final int EXT_HEADER_ALIGNMENT = 8;
|
|
|
|
// ==================== 工具方法 ====================
|
|
|
|
/**
|
|
* 获取Next Header的名称
|
|
*/
|
|
public static String getName(int nextHeader) {
|
|
switch (nextHeader) {
|
|
case HOP_BY_HOP_OPTIONS: return "Hop-by-Hop Options";
|
|
case ICMPv4: return "ICMPv4";
|
|
case IGMP: return "IGMP";
|
|
case IPv4: return "IPv4";
|
|
case TCP: return "TCP";
|
|
case EGP: return "EGP";
|
|
case IGP: return "IGP";
|
|
case UDP: return "UDP";
|
|
case IPv6: return "IPv6";
|
|
case ROUTING: return "Routing Header";
|
|
case FRAGMENT: return "Fragment Header";
|
|
case RSVP: return "RSVP";
|
|
case GRE: return "GRE";
|
|
case ESP: return "Encapsulating Security Payload";
|
|
case AH: return "Authentication Header";
|
|
case ICMPv6: return "ICMPv6";
|
|
case NO_NEXT_HEADER: return "No Next Header";
|
|
case DESTINATION_OPTIONS: return "Destination Options";
|
|
case MOBILITY: return "Mobility Header";
|
|
case HIP: return "Host Identity Protocol";
|
|
case SHIM6: return "Shim6 Protocol";
|
|
case EXPERIMENTAL_1: return "Experimental #1";
|
|
case EXPERIMENTAL_2: return "Experimental #2";
|
|
case RESERVED: return "Reserved";
|
|
case OSPF: return "OSPF";
|
|
case SCTP: return "SCTP";
|
|
case MPLS_IN_IP: return "MPLS in IP";
|
|
case MANET: return "MANET Protocols";
|
|
case WARP: return "WARP";
|
|
default: return "Unknown (" + nextHeader + ")";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查是否为IPv6扩展头
|
|
*/
|
|
public static boolean isExtensionHeader(int nextHeader) {
|
|
return nextHeader == HOP_BY_HOP_OPTIONS ||
|
|
nextHeader == ROUTING ||
|
|
nextHeader == FRAGMENT ||
|
|
nextHeader == DESTINATION_OPTIONS ||
|
|
nextHeader == MOBILITY ||
|
|
nextHeader == HIP ||
|
|
nextHeader == SHIM6;
|
|
}
|
|
|
|
/**
|
|
* 检查是否为传输层协议
|
|
*/
|
|
public static boolean isTransportProtocol(int nextHeader) {
|
|
return nextHeader == TCP ||
|
|
nextHeader == UDP ||
|
|
nextHeader == SCTP;
|
|
}
|
|
|
|
/**
|
|
* 检查是否为网络层协议
|
|
*/
|
|
public static boolean isNetworkProtocol(int nextHeader) {
|
|
return nextHeader == IPv4 ||
|
|
nextHeader == IPv6 ||
|
|
nextHeader == ICMPv4 ||
|
|
nextHeader == ICMPv6;
|
|
}
|
|
|
|
|
|
|
|
// TTL是否已减少的标志
|
|
private boolean TTLdecreased = false;
|
|
|
|
public boolean isTTLdecreased() {
|
|
return TTLdecreased;
|
|
}
|
|
|
|
public void setTTLdecreased(boolean tTLdecreased) {
|
|
TTLdecreased = tTLdecreased;
|
|
}
|
|
|
|
// IPv6头部数据缓冲区
|
|
private ByteBuffer IPv6header;
|
|
|
|
private IPv6HopByHopHeader hopByHopHeader;
|
|
|
|
private IPv6RoutingHeader routingHeader;
|
|
|
|
// IPv6扩展头部列表
|
|
private List<IPv6ExtHeader> headers = new ArrayList<>();
|
|
|
|
// IPv6负载数据
|
|
private IPv6Payload payload;
|
|
|
|
|
|
// IPv6头部固定长度
|
|
public static final int IPv6_HEADER_LENGTH = 40;
|
|
|
|
// IPv6地址在头部中的偏移量
|
|
private static final int SOURCE_ADDRESS_OFFSET = 8;
|
|
private static final int DESTINATION_ADDRESS_OFFSET = 24;
|
|
|
|
public IPv6Payload getPayload() {
|
|
return payload;
|
|
}
|
|
|
|
public void setPayload(IPv6Payload payload) {
|
|
this.payload = payload;
|
|
}
|
|
|
|
/**
|
|
* 默认构造函数,初始化IPv6头部缓冲区
|
|
*/
|
|
public IPv6Packet() {
|
|
IPv6header = NetworkPacket.bufferAllocator.allocate(IPv6_HEADER_LENGTH);
|
|
}
|
|
|
|
/**
|
|
* 从字节中提取IP版本号
|
|
* @param b 字节数据
|
|
* @return IP版本号
|
|
*/
|
|
public static int getIPVersion(byte b) {
|
|
return b >>> 4;
|
|
}
|
|
|
|
/**
|
|
* 获取IPv6版本号
|
|
* @return 版本号
|
|
*/
|
|
public int getVersion() {
|
|
return IPv6header.get(0) >>> 4;
|
|
}
|
|
|
|
/**
|
|
* 设置IPv6版本号
|
|
* @param version 版本号
|
|
*/
|
|
public void setVersion(int version) {
|
|
IPv6header.put(0, (byte) (IPv6header.get(0) & BIT_MASK_LOW_4_BITS | version << 4));
|
|
}
|
|
|
|
/**
|
|
* 获取流量类别
|
|
* @return 流量类别
|
|
*/
|
|
public int getTrafficClass() {
|
|
// 读取字节 0 和字节 1 组成一个 short(16 位)
|
|
short firstTwoBytes = IPv6header.getShort(0);
|
|
// 提取 Traffic Class:高 4 位(Version)去掉,剩下就是 8 位 Traffic Class
|
|
return (firstTwoBytes & 0x0FF0) >>> 4;
|
|
}
|
|
|
|
/**
|
|
* 设置流量类别
|
|
* @param trafficClass 流量类别
|
|
*/
|
|
public void setTrafficClass(int trafficClass) {
|
|
// 读取当前的两个字节
|
|
short firstTwoBytes = IPv6header.getShort(0);
|
|
// 清除原来的 Traffic Class 位(将中间 8 位清零)
|
|
short cleared = (short) (firstTwoBytes & 0xF00F); // 保留高 4 位和低 4 位
|
|
// 组合新的 Traffic Class
|
|
short newValue = (short) (cleared | ((trafficClass & 0xFF) << 4));
|
|
// 一次性写回
|
|
IPv6header.putShort(0, newValue);
|
|
}
|
|
|
|
/**
|
|
* 检查是否启用ECN(显式拥塞通知)
|
|
* @return 是否启用ECN
|
|
*/
|
|
public boolean isEnableECN() {
|
|
return (IPv6header.get(1) & 0b00110000) != 0;
|
|
}
|
|
|
|
/**
|
|
* 启用ECN(显式拥塞通知)
|
|
*/
|
|
public void enableECN() {
|
|
IPv6header.put(1, (byte) ((IPv6header.get(1) & 0b11101111) | 0b00100000));
|
|
}
|
|
|
|
/**
|
|
* 标记CE(拥塞经历)
|
|
*/
|
|
public void markCE() {
|
|
byte g=IPv6header.get(1);
|
|
if((g& 0b00110000) != 0) {
|
|
// 启用ECN
|
|
IPv6header.put(1, (byte) ( g| 0b00110000));
|
|
}
|
|
// new Exception().printStackTrace();
|
|
}
|
|
|
|
/**
|
|
* 检查是否标记了CE(拥塞经历)
|
|
* @return 是否标记了CE
|
|
*/
|
|
public boolean isCE() {
|
|
return ((IPv6header.get(1) >>> 4) & 0b11) == 0b11;
|
|
}
|
|
|
|
/**
|
|
* 获取流标签
|
|
* @return 流标签
|
|
*/
|
|
public int getFlowLabel() {
|
|
// 读取前 4 个字节(32 位)
|
|
int firstWord = IPv6header.getInt(0);
|
|
// 提取 Flow Label:高 12 位(Version + Traffic Class)去掉,剩下低 20 位
|
|
return firstWord & 0x000FFFFF;
|
|
}
|
|
|
|
/**
|
|
* 设置流标签
|
|
* @param flowLabel 流标签
|
|
*/
|
|
public void setFlowLabel(int flowLabel) {
|
|
// 读取当前前 4 个字节
|
|
int firstWord = IPv6header.getInt(0);
|
|
// 清除原来的 Flow Label(将低 20 位清零)
|
|
int cleared = firstWord & 0xFFF00000; // 保留高 12 位
|
|
// 组合新的 Flow Label(只取低 20 位)
|
|
int newWord = cleared | (flowLabel & 0x000FFFFF);
|
|
// 一次性写回
|
|
IPv6header.putInt(0, newWord);
|
|
}
|
|
|
|
/**
|
|
* 获取负载长度
|
|
* @return 负载长度
|
|
*/
|
|
public int getPayloadLength() {
|
|
return IPv6header.getShort(4) & BIT_MASK_LOW_16_BITS;
|
|
}
|
|
|
|
/**
|
|
* 设置负载长度
|
|
* @param payloadLength 负载长度
|
|
*/
|
|
public void setPayloadLength(int payloadLength) {
|
|
IPv6header.putShort(4, (short) payloadLength);
|
|
}
|
|
|
|
/**
|
|
* 获取下一个头部协议类型
|
|
* @return 下一个头部协议类型
|
|
*/
|
|
public int getNextHeader() {
|
|
return IPv6header.get(6) & BIT_MASK_LOW_8_BITS;
|
|
}
|
|
|
|
/**
|
|
* 设置下一个头部协议类型
|
|
* @param nextHeader 下一个头部协议类型
|
|
*/
|
|
public void setNextHeader(int nextHeader) {
|
|
IPv6header.put(6, (byte) nextHeader);
|
|
}
|
|
|
|
/**
|
|
* 获取跳数限制
|
|
* @return 跳数限制
|
|
*/
|
|
public int getHopLimit() {
|
|
return IPv6header.get(7) & BIT_MASK_LOW_8_BITS;
|
|
}
|
|
|
|
/**
|
|
* 设置跳数限制
|
|
* @param hopLimit 跳数限制
|
|
*/
|
|
public void setHopLimit(int hopLimit) {
|
|
IPv6header.put(7, (byte) hopLimit);
|
|
}
|
|
|
|
/**
|
|
* 获取原始源地址字节数组
|
|
* @param sourceAddress 用于存储源地址的字节数组
|
|
*/
|
|
public void getRawSourceAddressArray(byte[] sourceAddress) {
|
|
IPv6header.get(SOURCE_ADDRESS_OFFSET, sourceAddress, 0, sourceAddress.length);
|
|
}
|
|
|
|
/**
|
|
* 设置原始源地址字节数组
|
|
* @param sourceAddress 源地址字节数组
|
|
*/
|
|
public void setRawSourceAddressArray(byte[] sourceAddress) {
|
|
IPv6header.put(SOURCE_ADDRESS_OFFSET, sourceAddress, 0, sourceAddress.length);
|
|
}
|
|
|
|
/**
|
|
* 获取原始目标地址字节数组
|
|
* @param destinationAddress 用于存储目标地址的字节数组
|
|
*/
|
|
public void getRawDestinationAddressArray(byte[] destinationAddress) {
|
|
IPv6header.get(DESTINATION_ADDRESS_OFFSET, destinationAddress, 0, destinationAddress.length);
|
|
|
|
}
|
|
|
|
/**
|
|
* 设置原始目标地址字节数组
|
|
* @param destinationAddress 目标地址字节数组
|
|
*/
|
|
public void setRawDestinationAddressArray(byte[] destinationAddress) {
|
|
IPv6header.put(DESTINATION_ADDRESS_OFFSET, destinationAddress, 0, destinationAddress.length);
|
|
}
|
|
|
|
/**
|
|
* 获取原始源地址字节数组
|
|
* @return
|
|
*/
|
|
public IPv6Address getSourceAddress() {
|
|
return IPv6Address.valueOf(SOURCE_ADDRESS_OFFSET,IPv6header);
|
|
}
|
|
|
|
/**
|
|
* 设置原始源地址字节数组
|
|
* @param sourceAddress 源地址字节数组
|
|
*/
|
|
public void setSourceAddress(IPv6Address sourceAddress) {
|
|
sourceAddress.writeTo(SOURCE_ADDRESS_OFFSET,IPv6header);
|
|
}
|
|
|
|
|
|
/**
|
|
* 获取原始目标地址字节数组
|
|
*/
|
|
public IPv6Address getDestinationAddress() {
|
|
return IPv6Address.valueOf(DESTINATION_ADDRESS_OFFSET,IPv6header);
|
|
}
|
|
|
|
/**
|
|
* 设置原始目标地址字节数组
|
|
* @param destinationAddress 目标地址字节数组
|
|
*/
|
|
public void setDestinationAddress(IPv6Address destinationAddress) {
|
|
destinationAddress.writeTo(DESTINATION_ADDRESS_OFFSET,IPv6header);
|
|
}
|
|
|
|
/**
|
|
* 获取源地址
|
|
* @return 源地址
|
|
*/
|
|
public Inet6Address getSourceAddress2() {
|
|
byte[] b = new byte[IPV6_ADDRESS_LENGTH];
|
|
IPv6header.get(SOURCE_ADDRESS_OFFSET, b, 0, b.length);
|
|
try {
|
|
return (Inet6Address) Inet6Address.getByAddress(b);
|
|
} catch (UnknownHostException e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置源地址
|
|
* @param sourceAddress 源地址
|
|
*/
|
|
public void setSourceAddress2(Inet6Address sourceAddress) {
|
|
byte[] b = sourceAddress.getAddress();
|
|
IPv6header.put(SOURCE_ADDRESS_OFFSET, b, 0, b.length);
|
|
}
|
|
|
|
/**
|
|
* 获取目标地址
|
|
* @return 目标地址
|
|
*/
|
|
public Inet6Address getDestinationAddress2() {
|
|
byte[] b = new byte[IPV6_ADDRESS_LENGTH];
|
|
IPv6header.get(DESTINATION_ADDRESS_OFFSET, b, 0, b.length);
|
|
try {
|
|
return (Inet6Address) Inet6Address.getByAddress(b);
|
|
} catch (UnknownHostException e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置目标地址
|
|
* @param destinationAddress 目标地址
|
|
*/
|
|
public void setDestinationAddress2(Inet6Address destinationAddress) {
|
|
byte[] b = destinationAddress.getAddress();
|
|
IPv6header.put(DESTINATION_ADDRESS_OFFSET, b, 0, b.length);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* 获取流会话信息
|
|
* @return 流会话对象
|
|
*/
|
|
public FlowSession getFlowSession() {
|
|
return new FlowSession(getSourceAddress(), getDestinationAddress(), getFlowLabel());
|
|
}
|
|
|
|
/**
|
|
* 计算负载长度
|
|
* @return 负载长度
|
|
*/
|
|
private int calcPayloadLength() {
|
|
int lth = 0;
|
|
for (int i = 0; i < headers.size(); i++) {
|
|
int extHeaderLength=(int) headers.get(i).getTotalLength();
|
|
if(extHeaderLength<=0) {
|
|
throw new IllegalArgumentException("extHeaderLength:"+extHeaderLength+"<0");
|
|
}
|
|
lth += extHeaderLength;
|
|
}
|
|
lth += payload.getTotalLength();
|
|
return lth;
|
|
}
|
|
|
|
/**
|
|
* 获取数据包总长度
|
|
* @return 数据包总长度
|
|
*/
|
|
@Override
|
|
public long getTotalLength() {
|
|
return calcPayloadLength() + IPv6_HEADER_LENGTH;
|
|
}
|
|
|
|
/**
|
|
* 将数据包写入通道
|
|
* @param dto 可写字节通道
|
|
* @throws IOException 写入异常
|
|
*/
|
|
@Override
|
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
|
if (headers.isEmpty()) {
|
|
setNextHeader(payload.getProtocolNumber());
|
|
} else {
|
|
setNextHeader(headers.get(0).getProtocolNumber());
|
|
}
|
|
setPayloadLength(calcPayloadLength());
|
|
dto.write(IPv6header.slice(0, IPv6header.limit()));
|
|
for (int i = 0; i < headers.size(); i++) {
|
|
IPv6ExtHeader exth = headers.get(i);
|
|
if (i + 1 < headers.size()) {
|
|
exth.setNextHeader(headers.get(i + 1).getProtocolNumber());
|
|
} else {
|
|
exth.setNextHeader(payload.getProtocolNumber());
|
|
}
|
|
exth.writeToChannel(dto);
|
|
}
|
|
payload.writeToChannel(dto);
|
|
|
|
if(debug)
|
|
debug("send");
|
|
}
|
|
|
|
/**
|
|
* 从通道读取数据包
|
|
* @param din 可读字节通道
|
|
* @param length 数据长度
|
|
* @throws IOException 读取异常
|
|
*/
|
|
@Override
|
|
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
|
IPv6header.limit(IPv6_HEADER_LENGTH);
|
|
IPv6header.position(0);
|
|
while (IPv6header.hasRemaining()) {
|
|
if (din.read(IPv6header) == -1) {
|
|
throw new EOFException();
|
|
}
|
|
}
|
|
int payloadlength = getPayloadLength();
|
|
int nextheader = getNextHeader();
|
|
loop: while (true) {
|
|
IPv6ExtHeader ext;
|
|
switch (nextheader) {
|
|
|
|
case HOP_BY_HOP_OPTIONS: // Hop-by-Hop选项头部
|
|
ext = new IPv6HopByHopHeader();
|
|
ext.readFromChannel(din, 0);
|
|
nextheader = ext.getNextHeader();
|
|
payloadlength -= ext.getTotalLength();
|
|
headers.add(ext);
|
|
hopByHopHeader=(IPv6HopByHopHeader) ext;
|
|
break;
|
|
case DESTINATION_OPTIONS: // 目标选项头部
|
|
ext = new IPv6DestinationHeader();
|
|
ext.readFromChannel(din, 0);
|
|
nextheader = ext.getNextHeader();
|
|
payloadlength -= ext.getTotalLength();
|
|
headers.add(ext);
|
|
break;
|
|
case ROUTING: // 路由头部
|
|
ByteBuffer bbf = NetworkPacket.bufferAllocator.allocate(2048);
|
|
bbf.limit(4);
|
|
while (bbf.hasRemaining()) {
|
|
if (din.read(bbf) == -1) {
|
|
throw new EOFException();
|
|
}
|
|
}
|
|
|
|
int routingType = bbf.get(2) & BIT_MASK_LOW_8_BITS;
|
|
switch (routingType) {
|
|
case SRV6_ROUTING_TYPE: // SRv6路由类型
|
|
ext = new IPv6SegmentRoutingHeader(bbf);
|
|
break;
|
|
default: // 其他路由类型
|
|
ext = new IPv6RoutingHeader(-1, bbf);
|
|
break;
|
|
}
|
|
ext.readFromChannel(din, 0);
|
|
nextheader = ext.getNextHeader();
|
|
payloadlength -= ext.getTotalLength();
|
|
headers.add(ext);
|
|
routingHeader=(IPv6RoutingHeader) ext;
|
|
break;
|
|
case FRAGMENT: // 分段头部
|
|
ext = new IPv6ExtHeader(nextheader);
|
|
ext.readFromChannel(din, 0);
|
|
nextheader = ext.getNextHeader();
|
|
payloadlength -= ext.getTotalLength();
|
|
headers.add(ext);
|
|
break;
|
|
case ESP: // ESP头部
|
|
ext = new IPv6ExtHeader(nextheader);
|
|
ext.readFromChannel(din, 0);
|
|
nextheader = ext.getNextHeader();
|
|
payloadlength -= ext.getTotalLength();
|
|
headers.add(ext);
|
|
break;
|
|
case AH: // AH头部
|
|
ext = new IPv6ExtHeader(nextheader);
|
|
ext.readFromChannel(din, 0);
|
|
nextheader = ext.getNextHeader();
|
|
payloadlength -= ext.getTotalLength();
|
|
headers.add(ext);
|
|
break;
|
|
case NO_NEXT_HEADER: // 无下一个头部
|
|
ext = new IPv6ExtHeader(nextheader);
|
|
ext.readFromChannel(din, 0);
|
|
nextheader = ext.getNextHeader();
|
|
payloadlength -= ext.getTotalLength();
|
|
headers.add(ext);
|
|
break;
|
|
case ICMPv6:
|
|
ICMPv6Packet icmp=ICMPv6Packet.readICMPv6PacketFromChannel(din,payloadlength);
|
|
icmp.setParent(this);
|
|
this.payload=icmp;
|
|
break loop;
|
|
case UDP: // UDP协议
|
|
UDPPacket udp=new UDPPacket();
|
|
udp.setParent(this);
|
|
udp.readFromChannel(din,payloadlength);
|
|
this.payload=udp;
|
|
break loop;
|
|
case KLALBPacket.KLALB_PROTOCOL_NUMBER: // KLALB协议
|
|
KLALBPacket kp = KLALBPacket.readKLALBPacketFromChannel(din);
|
|
this.payload = kp;
|
|
break loop;
|
|
case KLTPPacket.KLTP_PROTOCOL_NUMBER: //KLTP协议
|
|
IPv6Payload epld = KLTPPacket.readKLTPPacketFromChannel(din);
|
|
this.payload = epld;
|
|
break loop;
|
|
default: // 其他协议类型
|
|
IPv6Payload pld = new IPv6DefaultPayload(nextheader);
|
|
pld.readFromChannel(din, payloadlength);
|
|
this.payload = pld;
|
|
break loop;
|
|
}
|
|
}
|
|
if(debug)
|
|
debug("recv");
|
|
}
|
|
|
|
private void debug(String description) {
|
|
StringBuilder sb=new StringBuilder();
|
|
sb.append(description);
|
|
sb.append(" total:");
|
|
sb.append(getPayloadLength());
|
|
sb.append(" ");
|
|
for (IPv6ExtHeader iPv6ExtHeader : headers) {
|
|
sb.append(iPv6ExtHeader.getTotalLength());
|
|
sb.append(' ');
|
|
}
|
|
if(payload!=null)
|
|
sb.append(payload.getTotalLength());
|
|
System.out.println(sb);
|
|
}
|
|
|
|
/**
|
|
* 转换为字符串表示
|
|
* @return 字符串表示
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
return "IPv6Packet [getVersion()=" + getVersion() + ", getTrafficClass()=" + getTrafficClass()
|
|
+ ", getFlowLabel()=" + getFlowLabel() + ", getPayloadLength()=" + getPayloadLength()
|
|
+ ", getNextHeader()=" + getNextHeader() + ", getHopLimit()=" + getHopLimit() + ", getSourceAddress()="
|
|
+ getSourceAddress() + ", getDestinationAddress()=" + getDestinationAddress() + ", getLength()="
|
|
+ getTotalLength() + ", headers=" + headers + ", payload=" + payload + "]";
|
|
}
|
|
|
|
/**
|
|
* IPv6负载数据类
|
|
*/
|
|
public static abstract class IPv6Payload extends NetworkPacket {
|
|
|
|
|
|
|
|
private IPv6Packet parent;
|
|
|
|
private int protocolNumber;
|
|
|
|
|
|
|
|
public IPv6Payload(int protocolNumber) {
|
|
this.protocolNumber=protocolNumber;
|
|
}
|
|
|
|
|
|
|
|
public int getProtocolNumber() {
|
|
return protocolNumber;
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
protected boolean needEndPosition() {
|
|
return true;
|
|
}
|
|
|
|
public void setParent(IPv6Packet parent) {
|
|
this.parent = parent;
|
|
}
|
|
public IPv6Packet getParent() {
|
|
return parent;
|
|
}
|
|
}
|
|
|
|
public static class IPv6DefaultPayload extends IPv6Payload{
|
|
|
|
private ByteBuffer data;
|
|
public ByteBuffer getData() {
|
|
return data;
|
|
}
|
|
public IPv6DefaultPayload(int protocolNumber) {
|
|
super(protocolNumber);
|
|
this.data = NetworkPacket.bufferAllocator.allocate(65535);
|
|
}
|
|
public long getTotalLength() {
|
|
return data.limit();
|
|
}
|
|
@Override
|
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
|
dto.write(data.slice(0, data.limit()));
|
|
}
|
|
|
|
@Override
|
|
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
|
data.limit((int) length);
|
|
while (data.hasRemaining()) {
|
|
if (din.read(data) == -1) {
|
|
throw new EOFException();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* IPv6扩展头部基类
|
|
*/
|
|
public static class IPv6ExtHeader extends NetworkPacket {
|
|
private ByteBuffer data;
|
|
|
|
private int protocolNumber;
|
|
|
|
private int bufferLength;
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "IPv6ExtHeader [protocolNumber=" + protocolNumber + ", getNextHeader()=" + getNextHeader()
|
|
+ ", getExtLength()=" + getExtLength() + "]";
|
|
}
|
|
|
|
public ByteBuffer getData() {
|
|
return data;
|
|
}
|
|
|
|
public IPv6ExtHeader(int type) {
|
|
this(type, -1);
|
|
}
|
|
|
|
protected IPv6ExtHeader(int protocolNumber, int bufferLength) {
|
|
this.protocolNumber = protocolNumber;
|
|
this.bufferLength=bufferLength;
|
|
if (bufferLength==-1) {
|
|
this.data = NetworkPacket.bufferAllocator.allocate(2048);
|
|
} else {
|
|
this.data = NetworkPacket.bufferAllocator.allocate(bufferLength);
|
|
}
|
|
}
|
|
|
|
protected IPv6ExtHeader(int protocolNumber, int bufferLength, ByteBuffer data) {
|
|
this.protocolNumber = protocolNumber;
|
|
this.bufferLength = bufferLength;
|
|
this.data = data;
|
|
}
|
|
|
|
public int getProtocolNumber() {
|
|
return protocolNumber;
|
|
}
|
|
|
|
public int getNextHeader() {
|
|
return data.get(0) & BIT_MASK_LOW_8_BITS;
|
|
}
|
|
|
|
public void setNextHeader(int nextHeader) {
|
|
data.put(0, (byte) nextHeader);
|
|
}
|
|
|
|
public int getExtLength() {
|
|
return data.get(1) & BIT_MASK_LOW_8_BITS;
|
|
}
|
|
|
|
protected void setExtLength(int extLength) {
|
|
data.put(1, (byte) extLength);
|
|
}
|
|
|
|
public long getTotalLength() {
|
|
return data.limit();
|
|
}
|
|
|
|
@Override
|
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
|
if (bufferLength==-1) {
|
|
int ext = (data.limit() - EXT_HEADER_ALIGNMENT) / EXT_HEADER_ALIGNMENT;
|
|
setExtLength(ext);
|
|
dto.write(data.slice(0, data.limit()));
|
|
} else {
|
|
dto.write(data.slice(0, bufferLength));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
|
data.limit(bufferLength);
|
|
while (data.hasRemaining()) {
|
|
if (din.read(data) == -1) {
|
|
throw new EOFException();
|
|
}
|
|
}
|
|
if (bufferLength==-1) {
|
|
int newLimit = getExtLength() * EXT_HEADER_ALIGNMENT + data.limit();
|
|
data.limit(newLimit);
|
|
while (data.hasRemaining()) {
|
|
if (din.read(data) == -1) {
|
|
throw new EOFException();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean needEndPosition() {
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* IPv6逐跳头部类
|
|
*/
|
|
public static class IPv6HopByHopHeader extends IPv6ExtHeader {
|
|
|
|
|
|
private final List<IPv6HopByHopTLV> tlvs = new ArrayList<IPv6HopByHopTLV>();
|
|
@Override
|
|
public String toString() {
|
|
return "IPv6HopByHopHeader [tlvs=" + tlvs + ", getProtocolNumber()=" + getProtocolNumber()
|
|
+ ", getNextHeader()=" + getNextHeader() + ", getExtLength()=" + getExtLength() + "]";
|
|
}
|
|
|
|
public IPv6HopByHopHeader() {
|
|
super(HOP_BY_HOP_OPTIONS,2);
|
|
}
|
|
|
|
|
|
public IPv6HopByHopHeader( ByteBuffer data) {
|
|
super(HOP_BY_HOP_OPTIONS, 2, data);
|
|
}
|
|
|
|
@Override
|
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
|
int exl = calcTLVLength();
|
|
if ((exl+2) % EXT_HEADER_ALIGNMENT != 0) {
|
|
throw new StreamCorruptedException("extLength % " + EXT_HEADER_ALIGNMENT + " !=0");
|
|
}
|
|
|
|
setExtLength(((exl+2) / EXT_HEADER_ALIGNMENT)-1);
|
|
super.writeToChannel(dto);
|
|
for (IPv6HopByHopTLV tlv : tlvs) {
|
|
IPv6HopByHopTLV.writeIPv6HopByHopTLVToChannel(dto, tlv);
|
|
}
|
|
}
|
|
|
|
private int calcTLVLength() {
|
|
int tlvsl = 0;
|
|
for (IPv6HopByHopTLV tlve : tlvs) {
|
|
tlvsl += tlve.getTotalLength();
|
|
}
|
|
return tlvsl;
|
|
}
|
|
|
|
@Override
|
|
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
|
super.readFromChannel(din, length);
|
|
int extl = getExtLength();
|
|
|
|
// 计算应该读取的总字节数
|
|
int expectedTotalBytes = (extl + 1) * EXT_HEADER_ALIGNMENT;
|
|
int tlvBytesToRead = expectedTotalBytes - 2; // 减去基础头的2字节
|
|
|
|
tlvs.clear();
|
|
int bytesRead = 0;
|
|
|
|
// 读取直到达到预期的字节数
|
|
while (bytesRead < tlvBytesToRead) {
|
|
IPv6HopByHopTLV tlv = IPv6HopByHopTLV.readIPv6HopByHopTLVFromChannel(din);
|
|
int tlvLength = (int) tlv.getTotalLength();
|
|
|
|
// 检查是否会超出预期范围
|
|
if (bytesRead + tlvLength > tlvBytesToRead) {
|
|
throw new StreamCorruptedException(
|
|
String.format("TLV overflow: read %d + %d > %d bytes",
|
|
bytesRead, tlvLength, tlvBytesToRead));
|
|
}
|
|
|
|
tlvs.add(tlv);
|
|
bytesRead += tlvLength;
|
|
}
|
|
|
|
// 验证实际读取的字节数与预期一致
|
|
if (bytesRead != tlvBytesToRead) {
|
|
throw new StreamCorruptedException(
|
|
String.format("TLV length mismatch: expected %d, got %d",
|
|
tlvBytesToRead, bytesRead));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public long getTotalLength() {
|
|
return calcTLVLength() + 2;
|
|
}
|
|
|
|
public List<IPv6HopByHopTLV> getTlvs() {
|
|
return tlvs;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* IPv6路由头部类
|
|
*/
|
|
public static class IPv6RoutingHeader extends IPv6ExtHeader {
|
|
@Override
|
|
public String toString() {
|
|
return "IPv6RoutingHeader [protocolNumber=" + getProtocolNumber() + ", getNextHeader()=" + getNextHeader()
|
|
+ ", getExtLength()=" + getExtLength() + ", getRoutingType()=" + getRoutingType() + "]";
|
|
}
|
|
|
|
public IPv6RoutingHeader() {
|
|
super(ROUTING);
|
|
}
|
|
|
|
public IPv6RoutingHeader(int bufferLength) {
|
|
super(ROUTING, bufferLength);
|
|
}
|
|
|
|
public IPv6RoutingHeader(int bufferLength, ByteBuffer data) {
|
|
super(ROUTING, bufferLength, data);
|
|
}
|
|
|
|
public int getRoutingType() {
|
|
return getData().get(2) & BIT_MASK_LOW_8_BITS;
|
|
}
|
|
|
|
public void setRoutingType(int routingTypr) {
|
|
getData().put(2, (byte) routingTypr);
|
|
}
|
|
|
|
public int getSegmentsLeft() {
|
|
return getData().get(3);
|
|
}
|
|
|
|
public void setSegmentsLeft(int segmentsLeft) {
|
|
getData().put(3, (byte) segmentsLeft);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* IPv6段路由头部类
|
|
*/
|
|
/**
|
|
* IPv6 Segment Routing Header (SRH) 实现
|
|
*
|
|
* <p>根据 RFC 8754 实现,支持SRv6扩展头和TLV选项</p>
|
|
*
|
|
* <pre>
|
|
* 0 1 2 3
|
|
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Next Header | Hdr Ext Len | Routing Type | Segments Left |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | Last Entry | Flags | Tag |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* | Segment List[0] (128-bit IPv6 address) |
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | ... |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* | |
|
|
* | Segment List[n] (128-bit IPv6 address) |
|
|
* | |
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* // //
|
|
* // Optional Type-Length-Value objects (variable) //
|
|
* // //
|
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
* </pre>
|
|
*/
|
|
public static class IPv6SegmentRoutingHeader extends IPv6RoutingHeader {
|
|
|
|
private final List<IPv6Address> addresses = new ArrayList<IPv6Address>();
|
|
private final List<IPv6SegmentRoutingTLV> tlvs = new ArrayList<IPv6SegmentRoutingTLV>();
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "IPv6SegmentRoutingHeader [addresses=" + addresses + ", tlvs=" + tlvs + ", getLastEntry()="
|
|
+ getLastEntry() + ", getFlags()=" + getFlags() + ", getTag()=" + getTag() + ", getAddresses()="
|
|
+ getAddresses() + ", getRoutingType()=" + getRoutingType() + ", getSegmentsLeft()="
|
|
+ getSegmentsLeft() + ", getProtocolNumber()=" + getProtocolNumber() + ", getNextHeader()="
|
|
+ getNextHeader() + ", getExtLength()=" + getExtLength() + "]";
|
|
}
|
|
|
|
public IPv6SegmentRoutingHeader() {
|
|
super(EXT_HEADER_ALIGNMENT);
|
|
setRoutingType(SRV6_ROUTING_TYPE);
|
|
}
|
|
|
|
public IPv6SegmentRoutingHeader(ByteBuffer bbf) {
|
|
super(EXT_HEADER_ALIGNMENT, bbf);
|
|
}
|
|
|
|
public IPv6SegmentRoutingHeader(List<IPv6Address> segs) {
|
|
this();
|
|
this.addresses.addAll(segs);
|
|
resetSegmentPos();
|
|
}
|
|
|
|
public void resetSegmentPos() {
|
|
int ln = addresses.size() - 1;
|
|
setLastEntry(ln);
|
|
setSegmentsLeft(ln);
|
|
}
|
|
|
|
public int getLastEntry() {
|
|
return getData().get(4) & BIT_MASK_LOW_8_BITS;
|
|
}
|
|
|
|
public void setLastEntry(int lastEntry) {
|
|
getData().put(4, (byte) lastEntry);
|
|
}
|
|
|
|
public int getFlags() {
|
|
return getData().get(5) & BIT_MASK_LOW_8_BITS;
|
|
}
|
|
|
|
public void setFlags(int flags) {
|
|
getData().put(5, (byte) flags);
|
|
}
|
|
|
|
public int getTag() {
|
|
return getData().getShort(6) & BIT_MASK_LOW_16_BITS;
|
|
}
|
|
|
|
public void setTag(int tag) {
|
|
getData().putShort(6, (short) tag);
|
|
}
|
|
|
|
public List<IPv6Address> getAddresses() {
|
|
return addresses;
|
|
}
|
|
|
|
public List<IPv6SegmentRoutingTLV> getTlvs() {
|
|
return tlvs;
|
|
}
|
|
|
|
@Override
|
|
public void writeToChannel(WritableByteChannel dto) throws IOException {
|
|
int exl = calcExtLength();
|
|
if (exl % EXT_HEADER_ALIGNMENT != 0) {
|
|
throw new StreamCorruptedException("extLength % " + EXT_HEADER_ALIGNMENT + " !=0");
|
|
}
|
|
|
|
setExtLength(exl / EXT_HEADER_ALIGNMENT);
|
|
setLastEntry(addresses.size() - 1);
|
|
super.writeToChannel(dto);
|
|
|
|
ByteBuffer addr=NetworkPacket.bufferAllocator.allocateHeap(addresses.size() *IPV6_ADDRESS_LENGTH);
|
|
for (IPv6Address inet6Address : addresses) {
|
|
inet6Address.writeTo(addr);
|
|
}
|
|
addr.flip();
|
|
dto.write(addr);
|
|
for (IPv6SegmentRoutingTLV tlv : tlvs) {
|
|
IPv6SegmentRoutingTLV.writeIPv6SegmentRoutingTLVToChannel(dto, tlv);
|
|
}
|
|
}
|
|
|
|
private int calcExtLength() {
|
|
int tlvsl = 0;
|
|
for (IPv6SegmentRoutingTLV tlve : tlvs) {
|
|
tlvsl += tlve.getTotalLength();
|
|
}
|
|
return addresses.size() * IPV6_ADDRESS_LENGTH + tlvsl;
|
|
}
|
|
|
|
/*@Override
|
|
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
|
super.readFromChannel(din, length);
|
|
int extl = getExtLength();
|
|
int laste = getLastEntry();
|
|
|
|
int rl = extl * EXT_HEADER_ALIGNMENT;
|
|
int usdl = 0;
|
|
|
|
// System.out.println("SR length:"+(laste+1));
|
|
addresses.clear();
|
|
ByteBuffer bfr = NetworkPacket.bufferAllocator.allocateHeap(IPV6_ADDRESS_LENGTH);
|
|
for (int i = 0; i < (laste + 1); i++) {
|
|
bfr.clear();
|
|
while (bfr.hasRemaining()) {
|
|
if (din.read(bfr) == -1) {
|
|
throw new EOFException();
|
|
}
|
|
}
|
|
bfr.flip();
|
|
usdl += bfr.limit();
|
|
Inet6Address addr = (Inet6Address) Inet6Address.getByAddress(bfr.array());
|
|
// System.out.println("SR:"+addr);
|
|
addresses.add(addr);
|
|
}
|
|
tlvs.clear();
|
|
while (usdl < rl) {
|
|
IPv6SegmentRoutingTLV tlv = IPv6SegmentRoutingTLV.readIPv6SegmentRoutingTLVFromChannel(din);
|
|
usdl += tlv.getTotalLength();
|
|
tlvs.add(tlv);
|
|
}
|
|
|
|
return;
|
|
}*/
|
|
@Override
|
|
public void readFromChannel(ReadableByteChannel din, long length) throws IOException {
|
|
super.readFromChannel(din, length);
|
|
|
|
ByteBuffer bfr = null;
|
|
int extl = getExtLength();
|
|
int laste = getLastEntry();
|
|
int rl = extl * EXT_HEADER_ALIGNMENT;
|
|
int usdl = 0;
|
|
|
|
// 验证lastEntry的合理性
|
|
if (laste < 0 ) {
|
|
throw new StreamCorruptedException("Invalid lastEntry: " + laste);
|
|
}
|
|
|
|
addresses.clear();
|
|
bfr = NetworkPacket.bufferAllocator.allocateHeap(IPV6_ADDRESS_LENGTH*(laste+1));
|
|
KNEChannels.readFully(din, bfr);
|
|
bfr.flip();
|
|
usdl += bfr.limit();
|
|
for (int i = 0; i <= laste; i++) { // 注意:应该是 <= laste
|
|
addresses.add(IPv6Address.valueOf(bfr));
|
|
}
|
|
|
|
tlvs.clear();
|
|
while (usdl < rl) {
|
|
IPv6SegmentRoutingTLV tlv = IPv6SegmentRoutingTLV.readIPv6SegmentRoutingTLVFromChannel(din);
|
|
usdl += tlv.getTotalLength();
|
|
tlvs.add(tlv);
|
|
}
|
|
|
|
// 验证读取的字节数与预期一致
|
|
if (usdl != rl) {
|
|
throw new StreamCorruptedException("Length mismatch: expected " + rl + ", got " + usdl);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// 辅助方法:确保读取完整数据
|
|
private int readFully(ReadableByteChannel channel, ByteBuffer buffer) throws IOException {
|
|
int totalRead = 0;
|
|
while (buffer.hasRemaining()) {
|
|
int read = channel.read(buffer);
|
|
if (read == -1) {
|
|
break;
|
|
}
|
|
totalRead += read;
|
|
}
|
|
return totalRead;
|
|
}
|
|
@Override
|
|
public long getTotalLength() {
|
|
return calcExtLength() + EXT_HEADER_ALIGNMENT;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* IPv6目标选项头部类
|
|
*/
|
|
public static class IPv6DestinationHeader extends IPv6ExtHeader {
|
|
@Override
|
|
public String toString() {
|
|
return "IPv6DestinationHeader [protocolNumber=" + getProtocolNumber() + ", getNextHeader()="
|
|
+ getNextHeader() + ", getExtLength()=" + getExtLength() + ", getRoutingType()=" + getRoutingType()
|
|
+ "]";
|
|
}
|
|
|
|
public IPv6DestinationHeader() {
|
|
super(DESTINATION_OPTIONS);
|
|
}
|
|
|
|
public int getRoutingType() {
|
|
return getData().get(2) & BIT_MASK_LOW_8_BITS;
|
|
}
|
|
|
|
public void setRoutingType(int routingTypr) {
|
|
getData().put(2, (byte) routingTypr);
|
|
}
|
|
|
|
public int getSegmentsLeft() {
|
|
return getData().get(3);
|
|
}
|
|
|
|
public void setSegmentsLeft(int segmentsLeft) {
|
|
getData().put(3, (byte) segmentsLeft);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取所有扩展头部
|
|
* @return 扩展头部列表
|
|
*/
|
|
public List<IPv6ExtHeader> getHeaders() {
|
|
return headers;
|
|
}
|
|
|
|
/**
|
|
* 获取IPv6逐跳头部
|
|
* @return IPv6段逐跳头部,如果不存在则返回null
|
|
*/
|
|
public IPv6HopByHopHeader getHopByHopHeader() {
|
|
return hopByHopHeader;
|
|
}
|
|
/**
|
|
* 获取路由头部
|
|
* @return 路由头部,如果不存在则返回null
|
|
*/
|
|
public IPv6RoutingHeader getRoutingHeader() {
|
|
return routingHeader;
|
|
}
|
|
|
|
|
|
|
|
public void setHopByHopHeader(IPv6HopByHopHeader hopByHopHeader) {
|
|
this.hopByHopHeader = hopByHopHeader;
|
|
}
|
|
|
|
public void setRoutingHeader(IPv6RoutingHeader routingHeader) {
|
|
this.routingHeader = routingHeader;
|
|
}
|
|
|
|
/**
|
|
* 获取SRv6段路由头部
|
|
* @return SRv6段路由头部,如果不存在则返回null
|
|
*/
|
|
public IPv6SegmentRoutingHeader getSegmentRoutingHeader() {
|
|
IPv6RoutingHeader rh=getRoutingHeader();
|
|
if(rh==null)
|
|
return null;
|
|
IPv6SegmentRoutingHeader srhh=null;
|
|
if (rh instanceof IPv6SegmentRoutingHeader) {
|
|
if (((IPv6SegmentRoutingHeader) rh).getRoutingType() == SRV6_ROUTING_TYPE) {
|
|
srhh = (IPv6SegmentRoutingHeader) rh;
|
|
}
|
|
}
|
|
|
|
return srhh;
|
|
}
|
|
|
|
|
|
|
|
public UUID getPacketID() {
|
|
IPv6HopByHopHeader hop=getHopByHopHeader();
|
|
if(hop==null)
|
|
return null;
|
|
List<IPv6HopByHopTLV> tlvs= hop.getTlvs();
|
|
for(IPv6HopByHopTLV tlv:tlvs) {
|
|
if(tlv instanceof KLALBOAMHopByHopTLV)
|
|
return ((KLALBOAMHopByHopTLV)tlv).getUUID();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
@Override
|
|
protected boolean needEndPosition() {
|
|
return false;
|
|
}
|
|
|
|
// 重路由计数器
|
|
private AtomicInteger rerouteCounter = new AtomicInteger(0);
|
|
|
|
public AtomicInteger getRerouteCounter() {
|
|
return rerouteCounter;
|
|
}
|
|
|
|
public long calculateAddressChecksum() {
|
|
long sum=0;
|
|
|
|
ByteBuffer dataCopy = IPv6header.slice(SOURCE_ADDRESS_OFFSET,32);
|
|
|
|
while (dataCopy.remaining() >= 2) {
|
|
sum += dataCopy.getChar();
|
|
}
|
|
|
|
if (dataCopy.remaining() == 1) {
|
|
sum += (dataCopy.get() & 0xFF) << 8;
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
|
|
|
|
|
|
} |