package org.kne.cloud.network.ipv6; import java.io.EOFException; import java.io.IOException; import java.net.Inet6Address; import java.net.InetAddress; 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.Iterator; import java.util.List; import org.kne.cloud.network.NetworkPacket; import org.kne.cloud.network.ipv6.IPv6Packet.IPv6ExtHeader; import org.kne.cloud.network.klalb.KLALBPacket; import org.kne.cloud.network.srv6.IPv6SegmentRoutingTLV; import org.kne.cloud.network.srv6.IpV6RoutingSRHData; import org.kne.cloud.network.srv6.SRv6Pad1TLV; import org.kne.cloud.network.srv6.SRv6PadNTLV; import org.kne.cloud.network.srv6.SRv6StreamSequenceTLV; import org.kne.cloud.network.srv6.SRv6TLV; import org.pcap4j.packet.namednumber.IpNumber; public class IPv6Packet extends NetworkPacket { private volatile ByteBuffer IPv6header ; private volatile List headers = new ArrayList<>(); private IPv6Payload payload; public static final int IPv6_HEADER_LENGTH = 40; public IPv6Payload getPayload() { return payload; } public void setPayload(IPv6Payload payload) { this.payload = payload; } public IPv6Packet() { IPv6header = NetworkPacket.databufferpool_40.borrow(); IPv6header.limit(IPv6_HEADER_LENGTH); } public static int getIPVersion(byte b) { return b>>>4; } public int getVersion() { return IPv6header.get(0) >>> 4; } public void setVersion(int version) { IPv6header.put(0, (byte) (IPv6header.get(0) & 0b00001111 | version << 4)); } public int getTrafficClass() { return (IPv6header.get(0) << 4) & (IPv6header.get(1) >>> 4) & 0xff; } public void setTrafficClass(int trafficClass) { IPv6header.put(0, (byte) (IPv6header.get(0) & 0b11110000 | (trafficClass >>> 4))); IPv6header.put(1, (byte) (IPv6header.get(1) & 0b00001111 | ((trafficClass & 0b00001111) << 4))); } public boolean isEnableECN() { return (IPv6header.get(1)&0b00110000)!=0; } public void enableECN() { IPv6header.put(1, (byte) ((IPv6header.get(1)&0b11101111)|0b00100000)); } public void markCE() { IPv6header.put(1,(byte) (IPv6header.get(1)|0b00110000)); } public boolean isCE() { return ((IPv6header.get(1)>>>4)&0b11)==0b11; } public int getFlowLabel() { return ((IPv6header.get(1) & 0b00001111) << 16) | (IPv6header.getShort(2) & 0xffff); } public void setFlowLabel(int flowLabel) { IPv6header.put(1, (byte) (IPv6header.get(1) & 0b11110000 | (flowLabel >>> 16))); IPv6header.putShort(2, (short) flowLabel); } public int getPayloadLength() { return IPv6header.getShort(4) & 0xffff; } public void setPayloadLength(int payloadLength) { IPv6header.putShort(4, (short) payloadLength); } public int getNextHeader() { return IPv6header.get(6) & 0xff; } public void setNextHeader(int nextHeader) { IPv6header.put(6, (byte) nextHeader); } public int getHopLimit() { return IPv6header.get(7) & 0xff; } public void setHopLimit(int hopLimit) { IPv6header.put(7, (byte) hopLimit); } public Inet6Address getSourceAddress() { byte[] b = new byte[16]; IPv6header.get(8, b, 0, b.length); try { return (Inet6Address) Inet6Address.getByAddress(b); } catch (UnknownHostException e) { return null; } } public void setSourceAddress(Inet6Address sourceAddress) { byte[] b = sourceAddress.getAddress(); IPv6header.put(8, b, 0, b.length); } public Inet6Address getDestinationAddress() { byte[] b = new byte[16]; IPv6header.get(24, b, 0, b.length); try { return (Inet6Address) Inet6Address.getByAddress(b); } catch (UnknownHostException e) { return null; } } public void setDestinationAddress(Inet6Address destinationAddress) { byte[] b = destinationAddress.getAddress(); IPv6header.put(24, b, 0, b.length); } public FlowSession getFlowSession() { return new FlowSession(getSourceAddress(), getDestinationAddress(), getFlowLabel()); } private int calcPayloadLength() { int lth=0; for (int i = 0; i < headers.size(); i++) { lth+= headers.get(i).getLength(); } lth+=payload.getLength(); return lth; } @Override public long getLength() { return calcPayloadLength()+IPv6_HEADER_LENGTH; } @Override public void doDisposeAfterSend() { super.doDisposeAfterSend(); payload.doDisposeAfterSend(); } @Override public void dispose() { super.dispose(); /*ByteBuffer headerx = IPv6header; IPv6header = null; if(headerx!=null) NetworkPacket.databufferpool_40.back(headerx);*/ } @Override public void disposeAll() { super.disposeAll(); for (int i = 0; i < headers.size(); i++) { headers.get(i).disposeAll(); } payload.disposeAll(); } @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 iterator = headers.iterator(); iterator.hasNext();) { IPv6ExtHeader iPv6ExtHeader = (IPv6ExtHeader) iterator.next(); if(iPv6ExtHeader.isSomeDisposed()) return true; } return false; } @Override public void unlockAll() { payload.unlockAll(); for (int i = 0; i < headers.size(); i++) { headers.get(i).unlockAll(); } super.unlockAll(); } @Override public String toString() { return "IPv6Packet [getVersion()=" + getVersion() + ", getTrafficClass()=" + getTrafficClass() + ", getFlowLabel()=" + getFlowLabel() + ", getPayloadLength()=" + getPayloadLength() + ", getNextHeader()=" + getNextHeader() + ", getHopLimit()=" + getHopLimit() + ", getSourceAddress()=" + getSourceAddress() + ", getDestinationAddress()=" + getDestinationAddress() + ", getLength()=" + getLength() + ", headers=" + headers + ", payload=" + payload + "]"; } public static class IPv6Payload extends NetworkPacket{ private ByteBuffer data ; private boolean onDefault=true; public ByteBuffer getData() { return data; } private int protocolNumber; public IPv6Payload(int protocolNumber) { this(protocolNumber,true); } protected IPv6Payload(int protocolNumber,boolean isonDefault) { this.protocolNumber = protocolNumber; this.onDefault=isonDefault; if(onDefault) this.data=NetworkPacket.databufferpool_65535.borrow(); } public int getProtocolNumber() { return protocolNumber; } public long getLength() { return data.limit(); } @Override protected void writeToChannel(WritableByteChannel dto) throws IOException { if(onDefault) dto.write(data.slice(0,data.limit())); } @Override protected void readFromChannel(ReadableByteChannel din, long length) throws IOException { if(onDefault) { data.limit((int) length); while (data.hasRemaining()) { if (din.read(data) == -1) { throw new EOFException(); } } } } @Override public void dispose() { super.dispose(); /*if(onDefault) { ByteBuffer datax = data; data = null; NetworkPacket.databufferpool_65535.back(datax); }*/ } @Override protected boolean needEndPosition() { return true; } } public static class IPv6ExtHeader extends NetworkPacket{ private ByteBuffer data ; private int protocolNumber; private boolean onDefault=true; @Override public String toString() { return "IPv6ExtHeader [protocolNumber=" + protocolNumber + ", getNextHeader()=" + getNextHeader() + ", getExtLength()=" + getExtLength() + "]"; } public ByteBuffer getData() { return data; } public IPv6ExtHeader(int type) { this(type,true); } protected IPv6ExtHeader(int protocolNumber,boolean isonDefault) { this.protocolNumber = protocolNumber; this.onDefault=isonDefault; if(onDefault) { this.data=NetworkPacket.databufferpool_2048.borrow(); }else { this.data=NetworkPacket.databufferpool_40.borrow(); } } protected IPv6ExtHeader(int protocolNumber,boolean isonDefault,ByteBuffer data) { this.protocolNumber = protocolNumber; this.onDefault=isonDefault; this.data=data; } public int getProtocolNumber() { return protocolNumber; } public int getNextHeader() { return data.get(0) & 0xff; } public void setNextHeader(int nextHeader) { data.put(0, (byte) nextHeader); } public int getExtLength() { return data.get(1) & 0xff; } protected void setExtLength(int extLength) { data.put(1, (byte) extLength); } public long getLength() { return data.limit(); } @Override protected void writeToChannel(WritableByteChannel dto) throws IOException { if(onDefault) { int ext=(data.limit()-8)/8; setExtLength(ext); dto.write(data.slice(0,data.limit())); }else { dto.write(data.slice(0,8)); } } @Override protected void readFromChannel(ReadableByteChannel din, long length) throws IOException { data.limit(8); while (data.hasRemaining()) { if (din.read(data) == -1) { throw new EOFException(); } } if(onDefault) { int newLimit=getExtLength()*8+data.limit(); data.limit(newLimit); while (data.hasRemaining()) { if (din.read(data) == -1) { throw new EOFException(); } } } } @Override protected boolean needEndPosition() { return false; } @Override public void dispose() { super.dispose(); /*ByteBuffer bbft=data; data=null; if(bbft!=null) { if(bbft.capacity()==40) { NetworkPacket.databufferpool_40.back(bbft); }else { NetworkPacket.databufferpool_2048.back(bbft); } }*/ } } public static class IPv6RoutingHeader extends IPv6ExtHeader{ @Override public String toString() { return "IPv6RoutingHeader [protocolNumber=" + getProtocolNumber() + ", getNextHeader()=" + getNextHeader() + ", getExtLength()=" + getExtLength()+ ", getRoutingType()="+getRoutingType() + "]"; } public IPv6RoutingHeader() { super(43); } public IPv6RoutingHeader(boolean onDefault) { super(43,onDefault); } public IPv6RoutingHeader( boolean isonDefault, ByteBuffer data) { super(43, isonDefault, data); } public int getRoutingType() { return getData().get(2)&0xff; } 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); } } public static class IPv6SegmentRoutingHeader extends IPv6RoutingHeader{ private final List addresses=new ArrayList(); private final List tlvs=new ArrayList(); @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(false); setRoutingType(4); } public IPv6SegmentRoutingHeader(ByteBuffer bbf) { super(false,bbf); } public IPv6SegmentRoutingHeader(List segs) { this(); this.addresses.addAll( segs); int ln=addresses.size()-1; setLastEntry(ln); setSegmentsLeft(ln); } public int getLastEntry() { return getData().get(4)&0xff; } public void setLastEntry(int lastEntry) { getData().put(4, (byte) lastEntry); } public int getFlags() { return getData().get(5)&0xff; } public void setFlags(int flags) { getData().put(5,(byte) flags); } public int getTag() { return getData().getShort(6)&0xffff; } public void setTag(int tag) { getData().putShort(6,(short) tag); } public List getAddresses() { return addresses; } @Override protected void writeToChannel(WritableByteChannel dto) throws IOException { setExtLength(calcExtLength()/8); setLastEntry(addresses.size()-1); super.writeToChannel(dto); for (Iterator iterator = addresses.iterator(); iterator.hasNext();) { Inet6Address inet6Address = (Inet6Address) iterator.next(); dto.write(ByteBuffer.wrap(inet6Address.getAddress())); } } private int calcExtLength() { int tlvsl=0; for (Iterator iterator = tlvs.iterator(); iterator.hasNext();) { IPv6SegmentRoutingTLV tlve = (IPv6SegmentRoutingTLV) iterator.next(); tlvsl+=tlve.getLength(); } return addresses.size()*16+tlvsl; } @Override protected void readFromChannel(ReadableByteChannel din, long length) throws IOException { super.readFromChannel(din, length); int extl=getExtLength(); int laste=getLastEntry(); int rl=extl*8; int usdl=0; //System.out.println("SR length:"+(laste+1)); addresses.clear(); ByteBuffer bfr=ByteBuffer.allocate(16); 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); } return; } @Override public long getLength() { return calcExtLength()+8; } } public static class IPv6DestinationHeader extends IPv6ExtHeader{ @Override public String toString() { return "IPv6DestinationHeader [protocolNumber=" + getProtocolNumber() + ", getNextHeader()=" + getNextHeader() + ", getExtLength()=" + getExtLength()+ ", getRoutingType()="+getRoutingType() + "]"; } public IPv6DestinationHeader() { super( 60); } public int getRoutingType() { return getData().get(2)&0xff; } 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); } } public List getHeaders() { return headers; } /*public IPv6DestinationHeader insertDestinationHeader(int index,int extLength) { long ptr; long lth=extLength*8+8; if(index==headers.size()) { ptr=payload.getPointer(); }else if(index=headers.size()) { irh.setNextHeader(payload.getType()); }else { irh.setNextHeader(headers.get(index).getType()); } if(index-1<0) { setNextHeader(irh.getType()); }else { headers.get(index-1).setNextHeader(irh.getType()); } headers.add(index, irh); analyse(); return irh; } public IPv6RoutingHeader insertSRHRoutingHeader(int index,IpV6RoutingSRHData srh) { long ptr; long lth=srh.length()+4; if(index==headers.size()) { ptr=payload.getPointer(); }else if(index=headers.size()) { irh.setNextHeader(payload.getType()); }else { irh.setNextHeader(headers.get(index).getType()); } if(index-1<0) { setNextHeader(irh.getType()); }else { headers.get(index-1).setNextHeader(irh.getType()); } headers.add(index, irh); irh.setRoutingType(4); irh.setSegmentsLeft(srh.getLastEntry()); irh.getData().put(4, srh.getRawData()); analyse(); return irh; }*/ @Override protected boolean needEndPosition() { return false; } }