]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Add support for IP_SENDSRCADDR for UDP pktinfo
authorSarah Day <sarahday@mit.edu>
Thu, 11 Feb 2016 20:39:04 +0000 (15:39 -0500)
committerGreg Hudson <ghudson@mit.edu>
Wed, 17 Feb 2016 20:37:17 +0000 (15:37 -0500)
FreeBSD uses IP_RECVDSTADDR and IP_SENDSRCADDR instead of IP_PKTINFO
for IPv4 pktinfo functionality.  Add support for using this when
IP_PKTINFO is not available.

src/lib/apputils/udppktinfo.c

index aa601faa19219d558b1304e669ebfc0255e3ac81..8fafb1583ce21d990ada6306b65556dd7d0e7f70 100644 (file)
@@ -36,7 +36,8 @@
 #define HAVE_IPV6_PKTINFO
 #endif
 
-#if defined(HAVE_IP_PKTINFO) || defined(HAVE_IPV6_PKTINFO)
+#if defined(HAVE_IP_PKTINFO) || defined(IP_SENDSRCADDR) ||      \
+    defined(HAVE_IPV6_PKTINFO)
 #define HAVE_PKTINFO_SUPPORT
 #endif
 
@@ -59,6 +60,9 @@ union pktinfo {
 #endif
 #ifdef HAVE_STRUCT_IN_PKTINFO
     struct in_pktinfo pi4;
+#endif
+#ifdef IP_RECVDSTADDR
+    struct in_addr iaddr;
 #endif
     char c;
 };
@@ -100,9 +104,20 @@ set_ipv4_recvpktinfo(int sock)
                       sizeof(sockopt));
 }
 
-#else /* HAVE_IP_PKTINFO */
+#elif defined(IP_RECVDSTADDR) /* HAVE_IP_PKTINFO */
+
+#define set_ipv4_pktinfo set_ipv4_recvdstaddr
+static inline krb5_error_code
+set_ipv4_recvdstaddr(int sock)
+{
+    int sockopt = 1;
+    return setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR, &sockopt,
+                      sizeof(sockopt));
+}
+
+#else /* HAVE_IP_PKTINFO || IP_RECVDSTADDR */
 #define set_ipv4_pktinfo(s) EINVAL
-#endif /* HAVE_IP_PKTINFO */
+#endif /* HAVE_IP_PKTINFO || IP_RECVDSTADDR */
 
 #ifdef HAVE_IPV6_PKTINFO
 
@@ -170,9 +185,37 @@ check_cmsg_ip_pktinfo(struct cmsghdr *cmsgptr, struct sockaddr *to,
     return 0;
 }
 
-#else /* HAVE_IP_PKTINFO */
+#elif defined(IP_RECVDSTADDR) /* HAVE_IP_PKTINFO */
+
+static inline struct in_addr *
+cmsg2sin(struct cmsghdr *cmsgptr)
+{
+    return (struct in_addr *)(void *)CMSG_DATA(cmsgptr);
+}
+
+#define check_cmsg_v4_pktinfo check_cmsg_ip_recvdstaddr
+static int
+check_cmsg_ip_recvdstaddr(struct cmsghdr *cmsgptr, struct sockaddr *to,
+                          socklen_t *tolen, aux_addressing_info * auxaddr)
+{
+    if (cmsgptr->cmsg_level == IPPROTO_IP &&
+        cmsgptr->cmsg_type == IP_RECVDSTADDR &&
+        *tolen >= sizeof(struct sockaddr_in)) {
+        struct in_addr *sin_addr;
+
+        memset(to, 0, sizeof(struct sockaddr_in));
+        sin_addr = cmsg2sin(cmsgptr);
+        sa2sin(to)->sin_addr = *sin_addr;
+        sa2sin(to)->sin_family = AF_INET;
+        *tolen = sizeof(struct sockaddr_in);
+        return 1;
+    }
+    return 0;
+}
+
+#else /* HAVE_IP_PKTINFO || IP_RECVDSTADDR */
 #define check_cmsg_v4_pktinfo(c, t, l, a) 0
-#endif /* HAVE_IP_PKTINFO */
+#endif /* HAVE_IP_PKTINFO || IP_RECVDSTADDR */
 
 #ifdef HAVE_IPV6_PKTINFO
 
@@ -314,9 +357,29 @@ set_msg_from_ip_pktinfo(struct msghdr *msg, struct cmsghdr *cmsgptr,
     return 0;
 }
 
-#else /* HAVE_IP_PKTINFO */
+#elif defined(IP_SENDSRCADDR) /* HAVE_IP_PKTINFO */
+
+#define set_msg_from_ipv4 set_msg_from_ip_sendsrcaddr
+static krb5_error_code
+set_msg_from_ip_sendsrcaddr(struct msghdr *msg, struct cmsghdr *cmsgptr,
+                            struct sockaddr *from, socklen_t fromlen,
+                            aux_addressing_info *auxaddr)
+{
+    struct in_addr *sin_addr = cmsg2sin(cmsgptr);
+    const struct sockaddr_in *from4 = sa2sin(from);
+    if (fromlen != sizeof(struct sockaddr_in))
+        return EINVAL;
+    cmsgptr->cmsg_level = IPPROTO_IP;
+    cmsgptr->cmsg_type = IP_SENDSRCADDR;
+    cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+    msg->msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
+    *sin_addr = from4->sin_addr;
+    return 0;
+}
+
+#else /* HAVE_IP_PKTINFO || IP_SENDSRCADDR */
 #define set_msg_from_ipv4(m, c, f, l, a) EINVAL
-#endif /* HAVE_IP_PKTINFO */
+#endif /* HAVE_IP_PKTINFO || IP_SENDSRCADDR */
 
 #ifdef HAVE_IPV6_PKTINFO