|
Packit Service |
99d1c0 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Copyright 2016 by the Massachusetts Institute of Technology.
|
|
Packit Service |
99d1c0 |
* All Rights Reserved.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* Export of this software from the United States of America may
|
|
Packit Service |
99d1c0 |
* require a specific license from the United States Government.
|
|
Packit Service |
99d1c0 |
* It is the responsibility of any person or organization contemplating
|
|
Packit Service |
99d1c0 |
* export to obtain such a license before exporting.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
|
Packit Service |
99d1c0 |
* distribute this software and its documentation for any purpose and
|
|
Packit Service |
99d1c0 |
* without fee is hereby granted, provided that the above copyright
|
|
Packit Service |
99d1c0 |
* notice appear in all copies and that both that copyright notice and
|
|
Packit Service |
99d1c0 |
* this permission notice appear in supporting documentation, and that
|
|
Packit Service |
99d1c0 |
* the name of M.I.T. not be used in advertising or publicity pertaining
|
|
Packit Service |
99d1c0 |
* to distribution of the software without specific, written prior
|
|
Packit Service |
99d1c0 |
* permission. Furthermore if you modify this software you must label
|
|
Packit Service |
99d1c0 |
* your software as modified software and not distribute it in such a
|
|
Packit Service |
99d1c0 |
* fashion that it might be confused with the original M.I.T. software.
|
|
Packit Service |
99d1c0 |
* M.I.T. makes no representations about the suitability of
|
|
Packit Service |
99d1c0 |
* this software for any purpose. It is provided "as is" without express
|
|
Packit Service |
99d1c0 |
* or implied warranty.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* macOS requires this define for IPV6_PKTINFO. */
|
|
Packit Service |
99d1c0 |
#define __APPLE_USE_RFC_3542
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#include "udppktinfo.h"
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#include <netinet/in.h>
|
|
Packit Service |
99d1c0 |
#include <sys/socket.h>
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO)
|
|
Packit Service |
99d1c0 |
#define HAVE_IP_PKTINFO
|
|
Packit Service |
99d1c0 |
#endif
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
|
|
Packit Service |
99d1c0 |
#define HAVE_IPV6_PKTINFO
|
|
Packit Service |
99d1c0 |
#endif
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#if defined(HAVE_IP_PKTINFO) || defined(IP_SENDSRCADDR) || \
|
|
Packit Service |
99d1c0 |
defined(HAVE_IPV6_PKTINFO)
|
|
Packit Service |
99d1c0 |
#define HAVE_PKTINFO_SUPPORT
|
|
Packit Service |
99d1c0 |
#endif
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Use RFC 3542 API below, but fall back from IPV6_RECVPKTINFO to IPV6_PKTINFO
|
|
Packit Service |
99d1c0 |
* for RFC 2292 implementations. */
|
|
Packit Service |
99d1c0 |
#if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
|
|
Packit Service |
99d1c0 |
#define IPV6_RECVPKTINFO IPV6_PKTINFO
|
|
Packit Service |
99d1c0 |
#endif
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Parallel, though not standardized. */
|
|
Packit Service |
99d1c0 |
#if !defined(IP_RECVPKTINFO) && defined(IP_PKTINFO)
|
|
Packit Service |
99d1c0 |
#define IP_RECVPKTINFO IP_PKTINFO
|
|
Packit Service |
99d1c0 |
#endif /* IP_RECVPKTINFO */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#if defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && \
|
|
Packit Service |
99d1c0 |
defined(HAVE_PKTINFO_SUPPORT)
|
|
Packit Service |
99d1c0 |
union pktinfo {
|
|
Packit Service |
99d1c0 |
#ifdef HAVE_STRUCT_IN6_PKTINFO
|
|
Packit Service |
99d1c0 |
struct in6_pktinfo pi6;
|
|
Packit Service |
99d1c0 |
#endif
|
|
Packit Service |
99d1c0 |
#ifdef HAVE_STRUCT_IN_PKTINFO
|
|
Packit Service |
99d1c0 |
struct in_pktinfo pi4;
|
|
Packit Service |
99d1c0 |
#endif
|
|
Packit Service |
99d1c0 |
#ifdef IP_RECVDSTADDR
|
|
Packit Service |
99d1c0 |
struct in_addr iaddr;
|
|
Packit Service |
99d1c0 |
#endif
|
|
Packit Service |
99d1c0 |
char c;
|
|
Packit Service |
99d1c0 |
};
|
|
Packit Service |
99d1c0 |
#endif /* HAVE_IPV6_PKTINFO && HAVE_STRUCT_CMSGHDR && HAVE_PKTINFO_SUPPORT */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#ifdef HAVE_IP_PKTINFO
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define set_ipv4_pktinfo set_ipv4_recvpktinfo
|
|
Packit Service |
99d1c0 |
static inline krb5_error_code
|
|
Packit Service |
99d1c0 |
set_ipv4_recvpktinfo(int sock)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
int sockopt = 1;
|
|
Packit Service |
99d1c0 |
return setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO, &sockopt,
|
|
Packit Service |
99d1c0 |
sizeof(sockopt));
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#elif defined(IP_RECVDSTADDR) /* HAVE_IP_PKTINFO */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define set_ipv4_pktinfo set_ipv4_recvdstaddr
|
|
Packit Service |
99d1c0 |
static inline krb5_error_code
|
|
Packit Service |
99d1c0 |
set_ipv4_recvdstaddr(int sock)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
int sockopt = 1;
|
|
Packit Service |
99d1c0 |
return setsockopt(sock, IPPROTO_IP, IP_RECVDSTADDR, &sockopt,
|
|
Packit Service |
99d1c0 |
sizeof(sockopt));
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#else /* HAVE_IP_PKTINFO || IP_RECVDSTADDR */
|
|
Packit Service |
99d1c0 |
#define set_ipv4_pktinfo(s) EINVAL
|
|
Packit Service |
99d1c0 |
#endif /* HAVE_IP_PKTINFO || IP_RECVDSTADDR */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#ifdef HAVE_IPV6_PKTINFO
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define set_ipv6_pktinfo set_ipv6_recvpktinfo
|
|
Packit Service |
99d1c0 |
static inline krb5_error_code
|
|
Packit Service |
99d1c0 |
set_ipv6_recvpktinfo(int sock)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
int sockopt = 1;
|
|
Packit Service |
99d1c0 |
return setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &sockopt,
|
|
Packit Service |
99d1c0 |
sizeof(sockopt));
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#else /* HAVE_IPV6_PKTINFO */
|
|
Packit Service |
99d1c0 |
#define set_ipv6_pktinfo(s) EINVAL
|
|
Packit Service |
99d1c0 |
#endif /* HAVE_IPV6_PKTINFO */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Set pktinfo option on a socket. Takes a socket and the socket address family
|
|
Packit Service |
99d1c0 |
* as arguments.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* Returns 0 on success, EINVAL if pktinfo is not supported for the address
|
|
Packit Service |
99d1c0 |
* family.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
set_pktinfo(int sock, int family)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
switch (family) {
|
|
Packit Service |
99d1c0 |
case AF_INET:
|
|
Packit Service |
99d1c0 |
return set_ipv4_pktinfo(sock);
|
|
Packit Service |
99d1c0 |
case AF_INET6:
|
|
Packit Service |
99d1c0 |
return set_ipv6_pktinfo(sock);
|
|
Packit Service |
99d1c0 |
default:
|
|
Packit Service |
99d1c0 |
return EINVAL;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#if defined(HAVE_PKTINFO_SUPPORT) && defined(CMSG_SPACE)
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Check if a socket is bound to a wildcard address.
|
|
Packit Service |
99d1c0 |
* Returns 1 if it is, 0 if it's bound to a specific address, or -1 on error
|
|
Packit Service |
99d1c0 |
* with errno set to the error.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
static int
|
|
Packit Service |
99d1c0 |
is_socket_bound_to_wildcard(int sock)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct sockaddr_storage bound_addr;
|
|
Packit Service |
99d1c0 |
socklen_t bound_addr_len = sizeof(bound_addr);
|
|
Packit Service |
99d1c0 |
struct sockaddr *sa = ss2sa(&bound_addr);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (getsockname(sock, sa, &bound_addr_len) < 0)
|
|
Packit Service |
99d1c0 |
return -1;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (!sa_is_inet(sa)) {
|
|
Packit Service |
99d1c0 |
errno = EINVAL;
|
|
Packit Service |
99d1c0 |
return -1;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return sa_is_wildcard(sa);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#ifdef HAVE_IP_PKTINFO
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static inline struct in_pktinfo *
|
|
Packit Service |
99d1c0 |
cmsg2pktinfo(struct cmsghdr *cmsgptr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
return (struct in_pktinfo *)(void *)CMSG_DATA(cmsgptr);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define check_cmsg_v4_pktinfo check_cmsg_ip_pktinfo
|
|
Packit Service |
99d1c0 |
static int
|
|
Packit Service |
99d1c0 |
check_cmsg_ip_pktinfo(struct cmsghdr *cmsgptr, struct sockaddr *to,
|
|
Packit Service |
99d1c0 |
socklen_t *tolen, aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct in_pktinfo *pktinfo;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (cmsgptr->cmsg_level == IPPROTO_IP &&
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_type == IP_PKTINFO &&
|
|
Packit Service |
99d1c0 |
*tolen >= sizeof(struct sockaddr_in)) {
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
memset(to, 0, sizeof(struct sockaddr_in));
|
|
Packit Service |
99d1c0 |
pktinfo = cmsg2pktinfo(cmsgptr);
|
|
Packit Service |
99d1c0 |
sa2sin(to)->sin_addr = pktinfo->ipi_addr;
|
|
Packit Service |
99d1c0 |
sa2sin(to)->sin_family = AF_INET;
|
|
Packit Service |
99d1c0 |
*tolen = sizeof(struct sockaddr_in);
|
|
Packit Service |
99d1c0 |
return 1;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
return 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#elif defined(IP_RECVDSTADDR) /* HAVE_IP_PKTINFO */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static inline struct in_addr *
|
|
Packit Service |
99d1c0 |
cmsg2sin(struct cmsghdr *cmsgptr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
return (struct in_addr *)(void *)CMSG_DATA(cmsgptr);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define check_cmsg_v4_pktinfo check_cmsg_ip_recvdstaddr
|
|
Packit Service |
99d1c0 |
static int
|
|
Packit Service |
99d1c0 |
check_cmsg_ip_recvdstaddr(struct cmsghdr *cmsgptr, struct sockaddr *to,
|
|
Packit Service |
99d1c0 |
socklen_t *tolen, aux_addressing_info * auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
if (cmsgptr->cmsg_level == IPPROTO_IP &&
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_type == IP_RECVDSTADDR &&
|
|
Packit Service |
99d1c0 |
*tolen >= sizeof(struct sockaddr_in)) {
|
|
Packit Service |
99d1c0 |
struct in_addr *sin_addr;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
memset(to, 0, sizeof(struct sockaddr_in));
|
|
Packit Service |
99d1c0 |
sin_addr = cmsg2sin(cmsgptr);
|
|
Packit Service |
99d1c0 |
sa2sin(to)->sin_addr = *sin_addr;
|
|
Packit Service |
99d1c0 |
sa2sin(to)->sin_family = AF_INET;
|
|
Packit Service |
99d1c0 |
*tolen = sizeof(struct sockaddr_in);
|
|
Packit Service |
99d1c0 |
return 1;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
return 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#else /* HAVE_IP_PKTINFO || IP_RECVDSTADDR */
|
|
Packit Service |
99d1c0 |
#define check_cmsg_v4_pktinfo(c, t, l, a) 0
|
|
Packit Service |
99d1c0 |
#endif /* HAVE_IP_PKTINFO || IP_RECVDSTADDR */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#ifdef HAVE_IPV6_PKTINFO
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static inline struct in6_pktinfo *
|
|
Packit Service |
99d1c0 |
cmsg2pktinfo6(struct cmsghdr *cmsgptr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
return (struct in6_pktinfo *)(void *)CMSG_DATA(cmsgptr);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define check_cmsg_v6_pktinfo check_cmsg_ipv6_pktinfo
|
|
Packit Service |
99d1c0 |
static int
|
|
Packit Service |
99d1c0 |
check_cmsg_ipv6_pktinfo(struct cmsghdr *cmsgptr, struct sockaddr *to,
|
|
Packit Service |
99d1c0 |
socklen_t *tolen, aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct in6_pktinfo *pktinfo;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_type == IPV6_PKTINFO &&
|
|
Packit Service |
99d1c0 |
*tolen >= sizeof(struct sockaddr_in6)) {
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
memset(to, 0, sizeof(struct sockaddr_in6));
|
|
Packit Service |
99d1c0 |
pktinfo = cmsg2pktinfo6(cmsgptr);
|
|
Packit Service |
99d1c0 |
sa2sin6(to)->sin6_addr = pktinfo->ipi6_addr;
|
|
Packit Service |
99d1c0 |
sa2sin6(to)->sin6_family = AF_INET6;
|
|
Packit Service |
99d1c0 |
*tolen = sizeof(struct sockaddr_in6);
|
|
Packit Service |
99d1c0 |
auxaddr->ipv6_ifindex = pktinfo->ipi6_ifindex;
|
|
Packit Service |
99d1c0 |
return 1;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
return 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
#else /* HAVE_IPV6_PKTINFO */
|
|
Packit Service |
99d1c0 |
#define check_cmsg_v6_pktinfo(c, t, l, a) 0
|
|
Packit Service |
99d1c0 |
#endif /* HAVE_IPV6_PKTINFO */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static int
|
|
Packit Service |
99d1c0 |
check_cmsg_pktinfo(struct cmsghdr *cmsgptr, struct sockaddr *to,
|
|
Packit Service |
99d1c0 |
socklen_t *tolen, aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
return check_cmsg_v4_pktinfo(cmsgptr, to, tolen, auxaddr) ||
|
|
Packit Service |
99d1c0 |
check_cmsg_v6_pktinfo(cmsgptr, to, tolen, auxaddr);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Receive a message from a socket.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* Arguments:
|
|
Packit Service |
99d1c0 |
* sock
|
|
Packit Service |
99d1c0 |
* buf - The buffer to store the message in.
|
|
Packit Service |
99d1c0 |
* len - buf length
|
|
Packit Service |
99d1c0 |
* flags
|
|
Packit Service |
99d1c0 |
* from - Set to the address that sent the message
|
|
Packit Service |
99d1c0 |
* fromlen
|
|
Packit Service |
99d1c0 |
* to - Set to the address that the message was sent to if possible.
|
|
Packit Service |
99d1c0 |
* May not be set in certain cases such as if pktinfo support is
|
|
Packit Service |
99d1c0 |
* missing. May be NULL.
|
|
Packit Service |
99d1c0 |
* tolen
|
|
Packit Service |
99d1c0 |
* auxaddr - Miscellaneous address information.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* Returns 0 on success, otherwise an error code.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
recv_from_to(int sock, void *buf, size_t len, int flags,
|
|
Packit Service |
99d1c0 |
struct sockaddr *from, socklen_t * fromlen,
|
|
Packit Service |
99d1c0 |
struct sockaddr *to, socklen_t * tolen,
|
|
Packit Service |
99d1c0 |
aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
int r;
|
|
Packit Service |
99d1c0 |
struct iovec iov;
|
|
Packit Service |
99d1c0 |
char cmsg[CMSG_SPACE(sizeof(union pktinfo))];
|
|
Packit Service |
99d1c0 |
struct cmsghdr *cmsgptr;
|
|
Packit Service |
99d1c0 |
struct msghdr msg;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Don't use pktinfo if the socket isn't bound to a wildcard address. */
|
|
Packit Service |
99d1c0 |
r = is_socket_bound_to_wildcard(sock);
|
|
Packit Service |
99d1c0 |
if (r < 0)
|
|
Packit Service |
99d1c0 |
return errno;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (!to || !tolen || !r)
|
|
Packit Service |
99d1c0 |
return recvfrom(sock, buf, len, flags, from, fromlen);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Clobber with something recognizeable in case we can't extract the
|
|
Packit Service |
99d1c0 |
* address but try to use it anyways. */
|
|
Packit Service |
99d1c0 |
memset(to, 0x40, *tolen);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
iov.iov_base = buf;
|
|
Packit Service |
99d1c0 |
iov.iov_len = len;
|
|
Packit Service |
99d1c0 |
memset(&msg, 0, sizeof(msg));
|
|
Packit Service |
99d1c0 |
msg.msg_name = from;
|
|
Packit Service |
99d1c0 |
msg.msg_namelen = *fromlen;
|
|
Packit Service |
99d1c0 |
msg.msg_iov = &iov;
|
|
Packit Service |
99d1c0 |
msg.msg_iovlen = 1;
|
|
Packit Service |
99d1c0 |
msg.msg_control = cmsg;
|
|
Packit Service |
99d1c0 |
msg.msg_controllen = sizeof(cmsg);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
r = recvmsg(sock, &msg, flags);
|
|
Packit Service |
99d1c0 |
if (r < 0)
|
|
Packit Service |
99d1c0 |
return r;
|
|
Packit Service |
99d1c0 |
*fromlen = msg.msg_namelen;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* On Darwin (and presumably all *BSD with KAME stacks), CMSG_FIRSTHDR
|
|
Packit Service |
99d1c0 |
* doesn't check for a non-zero controllen. RFC 3542 recommends making
|
|
Packit Service |
99d1c0 |
* this check, even though the (new) spec for CMSG_FIRSTHDR says it's
|
|
Packit Service |
99d1c0 |
* supposed to do the check.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
if (msg.msg_controllen) {
|
|
Packit Service |
99d1c0 |
cmsgptr = CMSG_FIRSTHDR(&msg;;
|
|
Packit Service |
99d1c0 |
while (cmsgptr) {
|
|
Packit Service |
99d1c0 |
if (check_cmsg_pktinfo(cmsgptr, to, tolen, auxaddr))
|
|
Packit Service |
99d1c0 |
return r;
|
|
Packit Service |
99d1c0 |
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
/* No info about destination addr was available. */
|
|
Packit Service |
99d1c0 |
*tolen = 0;
|
|
Packit Service |
99d1c0 |
return r;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#ifdef HAVE_IP_PKTINFO
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define set_msg_from_ipv4 set_msg_from_ip_pktinfo
|
|
Packit Service |
99d1c0 |
static krb5_error_code
|
|
Packit Service |
99d1c0 |
set_msg_from_ip_pktinfo(struct msghdr *msg, struct cmsghdr *cmsgptr,
|
|
Packit Service |
99d1c0 |
struct sockaddr *from, socklen_t fromlen,
|
|
Packit Service |
99d1c0 |
aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct in_pktinfo *p = cmsg2pktinfo(cmsgptr);
|
|
Packit Service |
99d1c0 |
const struct sockaddr_in *from4 = sa2sin(from);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (fromlen != sizeof(struct sockaddr_in))
|
|
Packit Service |
99d1c0 |
return EINVAL;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_level = IPPROTO_IP;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_type = IP_PKTINFO;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
|
Packit Service |
99d1c0 |
p->ipi_spec_dst = from4->sin_addr;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
|
|
Packit Service |
99d1c0 |
return 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#elif defined(IP_SENDSRCADDR) /* HAVE_IP_PKTINFO */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define set_msg_from_ipv4 set_msg_from_ip_sendsrcaddr
|
|
Packit Service |
99d1c0 |
static krb5_error_code
|
|
Packit Service |
99d1c0 |
set_msg_from_ip_sendsrcaddr(struct msghdr *msg, struct cmsghdr *cmsgptr,
|
|
Packit Service |
99d1c0 |
struct sockaddr *from, socklen_t fromlen,
|
|
Packit Service |
99d1c0 |
aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct in_addr *sin_addr = cmsg2sin(cmsgptr);
|
|
Packit Service |
99d1c0 |
const struct sockaddr_in *from4 = sa2sin(from);
|
|
Packit Service |
99d1c0 |
if (fromlen != sizeof(struct sockaddr_in))
|
|
Packit Service |
99d1c0 |
return EINVAL;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_level = IPPROTO_IP;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_type = IP_SENDSRCADDR;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
|
Packit Service |
99d1c0 |
msg->msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
|
|
Packit Service |
99d1c0 |
*sin_addr = from4->sin_addr;
|
|
Packit Service |
99d1c0 |
return 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#else /* HAVE_IP_PKTINFO || IP_SENDSRCADDR */
|
|
Packit Service |
99d1c0 |
#define set_msg_from_ipv4(m, c, f, l, a) EINVAL
|
|
Packit Service |
99d1c0 |
#endif /* HAVE_IP_PKTINFO || IP_SENDSRCADDR */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#ifdef HAVE_IPV6_PKTINFO
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#define set_msg_from_ipv6 set_msg_from_ipv6_pktinfo
|
|
Packit Service |
99d1c0 |
static krb5_error_code
|
|
Packit Service |
99d1c0 |
set_msg_from_ipv6_pktinfo(struct msghdr *msg, struct cmsghdr *cmsgptr,
|
|
Packit Service |
99d1c0 |
struct sockaddr *from, socklen_t fromlen,
|
|
Packit Service |
99d1c0 |
aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
struct in6_pktinfo *p = cmsg2pktinfo6(cmsgptr);
|
|
Packit Service |
99d1c0 |
const struct sockaddr_in6 *from6 = sa2sin6(from);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (fromlen != sizeof(struct sockaddr_in6))
|
|
Packit Service |
99d1c0 |
return EINVAL;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_level = IPPROTO_IPV6;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_type = IPV6_PKTINFO;
|
|
Packit Service |
99d1c0 |
cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
p->ipi6_addr = from6->sin6_addr;
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Because of the possibility of asymmetric routing, we
|
|
Packit Service |
99d1c0 |
* normally don't want to specify an interface. However,
|
|
Packit Service |
99d1c0 |
* macOS doesn't like sending from a link-local address
|
|
Packit Service |
99d1c0 |
* (which can come up in testing at least, if you wind up
|
|
Packit Service |
99d1c0 |
* with a "foo.local" name) unless we do specify the
|
|
Packit Service |
99d1c0 |
* interface.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
if (IN6_IS_ADDR_LINKLOCAL(&from6->sin6_addr))
|
|
Packit Service |
99d1c0 |
p->ipi6_ifindex = auxaddr->ipv6_ifindex;
|
|
Packit Service |
99d1c0 |
/* otherwise, already zero */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
|
|
Packit Service |
99d1c0 |
return 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#else /* HAVE_IPV6_PKTINFO */
|
|
Packit Service |
99d1c0 |
#define set_msg_from_ipv6(m, c, f, l, a) EINVAL
|
|
Packit Service |
99d1c0 |
#endif /* HAVE_IPV6_PKTINFO */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
static krb5_error_code
|
|
Packit Service |
99d1c0 |
set_msg_from(int family, struct msghdr *msg, struct cmsghdr *cmsgptr,
|
|
Packit Service |
99d1c0 |
struct sockaddr *from, socklen_t fromlen,
|
|
Packit Service |
99d1c0 |
aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
switch (family) {
|
|
Packit Service |
99d1c0 |
case AF_INET:
|
|
Packit Service |
99d1c0 |
return set_msg_from_ipv4(msg, cmsgptr, from, fromlen, auxaddr);
|
|
Packit Service |
99d1c0 |
case AF_INET6:
|
|
Packit Service |
99d1c0 |
return set_msg_from_ipv6(msg, cmsgptr, from, fromlen, auxaddr);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return EINVAL;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/*
|
|
Packit Service |
99d1c0 |
* Send a message to an address.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* Arguments:
|
|
Packit Service |
99d1c0 |
* sock
|
|
Packit Service |
99d1c0 |
* buf - The message to send.
|
|
Packit Service |
99d1c0 |
* len - buf length
|
|
Packit Service |
99d1c0 |
* flags
|
|
Packit Service |
99d1c0 |
* to - The address to send the message to.
|
|
Packit Service |
99d1c0 |
* tolen
|
|
Packit Service |
99d1c0 |
* from - The address to attempt to send the message from. May be NULL.
|
|
Packit Service |
99d1c0 |
* fromlen
|
|
Packit Service |
99d1c0 |
* auxaddr - Miscellaneous address information.
|
|
Packit Service |
99d1c0 |
*
|
|
Packit Service |
99d1c0 |
* Returns 0 on success, otherwise an error code.
|
|
Packit Service |
99d1c0 |
*/
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
send_to_from(int sock, void *buf, size_t len, int flags,
|
|
Packit Service |
99d1c0 |
const struct sockaddr *to, socklen_t tolen, struct sockaddr *from,
|
|
Packit Service |
99d1c0 |
socklen_t fromlen, aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
int r;
|
|
Packit Service |
99d1c0 |
struct iovec iov;
|
|
Packit Service |
99d1c0 |
struct msghdr msg;
|
|
Packit Service |
99d1c0 |
struct cmsghdr *cmsgptr;
|
|
Packit Service |
99d1c0 |
char cbuf[CMSG_SPACE(sizeof(union pktinfo))];
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
/* Don't use pktinfo if the socket isn't bound to a wildcard address. */
|
|
Packit Service |
99d1c0 |
r = is_socket_bound_to_wildcard(sock);
|
|
Packit Service |
99d1c0 |
if (r < 0)
|
|
Packit Service |
99d1c0 |
return errno;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (from == NULL || fromlen == 0 || from->sa_family != to->sa_family || !r)
|
|
Packit Service |
99d1c0 |
goto use_sendto;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
iov.iov_base = buf;
|
|
Packit Service |
99d1c0 |
iov.iov_len = len;
|
|
Packit Service |
99d1c0 |
/* Truncation? */
|
|
Packit Service |
99d1c0 |
if (iov.iov_len != len)
|
|
Packit Service |
99d1c0 |
return EINVAL;
|
|
Packit Service |
99d1c0 |
memset(cbuf, 0, sizeof(cbuf));
|
|
Packit Service |
99d1c0 |
memset(&msg, 0, sizeof(msg));
|
|
Packit Service |
99d1c0 |
msg.msg_name = (void *)to;
|
|
Packit Service |
99d1c0 |
msg.msg_namelen = tolen;
|
|
Packit Service |
99d1c0 |
msg.msg_iov = &iov;
|
|
Packit Service |
99d1c0 |
msg.msg_iovlen = 1;
|
|
Packit Service |
99d1c0 |
msg.msg_control = cbuf;
|
|
Packit Service |
99d1c0 |
/* CMSG_FIRSTHDR needs a non-zero controllen, or it'll return NULL on
|
|
Packit Service |
99d1c0 |
* Linux. */
|
|
Packit Service |
99d1c0 |
msg.msg_controllen = sizeof(cbuf);
|
|
Packit Service |
99d1c0 |
cmsgptr = CMSG_FIRSTHDR(&msg;;
|
|
Packit Service |
99d1c0 |
msg.msg_controllen = 0;
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
if (set_msg_from(from->sa_family, &msg, cmsgptr, from, fromlen, auxaddr))
|
|
Packit Service |
99d1c0 |
goto use_sendto;
|
|
Packit Service |
99d1c0 |
return sendmsg(sock, &msg, flags);
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
use_sendto:
|
|
Packit Service |
99d1c0 |
return sendto(sock, buf, len, flags, to, tolen);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#else /* HAVE_PKTINFO_SUPPORT && CMSG_SPACE */
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
recv_from_to(int sock, void *buf, size_t len, int flags,
|
|
Packit Service |
99d1c0 |
struct sockaddr *from, socklen_t *fromlen,
|
|
Packit Service |
99d1c0 |
struct sockaddr *to, socklen_t *tolen,
|
|
Packit Service |
99d1c0 |
aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
if (to && tolen) {
|
|
Packit Service |
99d1c0 |
/* Clobber with something recognizeable in case we try to use the
|
|
Packit Service |
99d1c0 |
* address. */
|
|
Packit Service |
99d1c0 |
memset(to, 0x40, *tolen);
|
|
Packit Service |
99d1c0 |
*tolen = 0;
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
return recvfrom(sock, buf, len, flags, from, fromlen);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
krb5_error_code
|
|
Packit Service |
99d1c0 |
send_to_from(int sock, void *buf, size_t len, int flags,
|
|
Packit Service |
99d1c0 |
const struct sockaddr *to, socklen_t tolen,
|
|
Packit Service |
99d1c0 |
struct sockaddr *from, socklen_t fromlen,
|
|
Packit Service |
99d1c0 |
aux_addressing_info *auxaddr)
|
|
Packit Service |
99d1c0 |
{
|
|
Packit Service |
99d1c0 |
return sendto(sock, buf, len, flags, to, tolen);
|
|
Packit Service |
99d1c0 |
}
|
|
Packit Service |
99d1c0 |
|
|
Packit Service |
99d1c0 |
#endif /* HAVE_PKTINFO_SUPPORT && CMSG_SPACE */
|