Java tutorial
/* * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.snbi.southplugin; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.UnknownHostException; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.cert.CertificateFactory; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SnbiPkt { // logger private static final Logger log = LoggerFactory.getLogger(SnbiInternal.class); // 4 bit protocol version field. private byte protocolVersion; // 4 bit reserved bits. private byte reservedBits; // 8 bits protocol type. private SnbiProtocolType protocolType; // 8 bit reserved flags. private Short flags; // 8 bits hop limit, number of hops a message can traverse. private Short hopLimit; // 16 bits Msg type. private SnbiMsgType msgType; // 16 bit msg length. private Integer msgLength; // 16 bits msg number. private Integer msgNumber; // 16 bits reserver bits. private Integer reserved_2; // TLV hash list. private Map<Integer, TLV> TLVHashList = null; // src IP address private InetAddress srcIP; // Dst IP address private InetAddress dstIP; /* * Header length is a combination of the following. protocol version (4bits) * + reserved bits (4bits) + protocol type (8bits) + flags (8bits) + * hoplimit (8bits) + message type (16bits) + msglength (16bits) + msgNumber (16bits) + * reserved_2 (16bits) */ private static final byte SNBIHEADERLENGTH = 12; /* * The interface on which the packet was received on. */ private NetworkInterface ingressIntf = null; private NetworkInterface egressIntf = null; /** * Constructor to create an SNBI packet from the protocol type and message * type. * * @param protocolType * - The protocol type of the message to be transmitted or * received. * @param msgType * - The message type of the message to be transmitted or * received. */ public SnbiPkt(SnbiProtocolType protocolType, SnbiMsgType msgType) { initPkt(); this.protocolVersion = 1; this.reservedBits = 0; this.protocolType = protocolType; this.msgType = msgType; // 1 byte reservedBits + ProtocolVersion, 1 byte protocolType, 1 byte // flags, 1 byte hoplimit, 2 bytes msgType, 2 byte msglength. this.msgLength = (int) SNBIHEADERLENGTH; } /** * Create an SNBI packet from the byte stream received. * * @param rcvStream * - The byte stream. * @param msgLength * - The length of the received data. * @throws BufferOverflowException */ public SnbiPkt(byte[] rcvStream, int msgLength) throws BufferOverflowException { if (rcvStream == null || msgLength == 0) { return; } initPkt(); try { ByteBuffer msgByteStream = null; msgByteStream = ByteBuffer.allocate(msgLength); msgByteStream.put(rcvStream, 0, msgLength); msgByteStream.flip(); parseMsgByteStream(msgByteStream); } catch (BufferOverflowException excpt) { log.error("Buffer overflow exception " + excpt); throw excpt; } } private void initPkt() { this.protocolVersion = 1; this.reservedBits = 0; this.hopLimit = 255; // 1 byte reservedBits + ProtocolVersion, 1 byte protocolType, 1 byte // flags, 1 byte hoplimit, 2 bytes msgType, 2 byte msglength. this.msgLength = 0; this.flags = 0; this.msgNumber = 0; this.reserved_2 = 0; this.srcIP = null; this.dstIP = null; this.ingressIntf = null; this.egressIntf = null; this.TLVHashList = new HashMap<Integer, TLV>(); } /* * Parse the message stream received. */ private void parseMsgByteStream(ByteBuffer msgByteStream) { parseMsgHeader(msgByteStream); parseMsgTLVs(msgByteStream); } /* * Parse the message headers. */ private void parseMsgHeader(ByteBuffer msgByteStream) { Byte byteval; int reservedVersion = msgByteStream.get(); // Get the first byte reserver bit + protocol version. reservedBits = (byte) (reservedVersion & 0x000f); protocolVersion = (byte) (reservedVersion >> 4 & 0x000f); protocolType = SnbiProtocolType.getEnumFromValue((short) msgByteStream.get()); flags = (short) msgByteStream.get(); byteval = msgByteStream.get(); hopLimit = byteval.shortValue(); msgType = SnbiMsgType.getEnumFromValue((int) msgByteStream.getShort()); msgLength = (int) msgByteStream.getShort(); msgNumber = (int) msgByteStream.getShort(); reserved_2 = (int) msgByteStream.getShort(); } /* * Parse the TLVs. */ private void parseMsgTLVs(ByteBuffer msgByteStream) { TLV tlv = null; int tlvType; int length; byte[] value = null; // For now we assume that we have parsed over the headers. Parse the // TLVs now. while (msgByteStream.hasRemaining()) { tlvType = msgByteStream.getShort(); length = msgByteStream.getShort() - TLV.SNBITLVHEADERLENGTH; value = new byte[length]; msgByteStream.get(value); tlv = new TLV(tlvType, value, length); // Only add the TLV, no need to increment the message length. addTLVInternal(tlv); } } /** * The network interface on which the packet should be sent out on. * * @param intf * - The interface on which the packet should be sent out on or * received from. */ public void setIngressInterface(NetworkInterface intf) { this.ingressIntf = intf; } public void setEgressInterface(NetworkInterface intf) { this.egressIntf = intf; } /** * Get the network interface. * * @return - The network interface that is set on the packet. */ public NetworkInterface getIngressInterface() { return (this.ingressIntf); } public NetworkInterface getEgressInterface() { return (this.egressIntf); } public InetAddress getSrcIP() { return this.srcIP; } public void setSrcIP(InetAddress addr) { this.srcIP = addr; } public InetAddress getDstIP() { return this.dstIP; } public void setDstIP(InetAddress addr) { this.dstIP = addr; } /** * Get the current message length of the packet. * * @return The message length. */ public int getMsgLength() { return msgLength; } /** * Get the message type of the packet. * * @return - The message type of the packet. */ public SnbiMsgType getmsgType() { return msgType; } /** * Get the version field in the packet. * * @return - The version field of the message. */ public byte getVersion() { return protocolVersion; } /** * Get the protocol type of the message. * * @return - The protocol type. */ public SnbiProtocolType getProtocolType() { return protocolType; } /** * Get a byte stream message constructed from the set of the TLVs and SNBI * header. * * @return - The byte stream. */ public byte[] getMsg() { ByteBuffer msgByteStream = null; msgByteStream = ByteBuffer.allocate(this.msgLength); updateByteStreamWithMsgHeader(msgByteStream); updateByteStreamWithMsgTLVs(msgByteStream); return msgByteStream.array(); } private void updateByteStreamWithMsgHeader(ByteBuffer msgByteStream) { if (msgByteStream == null) { return; } msgByteStream.put((byte) (reservedBits | protocolVersion << 4)); msgByteStream.put(protocolType.getValue().byteValue()); msgByteStream.put(flags.byteValue()); msgByteStream.put(hopLimit.byteValue()); msgByteStream.putShort(msgType.getValue().shortValue()); msgByteStream.putShort(msgLength.shortValue()); msgByteStream.putShort(msgNumber.shortValue()); msgByteStream.putShort(reserved_2.shortValue()); } private void updateByteStreamWithMsgTLVs(ByteBuffer msgByteStream) { short tlvlength = 0; if (msgByteStream == null) { return; } for (Entry<Integer, TLV> TLVlistEntry : TLVHashList.entrySet()) { TLV tlv = TLVlistEntry.getValue(); msgByteStream.putShort(tlv.getType().shortValue()); tlvlength = (short) (TLV.SNBITLVHEADERLENGTH + tlv.getLength().shortValue()); msgByteStream.putShort(tlvlength); msgByteStream.put(tlv.getValue()); } } public String getIfNameTLV() { Short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { return (this.getStringTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_IF_NAME.getValue())); } else { log.error("Cannot setIfName for protocol type " + this.protocolType); } return null; } // Add the Interface name to the TLV list. public void setIfNameTLV(NetworkInterface intf) { Short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { this.setStringTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_IF_NAME.getValue(), intf.getName()); } else { log.error("Cannot setIfName for protocol type " + this.protocolType); } } private void addIPV6addrTLV(int type, InetAddress inetAddress) { this.addTLV(new TLV(type, inetAddress.getAddress(), inetAddress.getAddress().length)); } // Add the link local address to the TLV list. public void setIPV6LLTLV(NetworkInterface intf) { Short protocolValue = this.protocolType.getValue(); Enumeration<InetAddress> inetAddresses = intf.getInetAddresses(); for (InetAddress inetAddress : Collections.list(inetAddresses)) { if (inetAddress.isLinkLocalAddress()) { if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { addIPV6addrTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_IF_V6ADDR.getValue(), inetAddress); } else if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { addIPV6addrTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_IF_V6ADDR.getValue(), inetAddress); } else { log.error("Cannot set IPV6LLTLV for protocol type " + this.protocolType); } return; } } } public InetAddress getIPV6LLTLV() { Short protocolValue = this.protocolType.getValue(); int tlvType = 0; if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { tlvType = SnbiNdTlvType.SNBI_ND_TLV_TYPE_IF_V6ADDR.getValue(); } else if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { tlvType = SnbiBsTlvType.SNBI_BS_TLV_TYPE_IF_V6ADDR.getValue(); } else { log.error("Cannot get IPV6LLTLV for protocol type " + this.protocolType); return null; } return getIPTLV(tlvType); } /** * Get the first string value in the TLV list corresponding to a type. * * @param type * - The type of the TLV. * @param stype * - The subtype of the TLV. * @return - The TLV string corresponding to a type and subtype. */ private String getStringTLV(int type) { TLV tlv = getTLV(type); if (tlv == null) { return null; } int strByteLength = tlv.getLength() - 1; // Ignore the null character. byte[] tmpStrByteArr = new byte[strByteLength]; System.arraycopy(tlv.getValue(), 0, tmpStrByteArr, 0, strByteLength); return new String(tmpStrByteArr); } private void setStringTLV(int type, String str) { // Stupid FE implementation requires null terminating string as well. byte nullCh = 0; int strByteLength = str.getBytes().length; byte[] tmpStrByteArr = new byte[strByteLength + 1]; System.arraycopy(str.getBytes(), 0, tmpStrByteArr, 0, strByteLength); tmpStrByteArr[strByteLength] = nullCh; this.addTLV(new TLV(type, tmpStrByteArr, tmpStrByteArr.length)); } public String getUDITLV() { short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { return (getStringTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_UDI.getValue())); } else if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { return (getStringTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_UDI.getValue())); } log.error("Cannot get UDITLV for protocol type " + this.protocolType); return null; } public void setUDITLV(String udi) { short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { setStringTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_UDI.getValue(), udi); } else if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { setStringTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_UDI.getValue(), udi); } else { log.error("Cannot set UDITLV for protocol type " + this.protocolType); } } /** * Get the TLV list of a particular type. * * @param type * - The type of the TLV. * @return the TLV list for a particular type. */ public TLV getTLV(int type) { if (TLVHashList == null) { return null; } return TLVHashList.get(type); } private void addTLVInternal(TLV tlv) { if (TLVHashList == null) { this.TLVHashList = new HashMap<Integer, TLV>(); } TLVHashList.put(tlv.getType(), tlv); } private InetAddress getIPTLV(int type) { TLV tlv = getTLV(type); if (tlv == null) { return null; } try { return InetAddress.getByAddress(tlv.getValue()); } catch (UnknownHostException e) { return null; } } public void setDeviceIDTLV(String deviceID) { short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { this.setStringTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_DEVICE_ID.getValue(), deviceID); } else if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { this.setStringTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_DEVICE_ID.getValue(), deviceID); } else { log.error("Cannot set DeviceID for protocol type " + this.protocolType); } } public String getDeviceIDTLV() { short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { return this.getStringTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_DEVICE_ID.getValue()); } else if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { return this.getStringTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_DEVICE_ID.getValue()); } else { log.error("Cannot get DeviceID for protocol type " + this.protocolType); } return null; } public String getDomainIDTLV() { short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { return this.getStringTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_DOMAIN_ID.getValue()); } else if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { return this.getStringTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_DOMAIN_ID.getValue()); } else { log.error("Cannot get DomainID for protocol type " + this.protocolType); } return null; } public void setDomainIDTLV(String domainName) { short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { this.setStringTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_DOMAIN_ID.getValue(), domainName); } else if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { this.setStringTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_DOMAIN_ID.getValue(), domainName); } else { log.error("Cannot set UDITLV for protocol type " + this.protocolType); } } public void setRegistrarIPaddrTLV(InetAddress addr) { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot add registart IP for protocol type " + this.protocolType); } addIPV6addrTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_RA_V6ADDR.getValue(), addr); } public InetAddress getRegistrarIPaddrTLV() { InetAddress inetaddr; short protocolValue = this.protocolType.getValue(); int tlvType; if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { tlvType = SnbiBsTlvType.SNBI_BS_TLV_TYPE_RA_V6ADDR.getValue(); inetaddr = getIPTLV(tlvType); if (inetaddr == null) { // if there is no IPV6 address try IPV4. tlvType = SnbiBsTlvType.SNBI_BS_TLV_TYPE_IF_V4ADDR.getValue(); inetaddr = getIPTLV(tlvType); } return inetaddr; } else { log.error("Cannot set UDITLV for protocol type " + this.protocolType); } return null; } private void addCertTLV(Integer type, X509Certificate cert) { byte[] certDer = null; try { certDer = cert.getEncoded(); } catch (CertificateEncodingException e) { log.error("Failed to add DER TLV type " + type); e.printStackTrace(); } this.addTLV(new TLV(type, certDer, certDer.length)); } private X509Certificate getCertTLV(int type) { TLV tlv = getTLV(type); if (tlv == null) { return null; } try { ByteArrayInputStream bis = new ByteArrayInputStream(tlv.getValue()); CertificateFactory cf = CertificateFactory.getInstance("X.509"); return (java.security.cert.X509Certificate) cf.generateCertificate(bis); } catch (CertificateException e) { log.error("Failed to obtain certificate of type " + type); e.printStackTrace(); } return null; } public void setCACertTLV(X509Certificate x509Certificate) { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot set CA certTLV for protocol type " + this.protocolType); return; } addCertTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_CA_CERTIFICATE.getValue(), x509Certificate); } public X509Certificate getCACertTLV() { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot get CA certTLV for protocol type " + this.protocolType); return null; } return getCertTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_CA_CERTIFICATE.getValue()); } /** * Add a TLV to the message. * * @param tlv * - The TLV to be added. */ private void addTLV(TLV tlv) { // Update the message length. this.msgLength += (TLV.SNBITLVHEADERLENGTH + tlv.getLength()); addTLVInternal(tlv); } public void setRegistrarCertTLV(X509Certificate cert) { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot set registar certTLV for protocol type " + this.protocolType); return; } addCertTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_RA_CERTIFICATE.getValue(), cert); } public X509Certificate getDomainCertTLV() { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot get Domain certTLV for protocol type " + this.protocolType); return null; } return getCertTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_DOMAIN_CERTIFICATE.getValue()); } public void setDomainCertTLV(X509Certificate cert) { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot set Domain certTLV for protocol type " + this.protocolType); return; } addCertTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_DOMAIN_CERTIFICATE.getValue(), cert); } public PKCS10CertificationRequest getPKCS10CSRTLV() { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot get pkc10 req for protocol type " + this.protocolType); return null; } TLV tlv = getTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_CERT_REQ.getValue()); try { PKCS10CertificationRequest pkcs10 = new PKCS10CertificationRequest(tlv.getValue()); return pkcs10; } catch (IOException e) { log.error("Failed to obtain PKCS10 from packet"); e.printStackTrace(); return null; } } public void setRegistrarIDTLV(String registrarID) { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot set registar ID for protocol type " + this.protocolType); return; } this.setStringTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_RA_ID.getValue(), registrarID); } public String getRegistrarIDTLV() { short protocolValue = this.protocolType.getValue(); if (protocolValue != SnbiProtocolType.SNBI_PROTOCOL_BOOTSTRAP.getValue()) { log.error("Cannot get registar ID for protocol type " + this.protocolType); return null; } return this.getStringTLV(SnbiBsTlvType.SNBI_BS_TLV_TYPE_RA_ID.getValue()); } public void setDeviceIPv6TLV(InetAddress nodeAddress) { short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { addIPV6addrTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_DEVICE_V6ADDR.getValue(), nodeAddress); } else { log.error("Cannot set UDITLV for protocol type " + this.protocolType); } } public InetAddress gettDeviceIPv6TLV() { short protocolValue = this.protocolType.getValue(); if (protocolValue == SnbiProtocolType.SNBI_PROTOCOL_ADJACENCY_DISCOVERY.getValue()) { return (getIPTLV(SnbiNdTlvType.SNBI_ND_TLV_TYPE_DEVICE_V6ADDR.getValue())); } else { log.error("Cannot set UDITLV for protocol type " + this.protocolType); } return null; } } /** * SNBI TLV class This is different from the normal type in that it contains a * type. */ class TLV { private Integer type; // 16 bits + 2 byte = 32 bits. private Integer length; // 16 bits + 2 byte = 32 bits private byte[] value; /* * TLV header length Type (16 bits) + Length (16bits). */ public static final byte SNBITLVHEADERLENGTH = 4; /** * create TLV with the given type, subtype, value and length. * * @param type * @param value * @param length */ public TLV(Integer type, byte[] value, Integer length) { this.type = type; this.length = length; this.value = value; } /** * Get the type of the TLV. */ public Integer getType() { return type; } /** * Get the length of the value. * * @return - The length of the value. */ public Integer getLength() { return length; } /** * Get the value of the TLV. * * @return - The value of the TLV. */ public byte[] getValue() { return value; } }