001/* 002 * To change this license header, choose License Headers in Project Properties. 003 * To change this template file, choose Tools | Templates 004 * and open the template in the editor. 005 */ 006package org.anarres.dhcp.server.pcap; 007 008import java.net.InetSocketAddress; 009import java.nio.ByteBuffer; 010import java.util.Arrays; 011import javax.annotation.Nonnull; 012import org.anarres.dhcp.common.address.InterfaceAddress; 013import org.apache.directory.server.dhcp.io.DhcpMessageDecoder; 014import org.apache.directory.server.dhcp.io.DhcpMessageEncoder; 015import org.apache.directory.server.dhcp.io.DhcpRequestContext; 016import org.apache.directory.server.dhcp.messages.DhcpMessage; 017import org.apache.directory.server.dhcp.service.DhcpService; 018import org.pcap4j.core.PacketListener; 019import org.pcap4j.packet.EthernetPacket; 020import org.pcap4j.packet.IpV4Packet; 021import org.pcap4j.packet.Packet; 022import org.pcap4j.packet.UdpPacket; 023import org.pcap4j.packet.UnknownPacket; 024import org.pcap4j.packet.namednumber.EtherType; 025import org.pcap4j.packet.namednumber.IpNumber; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028 029/** 030 * 031 * @author shevek 032 */ 033public class DhcpPacketListener implements PacketListener { 034 035 private static final Logger LOG = LoggerFactory.getLogger(DhcpPacketListener.class); 036 private final DhcpMessageDecoder decoder = new DhcpMessageDecoder(); 037 private final DhcpMessageEncoder encoder = new DhcpMessageEncoder(); 038 private final DhcpService service; 039 private final InterfaceAddress[] interfaceAddresses; 040 041 public DhcpPacketListener(@Nonnull DhcpService service, @Nonnull InterfaceAddress[] interfaceAddresses) { 042 this.service = service; 043 this.interfaceAddresses = interfaceAddresses; 044 } 045 046 public void gotPacket(Packet rawPacket) { 047 try { 048 LOG.info("Read raw " + rawPacket); 049 IpV4Packet ipPacket = rawPacket.get(IpV4Packet.class); 050 UdpPacket udpPacket = rawPacket.get(UdpPacket.class); 051 byte[] dhcpData = udpPacket.getPayload().getRawData(); 052 InetSocketAddress remoteAddress = new InetSocketAddress(ipPacket.getHeader().getSrcAddr(), udpPacket.getHeader().getSrcPort().valueAsInt()); 053 InetSocketAddress localAddress = new InetSocketAddress(ipPacket.getHeader().getDstAddr(), udpPacket.getHeader().getDstPort().valueAsInt()); 054 DhcpRequestContext context = new DhcpRequestContext(interfaceAddresses, remoteAddress, localAddress); 055 DhcpMessage request = decoder.decode(ByteBuffer.wrap(dhcpData)); 056 LOG.info("Read DHCP " + request); 057 DhcpMessage reply = service.getReplyFor(context, request); 058 if (reply == null) 059 return; 060 byte[] replyData = new byte[1536]; 061 ByteBuffer buffer = ByteBuffer.wrap(replyData); 062 encoder.encode(buffer, reply); 063 replyData = Arrays.copyOf(replyData, buffer.position()); // Truncate array to writer position. 064 UnknownPacket.Builder dhcpBuilder = new UnknownPacket.Builder() 065 .rawData(replyData); 066 UdpPacket.Builder udpBuilder = new UdpPacket.Builder() 067 .payloadBuilder(dhcpBuilder) 068 .srcPort(udpPacket.getHeader().getDstPort()) 069 .dstPort(udpPacket.getHeader().getSrcPort()) 070 .correctChecksumAtBuild(true) 071 .correctLengthAtBuild(true); 072 IpV4Packet.Builder ipBuilder = new IpV4Packet.Builder() 073 .payloadBuilder(udpBuilder) 074 .srcAddr(null) // TODO 075 .dstAddr(null) // TODO 076 .protocol(IpNumber.UDP) 077 .correctChecksumAtBuild(true) 078 .correctLengthAtBuild(true) 079 .paddingAtBuild(true); 080 EthernetPacket.Builder ethernetBuilder = new EthernetPacket.Builder() 081 .payloadBuilder(ipBuilder) 082 .type(EtherType.IPV4) 083 .paddingAtBuild(true); 084 Packet replyPacket = ethernetBuilder.build(); 085 // handle.sendPacket(replyPacket); 086 } catch (Exception e) { 087 LOG.error("DHCP failed", e); 088 } 089 } 090 091}