最近在使用 Flutter 开发APP,有个功能需要解析 CIDR 详细信息,所以就是要 dart 写了一段.

CIDR 示例

192.168.1.3/27

解析要求

解析出 可用地址数,起始地址,结束地址,子网掩码,网络地址,广播地址。

代码如下

import 'dart:math';

///
/// [CidrCalculator] can be used to fetch summary information for CIDR address like "192.168.0.2/22".
///
class CidrCalculator {
  static const String PATTERN = r'^(?:'
      r'(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/([1-9]|[1-2]\d|3[0-2])$';

  static bool isValid(String cidr) {
    return RegExp(PATTERN).hasMatch(cidr);
  }

  /// parse cidr address info
  static CidrInfo parse(String cidr) {
    if (!isValid(cidr)) {
      throw Exception("CIDR $cidr is invalid.");
    }

    int _maskLength;
    String _mask;
    String _ip;
    String _network;
    String _broadcast;
    String _first;
    String _last;
    int _available;

    /// get mask from mask length
    String getMaskCodeFromMaskLength(int length) {
      String maskBinary = '1' * length + '0' * (32 - length);
      return int.parse(maskBinary.substring(0, 8), radix: 2).toString() +
          '.' +
          int.parse(maskBinary.substring(8, 16), radix: 2).toString() +
          '.' +
          int.parse(maskBinary.substring(16, 24), radix: 2).toString() +
          '.' +
          int.parse(maskBinary.substring(24, 32), radix: 2).toString();
    }

    /// split address by dot
    List<String> splitAddress(String ipAddress) {
      return ipAddress.split(r'.');
    }

    /// convert to bin list
    List<String> convertToBinaryArray(List<String> array) {
      for (int i = 0; i < array.length; i++) {
        array[i] = (int.parse(array[i]) + 256).toRadixString(2).substring(1);
      }
      return array;
    }

    /// get network ID
    String getNetworkId() {
      List<String> ipArr = splitAddress(_ip);
      List<String> maskArr = splitAddress(_mask);
      List<String> networkArr = List(4);
      for (int i = 0; i < 4; i++) {
        networkArr[i] =
            (int.parse(ipArr[i]) & int.parse(maskArr[i])).toString();
      }
      String networkId = networkArr.join('.');

      return networkId;
    }

    /// get network broadcast address
    String getNetworkBroadcast() {
      List<String> maskArr = splitAddress(_mask);
      List<String> networkIdArr = splitAddress(_network);
      String maskBinaryString = convertToBinaryArray(maskArr).join(r'.');
      int hostIndexOfMask = maskBinaryString.indexOf(r'0');
      String networkIdBinaryString =
          convertToBinaryArray(networkIdArr).join(r'.');
      String netAddressOfNetwork =
          networkIdBinaryString.substring(0, hostIndexOfMask);
      String hostOfNetwork = networkIdBinaryString
          .substring(hostIndexOfMask, networkIdBinaryString.length)
          .replaceAll(RegExp(r'\d'), '1');
      List<String> broadcastStringArr =
          (netAddressOfNetwork + hostOfNetwork).split(r'.');
      for (int i = 0; i < 4; i++) {
        broadcastStringArr[i] =
            int.parse(broadcastStringArr[i], radix: 2).toString();
      }
      return broadcastStringArr.join(r'.');
    }

    /// get first host in cidr
    String getNetworkStart() {
      List<String> networkIdArr = splitAddress(_network);
      networkIdArr[3] = (int.parse(networkIdArr[3]) + 1).toString();
      return networkIdArr.join('.');
    }

    /// get last host in cidr
    String getNetworkEnd() {
      List<String> broadcastArr = splitAddress(_broadcast);
      broadcastArr[3] = (int.parse(broadcastArr[3]) - 1).toString();
      return broadcastArr.join('.');
    }

    _maskLength = int.parse(cidr.substring(cidr.indexOf(r'/') + 1));
    _ip = cidr.substring(0, cidr.indexOf(r'/'));
    _mask = getMaskCodeFromMaskLength(_maskLength);
    _network = getNetworkId();
    _broadcast = getNetworkBroadcast();
    _first = getNetworkStart();
    _last = getNetworkEnd();
    _available = pow(2, 32 - _maskLength) - 2;

    return CidrInfo(
      mask: _mask,
      network: _network,
      broadcast: _broadcast,
      first: _first,
      last: _last,
      available: _available,
    );
  }
}

class CidrInfo {
  /// netmask
  final String mask;

  /// Subnet ID
  final String network;

  /// broadcast address
  final String broadcast;

  /// first host address
  final String first;

  /// last host address
  final String last;

  /// available host addresses
  final int available;

  const CidrInfo({
    this.mask,
    this.network,
    this.broadcast,
    this.first,
    this.last,
    this.available,
  });

  @override
  String toString() {
    return "mask: $mask\nnetwork: $network\nbroadcast: $broadcast\nfirst: "
        "$first\nlast: $last\navailable: $available";
  }
}

使用示例

CidrInfo cidrInfo = CidrCalculator.parse("192.168.1.3/27");
print(cidrInfo);

输出

mask: 255.255.255.224
network: 192.168.1.0
broadcast: 192.168.1.31
first: 192.168.1.1
last: 192.168.1.30
available: 30
文章目录