use Net::DHCP::Packet;
use Net::DHCP::Constants 0.67;
-use CouchDB;
+use store;
use format;
use server;
sub client_mac_ip {
my ( $mac, $request_ip ) = @_;
+ if ( ! $mac ) {
+ warn "W: no mac in requiest\n";
+ return;
+ }
+
my $conf = $server::conf;
mkdir $conf unless -e $conf;
if ( $ip = client::ip_from_mac( $mac ) ) {
print "RENEW $mac $ip\n";
+ client::save_ip_mac( $ip, $mac );
return $ip;
- } elsif ( in_our_range( $request_ip ) ) {
+ } elsif ( ip::in_dhcp_range( $request_ip ) || $request_ip eq '0.0.0.0' ) {
$ip = client::next_ip( $mac );
print "NEW $mac $ip\n";
} else {
$ip = $request_ip;
client::save_ip_mac( $ip, $mac );
- warn "W: $ip our of server range $server::ip $server::netmask\n";
+ warn "W: $ip out of server range $server::ip/$server::netmask\n";
}
return $ip;
our $file;
our $transaction = 0; # FIXME predictible transaction numbers
-sub ip2bin { pack('C*', split(/\./, $_[0])) };
-sub in_our_range {
- my $ip = shift;
- return 1 if $ip eq '0.0.0.0';
- return 1 if (
- ( ip2bin($ip) & ip2bin($server::netmask) )
- eq
- ( ip2bin($server::ip) & ip2bin($server::netmask) )
- );
-}
-
sub process_packet {
my $sock = shift;
- server->refresh;
-
my $buf;
$sock->recv($buf, 1024);
my $size = 'empty';
return unless $buf;
my $dhcp = Net::DHCP::Packet->new($buf);
- $dhcp->comment( $transaction++ );
warn "recv: ", $dhcp->toString if $debug;
- my $mac = substr($dhcp->chaddr(),0,$dhcp->hlen()*2);
+ $dhcp->comment( $transaction++ );
+
+ my $mac = format::mac( substr($dhcp->chaddr(),0,$dhcp->hlen()*2) );
my $ip = client_mac_ip($mac, $dhcp->ciaddr);
my $hostname = $dhcp->getOptionValue(DHO_HOST_NAME);
- print "$ip ", client::conf( $ip => 'hostname', default => $hostname ), " >> /etc/hosts\n";
-
- my $audit = { mac => format::mac($mac), ip => $ip, hostname => $hostname };
+ print "$ip ", client::conf( $ip => 'hostname', default => $hostname ), " >> /etc/hosts\n" if $hostname;
+
+ my $audit = { mac => $mac, ip => $ip, hostname => $hostname,
+ options => {
+ map {
+ ( $_ => $dhcp->getOptionValue( $_ ) )
+ } @{ $dhcp->{options_order} }
+ },
+ };
=for later
config::for_ip( $ip );
+ my $server = server::as_hash_for $ip;
+
my $packet = {
Op => BOOTREPLY(),
Hops => $dhcp->hops(),
Flags => $dhcp->flags(),
Ciaddr => $dhcp->ciaddr(),
Yiaddr => $ip,
- Siaddr => $server::ip,
+ Siaddr => $server->{ip},
Giaddr => $dhcp->giaddr(),
Chaddr => $dhcp->chaddr(),
File => $file,
- DHO_DHCP_SERVER_IDENTIFIER() => $server::ip, # busybox/udhcpc needs it but doesn't request
+ DHO_DHCP_SERVER_IDENTIFIER() => $server->{ip}, # busybox/udhcpc needs it but doesn't request
};
my $options = {
- DHO_SUBNET_MASK() => $server::netmask,
- DHO_ROUTERS() => $server::ip,
- DHO_DOMAIN_NAME() => $server::domain_name,
- DHO_NAME_SERVERS() => $server::ip,
- DHO_DOMAIN_NAME_SERVERS() => $server::ip,
+ DHO_SUBNET_MASK() => $server->{netmask},
+ DHO_ROUTERS() => ( $server->{gw} || $server->{ip} ),
+ DHO_DOMAIN_NAME() => $server->{domain},
+ DHO_NAME_SERVERS() => $server->{ip},
+ DHO_DOMAIN_NAME_SERVERS() => ( $server->{dns} || $server->{ip} ),
DHO_HOST_NAME() => client::conf( $ip, 'hostname' ),
- DHO_BROADCAST_ADDRESS() => $server::bcast,
+ DHO_BROADCAST_ADDRESS() => $server->{bcast},
# DHO_NTP_SERVERS() => '',
};
my $messagetype = $dhcp->getOptionValue(DHO_DHCP_MESSAGE_TYPE());
+ my @type;
+
if ($messagetype eq DHCPDISCOVER()) {
- $audit->{type} = 'discover';
$packet->{Comment} = $dhcp->comment();
$packet->{DHO_DHCP_MESSAGE_TYPE()} = DHCPOFFER();
+ @type = qw( discover offer );
} elsif ($messagetype eq DHCPREQUEST()) {
- my $requested_ip = $dhcp->getOptionValue(DHO_DHCP_REQUESTED_ADDRESS());
- $audit->{type} = 'request';
+ @type = qw( request );
+ my $requested_ip = $dhcp->getOptionValue(DHO_DHCP_REQUESTED_ADDRESS()) || $dhcp->ciaddr();
if ( $ip eq $requested_ip ) {
$packet->{DHO_DHCP_MESSAGE_TYPE()} = DHCPACK();
$packet->{DHO_DHCP_LEASE_TIME()} = 5 * 60; # 5 min
# $packet->{DHO_ROOT_PATH()} = '/exports/foobar';
+ $type[1] = 'ack';
} else {
$packet->{DHO_DHCP_MESSAGE_TYPE()} = DHCPNAK();
- $packet->{DHO_DHCP_MESSAGE()} = "Bad request, expected $ip";
+ $packet->{DHO_DHCP_MESSAGE()} = "Bad request, expected $ip got $requested_ip";
+ $type[1] = 'nak';
}
} elsif ($messagetype eq DHCPINFORM()) {
- $audit->{type} = 'inform';
+ @type = qw( inform ignored );
} else {
- $audit->{type} = sprintf('ignored %x', $messagetype);
+ @type = ( $messagetype, 'ignored' );
}
- warn ">> $mac == $ip server: $server::ip", $file ? " file: $file\n" : "\n" if $debug;
+ warn "# type ",dump @type;
+ $audit->{type} = [ @type ];
+
$audit->{response} = $packet;
$packet = new Net::DHCP::Packet( %$packet );
warn "send ",$packet->toString() if $debug;
- if ( in_our_range( $ip ) ) {
+ if ( ip::in_dhcp_range( $ip ) ) {
my $buff = $packet->serialize();
my $reply = IO::Socket::INET->new(
- LocalAddr => $server::ip,
+ LocalAddr => $server->{ip},
LocalPort => 67,
Proto => "udp",
Broadcast => 1,
- PeerAddr => '255.255.255.255',
+# PeerAddr => '255.255.255.255',
+ PeerAddr => $server->{bcast},
PeerPort => 68,
Reuse => 1,
) or die "socket: $@";
$reply->send( $buff, 0 ) or die "Error sending: $!\n";
+ warn ">> $mac == $ip server: $server->{ip}", $file ? " file: $file\n" : "\n";
} else {
- $audit->{error} = "$ip our of our range $server::ip $server::netmask";
+ $audit->{error} = "$ip not in server range $server::ip $server::netmask - no packet sent";
+ warn $audit->{error};
}
- CouchDB::audit( $audit->{type}, $audit );
+ store::audit( @type, $audit );
# system("arp -s $ip $mac"),
print "DHCP listen on ",$sock->sockhost,":",$sock->sockport,"\n";
- CouchDB::audit( 'start', { addr => $sock->sockhost, port => $sock->sockport } );
+ store::audit( 'start', { addr => $sock->sockhost, port => $sock->sockport } );
while (1) {
+ server->refresh;
process_packet $sock;
}
}