jdnssec-tools/src/main/java/com/verisignlabs/dnssec/security/TypeMap.java

201 lines
5.1 KiB
Java

// Copyright (C) 2004, 2022 Verisign, Inc.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
package com.verisignlabs.dnssec.security;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.xbill.DNS.DNSOutput;
import org.xbill.DNS.Type;
/**
* This class represents the multiple type maps of the NSEC record. Currently it
* is just used to convert the wire format type map to the int array that
* org.xbill.DNS.NSECRecord uses. Note that there is now a very similar class in
* DNSjava: {@link org.xbill.DNS.TypeBitmap}.
*/
public class TypeMap {
private static final Integer[] integerArray = new Integer[0];
private static final byte[] emptyBitmap = new byte[0];
private Set<Integer> typeSet;
public TypeMap() {
this.typeSet = new HashSet<Integer>();
}
/** Add the given type to the typemap. */
public void set(int type) {
typeSet.add(type);
}
/** Remove the given type from the type map. */
public void clear(int type) {
typeSet.remove(type);
}
/** @return true if the given type is present in the type map. */
public boolean get(int type) {
return typeSet.contains(type);
}
/**
* Given an array of DNS type code, construct a TypeMap object.
*/
public static TypeMap fromTypes(int[] types) {
TypeMap m = new TypeMap();
if (types == null)
return m;
for (int i = 0; i < types.length; i++) {
m.set(types[i]);
}
return m;
}
/**
* Given an array of bytes representing a wire-format type map, construct the
* TypeMap object.
*/
public static TypeMap fromBytes(byte[] map) {
int m = 0;
TypeMap typemap = new TypeMap();
int page;
int byte_length;
while (m < map.length) {
page = map[m++];
byte_length = map[m++];
for (int i = 0; i < byte_length; i++) {
for (int j = 0; j < 8; j++) {
if ((map[m + i] & (1 << (7 - j))) != 0) {
typemap.set((page << 8) + (i * 8) + j);
}
}
}
m += byte_length;
}
return typemap;
}
/**
* Given list of type mnemonics, construct a TypeMap object.
*/
public static TypeMap fromString(String types) {
TypeMap typemap = new TypeMap();
for (String type : types.split("\\s+")) {
typemap.set(Type.value(type));
}
return typemap;
}
/** @return the normal string representation of the typemap. */
public String toString() {
int[] types = getTypes();
Arrays.sort(types);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < types.length; i++) {
if (i > 0)
sb.append(" ");
sb.append(Type.string(types[i]));
}
return sb.toString();
}
protected static void mapToWire(DNSOutput out, int[] types, int base, int start, int end) {
// calculate the length of this map by looking at the largest
// typecode in this section.
int max_type = types[end - 1] & 0xFF;
int map_length = (max_type / 8) + 1;
// write the map "header" -- the base and the length of the map.
out.writeU8(base & 0xFF);
out.writeU8(map_length & 0xFF);
// allocate a temporary scratch space for caculating the actual
// bitmap.
byte[] map = new byte[map_length];
// for each type in our sub-array, set its corresponding bit in the map.
for (int i = start; i < end; i++) {
map[(types[i] & 0xFF) / 8] |= (1 << (7 - types[i] % 8));
}
// write out the resulting binary bitmap.
for (int i = 0; i < map.length; i++) {
out.writeU8(map[i]);
}
}
public byte[] toWire() {
int[] types = getTypes();
if (types.length == 0)
return emptyBitmap;
Arrays.sort(types);
int mapbase = -1;
int mapstart = -1;
DNSOutput out = new DNSOutput();
for (int i = 0; i < types.length; i++) {
int base = (types[i] >> 8) & 0xFF;
if (base == mapbase)
continue;
if (mapstart >= 0) {
mapToWire(out, types, mapbase, mapstart, i);
}
mapbase = base;
mapstart = i;
}
mapToWire(out, types, mapbase, mapstart, types.length);
return out.toByteArray();
}
public int[] getTypes() {
Integer[] a = (Integer[]) typeSet.toArray(integerArray);
int[] res = new int[a.length];
for (int i = 0; i < res.length; i++) {
res[i] = a[i].intValue();
}
return res;
}
public static int[] fromWireToTypes(byte[] wire_fmt) {
return TypeMap.fromBytes(wire_fmt).getTypes();
}
public static byte[] fromTypesToWire(int[] types) {
return TypeMap.fromTypes(types).toWire();
}
}