1 1.1 christos /* -*- Mode: C; tab-width: 4 -*- 2 1.1 christos * 3 1.1 christos * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. 4 1.1 christos * 5 1.1 christos * Licensed under the Apache License, Version 2.0 (the "License"); 6 1.1 christos * you may not use this file except in compliance with the License. 7 1.1 christos * You may obtain a copy of the License at 8 1.1 christos * 9 1.1 christos * http://www.apache.org/licenses/LICENSE-2.0 10 1.1 christos * 11 1.1 christos * Unless required by applicable law or agreed to in writing, software 12 1.1 christos * distributed under the License is distributed on an "AS IS" BASIS, 13 1.1 christos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 1.1 christos * See the License for the specific language governing permissions and 15 1.1 christos * limitations under the License. 16 1.1 christos */ 17 1.1 christos 18 1.1 christos #include "mDNSUNP.h" 19 1.1 christos #include <ifaddrs.h> 20 1.1 christos 21 1.1 christos #include <assert.h> 22 1.1 christos #include <err.h> 23 1.1 christos #include <errno.h> 24 1.1 christos #include <string.h> 25 1.1 christos #include <stdlib.h> 26 1.1 christos #include <unistd.h> 27 1.1 christos #include <netinet/in.h> 28 1.1 christos #include <netinet/in_var.h> 29 1.1 christos #include <net/if_dl.h> 30 1.1 christos 31 1.1 christos 32 1.1 christos ssize_t 33 1.1 christos recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp, 34 1.1 christos struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, 35 1.1 christos u_char *ttl) 36 1.1 christos { 37 1.1 christos struct msghdr msg; 38 1.1 christos struct iovec iov[1]; 39 1.1 christos ssize_t n; 40 1.1 christos 41 1.1 christos #ifdef CMSG_FIRSTHDR 42 1.1 christos struct cmsghdr *cmptr; 43 1.1 christos union { 44 1.1 christos struct cmsghdr cm; 45 1.1 christos char control[1024]; 46 1.1 christos } control_un; 47 1.1 christos 48 1.1 christos *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be 49 1.1 christos 50 1.1 christos msg.msg_control = control_un.control; 51 1.1 christos msg.msg_controllen = sizeof(control_un.control); 52 1.1 christos msg.msg_flags = 0; 53 1.1 christos #else 54 1.1 christos memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */ 55 1.1 christos #endif /* CMSG_FIRSTHDR */ 56 1.1 christos 57 1.1 christos msg.msg_name = (char *) sa; 58 1.1 christos msg.msg_namelen = *salenptr; 59 1.1 christos iov[0].iov_base = (char *)ptr; 60 1.1 christos iov[0].iov_len = nbytes; 61 1.1 christos msg.msg_iov = iov; 62 1.1 christos msg.msg_iovlen = 1; 63 1.1 christos 64 1.1 christos if ( (n = recvmsg(fd, &msg, *flagsp)) < 0) 65 1.1 christos return(n); 66 1.1 christos 67 1.1 christos *salenptr = msg.msg_namelen; /* pass back results */ 68 1.1 christos if (pktp) { 69 1.1 christos /* 0.0.0.0, i/f = -1 */ 70 1.1 christos /* We set the interface to -1 so that the caller can 71 1.1 christos tell whether we returned a meaningful value or 72 1.1 christos just some default. Previously this code just 73 1.1 christos set the value to 0, but I'm concerned that 0 74 1.1 christos might be a valid interface value. 75 1.1 christos */ 76 1.1 christos memset(pktp, 0, sizeof(struct my_in_pktinfo)); 77 1.1 christos pktp->ipi_ifindex = -1; 78 1.1 christos } 79 1.1 christos /* end recvfrom_flags1 */ 80 1.1 christos 81 1.1 christos /* include recvfrom_flags2 */ 82 1.1 christos #ifndef CMSG_FIRSTHDR 83 1.1 christos #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc. 84 1.1 christos *flagsp = 0; /* pass back results */ 85 1.1 christos return(n); 86 1.1 christos #else 87 1.1 christos 88 1.1 christos *flagsp = msg.msg_flags; /* pass back results */ 89 1.1 christos if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) || 90 1.1 christos (msg.msg_flags & MSG_CTRUNC) || pktp == NULL) 91 1.1 christos return(n); 92 1.1 christos 93 1.1 christos for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; 94 1.1 christos cmptr = CMSG_NXTHDR(&msg, cmptr)) { 95 1.1 christos 96 1.1 christos #ifdef IP_PKTINFO 97 1.1 christos #if in_pktinfo_definition_is_missing 98 1.1 christos struct in_pktinfo 99 1.1 christos { 100 1.1 christos int ipi_ifindex; 101 1.1 christos struct in_addr ipi_spec_dst; 102 1.1 christos struct in_addr ipi_addr; 103 1.1 christos }; 104 1.1 christos #endif 105 1.1 christos if (cmptr->cmsg_level == IPPROTO_IP && 106 1.1 christos cmptr->cmsg_type == IP_PKTINFO) { 107 1.1 christos struct in_pktinfo *tmp; 108 1.1 christos struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 109 1.1 christos 110 1.1 christos tmp = (struct in_pktinfo *) CMSG_DATA(cmptr); 111 1.1 christos sin->sin_family = AF_INET; 112 1.1 christos sin->sin_addr = tmp->ipi_addr; 113 1.1 christos sin->sin_port = 0; 114 1.1 christos pktp->ipi_ifindex = tmp->ipi_ifindex; 115 1.1 christos continue; 116 1.1 christos } 117 1.1 christos #endif 118 1.1 christos 119 1.1 christos #ifdef IP_RECVDSTADDR 120 1.1 christos if (cmptr->cmsg_level == IPPROTO_IP && 121 1.1 christos cmptr->cmsg_type == IP_RECVDSTADDR) { 122 1.1 christos struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 123 1.1 christos 124 1.1 christos sin->sin_family = AF_INET; 125 1.1 christos sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr); 126 1.1 christos sin->sin_port = 0; 127 1.1 christos continue; 128 1.1 christos } 129 1.1 christos #endif 130 1.1 christos 131 1.1 christos #ifdef IP_RECVIF 132 1.1 christos if (cmptr->cmsg_level == IPPROTO_IP && 133 1.1 christos cmptr->cmsg_type == IP_RECVIF) { 134 1.1 christos struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr); 135 1.1 christos #ifndef HAVE_BROKEN_RECVIF_NAME 136 1.1 christos int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1); 137 1.1 christos strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen); 138 1.1 christos #endif 139 1.1 christos pktp->ipi_ifindex = sdl->sdl_index; 140 1.1 christos #ifdef HAVE_BROKEN_RECVIF_NAME 141 1.1 christos if (sdl->sdl_index == 0) { 142 1.1 christos pktp->ipi_ifindex = *(uint_t*)sdl; 143 1.1 christos } 144 1.1 christos #endif 145 1.1 christos assert(pktp->ipi_ifname[IFI_NAME - 1] == 0); 146 1.1 christos // null terminated because of memset above 147 1.1 christos continue; 148 1.1 christos } 149 1.1 christos #endif 150 1.1 christos 151 1.1 christos #ifdef IP_RECVTTL 152 1.1 christos if (cmptr->cmsg_level == IPPROTO_IP && 153 1.1 christos cmptr->cmsg_type == IP_RECVTTL) { 154 1.1 christos *ttl = *(u_char*)CMSG_DATA(cmptr); 155 1.1 christos continue; 156 1.1 christos } 157 1.1 christos else if (cmptr->cmsg_level == IPPROTO_IP && 158 1.1 christos cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL 159 1.1 christos *ttl = *(int*)CMSG_DATA(cmptr); 160 1.1 christos continue; 161 1.1 christos } 162 1.1 christos #endif 163 1.1 christos 164 1.1 christos #if defined(IPV6_PKTINFO) && HAVE_IPV6 165 1.1 christos if (cmptr->cmsg_level == IPPROTO_IPV6 && 166 1.1 christos cmptr->cmsg_type == IPV6_2292_PKTINFO) { 167 1.1 christos struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr; 168 1.1 christos struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr); 169 1.1 christos 170 1.1 christos sin6->sin6_family = AF_INET6; 171 1.1 christos #ifndef NOT_HAVE_SA_LEN 172 1.1 christos sin6->sin6_len = sizeof(*sin6); 173 1.1 christos #endif 174 1.1 christos sin6->sin6_addr = ip6_info->ipi6_addr; 175 1.1 christos sin6->sin6_flowinfo = 0; 176 1.1 christos sin6->sin6_scope_id = 0; 177 1.1 christos sin6->sin6_port = 0; 178 1.1 christos pktp->ipi_ifindex = ip6_info->ipi6_ifindex; 179 1.1 christos continue; 180 1.1 christos } 181 1.1 christos #endif 182 1.1 christos 183 1.1 christos #if defined(IPV6_HOPLIMIT) && HAVE_IPV6 184 1.1 christos if (cmptr->cmsg_level == IPPROTO_IPV6 && 185 1.1 christos cmptr->cmsg_type == IPV6_2292_HOPLIMIT) { 186 1.1 christos *ttl = *(int*)CMSG_DATA(cmptr); 187 1.1 christos continue; 188 1.1 christos } 189 1.1 christos #endif 190 1.1 christos assert(0); // unknown ancillary data 191 1.1 christos } 192 1.1 christos return(n); 193 1.1 christos #endif /* CMSG_FIRSTHDR */ 194 1.1 christos } 195