[CORD-1589] DHCPv6 option de/serializers

Change-Id: I8bd5ffaffc601dcd0d00ec2de9f570e38a995a1d
This commit is contained in:
Yi Tseng 2017-07-18 16:16:25 -07:00 committed by Thomas Vachuska
parent 9052b20927
commit ca34e1d29e
19 changed files with 2260 additions and 220 deletions

View File

@ -16,14 +16,22 @@
package org.onlab.packet;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import org.onlab.packet.dhcp.Dhcp6ClientIdOption;
import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
import org.onlab.packet.dhcp.Dhcp6IaNaOption;
import org.onlab.packet.dhcp.Dhcp6IaTaOption;
import org.onlab.packet.dhcp.Dhcp6Option;
import org.onlab.packet.dhcp.Dhcp6RelayOption;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
/**
@ -47,7 +55,7 @@ public class DHCP6 extends BasePacket {
private static final int TRANSACTION_ID_MASK = 0x00ffffff;
// Relay message types
private static final Set<Byte> RELAY_MSG_TYPES =
public static final Set<Byte> RELAY_MSG_TYPES =
ImmutableSet.of(MsgType.RELAY_FORW.value,
MsgType.RELAY_REPL.value);
@ -90,6 +98,13 @@ public class DHCP6 extends BasePacket {
}
}
private static final Map<Short, Deserializer<Dhcp6Option>> OPT_DESERIALIZERS =
ImmutableMap.of(OptionCode.IA_NA.value, Dhcp6IaNaOption.deserializer(),
OptionCode.IA_TA.value, Dhcp6IaTaOption.deserializer(),
OptionCode.IAADDR.value, Dhcp6IaAddressOption.deserializer(),
OptionCode.RELAY_MSG.value, Dhcp6RelayOption.deserializer(),
OptionCode.CLIENTID.value, Dhcp6ClientIdOption.deserializer());
// general field
private byte msgType; // 1 byte
private List<Dhcp6Option> options;
@ -138,9 +153,7 @@ public class DHCP6 extends BasePacket {
// serialize options
options.forEach(option -> {
bb.putShort(option.getCode());
bb.putShort(option.getLength());
bb.put(option.getData());
bb.put(option.serialize());
});
return bb.array();
@ -170,7 +183,7 @@ public class DHCP6 extends BasePacket {
}
// peek message type
dhcp6.msgType = bb.array()[0];
dhcp6.msgType = (byte) (0xff & bb.array()[offset]);
if (RELAY_MSG_TYPES.contains(dhcp6.msgType)) {
bb.get(); // drop message type
dhcp6.hopCount = bb.get();
@ -186,26 +199,25 @@ public class DHCP6 extends BasePacket {
}
dhcp6.options = Lists.newArrayList();
while (bb.remaining() >= OPT_CODE_SIZE) {
Dhcp6Option option = new Dhcp6Option();
short code = bb.getShort();
if (bb.remaining() < OPT_LEN_SIZE) {
while (bb.remaining() >= Dhcp6Option.DEFAULT_LEN) {
// create temporary byte buffer for reading code and length
ByteBuffer optByteBuffer =
ByteBuffer.wrap(data, bb.position(), length - bb.position());
short code = optByteBuffer.getShort();
short optionLen = (short) (0xffff & optByteBuffer.getShort());
if (optByteBuffer.remaining() < optionLen) {
throw new DeserializationException(
"Buffer underflow while reading DHCPv6 option");
}
short optionLen = bb.getShort();
if (bb.remaining() < optionLen) {
throw new DeserializationException(
"Buffer underflow while reading DHCPv6 option");
}
byte[] optionData = new byte[optionLen];
Dhcp6Option option;
byte[] optionData = new byte[Dhcp6Option.DEFAULT_LEN + optionLen];
bb.get(optionData);
option.setCode(code);
option.setLength(optionLen);
option.setData(optionData);
if (OPT_DESERIALIZERS.containsKey(code)) {
option = OPT_DESERIALIZERS.get(code).deserialize(optionData, 0, optionData.length);
} else {
option = Dhcp6Option.deserializer().deserialize(optionData, 0, optionData.length);
}
option.setParent(dhcp6);
dhcp6.options.add(option);
}
@ -267,6 +279,15 @@ public class DHCP6 extends BasePacket {
return linkAddress;
}
/**
* Gets IPv6 link address.
*
* @return the IPv6 link address
*/
public Ip6Address getIp6LinkAddress() {
return linkAddress == null ? null : Ip6Address.valueOf(linkAddress);
}
/**
* Gets the peer address of this DHCPv6 relay message.
*
@ -276,6 +297,15 @@ public class DHCP6 extends BasePacket {
return peerAddress;
}
/**
* Gets IPv6 peer address.
*
* @return the IPv6 peer address
*/
public Ip6Address getIp6PeerAddress() {
return peerAddress == null ? null : Ip6Address.valueOf(peerAddress);
}
/**
* Sets message type.
*
@ -329,4 +359,24 @@ public class DHCP6 extends BasePacket {
public void setPeerAddress(byte[] peerAddress) {
this.peerAddress = peerAddress;
}
@Override
public String toString() {
if (RELAY_MSG_TYPES.contains(msgType)) {
// relay message
return toStringHelper(getClass())
.add("msgType", msgType)
.add("hopCount", hopCount)
.add("linkAddress", Ip6Address.valueOf(linkAddress))
.add("peerAddress", Ip6Address.valueOf(peerAddress))
.add("options", options)
.toString();
} else {
return toStringHelper(getClass())
.add("msgType", msgType)
.add("transactionId", transactionId)
.add("options", options)
.toString();
}
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet.dhcp;
import org.onlab.packet.DHCP6;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import java.nio.ByteBuffer;
/**
* DHCPv6 Client Identifier Option.
*/
public final class Dhcp6ClientIdOption extends Dhcp6Option {
@Override
public short getCode() {
return DHCP6.OptionCode.CLIENTID.value();
}
@Override
public short getLength() {
return (short) payload.serialize().length;
}
@Override
public byte[] getData() {
return payload.serialize();
}
@Override
public void setData(byte[] data) {
try {
Dhcp6Duid duid = Dhcp6Duid.deserializer().deserialize(data, 0, data.length);
this.setDuid(duid);
} catch (DeserializationException e) {
throw new RuntimeException("Invalid DUID");
}
}
public Dhcp6Duid getDuid() {
return (Dhcp6Duid) payload;
}
public void setDuid(Dhcp6Duid duid) {
this.setPayload(duid);
duid.setParent(this);
}
public static Deserializer<Dhcp6Option> deserializer() {
return (data, offset, length) -> {
Dhcp6Option dhcp6Option =
Dhcp6Option.deserializer().deserialize(data, offset, length);
Dhcp6ClientIdOption clientIdentifier = new Dhcp6ClientIdOption();
if (dhcp6Option.getLength() < DEFAULT_LEN) {
throw new DeserializationException("Invalid length of Client Id option");
}
Dhcp6Duid duid =
Dhcp6Duid.deserializer().deserialize(dhcp6Option.getData(), 0, dhcp6Option.getLength());
clientIdentifier.setPayload(duid);
return clientIdentifier;
};
}
@Override
public byte[] serialize() {
ByteBuffer bb = ByteBuffer.allocate(this.getLength() + Dhcp6Option.DEFAULT_LEN);
bb.putShort(getCode());
bb.putShort(getLength());
bb.put(payload.serialize());
return bb.array();
}
}

View File

@ -0,0 +1,181 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet.dhcp;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import java.nio.ByteBuffer;
public class Dhcp6Duid extends BasePacket {
private static final int DEFAULT_LLT_LEN = 8;
private static final int DEFAULT_EN_LEN = 6;
private static final int DEFAULT_LL_LEN = 4;
public enum DuidType {
DUID_LLT((short) 1),
DUID_EN((short) 2),
DUID_LL((short) 3);
private short value;
DuidType(short value) {
this.value = value;
}
public short getValue() {
return value;
}
public static DuidType of(short type) {
switch (type) {
case 1:
return DUID_LLT;
case 2:
return DUID_EN;
case 3:
return DUID_LL;
default:
throw new RuntimeException("Unknown type: " + type);
}
}
}
// general field
private DuidType duidType;
// fields for DUID_LLT & DUID_LL
private short hardwareType;
private int duidTime;
private byte[] linkLayerAddress;
// fields for DUID_EN
private int enterpriseNumber;
private byte[] identifier;
public DuidType getDuidType() {
return duidType;
}
public void setDuidType(DuidType duidType) {
this.duidType = duidType;
}
public short getHardwareType() {
return hardwareType;
}
public void setHardwareType(short hardwareType) {
this.hardwareType = hardwareType;
}
public int getDuidTime() {
return duidTime;
}
public void setDuidTime(int duidTime) {
this.duidTime = duidTime;
}
public byte[] getLinkLayerAddress() {
return linkLayerAddress;
}
public void setLinkLayerAddress(byte[] linkLayerAddress) {
this.linkLayerAddress = linkLayerAddress;
}
public int getEnterpriseNumber() {
return enterpriseNumber;
}
public void setEnterpriseNumber(int enterpriseNumber) {
this.enterpriseNumber = enterpriseNumber;
}
public byte[] getIdentifier() {
return identifier;
}
public void setIdentifier(byte[] identifier) {
this.identifier = identifier;
}
@Override
public byte[] serialize() {
ByteBuffer byteBuffer;
switch (duidType) {
case DUID_LLT:
byteBuffer = ByteBuffer.allocate(DEFAULT_LLT_LEN + linkLayerAddress.length);
byteBuffer.putShort(duidType.value);
byteBuffer.putShort(hardwareType);
byteBuffer.putInt(duidTime);
byteBuffer.put(linkLayerAddress);
break;
case DUID_EN:
byteBuffer = ByteBuffer.allocate(DEFAULT_EN_LEN + identifier.length);
byteBuffer.putShort(duidType.value);
byteBuffer.putInt(enterpriseNumber);
byteBuffer.put(identifier);
break;
case DUID_LL:
byteBuffer = ByteBuffer.allocate(DEFAULT_LL_LEN + linkLayerAddress.length);
byteBuffer.putShort(duidType.value);
byteBuffer.putShort(hardwareType);
byteBuffer.put(linkLayerAddress);
break;
default:
throw new RuntimeException("Unknown duidType: " + duidType.toString());
}
return byteBuffer.array();
}
@Override
public IPacket deserialize(byte[] data, int offset, int length) {
return null;
}
public static Deserializer<Dhcp6Duid> deserializer() {
return (data, offset, length) -> {
Dhcp6Duid duid = new Dhcp6Duid();
ByteBuffer byteBuffer = ByteBuffer.wrap(data, offset, length);
DuidType duidType = DuidType.of(byteBuffer.getShort());
duid.setDuidType(duidType);
switch (duidType) {
case DUID_LLT:
duid.setHardwareType(byteBuffer.getShort());
duid.setDuidTime(byteBuffer.getInt());
duid.linkLayerAddress = new byte[length - DEFAULT_LLT_LEN];
byteBuffer.get(duid.linkLayerAddress);
break;
case DUID_EN:
duid.setEnterpriseNumber(byteBuffer.getInt());
duid.identifier = new byte[length - DEFAULT_EN_LEN];
byteBuffer.get(duid.identifier);
break;
case DUID_LL:
duid.setHardwareType(byteBuffer.getShort());
duid.linkLayerAddress = new byte[length - DEFAULT_LL_LEN];
byteBuffer.get(duid.linkLayerAddress);
break;
default:
throw new RuntimeException("Unknown type: " + duidType);
}
return duid;
};
}
}

View File

@ -0,0 +1,203 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet.dhcp;
import org.onlab.packet.DHCP6;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import org.onlab.packet.Ip6Address;
import java.nio.ByteBuffer;
import java.util.Objects;
/**
* IA Address option for DHCPv6.
* Based on RFC-3315.
*/
public final class Dhcp6IaAddressOption extends Dhcp6Option {
public static final int DEFAULT_LEN = 24;
private Ip6Address ip6Address;
private int preferredLifetime;
private int validLifetime;
private IPacket options;
@Override
public short getCode() {
return DHCP6.OptionCode.IAADDR.value();
}
@Override
public short getLength() {
return (short) (options == null ? DEFAULT_LEN : DEFAULT_LEN + options.serialize().length);
}
/**
* Sets IPv6 address.
*
* @param ip6Address the IPv6 address
*/
public void setIp6Address(Ip6Address ip6Address) {
this.ip6Address = ip6Address;
}
/**
* Sets preferred lifetime.
*
* @param preferredLifetime the preferred lifetime
*/
public void setPreferredLifetime(int preferredLifetime) {
this.preferredLifetime = preferredLifetime;
}
/**
* Sets valid lifetime.
*
* @param validLifetime the valid lifetime
*/
public void setValidLifetime(int validLifetime) {
this.validLifetime = validLifetime;
}
/**
* Sets options data.
*
* @param options the options data
*/
public void setOptions(IPacket options) {
this.options = options;
}
/**
* Gets IPv6 address.
*
* @return the IPv6 address
*/
public Ip6Address getIp6Address() {
return ip6Address;
}
/**
* Gets preferred lifetime.
*
* @return the preferred lifetime
*/
public int getPreferredLifetime() {
return preferredLifetime;
}
/**
* Gets valid lifetime.
*
* @return the valid lifetime
*/
public int getValidLifetime() {
return validLifetime;
}
/**
* Gets options of IA Address option.
*
* @return the options data
*/
public IPacket getOptions() {
return options;
}
public static Deserializer<Dhcp6Option> deserializer() {
return (data, offset, length) -> {
Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
Dhcp6Option dhcp6Option =
Dhcp6Option.deserializer().deserialize(data, offset, length);
iaAddressOption.setPayload(dhcp6Option.getPayload());
if (dhcp6Option.getLength() < DEFAULT_LEN) {
throw new DeserializationException("Invalid length of IA address option");
}
ByteBuffer bb = ByteBuffer.wrap(dhcp6Option.getData());
byte[] ipv6Addr = new byte[16];
bb.get(ipv6Addr);
iaAddressOption.ip6Address = Ip6Address.valueOf(ipv6Addr);
iaAddressOption.preferredLifetime = bb.getInt();
iaAddressOption.validLifetime = bb.getInt();
// options length of IA Address option
int optionsLen = dhcp6Option.getLength() - DEFAULT_LEN;
if (optionsLen > 0) {
byte[] optionsData = new byte[optionsLen];
bb.get(optionsData);
iaAddressOption.options =
Data.deserializer().deserialize(optionsData, 0, optionsLen);
}
return iaAddressOption;
};
}
@Override
public byte[] serialize() {
int payloadLen = options == null ? DEFAULT_LEN : DEFAULT_LEN + options.serialize().length;
ByteBuffer bb = ByteBuffer.allocate(payloadLen + Dhcp6Option.DEFAULT_LEN);
bb.putShort(DHCP6.OptionCode.IAADDR.value());
bb.putShort((short) payloadLen);
bb.put(ip6Address.toOctets());
bb.putInt(preferredLifetime);
bb.putInt(validLifetime);
if (options != null) {
bb.put(options.serialize());
}
return bb.array();
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), ip6Address, preferredLifetime,
validLifetime, options);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Dhcp6IaAddressOption)) {
return false;
}
final Dhcp6IaAddressOption other = (Dhcp6IaAddressOption) obj;
return Objects.equals(getCode(), other.getCode()) &&
Objects.equals(getLength(), other.getLength()) &&
Objects.equals(ip6Address, other.ip6Address) &&
Objects.equals(preferredLifetime, other.preferredLifetime) &&
Objects.equals(validLifetime, other.validLifetime) &&
Objects.equals(options, other.options);
}
@Override
public String toString() {
return getToStringHelper()
.add("ip6Address", ip6Address)
.add("preferredLifetime", preferredLifetime)
.add("validLifetime", validLifetime)
.add("options", options)
.toString();
}
}

View File

@ -0,0 +1,243 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet.dhcp;
import com.google.common.collect.Lists;
import org.onlab.packet.DHCP6;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Objects;
/**
* DHCPv6 Identity Association for Non-temporary Addresses Option.
* Based on RFC-3315
*/
public final class Dhcp6IaNaOption extends Dhcp6Option {
public static final int DEFAULT_LEN = 12;
private int iaId;
private int t1;
private int t2;
private List<Dhcp6Option> options;
@Override
public short getCode() {
return DHCP6.OptionCode.IA_NA.value();
}
@Override
public short getLength() {
return (short) (DEFAULT_LEN + options.stream()
.mapToInt(opt -> (int) opt.getLength() + Dhcp6Option.DEFAULT_LEN)
.sum());
}
/**
* Gets Identity Association ID.
*
* @return the Identity Association ID
*/
public int getIaId() {
return iaId;
}
/**
* Sets Identity Association ID.
*
* @param iaId the Identity Association ID.
*/
public void setIaId(int iaId) {
this.iaId = iaId;
}
/**
* Gets time 1.
* The time at which the client contacts the
* server from which the addresses in the IA_NA
* were obtained to extend the lifetimes of the
* addresses assigned to the IA_NA; T1 is a
* time duration relative to the current time
* expressed in units of seconds.
*
* @return the value of time 1
*/
public int getT1() {
return t1;
}
/**
* Sets time 1.
*
* @param t1 the value of time 1
*/
public void setT1(int t1) {
this.t1 = t1;
}
/**
* Gets time 2.
* The time at which the client contacts any
* available server to extend the lifetimes of
* the addresses assigned to the IA_NA; T2 is a
* time duration relative to the current time
* expressed in units of seconds.
*
* @return the value of time 2
*/
public int getT2() {
return t2;
}
/**
* Sets time 2.
*
* @param t2 the value of time 2
*/
public void setT2(int t2) {
this.t2 = t2;
}
/**
* Gets sub-options.
*
* @return sub-options of this option
*/
public List<Dhcp6Option> getOptions() {
return options;
}
/**
* Sets sub-options.
*
* @param options the sub-options of this option
*/
public void setOptions(List<Dhcp6Option> options) {
this.options = options;
}
/**
* Default constructor.
*/
public Dhcp6IaNaOption() {
}
/**
* Constructs a DHCPv6 IA NA option with DHCPv6 option.
*
* @param dhcp6Option the DHCPv6 option
*/
public Dhcp6IaNaOption(Dhcp6Option dhcp6Option) {
super(dhcp6Option);
}
/**
* Gets deserializer.
*
* @return the deserializer
*/
public static Deserializer<Dhcp6Option> deserializer() {
return (data, offset, length) -> {
Dhcp6Option dhcp6Option =
Dhcp6Option.deserializer().deserialize(data, offset, length);
if (dhcp6Option.getLength() < DEFAULT_LEN) {
throw new DeserializationException("Invalid IA NA option data");
}
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption(dhcp6Option);
byte[] optionData = iaNaOption.getData();
ByteBuffer bb = ByteBuffer.wrap(optionData);
iaNaOption.iaId = bb.getInt();
iaNaOption.t1 = bb.getInt();
iaNaOption.t2 = bb.getInt();
iaNaOption.options = Lists.newArrayList();
while (bb.remaining() >= Dhcp6Option.DEFAULT_LEN) {
Dhcp6Option option;
ByteBuffer optByteBuffer = ByteBuffer.wrap(optionData,
bb.position(),
optionData.length - bb.position());
short code = optByteBuffer.getShort();
short len = optByteBuffer.getShort();
byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + len];
bb.get(subOptData);
// TODO: put more sub-options?
if (code == DHCP6.OptionCode.IAADDR.value()) {
option = Dhcp6IaAddressOption.deserializer()
.deserialize(subOptData, 0, subOptData.length);
} else {
option = Dhcp6Option.deserializer()
.deserialize(subOptData, 0, subOptData.length);
}
iaNaOption.options.add(option);
}
return iaNaOption;
};
}
@Override
public byte[] serialize() {
int payloadLen = DEFAULT_LEN + options.stream()
.mapToInt(opt -> (int) opt.getLength() + Dhcp6Option.DEFAULT_LEN)
.sum();
int len = Dhcp6Option.DEFAULT_LEN + payloadLen;
ByteBuffer bb = ByteBuffer.allocate(len);
bb.putShort(DHCP6.OptionCode.IA_NA.value());
bb.putShort((short) payloadLen);
bb.putInt(iaId);
bb.putInt(t1);
bb.putInt(t2);
options.stream().map(Dhcp6Option::serialize).forEach(bb::put);
return bb.array();
}
@Override
public int hashCode() {
return 31 * super.hashCode() + Objects.hash(iaId, t1, t2, options);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
if (!super.equals(obj)) {
return false;
}
final Dhcp6IaNaOption other = (Dhcp6IaNaOption) obj;
return Objects.equals(this.iaId, other.iaId)
&& Objects.equals(this.t1, other.t1)
&& Objects.equals(this.t2, other.t2)
&& Objects.equals(this.options, other.options);
}
@Override
public String toString() {
return getToStringHelper()
.add("iaId", iaId)
.add("t1", t1)
.add("t2", t2)
.add("options", options)
.toString();
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet.dhcp;
import com.google.common.collect.Lists;
import org.onlab.packet.DHCP6;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Objects;
public final class Dhcp6IaTaOption extends Dhcp6Option {
public static final int DEFAULT_LEN = 4;
private int iaId;
private List<Dhcp6Option> options;
@Override
public short getCode() {
return DHCP6.OptionCode.IA_TA.value();
}
@Override
public short getLength() {
return (short) (DEFAULT_LEN + options.stream()
.mapToInt(opt -> (int) opt.getLength() + Dhcp6Option.DEFAULT_LEN)
.sum());
}
/**
* Gets Identity Association ID.
*
* @return the Identity Association ID
*/
public int getIaId() {
return iaId;
}
/**
* Sets Identity Association ID.
*
* @param iaId the Identity Association ID.
*/
public void setIaId(int iaId) {
this.iaId = iaId;
}
/**
* Gets sub-options.
*
* @return sub-options of this option
*/
public List<Dhcp6Option> getOptions() {
return options;
}
/**
* Sets sub-options.
*
* @param options the sub-options of this option
*/
public void setOptions(List<Dhcp6Option> options) {
this.options = options;
}
/**
* Default constructor.
*/
public Dhcp6IaTaOption() {
}
/**
* Constructs a DHCPv6 IA TA option with DHCPv6 option.
*
* @param dhcp6Option the DHCPv6 option
*/
public Dhcp6IaTaOption(Dhcp6Option dhcp6Option) {
super(dhcp6Option);
}
/**
* Gets deserializer.
*
* @return the deserializer
*/
public static Deserializer<Dhcp6Option> deserializer() {
return (data, offset, length) -> {
Dhcp6Option dhcp6Option =
Dhcp6Option.deserializer().deserialize(data, offset, length);
if (dhcp6Option.getLength() < DEFAULT_LEN) {
throw new DeserializationException("Invalid IA NA option data");
}
Dhcp6IaTaOption iaTaOption = new Dhcp6IaTaOption(dhcp6Option);
byte[] optionData = iaTaOption.getData();
ByteBuffer bb = ByteBuffer.wrap(optionData);
iaTaOption.iaId = bb.getInt();
iaTaOption.options = Lists.newArrayList();
while (bb.remaining() >= Dhcp6Option.DEFAULT_LEN) {
Dhcp6Option option;
ByteBuffer optByteBuffer = ByteBuffer.wrap(optionData,
bb.position(),
optionData.length - bb.position());
short code = optByteBuffer.getShort();
short len = optByteBuffer.getShort();
byte[] subOptData = new byte[Dhcp6Option.DEFAULT_LEN + len];
bb.get(subOptData);
// TODO: put more sub-options?
if (code == DHCP6.OptionCode.IAADDR.value()) {
option = Dhcp6IaAddressOption.deserializer()
.deserialize(subOptData, 0, subOptData.length);
} else {
option = Dhcp6Option.deserializer()
.deserialize(subOptData, 0, subOptData.length);
}
iaTaOption.options.add(option);
}
return iaTaOption;
};
}
@Override
public byte[] serialize() {
int payloadLen = DEFAULT_LEN + options.stream()
.mapToInt(opt -> (int) opt.getLength())
.sum();
int len = Dhcp6Option.DEFAULT_LEN + payloadLen;
ByteBuffer bb = ByteBuffer.allocate(len);
bb.putShort(DHCP6.OptionCode.IA_TA.value());
bb.putShort((short) payloadLen);
bb.putInt(iaId);
options.stream().map(Dhcp6Option::serialize).forEach(bb::put);
return bb.array();
}
@Override
public int hashCode() {
return 31 * super.hashCode() + Objects.hash(iaId, options);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Dhcp6IaTaOption other = (Dhcp6IaTaOption) obj;
return Objects.equals(this.iaId, other.iaId)
&& Objects.equals(this.options, other.options);
}
@Override
public String toString() {
return getToStringHelper()
.add("iaId", iaId)
.add("options", options)
.toString();
}
}

View File

@ -16,14 +16,45 @@
package org.onlab.packet.dhcp;
import com.google.common.base.MoreObjects.ToStringHelper;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Data;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
import java.nio.ByteBuffer;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Representation of an DHCPv6 Option.
* Base on RFC-3315.
*/
public class Dhcp6Option {
public class Dhcp6Option extends BasePacket {
public static final int DEFAULT_LEN = 4;
private short code;
private short length;
private byte[] data;
// XXX: use "payload" from BasePacket for option data.
/**
* Default constructor.
*/
public Dhcp6Option() {
}
/**
* Constructs a DHCPv6 option based on information from other DHCPv6 option.
*
* @param dhcp6Option other DHCPv6 option
*/
public Dhcp6Option(Dhcp6Option dhcp6Option) {
this.code = (short) (0xffff & dhcp6Option.code);
this.length = (short) (0xffff & dhcp6Option.length);
this.payload = dhcp6Option.payload;
this.payload.setParent(this);
}
/**
* Sets the code of this option.
@ -35,12 +66,16 @@ public class Dhcp6Option {
}
/**
* Sets the data and length of this option.
* Sets the data of this option.
*
* @param data the data to set
*/
public void setData(byte[] data) {
this.data = data;
try {
this.payload = Data.deserializer().deserialize(data, 0, data.length);
} catch (DeserializationException e) {
throw new RuntimeException("Invalid data");
}
}
/**
@ -76,6 +111,80 @@ public class Dhcp6Option {
* @return the data of this option
*/
public byte[] getData() {
return data;
return payload.serialize();
}
/**
* Gets deserializer of DHCPv6 option.
*
* @return the deserializer of DHCPv6 option
*/
public static Deserializer<Dhcp6Option> deserializer() {
return (data, offset, len) -> {
Dhcp6Option dhcp6Option = new Dhcp6Option();
if (len < DEFAULT_LEN) {
throw new DeserializationException("DHCPv6 option code length" +
"should be at least 4 bytes");
}
ByteBuffer bb = ByteBuffer.wrap(data, offset, len);
dhcp6Option.code = (short) (0xff & bb.getShort());
dhcp6Option.length = (short) (0xff & bb.getShort());
byte[] optData = new byte[dhcp6Option.length];
bb.get(optData);
dhcp6Option.setData(optData);
return dhcp6Option;
};
}
@Override
public byte[] serialize() {
ByteBuffer bb = ByteBuffer.allocate(DEFAULT_LEN + getLength());
bb.putShort(getCode());
bb.putShort(getLength());
bb.put(payload.serialize());
return bb.array();
}
@Override
public IPacket deserialize(byte[] data, int offset, int length) {
try {
return deserializer().deserialize(data, offset, length);
} catch (DeserializationException e) {
throw new RuntimeException("Can't deserialize data for DHCPv6 option.", e);
}
}
protected ToStringHelper getToStringHelper() {
return toStringHelper(Dhcp6Option.class)
.add("code", code)
.add("length", length);
}
@Override
public String toString() {
return getToStringHelper()
.add("data", payload.toString())
.toString();
}
@Override
public int hashCode() {
return 31 * super.hashCode() + Objects.hash(code, length);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
if (!super.equals(obj)) {
return false;
}
final Dhcp6Option other = (Dhcp6Option) obj;
return Objects.equals(this.code, other.code)
&& Objects.equals(this.length, other.length);
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet.dhcp;
import org.onlab.packet.DHCP6;
import org.onlab.packet.Deserializer;
import org.onlab.packet.IPacket;
/**
* Relay option for DHCPv6.
* Based on RFC-3315.
*/
public final class Dhcp6RelayOption extends Dhcp6Option {
@Override
public short getCode() {
return DHCP6.OptionCode.RELAY_MSG.value();
}
@Override
public short getLength() {
return (short) payload.serialize().length;
}
/**
* Default constructor.
*/
public Dhcp6RelayOption() {
}
/**
* Constructs a DHCPv6 relay option with DHCPv6 option.
*
* @param dhcp6Option the DHCPv6 option
*/
public Dhcp6RelayOption(Dhcp6Option dhcp6Option) {
super(dhcp6Option);
}
/**
* Gets deserializer for DHCPv6 relay option.
*
* @return the deserializer
*/
public static Deserializer<Dhcp6Option> deserializer() {
return (data, offset, len) -> {
Dhcp6Option dhcp6Option = Dhcp6Option.deserializer().deserialize(data, offset, len);
IPacket payload = DHCP6.deserializer()
.deserialize(dhcp6Option.getData(), 0, dhcp6Option.getLength());
Dhcp6RelayOption relayOption = new Dhcp6RelayOption(dhcp6Option);
relayOption.setPayload(payload);
payload.setParent(relayOption);
return relayOption;
};
}
}

View File

@ -1,194 +0,0 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.onlab.packet.dhcp.Dhcp6Option;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import java.nio.ByteBuffer;
public class Dhcp6Test {
private static final int OPT_CLIENT_ID = 0xBEEFBEEF;
private static final byte[] OPT_CLIENT_ID_BYTE_ARR =
{(byte) 0xBE, (byte) 0xEF, (byte) 0xBE, (byte) 0xEF};
private static final short OPT_CLIENT_ID_SIZE = 4;
private static final int OPT_AUTH = 0xBA11BA11;
private static final byte[] OPT_AUTH_BYTE_AR =
{(byte) 0xBA, 0x11, (byte) 0xBA, 0x11};
private static final short OPT_AUTH_SIZE = 4;
private static final int TRANSACTION_ID = 0xC0FFEE;
private static final byte[] TRANSACTION_ID_BYTE_ARR =
{(byte) 0xC0, (byte) 0xFF, (byte) 0xEE};
private static final byte HOP_COUNT = 3;
private static final Ip6Address LINK_ADDRESS = Ip6Address.valueOf("1111:2222::8888");
private static final Ip6Address PEER_ADDRESS = Ip6Address.valueOf("3333:4444::9999");
Deserializer<DHCP6> deserializer = DHCP6.deserializer();
private byte[] byteHeader;
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
/**
* Truncated a simple DHCPv6 payload.
*/
@Test
public void testDeserializeTruncated() throws Exception {
ByteBuffer bb = ByteBuffer.allocate(4);
bb.put(DHCP6.MsgType.REQUEST.value());
bb.put(TRANSACTION_ID_BYTE_ARR);
byteHeader = bb.array();
PacketTestUtils.testDeserializeTruncated(deserializer, byteHeader);
}
/**
* Basic DHCPv6 header with one msg type and one transaction id.
*/
@Test
public void testDeserializeDefaultPayload() throws Exception {
ByteBuffer bb = ByteBuffer.allocate(12);
bb.put(DHCP6.MsgType.REQUEST.value());
bb.put(TRANSACTION_ID_BYTE_ARR);
// put a simple client id (4 bytes)
bb.putShort(DHCP6.OptionCode.CLIENTID.value());
bb.putShort(OPT_CLIENT_ID_SIZE);
bb.putInt(OPT_CLIENT_ID);
byteHeader = bb.array();
DHCP6 dhcp6 = deserializer.deserialize(byteHeader, 0, byteHeader.length);
assertEquals(dhcp6.getMsgType(), DHCP6.MsgType.REQUEST.value());
assertEquals(dhcp6.getTransactionId(), TRANSACTION_ID);
assertEquals(dhcp6.getOptions().size(), 1);
Dhcp6Option clientIdOption = dhcp6.getOptions().get(0);
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertArrayEquals(clientIdOption.getData(), OPT_CLIENT_ID_BYTE_ARR);
}
/**
* DHCPv6 header with relay agent information.
*/
@Test
public void testDeserializeRelayAgent() throws Exception {
ByteBuffer bb = ByteBuffer.allocate(42);
bb.put(DHCP6.MsgType.RELAY_FORW.value());
bb.put(HOP_COUNT);
bb.put(LINK_ADDRESS.toOctets());
bb.put(PEER_ADDRESS.toOctets());
// put a simple client id (4 bytes)
bb.putShort(DHCP6.OptionCode.CLIENTID.value());
bb.putShort(OPT_CLIENT_ID_SIZE);
bb.putInt(OPT_CLIENT_ID);
byteHeader = bb.array();
DHCP6 dhcp6 = deserializer.deserialize(byteHeader, 0, byteHeader.length);
assertEquals(dhcp6.getMsgType(), DHCP6.MsgType.RELAY_FORW.value());
assertEquals(dhcp6.getHopCount(), HOP_COUNT);
assertArrayEquals(dhcp6.getLinkAddress(), LINK_ADDRESS.toOctets());
assertArrayEquals(dhcp6.getPeerAddress(), PEER_ADDRESS.toOctets());
assertEquals(dhcp6.getOptions().size(), 1);
Dhcp6Option clientIdOption = dhcp6.getOptions().get(0);
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertArrayEquals(clientIdOption.getData(), OPT_CLIENT_ID_BYTE_ARR);
}
/**
* Serialize DHCPv6 header with default payload and options.
*/
@Test
public void testSerializeDefaultPayload() throws Exception {
DHCP6 dhcp6 = new DHCP6();
dhcp6.setMsgType(DHCP6.MsgType.REQUEST.value());
dhcp6.setTransactionId(TRANSACTION_ID);
Dhcp6Option opt1 = new Dhcp6Option();
opt1.setCode(DHCP6.OptionCode.CLIENTID.value());
opt1.setLength(OPT_CLIENT_ID_SIZE);
opt1.setData(OPT_CLIENT_ID_BYTE_ARR);
Dhcp6Option opt2 = new Dhcp6Option();
opt2.setCode(DHCP6.OptionCode.AUTH.value());
opt2.setLength(OPT_AUTH_SIZE);
opt2.setData(OPT_AUTH_BYTE_AR);
dhcp6.setOptions(ImmutableList.of(opt1, opt2));
byte[] serialized = dhcp6.serialize();
ByteBuffer expected = ByteBuffer.allocate(20)
.put(DHCP6.MsgType.REQUEST.value())
.put(TRANSACTION_ID_BYTE_ARR)
.putShort(DHCP6.OptionCode.CLIENTID.value())
.putShort(OPT_CLIENT_ID_SIZE)
.putInt(OPT_CLIENT_ID)
.putShort(DHCP6.OptionCode.AUTH.value())
.putShort(OPT_AUTH_SIZE)
.putInt(OPT_AUTH);
assertArrayEquals(serialized, expected.array());
}
/**
* Serialize DHCPv6 header with relay agent payload and options.
*/
@Test
public void testSerializeRelayAgent() throws Exception {
DHCP6 dhcp6 = new DHCP6();
dhcp6.setMsgType(DHCP6.MsgType.RELAY_FORW.value());
dhcp6.setHopCount(HOP_COUNT);
dhcp6.setLinkAddress(LINK_ADDRESS.toOctets());
dhcp6.setPeerAddress(PEER_ADDRESS.toOctets());
Dhcp6Option opt1 = new Dhcp6Option();
opt1.setCode(DHCP6.OptionCode.CLIENTID.value());
opt1.setLength(OPT_CLIENT_ID_SIZE);
opt1.setData(OPT_CLIENT_ID_BYTE_ARR);
Dhcp6Option opt2 = new Dhcp6Option();
opt2.setCode(DHCP6.OptionCode.AUTH.value());
opt2.setLength(OPT_AUTH_SIZE);
opt2.setData(OPT_AUTH_BYTE_AR);
dhcp6.setOptions(ImmutableList.of(opt1, opt2));
byte[] serialized = dhcp6.serialize();
ByteBuffer expected = ByteBuffer.allocate(50)
.put(DHCP6.MsgType.RELAY_FORW.value())
.put(HOP_COUNT)
.put(LINK_ADDRESS.toOctets())
.put(PEER_ADDRESS.toOctets())
.putShort(DHCP6.OptionCode.CLIENTID.value())
.putShort(OPT_CLIENT_ID_SIZE)
.putInt(OPT_CLIENT_ID)
.putShort(DHCP6.OptionCode.AUTH.value())
.putShort(OPT_AUTH_SIZE)
.putInt(OPT_AUTH);
assertArrayEquals(serialized, expected.array());
}
}

View File

@ -0,0 +1,586 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet.dhcp;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.onlab.packet.DHCP6;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.MacAddress;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.*;
/**
* Test serializing/deserializing DHCPv6 relay message.
*/
public class Dhcp6RelayTest {
private static final String SOLICIT = "dhcp6_relay_solicit.bin";
private static final String ADVERTISE = "dhcp6_relay_advertise.bin";
private static final String REQUEST = "dhcp6_relay_request.bin";
private static final String REPLY = "dhcp6_relay_reply.bin";
private static final int HOP_COUNT = 0;
private static final Ip6Address LINK_ADDRESS = Ip6Address.valueOf("2000::2ff");
private static final Ip6Address PEER_ADDRESS = Ip6Address.valueOf("fe80::1");
private static final int XID_1 = 13346301;
private static final int XID_2 = 9807588;
private static final int IA_ID = 1;
private static final int T1_CLIENT = 3600;
private static final int T2_CLIENT = 5400;
private static final int T1_SERVER = 0;
private static final int T2_SERVER = 0;
private static final Ip6Address IA_ADDRESS = Ip6Address.valueOf("2000::201");
private static final int PREFFERRED_LT_SERVER = 375;
private static final int VALID_LT_SERVER = 600;
private static final int PREFFERRED_LT_REQ = 7200;
private static final int VALID_LT_REQ = 7500;
private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:bb:00:00:00:01");
private static final int CLIENT_DUID_TIME = 0x210016b4;
/**
* Test deserialize relay message with solicit message.
*
* @throws Exception exception while deserialize the DHCPv6 payload
*/
@Test
public void deserializeSolicit() throws Exception {
byte[] data = IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(SOLICIT));
DHCP6 relayMsg = DHCP6.deserializer().deserialize(data, 0, data.length);
assertEquals(relayMsg.getMsgType(), DHCP6.MsgType.RELAY_FORW.value());
assertEquals(relayMsg.getHopCount(), HOP_COUNT);
assertEquals(relayMsg.getIp6LinkAddress(), LINK_ADDRESS);
assertEquals(relayMsg.getIp6PeerAddress(), PEER_ADDRESS);
assertEquals(relayMsg.getOptions().size(), 1);
Dhcp6Option option = relayMsg.getOptions().get(0);
assertEquals(option.getCode(), DHCP6.OptionCode.RELAY_MSG.value());
assertEquals(option.getLength(), 56);
assertTrue(option.getPayload() instanceof DHCP6);
DHCP6 relaiedDhcp6 = (DHCP6) option.getPayload();
assertEquals(relaiedDhcp6.getMsgType(), DHCP6.MsgType.SOLICIT.value());
assertEquals(relaiedDhcp6.getTransactionId(), XID_1);
assertEquals(relaiedDhcp6.getOptions().size(), 4);
// Client ID
option = relaiedDhcp6.getOptions().get(0);
assertTrue(option instanceof Dhcp6ClientIdOption);
Dhcp6ClientIdOption clientIdOption = (Dhcp6ClientIdOption) option;
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertEquals(clientIdOption.getLength(), 14);
assertEquals(clientIdOption.getDuid().getDuidType(), Dhcp6Duid.DuidType.DUID_LLT);
assertEquals(clientIdOption.getDuid().getHardwareType(), 1);
assertEquals(clientIdOption.getDuid().getDuidTime(), CLIENT_DUID_TIME);
assertArrayEquals(clientIdOption.getDuid().getLinkLayerAddress(), CLIENT_MAC.toBytes());
// ORO
option = relaiedDhcp6.getOptions().get(1);
assertEquals(option.getCode(), DHCP6.OptionCode.ORO.value());
assertEquals(option.getLength(), 8);
assertArrayEquals(option.getData(),
new byte[]{0, 23, 0, 24, 0, 39, 0, 31});
// ELAPSED_TIME
option = relaiedDhcp6.getOptions().get(2);
assertEquals(option.getCode(), DHCP6.OptionCode.ELAPSED_TIME.value());
assertEquals(option.getLength(), 2);
assertArrayEquals(option.getData(),
new byte[]{0, 0});
// IA NA
option = relaiedDhcp6.getOptions().get(3);
assertTrue(option instanceof Dhcp6IaNaOption);
Dhcp6IaNaOption iaNaOption = (Dhcp6IaNaOption) option;
assertEquals(iaNaOption.getCode(), DHCP6.OptionCode.IA_NA.value());
assertEquals(iaNaOption.getLength(), 12);
assertEquals(iaNaOption.getIaId(), IA_ID);
assertEquals(iaNaOption.getT1(), T1_CLIENT);
assertEquals(iaNaOption.getT2(), T2_CLIENT);
assertEquals(iaNaOption.getOptions().size(), 0);
assertArrayEquals(data, relayMsg.serialize());
}
/**
* Test serialize relay message with solicit message.
*
* @throws Exception exception while serialize the DHCPv6 payload
*/
@Test
public void serializeSolicit() throws Exception {
DHCP6 relayMsg = new DHCP6();
relayMsg.setMsgType(DHCP6.MsgType.RELAY_FORW.value());
relayMsg.setHopCount((byte) HOP_COUNT);
relayMsg.setLinkAddress(LINK_ADDRESS.toOctets());
relayMsg.setPeerAddress(PEER_ADDRESS.toOctets());
DHCP6 relaiedDhcp6 = new DHCP6();
relaiedDhcp6.setMsgType(DHCP6.MsgType.SOLICIT.value());
relaiedDhcp6.setTransactionId(XID_1);
List<Dhcp6Option> options = Lists.newArrayList();
// Client ID
Dhcp6Duid duid = new Dhcp6Duid();
duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
duid.setHardwareType((short) 1);
duid.setDuidTime(CLIENT_DUID_TIME);
duid.setLinkLayerAddress(CLIENT_MAC.toBytes());
Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
clientIdOption.setDuid(duid);
options.add(clientIdOption);
// Option request
Dhcp6Option option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.ORO.value());
option.setLength((short) 8);
option.setData(new byte[]{0, 23, 0, 24, 0, 39, 0, 31});
options.add(option);
// Elapsed Time
option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.ELAPSED_TIME.value());
option.setLength((short) 2);
option.setData(new byte[]{0, 0});
options.add(option);
// IA NA
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
iaNaOption.setIaId(IA_ID);
iaNaOption.setT1(T1_CLIENT);
iaNaOption.setT2(T2_CLIENT);
iaNaOption.setOptions(Collections.emptyList());
options.add(iaNaOption);
relaiedDhcp6.setOptions(options);
Dhcp6RelayOption relayOption = new Dhcp6RelayOption();
relayOption.setPayload(relaiedDhcp6);
relayMsg.setOptions(ImmutableList.of(relayOption));
assertArrayEquals(IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(SOLICIT)),
relayMsg.serialize());
}
/**
* Test deserialize relay message with advertise message.
*
* @throws Exception exception while deserialize the DHCPv6 payload
*/
@Test
public void deserializeAdvertise() throws Exception {
byte[] data = IOUtils.toByteArray(getClass().getResource(ADVERTISE));
DHCP6 relayMsg = DHCP6.deserializer().deserialize(data, 0, data.length);
assertEquals(relayMsg.getMsgType(), DHCP6.MsgType.RELAY_REPL.value());
assertEquals(relayMsg.getHopCount(), HOP_COUNT);
assertEquals(relayMsg.getIp6LinkAddress(), LINK_ADDRESS);
assertEquals(relayMsg.getIp6PeerAddress(), PEER_ADDRESS);
assertEquals(relayMsg.getOptions().size(), 1);
Dhcp6Option option = relayMsg.getOptions().get(0);
assertEquals(option.getCode(), DHCP6.OptionCode.RELAY_MSG.value());
assertEquals(option.getLength(), 84);
assertTrue(option.getPayload() instanceof DHCP6);
DHCP6 relaiedDhcp6 = (DHCP6) option.getPayload();
assertEquals(relaiedDhcp6.getMsgType(), DHCP6.MsgType.ADVERTISE.value());
assertEquals(relaiedDhcp6.getTransactionId(), XID_1);
assertEquals(relaiedDhcp6.getOptions().size(), 3);
// IA NA
option = relaiedDhcp6.getOptions().get(0);
assertTrue(option instanceof Dhcp6IaNaOption);
Dhcp6IaNaOption iaNaOption = (Dhcp6IaNaOption) option;
assertEquals(iaNaOption.getCode(), DHCP6.OptionCode.IA_NA.value());
assertEquals(iaNaOption.getLength(), 40);
assertEquals(iaNaOption.getIaId(), IA_ID);
assertEquals(iaNaOption.getT1(), T1_SERVER);
assertEquals(iaNaOption.getT2(), T2_SERVER);
assertEquals(iaNaOption.getOptions().size(), 1);
// IA Address (in IA NA)
assertTrue(iaNaOption.getOptions().get(0) instanceof Dhcp6IaAddressOption);
Dhcp6IaAddressOption iaAddressOption =
(Dhcp6IaAddressOption) iaNaOption.getOptions().get(0);
assertEquals(iaAddressOption.getIp6Address(), IA_ADDRESS);
assertEquals(iaAddressOption.getPreferredLifetime(), PREFFERRED_LT_SERVER);
assertEquals(iaAddressOption.getValidLifetime(), VALID_LT_SERVER);
assertNull(iaAddressOption.getOptions());
// Client ID
option = relaiedDhcp6.getOptions().get(1);
assertTrue(option instanceof Dhcp6ClientIdOption);
Dhcp6ClientIdOption clientIdOption = (Dhcp6ClientIdOption) option;
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertEquals(clientIdOption.getLength(), 14);
assertEquals(clientIdOption.getDuid().getDuidType(), Dhcp6Duid.DuidType.DUID_LLT);
assertEquals(clientIdOption.getDuid().getHardwareType(), 1);
assertEquals(clientIdOption.getDuid().getDuidTime(), CLIENT_DUID_TIME);
assertArrayEquals(clientIdOption.getDuid().getLinkLayerAddress(), CLIENT_MAC.toBytes());
// Server ID
option = relaiedDhcp6.getOptions().get(2);
assertEquals(option.getCode(), DHCP6.OptionCode.SERVERID.value());
assertEquals(option.getLength(), 14);
assertArrayEquals(option.getData(),
new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
assertArrayEquals(data, relayMsg.serialize());
}
/**
* Test serialize relay message with advertise message.
*
* @throws Exception exception while serialize the DHCPv6 payload
*/
@Test
public void serializeAdvertise() throws Exception {
DHCP6 relayMsg = new DHCP6();
relayMsg.setMsgType(DHCP6.MsgType.RELAY_REPL.value());
relayMsg.setHopCount((byte) HOP_COUNT);
relayMsg.setLinkAddress(LINK_ADDRESS.toOctets());
relayMsg.setPeerAddress(PEER_ADDRESS.toOctets());
DHCP6 relaiedDhcp6 = new DHCP6();
relaiedDhcp6.setMsgType(DHCP6.MsgType.ADVERTISE.value());
relaiedDhcp6.setTransactionId(XID_1);
List<Dhcp6Option> options = Lists.newArrayList();
// IA address
Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
iaAddressOption.setIp6Address(IA_ADDRESS);
iaAddressOption.setPreferredLifetime(PREFFERRED_LT_SERVER);
iaAddressOption.setValidLifetime(VALID_LT_SERVER);
// IA NA
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
iaNaOption.setIaId(IA_ID);
iaNaOption.setT1(T1_SERVER);
iaNaOption.setT2(T2_SERVER);
iaNaOption.setOptions(ImmutableList.of(iaAddressOption));
options.add(iaNaOption);
// Client ID
Dhcp6Duid duid = new Dhcp6Duid();
duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
duid.setHardwareType((short) 1);
duid.setDuidTime(CLIENT_DUID_TIME);
duid.setLinkLayerAddress(CLIENT_MAC.toBytes());
Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
clientIdOption.setDuid(duid);
options.add(clientIdOption);
// Server ID
Dhcp6Option option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.SERVERID.value());
option.setLength((short) 14);
option.setData(new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
options.add(option);
relaiedDhcp6.setOptions(options);
Dhcp6RelayOption relayOption = new Dhcp6RelayOption();
relayOption.setPayload(relaiedDhcp6);
relayMsg.setOptions(ImmutableList.of(relayOption));
assertArrayEquals(IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(ADVERTISE)),
relayMsg.serialize());
}
/**
* Test deserialize relay message with request message.
*
* @throws Exception exception while deserialize the DHCPv6 payload
*/
@Test
public void deserializeRequest() throws Exception {
byte[] data = IOUtils.toByteArray(getClass().getResource(REQUEST));
DHCP6 relayMsg = DHCP6.deserializer().deserialize(data, 0, data.length);
assertEquals(relayMsg.getMsgType(), DHCP6.MsgType.RELAY_FORW.value());
assertEquals(relayMsg.getHopCount(), HOP_COUNT);
assertEquals(relayMsg.getIp6LinkAddress(), LINK_ADDRESS);
assertEquals(relayMsg.getIp6PeerAddress(), PEER_ADDRESS);
assertEquals(relayMsg.getOptions().size(), 1);
Dhcp6Option option = relayMsg.getOptions().get(0);
assertEquals(option.getCode(), DHCP6.OptionCode.RELAY_MSG.value());
assertEquals(option.getLength(), 102);
assertTrue(option.getPayload() instanceof DHCP6);
DHCP6 relaiedDhcp6 = (DHCP6) option.getPayload();
assertEquals(relaiedDhcp6.getMsgType(), DHCP6.MsgType.REQUEST.value());
assertEquals(relaiedDhcp6.getTransactionId(), XID_2);
assertEquals(relaiedDhcp6.getOptions().size(), 5);
// Client ID
option = relaiedDhcp6.getOptions().get(0);
assertTrue(option instanceof Dhcp6ClientIdOption);
Dhcp6ClientIdOption clientIdOption = (Dhcp6ClientIdOption) option;
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertEquals(clientIdOption.getLength(), 14);
assertEquals(clientIdOption.getDuid().getDuidType(), Dhcp6Duid.DuidType.DUID_LLT);
assertEquals(clientIdOption.getDuid().getHardwareType(), 1);
assertEquals(clientIdOption.getDuid().getDuidTime(), CLIENT_DUID_TIME);
assertArrayEquals(clientIdOption.getDuid().getLinkLayerAddress(), CLIENT_MAC.toBytes());
// Server ID
option = relaiedDhcp6.getOptions().get(1);
assertEquals(option.getCode(), DHCP6.OptionCode.SERVERID.value());
assertEquals(option.getLength(), 14);
assertArrayEquals(option.getData(),
new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
// Option Request
option = relaiedDhcp6.getOptions().get(2);
assertEquals(option.getCode(), DHCP6.OptionCode.ORO.value());
assertEquals(option.getLength(), 8);
assertArrayEquals(option.getData(), new byte[]{0, 23, 0, 24, 0, 39, 0, 31});
// ELAPSED_TIME
option = relaiedDhcp6.getOptions().get(3);
assertEquals(option.getCode(), DHCP6.OptionCode.ELAPSED_TIME.value());
assertEquals(option.getLength(), 2);
assertArrayEquals(option.getData(),
new byte[]{0, 0});
// IA NA
option = relaiedDhcp6.getOptions().get(4);
assertTrue(option instanceof Dhcp6IaNaOption);
Dhcp6IaNaOption iaNaOption = (Dhcp6IaNaOption) option;
assertEquals(iaNaOption.getCode(), DHCP6.OptionCode.IA_NA.value());
assertEquals(iaNaOption.getLength(), 40);
assertEquals(iaNaOption.getIaId(), IA_ID);
assertEquals(iaNaOption.getT1(), T1_CLIENT);
assertEquals(iaNaOption.getT2(), T2_CLIENT);
assertEquals(iaNaOption.getOptions().size(), 1);
// IA Address (in IA NA)
assertTrue(iaNaOption.getOptions().get(0) instanceof Dhcp6IaAddressOption);
Dhcp6IaAddressOption iaAddressOption =
(Dhcp6IaAddressOption) iaNaOption.getOptions().get(0);
assertEquals(iaAddressOption.getIp6Address(), IA_ADDRESS);
assertEquals(iaAddressOption.getPreferredLifetime(), PREFFERRED_LT_REQ);
assertEquals(iaAddressOption.getValidLifetime(), VALID_LT_REQ);
assertNull(iaAddressOption.getOptions());
assertArrayEquals(data, relayMsg.serialize());
}
/**
* Test serialize relay message with request message.
*
* @throws Exception exception while serialize the DHCPv6 payload
*/
@Test
public void serializeRequest() throws Exception {
DHCP6 relayMsg = new DHCP6();
relayMsg.setMsgType(DHCP6.MsgType.RELAY_FORW.value());
relayMsg.setHopCount((byte) HOP_COUNT);
relayMsg.setLinkAddress(LINK_ADDRESS.toOctets());
relayMsg.setPeerAddress(PEER_ADDRESS.toOctets());
DHCP6 relaiedDhcp6 = new DHCP6();
relaiedDhcp6.setMsgType(DHCP6.MsgType.REQUEST.value());
relaiedDhcp6.setTransactionId(XID_2);
List<Dhcp6Option> options = Lists.newArrayList();
// Client ID
Dhcp6Duid duid = new Dhcp6Duid();
duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
duid.setHardwareType((short) 1);
duid.setDuidTime(CLIENT_DUID_TIME);
duid.setLinkLayerAddress(CLIENT_MAC.toBytes());
Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
clientIdOption.setDuid(duid);
options.add(clientIdOption);
// Server ID
Dhcp6Option option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.SERVERID.value());
option.setLength((short) 14);
option.setData(new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
options.add(option);
// Option request
option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.ORO.value());
option.setLength((short) 8);
option.setData(new byte[]{0, 23, 0, 24, 0, 39, 0, 31});
options.add(option);
// Elapsed Time
option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.ELAPSED_TIME.value());
option.setLength((short) 2);
option.setData(new byte[]{0, 0});
options.add(option);
// IA address
Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
iaAddressOption.setIp6Address(IA_ADDRESS);
iaAddressOption.setPreferredLifetime(PREFFERRED_LT_REQ);
iaAddressOption.setValidLifetime(VALID_LT_REQ);
// IA NA
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
iaNaOption.setIaId(IA_ID);
iaNaOption.setT1(T1_CLIENT);
iaNaOption.setT2(T2_CLIENT);
iaNaOption.setOptions(ImmutableList.of(iaAddressOption));
options.add(iaNaOption);
relaiedDhcp6.setOptions(options);
Dhcp6RelayOption relayOption = new Dhcp6RelayOption();
relayOption.setPayload(relaiedDhcp6);
relayMsg.setOptions(ImmutableList.of(relayOption));
assertArrayEquals(IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(REQUEST)),
relayMsg.serialize());
}
/**
* Test deserialize relay message with reply message.
*
* @throws Exception exception while deserialize the DHCPv6 payload
*/
@Test
public void deserializeReply() throws Exception {
byte[] data = IOUtils.toByteArray(getClass().getResource(REPLY));
DHCP6 relayMsg = DHCP6.deserializer().deserialize(data, 0, data.length);
assertEquals(relayMsg.getMsgType(), DHCP6.MsgType.RELAY_REPL.value());
assertEquals(relayMsg.getHopCount(), HOP_COUNT);
assertEquals(relayMsg.getIp6LinkAddress(), LINK_ADDRESS);
assertEquals(relayMsg.getIp6PeerAddress(), PEER_ADDRESS);
assertEquals(relayMsg.getOptions().size(), 1);
Dhcp6Option option = relayMsg.getOptions().get(0);
assertEquals(option.getCode(), DHCP6.OptionCode.RELAY_MSG.value());
assertEquals(option.getLength(), 84);
assertTrue(option.getPayload() instanceof DHCP6);
DHCP6 relaiedDhcp6 = (DHCP6) option.getPayload();
assertEquals(relaiedDhcp6.getMsgType(), DHCP6.MsgType.REPLY.value());
assertEquals(relaiedDhcp6.getTransactionId(), XID_2);
assertEquals(relaiedDhcp6.getOptions().size(), 3);
// IA NA
option = relaiedDhcp6.getOptions().get(0);
assertTrue(option instanceof Dhcp6IaNaOption);
Dhcp6IaNaOption iaNaOption = (Dhcp6IaNaOption) option;
assertEquals(iaNaOption.getCode(), DHCP6.OptionCode.IA_NA.value());
assertEquals(iaNaOption.getLength(), 40);
assertEquals(iaNaOption.getIaId(), IA_ID);
assertEquals(iaNaOption.getT1(), T1_SERVER);
assertEquals(iaNaOption.getT2(), T2_SERVER);
assertEquals(iaNaOption.getOptions().size(), 1);
// IA Address (in IA NA)
assertTrue(iaNaOption.getOptions().get(0) instanceof Dhcp6IaAddressOption);
Dhcp6IaAddressOption iaAddressOption =
(Dhcp6IaAddressOption) iaNaOption.getOptions().get(0);
assertEquals(iaAddressOption.getIp6Address(), IA_ADDRESS);
assertEquals(iaAddressOption.getPreferredLifetime(), PREFFERRED_LT_SERVER);
assertEquals(iaAddressOption.getValidLifetime(), VALID_LT_SERVER);
assertNull(iaAddressOption.getOptions());
// Client ID
option = relaiedDhcp6.getOptions().get(1);
assertTrue(option instanceof Dhcp6ClientIdOption);
Dhcp6ClientIdOption clientIdOption = (Dhcp6ClientIdOption) option;
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertEquals(clientIdOption.getLength(), 14);
assertEquals(clientIdOption.getDuid().getDuidType(), Dhcp6Duid.DuidType.DUID_LLT);
assertEquals(clientIdOption.getDuid().getHardwareType(), 1);
assertEquals(clientIdOption.getDuid().getDuidTime(), CLIENT_DUID_TIME);
assertArrayEquals(clientIdOption.getDuid().getLinkLayerAddress(), CLIENT_MAC.toBytes());
// Server ID
option = relaiedDhcp6.getOptions().get(2);
assertEquals(option.getCode(), DHCP6.OptionCode.SERVERID.value());
assertEquals(option.getLength(), 14);
assertArrayEquals(option.getData(),
new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
assertArrayEquals(data, relayMsg.serialize());
}
@Test
public void serializeReply() throws Exception {
DHCP6 relayMsg = new DHCP6();
relayMsg.setMsgType(DHCP6.MsgType.RELAY_REPL.value());
relayMsg.setHopCount((byte) HOP_COUNT);
relayMsg.setLinkAddress(LINK_ADDRESS.toOctets());
relayMsg.setPeerAddress(PEER_ADDRESS.toOctets());
DHCP6 relaiedDhcp6 = new DHCP6();
relaiedDhcp6.setMsgType(DHCP6.MsgType.REPLY.value());
relaiedDhcp6.setTransactionId(XID_2);
List<Dhcp6Option> options = Lists.newArrayList();
// IA address
Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
iaAddressOption.setIp6Address(IA_ADDRESS);
iaAddressOption.setPreferredLifetime(PREFFERRED_LT_SERVER);
iaAddressOption.setValidLifetime(VALID_LT_SERVER);
// IA NA
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
iaNaOption.setIaId(IA_ID);
iaNaOption.setT1(T1_SERVER);
iaNaOption.setT2(T2_SERVER);
iaNaOption.setOptions(ImmutableList.of(iaAddressOption));
options.add(iaNaOption);
// Client ID
Dhcp6Duid duid = new Dhcp6Duid();
duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
duid.setHardwareType((short) 1);
duid.setDuidTime(CLIENT_DUID_TIME);
duid.setLinkLayerAddress(CLIENT_MAC.toBytes());
Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
clientIdOption.setDuid(duid);
options.add(clientIdOption);
// Server ID
Dhcp6Option option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.SERVERID.value());
option.setLength((short) 14);
option.setData(new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
options.add(option);
relaiedDhcp6.setOptions(options);
Dhcp6RelayOption relayOption = new Dhcp6RelayOption();
relayOption.setPayload(relaiedDhcp6);
relayMsg.setOptions(ImmutableList.of(relayOption));
assertArrayEquals(IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(REPLY)),
relayMsg.serialize());
}
}

View File

@ -0,0 +1,524 @@
/*
* Copyright 2017-present Open Networking Laboratory
*
* 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.onlab.packet.dhcp;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.onlab.packet.DHCP6;
import org.onlab.packet.Deserializer;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.PacketTestUtils;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.*;
import static org.junit.Assert.assertNull;
public class Dhcp6Test {
private static final String SOLICIT = "dhcp6_solicit.bin";
private static final String ADVERTISE = "dhcp6_advertise.bin";
private static final String REQUEST = "dhcp6_request.bin";
private static final String REPLY = "dhcp6_reply.bin";
private static final int XID_1 = 13346301;
private static final int XID_2 = 9807588;
private static final int IA_ID = 1;
private static final int T1_CLIENT = 3600;
private static final int T2_CLIENT = 5400;
private static final int T1_SERVER = 0;
private static final int T2_SERVER = 0;
private static final Ip6Address IA_ADDRESS = Ip6Address.valueOf("2000::201");
private static final int PREFFERRED_LT_SERVER = 375;
private static final int VALID_LT_SERVER = 600;
private static final int PREFFERRED_LT_REQ = 7200;
private static final int VALID_LT_REQ = 7500;
private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:bb:00:00:00:01");
private static final int CLIENT_DUID_TIME = 0x210016b4;
private Deserializer<DHCP6> deserializer = DHCP6.deserializer();
@Test
public void testDeserializeBadInput() throws Exception {
PacketTestUtils.testDeserializeBadInput(deserializer);
}
/**
* Truncated a simple DHCPv6 payload.
*/
@Test
public void testDeserializeTruncated() throws Exception {
ByteBuffer bb = ByteBuffer.allocate(4);
bb.put(DHCP6.MsgType.REQUEST.value());
bb.put(new byte[]{0x00, 0x00});
PacketTestUtils.testDeserializeTruncated(deserializer, bb.array());
}
/**
* Test DHCPv6 solicit message.
*
* @throws Exception exception while deserialize the DHCPv6 payload
*/
@Test
public void testDeserializeSolicit() throws Exception {
byte[] data = IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(SOLICIT));
DHCP6 dhcp6 = DHCP6.deserializer().deserialize(data, 0, data.length);
assertEquals(dhcp6.getMsgType(), DHCP6.MsgType.SOLICIT.value());
assertEquals(dhcp6.getTransactionId(), XID_1);
assertEquals(dhcp6.getOptions().size(), 4);
// Client ID
Dhcp6Option option = dhcp6.getOptions().get(0);
assertTrue(option instanceof Dhcp6ClientIdOption);
Dhcp6ClientIdOption clientIdOption = (Dhcp6ClientIdOption) option;
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertEquals(clientIdOption.getLength(), 14);
assertEquals(clientIdOption.getDuid().getDuidType(), Dhcp6Duid.DuidType.DUID_LLT);
assertEquals(clientIdOption.getDuid().getHardwareType(), 1);
assertEquals(clientIdOption.getDuid().getDuidTime(), CLIENT_DUID_TIME);
assertArrayEquals(clientIdOption.getDuid().getLinkLayerAddress(), CLIENT_MAC.toBytes());
// ORO
option = dhcp6.getOptions().get(1);
assertEquals(option.getCode(), DHCP6.OptionCode.ORO.value());
assertEquals(option.getLength(), 8);
assertArrayEquals(option.getData(),
new byte[]{0, 23, 0, 24, 0, 39, 0, 31});
// ELAPSED_TIME
option = dhcp6.getOptions().get(2);
assertEquals(option.getCode(), DHCP6.OptionCode.ELAPSED_TIME.value());
assertEquals(option.getLength(), 2);
assertArrayEquals(option.getData(),
new byte[]{0, 0});
// IA NA
option = dhcp6.getOptions().get(3);
assertTrue(option instanceof Dhcp6IaNaOption);
Dhcp6IaNaOption iaNaOption = (Dhcp6IaNaOption) option;
assertEquals(iaNaOption.getCode(), DHCP6.OptionCode.IA_NA.value());
assertEquals(iaNaOption.getLength(), 12);
assertEquals(iaNaOption.getIaId(), IA_ID);
assertEquals(iaNaOption.getT1(), T1_CLIENT);
assertEquals(iaNaOption.getT2(), T2_CLIENT);
assertEquals(iaNaOption.getOptions().size(), 0);
assertArrayEquals(data, dhcp6.serialize());
}
/**
* Test serialize solicit message.
*
* @throws Exception exception while serialize the DHCPv6 payload
*/
@Test
public void serializeSolicit() throws Exception {
DHCP6 dhcp6 = new DHCP6();
dhcp6.setMsgType(DHCP6.MsgType.SOLICIT.value());
dhcp6.setTransactionId(XID_1);
List<Dhcp6Option> options = Lists.newArrayList();
// Client ID
Dhcp6Duid duid = new Dhcp6Duid();
duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
duid.setHardwareType((short) 1);
duid.setDuidTime(CLIENT_DUID_TIME);
duid.setLinkLayerAddress(CLIENT_MAC.toBytes());
Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
clientIdOption.setDuid(duid);
options.add(clientIdOption);
// Option request
Dhcp6Option option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.ORO.value());
option.setLength((short) 8);
option.setData(new byte[]{0, 23, 0, 24, 0, 39, 0, 31});
options.add(option);
// Elapsed Time
option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.ELAPSED_TIME.value());
option.setLength((short) 2);
option.setData(new byte[]{0, 0});
options.add(option);
// IA NA
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
iaNaOption.setIaId(IA_ID);
iaNaOption.setT1(T1_CLIENT);
iaNaOption.setT2(T2_CLIENT);
iaNaOption.setOptions(Collections.emptyList());
options.add(iaNaOption);
dhcp6.setOptions(options);
Dhcp6RelayOption relayOption = new Dhcp6RelayOption();
relayOption.setPayload(dhcp6);
assertArrayEquals(IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(SOLICIT)),
dhcp6.serialize());
}
/**
* Test deserialize advertise message.
*
* @throws Exception exception while deserialize the DHCPv6 payload
*/
@Test
public void deserializeAdvertise() throws Exception {
byte[] data = IOUtils.toByteArray(getClass().getResource(ADVERTISE));
DHCP6 dhcp6 = DHCP6.deserializer().deserialize(data, 0, data.length);
assertEquals(dhcp6.getMsgType(), DHCP6.MsgType.ADVERTISE.value());
assertEquals(dhcp6.getTransactionId(), XID_1);
assertEquals(dhcp6.getOptions().size(), 3);
// IA NA
Dhcp6Option option = dhcp6.getOptions().get(0);
assertTrue(option instanceof Dhcp6IaNaOption);
Dhcp6IaNaOption iaNaOption = (Dhcp6IaNaOption) option;
assertEquals(iaNaOption.getCode(), DHCP6.OptionCode.IA_NA.value());
assertEquals(iaNaOption.getLength(), 40);
assertEquals(iaNaOption.getIaId(), IA_ID);
assertEquals(iaNaOption.getT1(), T1_SERVER);
assertEquals(iaNaOption.getT2(), T2_SERVER);
assertEquals(iaNaOption.getOptions().size(), 1);
// IA Address (in IA NA)
assertTrue(iaNaOption.getOptions().get(0) instanceof Dhcp6IaAddressOption);
Dhcp6IaAddressOption iaAddressOption =
(Dhcp6IaAddressOption) iaNaOption.getOptions().get(0);
assertEquals(iaAddressOption.getIp6Address(), IA_ADDRESS);
assertEquals(iaAddressOption.getPreferredLifetime(), PREFFERRED_LT_SERVER);
assertEquals(iaAddressOption.getValidLifetime(), VALID_LT_SERVER);
assertNull(iaAddressOption.getOptions());
// Client ID
option = dhcp6.getOptions().get(1);
assertTrue(option instanceof Dhcp6ClientIdOption);
Dhcp6ClientIdOption clientIdOption = (Dhcp6ClientIdOption) option;
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertEquals(clientIdOption.getLength(), 14);
assertEquals(clientIdOption.getDuid().getDuidType(), Dhcp6Duid.DuidType.DUID_LLT);
assertEquals(clientIdOption.getDuid().getHardwareType(), 1);
assertEquals(clientIdOption.getDuid().getDuidTime(), CLIENT_DUID_TIME);
assertArrayEquals(clientIdOption.getDuid().getLinkLayerAddress(), CLIENT_MAC.toBytes());
// Server ID
option = dhcp6.getOptions().get(2);
assertEquals(option.getCode(), DHCP6.OptionCode.SERVERID.value());
assertEquals(option.getLength(), 14);
assertArrayEquals(option.getData(),
new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
assertArrayEquals(data, dhcp6.serialize());
}
/**
* Test serialize advertise message.
*
* @throws Exception exception while serialize the DHCPv6 payload
*/
@Test
public void serializeAdvertise() throws Exception {
DHCP6 dhcp6 = new DHCP6();
dhcp6.setMsgType(DHCP6.MsgType.ADVERTISE.value());
dhcp6.setTransactionId(XID_1);
List<Dhcp6Option> options = Lists.newArrayList();
// IA address
Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
iaAddressOption.setIp6Address(IA_ADDRESS);
iaAddressOption.setPreferredLifetime(PREFFERRED_LT_SERVER);
iaAddressOption.setValidLifetime(VALID_LT_SERVER);
// IA NA
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
iaNaOption.setIaId(IA_ID);
iaNaOption.setT1(T1_SERVER);
iaNaOption.setT2(T2_SERVER);
iaNaOption.setOptions(ImmutableList.of(iaAddressOption));
options.add(iaNaOption);
// Client ID
Dhcp6Duid duid = new Dhcp6Duid();
duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
duid.setHardwareType((short) 1);
duid.setDuidTime(CLIENT_DUID_TIME);
duid.setLinkLayerAddress(CLIENT_MAC.toBytes());
Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
clientIdOption.setDuid(duid);
options.add(clientIdOption);
// Server ID
Dhcp6Option option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.SERVERID.value());
option.setLength((short) 14);
option.setData(new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
options.add(option);
dhcp6.setOptions(options);
Dhcp6RelayOption relayOption = new Dhcp6RelayOption();
relayOption.setPayload(dhcp6);
assertArrayEquals(IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(ADVERTISE)),
dhcp6.serialize());
}
/**
* Test deserialize request message.
*
* @throws Exception exception while deserialize the DHCPv6 payload
*/
@Test
public void deserializeRequest() throws Exception {
byte[] data = IOUtils.toByteArray(getClass().getResource(REQUEST));
DHCP6 dhcp6 = DHCP6.deserializer().deserialize(data, 0, data.length);
assertEquals(dhcp6.getMsgType(), DHCP6.MsgType.REQUEST.value());
assertEquals(dhcp6.getTransactionId(), XID_2);
assertEquals(dhcp6.getOptions().size(), 5);
// Client ID
Dhcp6Option option = dhcp6.getOptions().get(0);
assertTrue(option instanceof Dhcp6ClientIdOption);
Dhcp6ClientIdOption clientIdOption = (Dhcp6ClientIdOption) option;
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertEquals(clientIdOption.getLength(), 14);
assertEquals(clientIdOption.getDuid().getDuidType(), Dhcp6Duid.DuidType.DUID_LLT);
assertEquals(clientIdOption.getDuid().getHardwareType(), 1);
assertEquals(clientIdOption.getDuid().getDuidTime(), CLIENT_DUID_TIME);
assertArrayEquals(clientIdOption.getDuid().getLinkLayerAddress(), CLIENT_MAC.toBytes());
// Server ID
option = dhcp6.getOptions().get(1);
assertEquals(option.getCode(), DHCP6.OptionCode.SERVERID.value());
assertEquals(option.getLength(), 14);
assertArrayEquals(option.getData(),
new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
// Option Request
option = dhcp6.getOptions().get(2);
assertEquals(option.getCode(), DHCP6.OptionCode.ORO.value());
assertEquals(option.getLength(), 8);
assertArrayEquals(option.getData(), new byte[]{0, 23, 0, 24, 0, 39, 0, 31});
// ELAPSED_TIME
option = dhcp6.getOptions().get(3);
assertEquals(option.getCode(), DHCP6.OptionCode.ELAPSED_TIME.value());
assertEquals(option.getLength(), 2);
assertArrayEquals(option.getData(),
new byte[]{0, 0});
// IA NA
option = dhcp6.getOptions().get(4);
assertTrue(option instanceof Dhcp6IaNaOption);
Dhcp6IaNaOption iaNaOption = (Dhcp6IaNaOption) option;
assertEquals(iaNaOption.getCode(), DHCP6.OptionCode.IA_NA.value());
assertEquals(iaNaOption.getLength(), 40);
assertEquals(iaNaOption.getIaId(), IA_ID);
assertEquals(iaNaOption.getT1(), T1_CLIENT);
assertEquals(iaNaOption.getT2(), T2_CLIENT);
assertEquals(iaNaOption.getOptions().size(), 1);
// IA Address (in IA NA)
assertTrue(iaNaOption.getOptions().get(0) instanceof Dhcp6IaAddressOption);
Dhcp6IaAddressOption iaAddressOption =
(Dhcp6IaAddressOption) iaNaOption.getOptions().get(0);
assertEquals(iaAddressOption.getIp6Address(), IA_ADDRESS);
assertEquals(iaAddressOption.getPreferredLifetime(), PREFFERRED_LT_REQ);
assertEquals(iaAddressOption.getValidLifetime(), VALID_LT_REQ);
assertNull(iaAddressOption.getOptions());
assertArrayEquals(data, dhcp6.serialize());
}
/**
* Test serialize request message.
*
* @throws Exception exception while serialize the DHCPv6 payload
*/
@Test
public void serializeRequest() throws Exception {
DHCP6 dhcp6 = new DHCP6();
dhcp6.setMsgType(DHCP6.MsgType.REQUEST.value());
dhcp6.setTransactionId(XID_2);
List<Dhcp6Option> options = Lists.newArrayList();
// Client ID
Dhcp6Duid duid = new Dhcp6Duid();
duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
duid.setHardwareType((short) 1);
duid.setDuidTime(CLIENT_DUID_TIME);
duid.setLinkLayerAddress(CLIENT_MAC.toBytes());
Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
clientIdOption.setDuid(duid);
options.add(clientIdOption);
// Server ID
Dhcp6Option option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.SERVERID.value());
option.setLength((short) 14);
option.setData(new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
options.add(option);
// Option request
option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.ORO.value());
option.setLength((short) 8);
option.setData(new byte[]{0, 23, 0, 24, 0, 39, 0, 31});
options.add(option);
// Elapsed Time
option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.ELAPSED_TIME.value());
option.setLength((short) 2);
option.setData(new byte[]{0, 0});
options.add(option);
// IA address
Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
iaAddressOption.setIp6Address(IA_ADDRESS);
iaAddressOption.setPreferredLifetime(PREFFERRED_LT_REQ);
iaAddressOption.setValidLifetime(VALID_LT_REQ);
// IA NA
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
iaNaOption.setIaId(IA_ID);
iaNaOption.setT1(T1_CLIENT);
iaNaOption.setT2(T2_CLIENT);
iaNaOption.setOptions(ImmutableList.of(iaAddressOption));
options.add(iaNaOption);
dhcp6.setOptions(options);
Dhcp6RelayOption relayOption = new Dhcp6RelayOption();
relayOption.setPayload(dhcp6);
assertArrayEquals(IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(REQUEST)),
dhcp6.serialize());
}
/**
* Test deserialize relay message with reply message.
*
* @throws Exception exception while deserialize the DHCPv6 payload
*/
@Test
public void deserializeReply() throws Exception {
byte[] data = IOUtils.toByteArray(getClass().getResource(REPLY));
DHCP6 dhcp6 = DHCP6.deserializer().deserialize(data, 0, data.length);
assertEquals(dhcp6.getMsgType(), DHCP6.MsgType.REPLY.value());
assertEquals(dhcp6.getTransactionId(), XID_2);
assertEquals(dhcp6.getOptions().size(), 3);
// IA NA
Dhcp6Option option = dhcp6.getOptions().get(0);
assertTrue(option instanceof Dhcp6IaNaOption);
Dhcp6IaNaOption iaNaOption = (Dhcp6IaNaOption) option;
assertEquals(iaNaOption.getCode(), DHCP6.OptionCode.IA_NA.value());
assertEquals(iaNaOption.getLength(), 40);
assertEquals(iaNaOption.getIaId(), IA_ID);
assertEquals(iaNaOption.getT1(), T1_SERVER);
assertEquals(iaNaOption.getT2(), T2_SERVER);
assertEquals(iaNaOption.getOptions().size(), 1);
// IA Address (in IA NA)
assertTrue(iaNaOption.getOptions().get(0) instanceof Dhcp6IaAddressOption);
Dhcp6IaAddressOption iaAddressOption =
(Dhcp6IaAddressOption) iaNaOption.getOptions().get(0);
assertEquals(iaAddressOption.getIp6Address(), IA_ADDRESS);
assertEquals(iaAddressOption.getPreferredLifetime(), PREFFERRED_LT_SERVER);
assertEquals(iaAddressOption.getValidLifetime(), VALID_LT_SERVER);
assertNull(iaAddressOption.getOptions());
// Client ID
option = dhcp6.getOptions().get(1);
assertTrue(option instanceof Dhcp6ClientIdOption);
Dhcp6ClientIdOption clientIdOption = (Dhcp6ClientIdOption) option;
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertEquals(clientIdOption.getLength(), 14);
assertEquals(clientIdOption.getDuid().getDuidType(), Dhcp6Duid.DuidType.DUID_LLT);
assertEquals(clientIdOption.getDuid().getHardwareType(), 1);
assertEquals(clientIdOption.getDuid().getDuidTime(), CLIENT_DUID_TIME);
assertArrayEquals(clientIdOption.getDuid().getLinkLayerAddress(), CLIENT_MAC.toBytes());
// Server ID
option = dhcp6.getOptions().get(2);
assertEquals(option.getCode(), DHCP6.OptionCode.SERVERID.value());
assertEquals(option.getLength(), 14);
assertArrayEquals(option.getData(),
new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
assertArrayEquals(data, dhcp6.serialize());
}
@Test
public void serializeReply() throws Exception {
DHCP6 dhcp6 = new DHCP6();
dhcp6.setMsgType(DHCP6.MsgType.REPLY.value());
dhcp6.setTransactionId(XID_2);
List<Dhcp6Option> options = Lists.newArrayList();
// IA address
Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
iaAddressOption.setIp6Address(IA_ADDRESS);
iaAddressOption.setPreferredLifetime(PREFFERRED_LT_SERVER);
iaAddressOption.setValidLifetime(VALID_LT_SERVER);
// IA NA
Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
iaNaOption.setIaId(IA_ID);
iaNaOption.setT1(T1_SERVER);
iaNaOption.setT2(T2_SERVER);
iaNaOption.setOptions(ImmutableList.of(iaAddressOption));
options.add(iaNaOption);
// Client ID
Dhcp6Duid duid = new Dhcp6Duid();
duid.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
duid.setHardwareType((short) 1);
duid.setDuidTime(CLIENT_DUID_TIME);
duid.setLinkLayerAddress(CLIENT_MAC.toBytes());
Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
clientIdOption.setDuid(duid);
options.add(clientIdOption);
// Server ID
Dhcp6Option option = new Dhcp6Option();
option.setCode(DHCP6.OptionCode.SERVERID.value());
option.setLength((short) 14);
option.setData(new byte[]{0, 1, 0, 1, 32, -1, -8, -17, 0, -103, 102, 0, 0, 1});
options.add(option);
dhcp6.setOptions(options);
Dhcp6RelayOption relayOption = new Dhcp6RelayOption();
relayOption.setPayload(dhcp6);
assertArrayEquals(IOUtils.toByteArray(Dhcp6RelayTest.class.getResource(REPLY)),
dhcp6.serialize());
}
}