DnsRecordValueTranscoder.java
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bremersee.dccon.repository.ldap.transcoder;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import lombok.extern.slf4j.Slf4j;
import org.bremersee.dccon.model.DnsRecord;
import org.bremersee.dccon.repository.DnsRecordType;
import org.bremersee.exception.ServiceException;
import org.ldaptive.io.AbstractBinaryValueTranscoder;
/**
* The dns record value transcoder.
*
* @author Christian Bremer
*/
@Slf4j
public class DnsRecordValueTranscoder extends AbstractBinaryValueTranscoder<DnsRecord> {
private static final long ACTIVE_DIRECTORY_START_TIME;
static {
final GregorianCalendar cal = new GregorianCalendar();
cal.setTimeZone(TimeZone.getTimeZone("GMT"));
cal.set(1601, Calendar.JANUARY, 1, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
ACTIVE_DIRECTORY_START_TIME = cal.getTimeInMillis();
}
@Override
public DnsRecord decodeBinaryValue(final byte[] value) {
if (value == null || value.length < 24) {
return null;
}
try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(value))) {
int dataLength = Short.reverseBytes((short) dis.readUnsignedShort()); // 2 bytes
int type = Short.reverseBytes((short) dis.readUnsignedShort()); // 2 bytes
int version = dis.readUnsignedByte(); // 1 byte
int rank = dis.readUnsignedByte(); // 1 byte
int flags = Short.reverseBytes((short) dis.readUnsignedShort()); // 2 bytes
int serial = Integer.reverseBytes(dis.readInt()); // 4 bytes
int ttlSeconds = dis.readInt(); // 4 bytes
int reserved = Integer.reverseBytes(dis.readInt()); // 4 bytes
int timeStamp = Integer.reverseBytes(dis.readInt()); // 4 bytes
byte[] data = value.length > 24
? Arrays.copyOfRange(value, 24, value.length)
: new byte[0];
long timeStampMillis = ACTIVE_DIRECTORY_START_TIME + Duration.ofHours(timeStamp).toMillis();
OffsetDateTime dateTime = OffsetDateTime.ofInstant(
new Date(timeStampMillis).toInstant(),
ZoneOffset.UTC);
DnsRecordType typeMapping = DnsRecordType.fromValue(type);
log.debug("msg=[DNS record value decoded.] dataLength=[{}] type=[{}] version=[{}] "
+ "rank=[{}] flags=[{}] serial=[{}] ttlSeconds=[{}] reserved=[{}] timeStamp=[{}] "
+ "data(size)=[{}]", dataLength, typeMapping.name(), version, rank, flags, serial,
ttlSeconds, reserved, dateTime, data.length);
final DnsRecord dnsRecord = new DnsRecord();
dnsRecord.setRecordRawValue(value);
dnsRecord.setRecordType(typeMapping.name());
dnsRecord.setSerial(serial);
dnsRecord.setTimeStamp(dateTime);
dnsRecord.setTtlSeconds(ttlSeconds);
dnsRecord.setVersion(version);
return typeMapping.mapData(data, () -> dnsRecord);
} catch (final IOException e) {
final ServiceException se = ServiceException.internalServerError(
"Decoding dns record value failed.",
"org.bremersee:dc-con-app:d62e15c8-5410-4608-b663-20a716908102", e);
log.error("msg=[Decoding dns record value failed.]", se);
throw se;
}
}
@Override
public byte[] encodeBinaryValue(final DnsRecord value) {
return value.getRecordRawValue();
}
@Override
public Class<DnsRecord> getType() {
return DnsRecord.class;
}
}