[ONOS-2596] BGP Open message validation
Change-Id: I2da98830159ed57e3727aae8d02af9f438586815
diff --git a/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPErrorType.java b/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPErrorType.java
index f643ae0..9ca7ee3 100644
--- a/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPErrorType.java
+++ b/bgp/bgpio/src/main/java/org/onosproject/bgpio/types/BGPErrorType.java
@@ -28,8 +28,8 @@
public static final byte OPEN_MESSAGE_ERROR = 2;
public static final byte UPDATE_MESSAGE_ERROR = 3;
public static final byte HOLD_TIMER_EXPIRED = 4;
- public static final byte FINITE_STATE_MACHINE_ERROR = 4;
- public static final byte CEASE = 5;
+ public static final byte FINITE_STATE_MACHINE_ERROR = 5;
+ public static final byte CEASE = 6;
//Message Header Error subcodes
public static final byte CONNECTION_NOT_SYNCHRONIZED = 1;
@@ -42,6 +42,7 @@
public static final byte BAD_BGP_IDENTIFIER = 3;
public static final byte UNSUPPORTED_OPTIONAL_PARAMETER = 4;
public static final byte UNACCEPTABLE_HOLD_TIME = 5;
+ public static final byte UNSUPPORTED_CAPABILITY = 7;
//UPDATE Message Error subcodes
public static final byte MALFORMED_ATTRIBUTE_LIST = 1;
diff --git a/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java b/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java
index 4e419c8..7f47a02 100755
--- a/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java
+++ b/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java
@@ -17,14 +17,20 @@
package org.onosproject.bgp.controller.impl;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import java.net.UnknownHostException;
import java.nio.channels.ClosedChannelException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.LinkedList;
+import java.util.ListIterator;
import java.util.concurrent.RejectedExecutionException;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
@@ -47,6 +53,10 @@
import org.onosproject.bgpio.protocol.BGPOpenMsg;
import org.onosproject.bgpio.protocol.BGPType;
import org.onosproject.bgpio.protocol.BGPVersion;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.types.FourOctetAsNumCapabilityTlv;
+import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -56,7 +66,7 @@
class BGPChannelHandler extends IdleStateAwareChannelHandler {
private static final Logger log = LoggerFactory.getLogger(BGPChannelHandler.class);
-
+ static final int BGP_MIN_HOLDTIME = 3;
static final int BGP_MAX_KEEPALIVE_INTERVAL = 3;
private BGPPeer bgpPeer;
private BGPId thisbgpId;
@@ -68,6 +78,13 @@
private int peerIdentifier;
private BGPPacketStatsImpl bgpPacketStats;
static final int MAX_WRONG_COUNT_PACKET = 5;
+ static final byte MULTI_PROTOCOL_EXTN_CAPA_TYPE = 1;
+ static final byte FOUR_OCTET_AS_NUM_CAPA_TYPE = 65;
+ static final int AS_TRANS = 23456;
+ static final int MAX_AS2_NUM = 65535;
+ static final short AFI = 16388;
+ static final byte RES = 0;
+ static final byte SAFI = 71;
// State needs to be volatile because the HandshakeTimeoutHandler
// needs to check if the handshake is complete
@@ -636,15 +653,197 @@
}
/**
- * Open message validation.
+ * BGP open message validation.
*
* @param h channel handler
- * @param pOpenmsg open message
- * @return true if validation succeed, otherwise false
- * @throws BGPParseException when received invalid message
+ * @param openMsg open message
+ * @return true if valid message, otherwise false
+ * @throws BGPParseException throw exception
*/
- public boolean openMsgValidation(BGPChannelHandler h, BGPOpenMsg pOpenmsg) throws BGPParseException {
- // TODO: Open message validation.
+ public boolean openMsgValidation(BGPChannelHandler h, BGPOpenMsg openMsg) throws BGPParseException {
+ boolean result;
+
+ // Validate BGP ID
+ result = bgpIdValidation(openMsg);
+ if (!result) {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.BAD_BGP_IDENTIFIER, null);
+ }
+
+ // Validate AS number
+ result = asNumberValidation(h, openMsg);
+ if (!result) {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.BAD_PEER_AS, null);
+ }
+
+ // Validate hold timer
+ if ((openMsg.getHoldTime() != 0) && (openMsg.getHoldTime() < BGP_MIN_HOLDTIME)) {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.UNACCEPTABLE_HOLD_TIME, null);
+ }
+
+ // Validate capabilities
+ result = capabilityValidation(h, openMsg);
+ return result;
+ }
+
+ /**
+ * Capability Validation.
+ *
+ * @param h channel handler
+ * @param openmsg open message
+ * @return success or failure
+ * @throws BGPParseException
+ */
+ private boolean capabilityValidation(BGPChannelHandler h, BGPOpenMsg openmsg) throws BGPParseException {
+ log.debug("capabilityValidation");
+
+ boolean isMultiProtocolcapabilityExists = false;
+ boolean isFourOctetCapabilityExits = false;
+ int capAsNum = 0;
+
+ List<BGPValueType> capabilityTlv = openmsg.getCapabilityTlv();
+ ListIterator<BGPValueType> listIterator = capabilityTlv.listIterator();
+ List<BGPValueType> unSupportedCapabilityTlv = new LinkedList<>();
+ ListIterator<BGPValueType> unSupportedCaplistIterator = unSupportedCapabilityTlv.listIterator();
+ BGPValueType tempTlv;
+ boolean isLargeAsCapabilityCfg = h.bgpconfig.getLargeASCapability();
+ boolean isLsCapabilityCfg = h.bgpconfig.getLsCapability();
+
+ while (listIterator.hasNext()) {
+ BGPValueType tlv = listIterator.next();
+ if (tlv.getType() == MULTI_PROTOCOL_EXTN_CAPA_TYPE) {
+ isMultiProtocolcapabilityExists = true;
+ }
+ if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
+ isFourOctetCapabilityExits = true;
+ capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
+ }
+ }
+
+ if (isFourOctetCapabilityExits) {
+ if (capAsNum > MAX_AS2_NUM) {
+ if (openmsg.getAsNumber() != AS_TRANS) {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.BAD_PEER_AS, null);
+ }
+ } else {
+ if (capAsNum != openmsg.getAsNumber()) {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.BAD_PEER_AS, null);
+ }
+ }
+ }
+
+ if ((isLsCapabilityCfg)) {
+ if (!isMultiProtocolcapabilityExists) {
+ tempTlv = new MultiProtocolExtnCapabilityTlv(AFI, RES, SAFI);
+ unSupportedCapabilityTlv.add(tempTlv);
+ }
+ }
+
+ if ((isLargeAsCapabilityCfg)) {
+ if (!isFourOctetCapabilityExits) {
+ tempTlv = new FourOctetAsNumCapabilityTlv(h.bgpconfig.getAsNumber());
+ unSupportedCapabilityTlv.add(tempTlv);
+ }
+ }
+
+ if (unSupportedCaplistIterator.hasNext()) {
+ ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
+ while (unSupportedCaplistIterator.hasNext()) {
+ BGPValueType tlv = unSupportedCaplistIterator.next();
+ tlv.write(buffer);
+ }
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
+ BGPErrorType.UNSUPPORTED_CAPABILITY, buffer);
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * AS Number Validation.
+ *
+ * @param h channel Handler
+ * @param openMsg open message
+ * @return true or false
+ */
+ private boolean asNumberValidation(BGPChannelHandler h, BGPOpenMsg openMsg) {
+ log.debug("AS Num validation");
+
+ int capAsNum = 0;
+ boolean isFourOctetCapabilityExits = false;
+
+ BGPPeerCfg peerCfg = h.bgpconfig.displayPeers(peerAddr);
+ List<BGPValueType> capabilityTlv = openMsg.getCapabilityTlv();
+ ListIterator<BGPValueType> listIterator = capabilityTlv.listIterator();
+
+ while (listIterator.hasNext()) {
+ BGPValueType tlv = listIterator.next();
+ if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
+ isFourOctetCapabilityExits = true;
+ capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
+ }
+ }
+
+ if (peerCfg.getAsNumber() > MAX_AS2_NUM) {
+ if (openMsg.getAsNumber() != AS_TRANS) {
+ return false;
+ }
+
+ if (!isFourOctetCapabilityExits) {
+ return false;
+ }
+
+ if (peerCfg.getAsNumber() != capAsNum) {
+ return false;
+ }
+
+ isIbgpSession = peerCfg.getIsIBgp();
+ if (isIbgpSession) {
+ // IBGP - AS number should be same for Peer and local if it is IBGP
+ if (h.bgpconfig.getAsNumber() != capAsNum) {
+ return false;
+ }
+ }
+ } else {
+
+ if (openMsg.getAsNumber() != peerCfg.getAsNumber()) {
+ return false;
+ }
+
+ if (isFourOctetCapabilityExits) {
+ if (capAsNum != peerCfg.getAsNumber()) {
+ return false;
+ }
+ }
+
+ isIbgpSession = peerCfg.getIsIBgp();
+ if (isIbgpSession) {
+ // IBGP - AS number should be same for Peer and local if it is IBGP
+ if (openMsg.getAsNumber() != h.bgpconfig.getAsNumber()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Validates BGP ID.
+ *
+ * @param openMsg open message
+ * @return true or false
+ */
+ private boolean bgpIdValidation(BGPOpenMsg openMsg) {
+ String openMsgBgpId = Ip4Address.valueOf(openMsg.getBgpId()).toString();
+
+ InetAddress ipAddress;
+ try {
+ ipAddress = InetAddress.getByName(openMsgBgpId);
+ if (ipAddress.isMulticastAddress()) {
+ return false;
+ }
+ } catch (UnknownHostException e) {
+ log.debug("InetAddress convertion failed");
+ }
return true;
}
}