// Copyright 2012 Citrix Systems, Inc. Licensed under the
// Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. Citrix Systems, Inc.
// reserves all rights not expressly granted by 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.
//
// Automatically generated by addcopyright.py at 04/03/2012
package com.cloud.agent.dhcp;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Formatter;
import org.apache.log4j.Logger;
import org.jnetpcap.packet.JMemoryPacket;
import org.jnetpcap.packet.JPacket;
import org.jnetpcap.packet.PcapPacket;
import org.jnetpcap.protocol.lan.Ethernet;
import org.jnetpcap.protocol.lan.IEEE802dot1q;
import org.jnetpcap.protocol.network.Ip4;
import org.jnetpcap.protocol.tcpip.Udp;
import com.cloud.agent.dhcp.DhcpSnooperImpl.DHCPState;
public class DhcpPacketParser implements Runnable {
private static final Logger s_logger = Logger
.getLogger(DhcpPacketParser.class);
private enum DHCPPACKET {
OP(0), HTYPE(1), HLEN(2), HOPS(3), XID(4), SECS(8), FLAGS(10), CIADDR(
12), YIADDR(16), SIDADDR(20), GIADDR(24), CHADDR(28), SNAME(44), FILE(
108), MAGIC(236), OPTIONS(240);
int offset;
DHCPPACKET(int i) {
offset = i;
}
int getValue() {
return offset;
}
}
private enum DHCPOPTIONTYPE {
PAD(0), MESSAGETYPE(53), REQUESTEDIP(50), END(255);
int type;
DHCPOPTIONTYPE(int i) {
type = i;
}
int getValue() {
return type;
}
}
private enum DHCPMSGTYPE {
DHCPDISCOVER(1), DHCPOFFER(2), DHCPREQUEST(3), DHCPDECLINE(4), DHCPACK(
5), DHCPNAK(6), DHCPRELEASE(7), DHCPINFORM(8);
int _type;
DHCPMSGTYPE(int type) {
_type = type;
}
int getValue() {
return _type;
}
public static DHCPMSGTYPE valueOf(int type) {
for (DHCPMSGTYPE t : values()) {
if (type == t.getValue()) {
return t;
}
}
return null;
}
}
private class DHCPMSG {
DHCPMSGTYPE msgType;
byte[] caddr;
byte[] yaddr;
byte[] chaddr;
byte[] requestedIP;
public DHCPMSG() {
caddr = new byte[4];
yaddr = new byte[4];
chaddr = new byte[6];
}
}
private PcapPacket _buffer;
private int _offset;
private int _len;
private DhcpSnooperImpl _manager;
public DhcpPacketParser(PcapPacket buffer, int offset, int len,
DhcpSnooperImpl manager) {
_buffer = buffer;
_offset = offset;
_len = len;
_manager = manager;
}
private int getPos(int pos) {
return _offset + pos;
}
private byte getByte(int offset) {
return _buffer.getByte(getPos(offset));
}
private void getByteArray(int offset, byte[] array) {
_buffer.getByteArray(getPos(offset), array);
}
private long getUInt(int offset) {
return _buffer.getUInt(getPos(offset));
}
private DHCPMSG getDhcpMsg() {
long magic = getUInt(DHCPPACKET.MAGIC.getValue());
if (magic != 0x63538263) {
return null;
}
DHCPMSG msg = new DHCPMSG();
int pos = DHCPPACKET.OPTIONS.getValue();
while (pos <= _len) {
int type = (int) getByte(pos++) & 0xff;
if (type == DHCPOPTIONTYPE.END.getValue()) {
break;
}
if (type == DHCPOPTIONTYPE.PAD.getValue()) {
continue;
}
int len = 0;
if (pos <= _len) {
len = ((int) getByte(pos++)) & 0xff;
}
if (type == DHCPOPTIONTYPE.MESSAGETYPE.getValue()
|| type == DHCPOPTIONTYPE.REQUESTEDIP.getValue()) {
/* Read data only if needed */
byte[] data = null;
if ((len + pos) <= _len) {
data = new byte[len];
getByteArray(pos, data);
}
if (type == DHCPOPTIONTYPE.MESSAGETYPE.getValue()) {
msg.msgType = DHCPMSGTYPE.valueOf((int) data[0]);
} else if (type == DHCPOPTIONTYPE.REQUESTEDIP.getValue()) {
msg.requestedIP = data;
}
}
pos += len;
}
if (msg.msgType == DHCPMSGTYPE.DHCPREQUEST) {
getByteArray(DHCPPACKET.CHADDR.getValue(), msg.chaddr);
getByteArray(DHCPPACKET.CIADDR.getValue(), msg.caddr);
} else if (msg.msgType == DHCPMSGTYPE.DHCPACK) {
getByteArray(DHCPPACKET.YIADDR.getValue(), msg.yaddr);
}
return msg;
}
private String formatMacAddress(byte[] mac) {
StringBuffer sb = new StringBuffer();
Formatter formatter = new Formatter(sb);
for (int i = 0; i < mac.length; i++) {
formatter.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : "");
}
return sb.toString();
}
private String getDestMacAddress() {
Ethernet ether = new Ethernet();
if (_buffer.hasHeader(ether)) {
byte[] destMac = ether.destination();
return formatMacAddress(destMac);
}
return null;
}
private InetAddress getDHCPServerIP() {
Ip4 ip = new Ip4();
if (_buffer.hasHeader(ip)) {
try {
return InetAddress.getByAddress(ip.source());
} catch (UnknownHostException e) {
s_logger.debug("Failed to get dhcp server ip address: "
+ e.toString());
}
}
return null;
}
@Override
public void run() {
DHCPMSG msg = getDhcpMsg();
if (msg == null) {
return;
}
if (msg.msgType == DHCPMSGTYPE.DHCPACK) {
InetAddress ip = null;
try {
ip = InetAddress.getByAddress(msg.yaddr);
String macAddr = getDestMacAddress();
_manager.setIPAddr(macAddr, ip, DHCPState.DHCPACKED,
getDHCPServerIP());
} catch (UnknownHostException e) {
}
} else if (msg.msgType == DHCPMSGTYPE.DHCPREQUEST) {
InetAddress ip = null;
if (msg.requestedIP != null) {
try {
ip = InetAddress.getByAddress(msg.requestedIP);
} catch (UnknownHostException e) {
}
}
if (ip == null) {
try {
ip = InetAddress.getByAddress(msg.caddr);
} catch (UnknownHostException e) {
}
}
if (ip != null) {
String macAddr = formatMacAddress(msg.chaddr);
_manager.setIPAddr(macAddr, ip, DHCPState.DHCPREQUESTED, null);
}
}
}
private void test() {
JPacket packet = new JMemoryPacket(
Ethernet.ID,
" 06fa 8800 00b3 0656 d200 0027 8100 001a 0800 4500 0156 64bf 0000 4011 f3f2 ac1a 6412 ac1a 649e 0043 0044 0001 0000 0001");
Ethernet eth = new Ethernet();
if (packet.hasHeader(eth)) {
System.out.print(" ether:" + eth);
}
IEEE802dot1q vlan = new IEEE802dot1q();
if (packet.hasHeader(vlan)) {
System.out.print(" vlan: " + vlan);
}
if (packet.hasHeader(Udp.ID)) {
System.out.print("has udp");
}
}
}