#
# pfdhcplistener fix for IP Helper based setups (#1149)
# should apply cleanly on 1.9.x, 2.0.0 (maybe 1.8.x)
#
# Olivier Bilodeau on 2011-01-13
#
============================================================
--- pf/sbin/pfdhcplistener	a1eab0260ea67e5022096bf639b88b40a0ee8526
+++ pf/sbin/pfdhcplistener	3f5129251041956df73a97dfb07f213ecfba75ce
@@ -116,11 +122,14 @@ sub dhcp_detector {
     my $err;
     my $pcap_t = Net::Pcap::pcap_open_live( $eth, 576, 1, 0, \$err );
 
-    if ( ( Net::Pcap::compile( $pcap_t, \$filter_t, $filter, $opt, 0 ) )
-        == -1 )
-    {
+    if (!defined($pcap_t)) {
+        $logger->logdie("Unable to initiate packet capture. Is $eth an actual network interface?");
+    }
+
+    if ((Net::Pcap::compile( $pcap_t, \$filter_t, $filter, $opt, 0 )) == -1) {
         $logger->logdie("Unable to compile filter string '$filter'");
     }
+
     Net::Pcap::setfilter( $pcap_t, $filter_t );
     Net::Pcap::loop( $pcap_t, -1, \&process_pkt, $eth );
 }
@@ -282,11 +291,7 @@ sub listen_dhcp {
                 pfmailer(%rogue_message);
             }
         } elsif ( defined( $options{'53'}[0] ) && $options{'53'}[0] == 5 ) {
-            my $lease_length = undef;
-            if ( exists( $options{51} ) ) {
-                $lease_length
-                    = unpack( "N", pack( "C4", @{ $options{51} } ) );
-            }
+            my $lease_length = get_lease_length();
 
             if ($yiaddr) {
                 $yiaddr = int2ip($yiaddr);
@@ -322,8 +327,19 @@ sub listen_dhcp {
     } elsif ( $op == 1 ) {
         if ( defined( $options{'53'}[0] ) && $options{'53'}[0] == 1 ) {
             $logger->debug("DHCPDISCOVER from $chaddr");
+
         } elsif ( defined( $options{'53'}[0] ) && $options{'53'}[0] == 3 ) {
             $logger->debug("DHCPREQUEST from $chaddr");
+            my $lease_length = get_lease_length(%options);
+            my $client_ip = get_requested_ip(%options);
+            if ($client_ip) {
+                $logger->info(
+                    "DHCPREQUEST from $chaddr ($client_ip)"
+                    . ( defined($lease_length) ? " with lease of $lease_length seconds" : "")
+                );
+                update_iplog( $chaddr, $client_ip, $lease_length );
+            }
+
         } elsif ( defined( $options{'53'}[0] ) && $options{'53'}[0] == 7 ) {
             $ciaddr = int2ip($ciaddr);
             $logger->debug("DHCPRELEASE from $chaddr ($ciaddr)");
@@ -337,7 +353,7 @@ sub listen_dhcp {
 
         my %tmp;
         $tmp{'dhcp_fingerprint'} = "";
-        my $fingerprint_data;
+        my $fingerprint_data = '';
         if ( defined( $options{'55'} ) ) {
             my $dhcp_fingerprint = join( ",", @{ $options{'55'} } );
             $tmp{'dhcp_fingerprint'} = $dhcp_fingerprint;
@@ -458,6 +474,42 @@ sub update_iplog {
     iplog_open( $srcmac, $srcip, $lease_length );
 }
 
+=item get_lease_length
+
+Grab DHCP lease duration from DHCP Option 51. See RFC 2132 for details.
+
+Option 51: IP Address Lease Time
+
+=cut
+sub get_lease_length {
+    my (%options) = @_;
+
+    my $lease_length;
+    if ( exists( $options{51} ) ) {
+        $lease_length = unpack( "N", pack( "C4", @{ $options{51} } ) );
+    }
+
+    return $lease_length;
+}
+
+=item get_requested_ip
+
+Grab IP address from DHCP Option 50. See RFC 2132 for details.
+
+Option 50: Requested IP Address
+
+=cut
+sub get_requested_ip {
+    my (%options) = @_;
+
+    my $req_ip;
+    if ( exists( $options{50} ) ) {
+        $req_ip = int2ip( unpack( "N", pack( "C4", @{$options{50}} ) ) );
+    }
+
+    return $req_ip;
+}
+
 sub daemonize {
     chdir '/' or $logger->logdie("Can't chdir to /: $!");
     open STDIN, '<', '/dev/null'
