/*
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.hq.plugin.netservices;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Random;
import java.util.StringTokenizer;
//not a full-blown client, just enough to do dhcp discover
//http://www.faqs.org/rfcs/rfc2131.html
public class DHCPClient {
private static final Random random = new Random();
private static final int MESSAGE_TYPE = 53;
private int port;
private InetAddress address;
private DatagramSocket socket;
public DHCPClient(InetAddress address, int port)
throws SocketException {
this.socket = new DatagramSocket(68); //default client port
this.address = address;
this.port = port;
}
public void setTimeout(int millis) {
try {
this.socket.setSoTimeout(millis);
} catch (SocketException e) {
e.printStackTrace();
}
}
public void close() {
this.socket.close();
}
public void send(Packet packet)
throws IOException {
byte[] data = packet.encode();
DatagramPacket request =
new DatagramPacket(data,
data.length,
this.address,
this.port);
this.socket.send(request);
}
public Packet receive()
throws IOException {
byte[] data = new byte[1024];
DatagramPacket response =
new DatagramPacket(data, data.length);
this.socket.receive(response);
Packet packet = new Packet();
packet.decode(response.getData());
return packet;
}
private static String addrToText(byte src[]) {
return
(src[0] & 0xff) + "." +
(src[1] & 0xff) + "." +
(src[2] & 0xff) + "." +
(src[3] & 0xff);
}
public static byte[] decodeHwaddr(String hwaddr) {
StringTokenizer token =
new StringTokenizer(hwaddr, ":");
byte[] data = new byte[Packet.CHADDR_LEN];
for (int i=0; i<Packet.HWADDR_LEN; i++) {
data[i] =
(byte)Integer.parseInt(token.nextToken(), 16);
}
return data;
}
public class Packet {
private static final int ADDR_LEN = 4;
private static final int CHADDR_LEN = 16;
private static final int SNAME_LEN = 64;
private static final int FILE_LEN = 128;
private static final int OPTIONS_LEN = 312;
private static final int HWADDR_LEN = 6;
public byte op = (byte)1; //BOOTREQUEST
public byte htype = (byte)1; //ETHERNET
public byte hlen = (byte)HWADDR_LEN;
public byte hops = (byte)0;
public int xid;
public short secs = (short)0;
public short flags = (short)0;
public byte[] ciaddr = new byte[ADDR_LEN];
public byte[] yiaddr = new byte[ADDR_LEN];
public byte[] siaddr = new byte[ADDR_LEN];
public byte[] giaddr = new byte[ADDR_LEN];
public byte[] chaddr = new byte[CHADDR_LEN];
public byte[] sname = new byte[SNAME_LEN];
public byte[] file = new byte[FILE_LEN];
public byte[] options = new byte[OPTIONS_LEN];
public String getYaddress() {
return addrToText(this.yiaddr);
}
public String getSaddress() {
return addrToText(this.siaddr);
}
public byte[] encode()
throws IOException {
ByteArrayOutputStream bytes =
new ByteArrayOutputStream();
DataOutputStream stream =
new DataOutputStream(bytes);
stream.writeByte(this.op);
stream.writeByte(this.htype);
stream.writeByte(this.hlen);
stream.writeByte(this.hops);
stream.writeInt(this.xid);
stream.writeShort(this.secs);
stream.writeShort(this.flags);
stream.write(this.ciaddr, 0, ADDR_LEN);
stream.write(this.yiaddr, 0, ADDR_LEN);
stream.write(this.siaddr, 0, ADDR_LEN);
stream.write(this.giaddr, 0, ADDR_LEN);
stream.write(this.chaddr, 0, CHADDR_LEN);
stream.write(this.sname, 0, SNAME_LEN);
stream.write(this.file, 0, FILE_LEN);
stream.write(this.options, 0, OPTIONS_LEN);
return bytes.toByteArray();
}
public void decode(byte[] data)
throws IOException {
ByteArrayInputStream bytes =
new ByteArrayInputStream(data, 0, data.length);
DataInputStream stream = new DataInputStream(bytes);
this.op = stream.readByte();
this.htype = stream.readByte();
this.hlen = stream.readByte();
this.hops = stream.readByte();
this.xid = stream.readInt();
this.secs = stream.readShort();
this.flags = stream.readShort();
stream.readFully(this.ciaddr, 0, ADDR_LEN);
stream.readFully(this.yiaddr, 0, ADDR_LEN);
stream.readFully(this.siaddr, 0, ADDR_LEN);
stream.readFully(this.giaddr, 0, ADDR_LEN);
stream.readFully(this.chaddr, 0, CHADDR_LEN);
stream.readFully(this.sname, 0, SNAME_LEN);
stream.readFully(this.file, 0, FILE_LEN);
stream.readFully(this.options, 0, OPTIONS_LEN);
}
}
public Packet getDiscoverPacket(byte[] hwaddr) {
Packet packet = new Packet();
packet.xid = random.nextInt();
packet.chaddr = hwaddr;
byte[] options = packet.options;
int ix = 0;
//vendor cookie as per rfc
options[ix++] = (byte)99;
options[ix++] = (byte)130;
options[ix++] = (byte)83;
options[ix++] = (byte)99;
options[ix++] = (byte)MESSAGE_TYPE;
options[ix++] = (byte)1; //message option length
options[ix++] = (byte)1; //DHCPDISCOVER
options[ix++] = (byte)255; //terminator
return packet;
}
}