Browse Source

[2765] Applied patch for DHCPv4 silently failing when DHCP port in use.

Marcin Siodelski 11 years ago
parent
commit
0119b50f66
2 changed files with 55 additions and 1 deletions
  1. 21 1
      src/lib/dhcp/pkt_filter_lpf.cc
  2. 34 0
      src/lib/dhcp/tests/iface_mgr_unittest.cc

+ 21 - 1
src/lib/dhcp/pkt_filter_lpf.cc

@@ -103,9 +103,29 @@ namespace isc {
 namespace dhcp {
 namespace dhcp {
 
 
 int
 int
-PktFilterLPF::openSocket(const Iface& iface, const isc::asiolink::IOAddress&,
+PktFilterLPF::openSocket(const Iface& iface,
+                         const isc::asiolink::IOAddress& addr,
                          const uint16_t port, const bool,
                          const uint16_t port, const bool,
                          const bool) {
                          const bool) {
+    // Let's check if a socket is already in use
+    int sock_check = socket(AF_INET, SOCK_DGRAM, 0);
+    if (sock_check < 0) {
+        isc_throw(SocketConfigError, "Failed to create dgram socket");
+    }
+
+    struct sockaddr_in addr4;
+    memset(& addr4, 0, sizeof(addr4));
+    addr4.sin_family = AF_INET;
+    addr4.sin_addr.s_addr = htonl(addr);
+    addr4.sin_port = htons(port);
+
+    if (bind(sock_check, (struct sockaddr *)& addr4, sizeof(addr4)) < 0) {
+        // We return negative, the proper error message will be displayed
+        // by the IfaceMgr ...
+        close(sock_check);
+        return (-1);
+    }
+    close(sock_check);
 
 
     int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
     int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
     if (sock < 0) {
     if (sock < 0) {

+ 34 - 0
src/lib/dhcp/tests/iface_mgr_unittest.cc

@@ -986,6 +986,40 @@ TEST_F(IfaceMgrTest, setMatchingPacketFilter) {
     EXPECT_TRUE(iface_mgr->isDirectResponseSupported());
     EXPECT_TRUE(iface_mgr->isDirectResponseSupported());
 }
 }
 
 
+TEST_F(IfaceMgrTest, checkPacketFilterLPFSocket) {
+    IOAddress loAddr("127.0.0.1");
+    int socket1 = 0, socket2 = 0;
+    // Create two instances of IfaceMgr.
+    boost::scoped_ptr<NakedIfaceMgr> iface_mgr1(new NakedIfaceMgr());
+    ASSERT_TRUE(iface_mgr1);
+    boost::scoped_ptr<NakedIfaceMgr> iface_mgr2(new NakedIfaceMgr());
+    ASSERT_TRUE(iface_mgr2);
+
+    // Let IfaceMgr figure out which Packet Filter to use when
+    // direct response capability is not desired. It should pick
+    // PktFilterInet.
+    EXPECT_NO_THROW(iface_mgr1->setMatchingPacketFilter(false));
+    // Let's open a loopback socket with handy unpriviliged port number
+    socket1 = iface_mgr1->openSocket(LOOPBACK, loAddr,
+                                     DHCP4_SERVER_PORT + 10000);
+
+    EXPECT_GE(socket1, 0);
+
+    // Then the second use PkFilterLPF mode
+    EXPECT_NO_THROW(iface_mgr2->setMatchingPacketFilter(true));
+    // This socket opening attempt should not return positive value
+    // The first socket already opened same port
+    EXPECT_NO_THROW(
+        socket2 = iface_mgr2->openSocket(LOOPBACK, loAddr,
+                                         DHCP4_SERVER_PORT + 10000);
+    );
+
+    EXPECT_LE(socket2, 0);
+
+    close(socket2);
+    close(socket1);
+}
+
 #else
 #else
 
 
 // This non-Linux specific test checks whether it is possible to use
 // This non-Linux specific test checks whether it is possible to use