IpMatcher.java [src/csip] Revision:   Date:
/*
 * $Id$
 *
 * This file is part of the Cloud Services Integration Platform (CSIP),
 * a Model-as-a-Service framework, API and application suite.
 *
 * 2012-2022, Olaf David and others, OMSLab, Colorado State University.
 *
 * OMSLab licenses this file to you under the MIT license.
 * See the LICENSE file in the project root for more information.
 */
package csip;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;

/**
 * Matches an IP Address or subnet mask against another address.
 *
 */
class IpMatcher {

  int netMask = -1;
  InetAddress expectedIpAddr;


  IpMatcher(String expectedIp) throws UnknownHostException {
    if (expectedIp.indexOf('/') > 0) {
      String[] addrAndMask = expectedIp.split("/");
      expectedIp = addrAndMask[0];
      netMask = Integer.parseInt(addrAndMask[1]);
    }
    expectedIpAddr = InetAddress.getByName(expectedIp);
  }


  boolean matches(String actualIp) throws UnknownHostException {
    InetAddress actualIpAddr = InetAddress.getByName(actualIp);
    // compare v4 with v4 vs v6 with v6
    if (!expectedIpAddr.getClass().equals(actualIpAddr.getClass())) 
      return false;
    
    if (netMask == -1) 
      return actualIpAddr.equals(expectedIpAddr);

    int oddBits = netMask % 8;
    int netMaskBytes = netMask / 8 + (oddBits == 0 ? 0 : 1);
    byte[] mask = new byte[netMaskBytes];

    Arrays.fill(mask, 0, oddBits == 0 ? mask.length : mask.length - 1, (byte) 0xFF);

    if (oddBits != 0) {
      int finalByte = (1 << oddBits) - 1;
      finalByte <<= 8 - oddBits;
      mask[mask.length - 1] = (byte) finalByte;
    }

    byte[] actAddr = actualIpAddr.getAddress();
    byte[] expAddr = expectedIpAddr.getAddress();
    for (int i = 0; i < mask.length; i++) {
      if ((actAddr[i] & mask[i]) != (expAddr[i] & mask[i])) 
        return false;
    }
    return true;
  }

}