Parcourir la source

[5003] PoC using IP_RECVDSTADDR on BSD.

This option is used on BSD systems to
retrieve local IP address.
Marcin Siodelski il y a 8 ans
Parent
commit
cb7a76ef1b
1 fichiers modifiés avec 43 ajouts et 5 suppressions
  1. 43 5
      src/lib/dhcp/pkt_filter_inet.cc

+ 43 - 5
src/lib/dhcp/pkt_filter_inet.cc

@@ -86,12 +86,19 @@ PktFilterInet::openSocket(Iface& iface,
 
 
     // if there is no support for IP_PKTINFO, we are really out of luck
     // if there is no support for IP_PKTINFO, we are really out of luck
     // it will be difficult to undersand, where this packet came from
     // it will be difficult to undersand, where this packet came from
-#if defined(IP_PKTINFO)
+#if defined (IP_PKTINFO) && defined (OS_LINUX)
     int flag = 1;
     int flag = 1;
     if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
     if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
         close(sock);
         close(sock);
         isc_throw(SocketConfigError, "setsockopt: IP_PKTINFO: failed.");
         isc_throw(SocketConfigError, "setsockopt: IP_PKTINFO: failed.");
     }
     }
+
+#elif defined (IP_RECVDSTADDR) && defined (OS_BSD)
+    int flag = 1;
+    if (setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR, &flag, sizeof(flag)) != 0) {
+        close(sock);
+        isc_throw(SocketConfigError, "setsockopt: IP_RECVDSTADDR: failed.");
+    }
 #endif
 #endif
 
 
     SocketInfo sock_desc(addr, port, sock);
     SocketInfo sock_desc(addr, port, sock);
@@ -154,17 +161,16 @@ PktFilterInet::receive(Iface& iface, const SocketInfo& socket_info) {
     pkt->setRemotePort(from_port);
     pkt->setRemotePort(from_port);
     pkt->setLocalPort(socket_info.port_);
     pkt->setLocalPort(socket_info.port_);
 
 
+    struct cmsghdr* cmsg;
+    cmsg = CMSG_FIRSTHDR(&m);
+
 // In the future the OS-specific code may be abstracted to a different
 // In the future the OS-specific code may be abstracted to a different
 // file but for now we keep it here because there is no code yet, which
 // file but for now we keep it here because there is no code yet, which
 // is specific to non-Linux systems.
 // is specific to non-Linux systems.
 #if defined (IP_PKTINFO) && defined (OS_LINUX)
 #if defined (IP_PKTINFO) && defined (OS_LINUX)
-    struct cmsghdr* cmsg;
     struct in_pktinfo* pktinfo;
     struct in_pktinfo* pktinfo;
-    struct in_addr to_addr;
-
     memset(&to_addr, 0, sizeof(to_addr));
     memset(&to_addr, 0, sizeof(to_addr));
 
 
-    cmsg = CMSG_FIRSTHDR(&m);
     while (cmsg != NULL) {
     while (cmsg != NULL) {
         if ((cmsg->cmsg_level == IPPROTO_IP) &&
         if ((cmsg->cmsg_level == IPPROTO_IP) &&
             (cmsg->cmsg_type == IP_PKTINFO)) {
             (cmsg->cmsg_type == IP_PKTINFO)) {
@@ -184,6 +190,21 @@ PktFilterInet::receive(Iface& iface, const SocketInfo& socket_info) {
         }
         }
         cmsg = CMSG_NXTHDR(&m, cmsg);
         cmsg = CMSG_NXTHDR(&m, cmsg);
     }
     }
+
+#elif defined (IP_RECVDSTADDR) && defined (OS_BSD)
+    struct in_addr* to_addr;
+
+    while (cmsg != NULL) {
+        if ((cmsg->cmsg_level == IPPROTO_IP) &&
+            (cmsg->cmsg_type == IP_RECVDSTADDR)) {
+            to_addr = (struct in_addr*)CMSG_DATA(cmsg);
+
+            pkt->setLocalAddr(IOAddress(htonl(to_addr->s_addr)));
+            break;
+        }
+        cmsg = CMSG_NXTHDR(&m, cmsg);
+    }
+
 #endif
 #endif
 
 
     return (pkt);
     return (pkt);
@@ -239,6 +260,23 @@ PktFilterInet::send(const Iface&, uint16_t sockfd,
     pktinfo->ipi_ifindex = pkt->getIndex();
     pktinfo->ipi_ifindex = pkt->getIndex();
     pktinfo->ipi_spec_dst.s_addr = htonl(pkt->getLocalAddr()); // set the source IP address
     pktinfo->ipi_spec_dst.s_addr = htonl(pkt->getLocalAddr()); // set the source IP address
     m.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
     m.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+
+#elif defined (IP_RECVDSTADDR) && defined (OS_BSD)
+/*    // Setting the interface is a bit more involved.
+    //
+    // We have to create a "control message", and set that to
+    // define the IPv4 packet information. We set the source address
+    // to handle correctly interfaces with multiple addresses.
+    m.msg_control = &control_buf_[0];
+    m.msg_controllen = control_buf_len_;
+    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
+    cmsg->cmsg_level = IPPROTO_IP;
+    cmsg->cmsg_type = IP_RECVDSTADDR;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+    struct in_addr* pktinfo =(struct in_addr *)CMSG_DATA(cmsg);
+    memset(pktinfo, 0, sizeof(struct in_addr));
+    pktinfo->s_addr = htonl(pkt->getLocalAddr());
+    m.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); */
 #endif
 #endif
 
 
     pkt->updateTimestamp();
     pkt->updateTimestamp();