1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include "mDNSUNP.h" 19 #include <ifaddrs.h> 20 21 #include <assert.h> 22 #include <err.h> 23 #include <errno.h> 24 #include <string.h> 25 #include <stdlib.h> 26 #include <unistd.h> 27 #include <netinet/in.h> 28 #include <netinet/in_var.h> 29 #include <net/if_dl.h> 30 31 static int 32 copyaddr(struct sockaddr **dst, const struct sockaddr *src, socklen_t len) 33 { 34 if (src == NULL) 35 return 1; 36 37 *dst = calloc(1, len); 38 if (*dst == NULL) 39 return 0; 40 41 memcpy(*dst, src, len); 42 return 1; 43 } 44 45 struct ifi_info * 46 get_ifi_info(int family, int doaliases) 47 { 48 struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr; 49 struct ifaddrs *ifal, *ifa; 50 51 if (getifaddrs(&ifal) == -1) { 52 warn("getifaddrs"); 53 return NULL; 54 } 55 56 ifihead = NULL; 57 ifipnext = &ifihead; 58 59 for (ifa = ifal; ifa; ifa = ifa->ifa_next) { 60 struct sockaddr *sa = ifa->ifa_addr; 61 int flags = ifa->ifa_flags; 62 int addrflags = ifa->ifa_addrflags; 63 64 #if 0 65 /* 66 * Include the loopback so that we return at least one 67 * address, so that mdnsd does not exit before we get 68 * a dhcp address 69 */ 70 if (flags & IFF_LOOPBACK) 71 continue; /* ignore loopback interfaces */ 72 #endif 73 74 if ((flags & IFF_UP) == 0) 75 continue; /* ignore if interface not up */ 76 77 if (sa == NULL || sa->sa_family != family) 78 continue; /* ignore if not the desired family */ 79 80 switch (sa->sa_family) { 81 case AF_INET: 82 if (addrflags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) 83 continue; 84 85 break; 86 #if defined(AF_INET6) && HAVE_IPV6 87 case AF_INET6: 88 if (addrflags & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED)) 89 continue; 90 #endif 91 break; 92 default: 93 continue; 94 } 95 96 ifi = calloc(1, sizeof(*ifi)); 97 if (ifi == NULL) 98 goto gotError; 99 100 ifipold = *ifipnext; /* need this later */ 101 ifiptr = ifipnext; 102 *ifipnext = ifi; /* prev points to new one */ 103 ifipnext = &ifi->ifi_next; /* pointer to next one */ 104 105 ifi->ifi_flags = flags; /* IFF_xxx values */ 106 ifi->ifi_myflags = 0; /* IFI_xxx values */ 107 ifi->ifi_index = if_nametoindex(ifa->ifa_name); 108 memcpy(ifi->ifi_name, ifa->ifa_name, IFI_NAME); 109 ifi->ifi_name[IFI_NAME-1] = '\0'; 110 if (!copyaddr(&ifi->ifi_addr, ifa->ifa_addr, sa->sa_len)) 111 goto gotError; 112 if (!copyaddr(&ifi->ifi_netmask, ifa->ifa_netmask, sa->sa_len)) 113 goto gotError; 114 115 if ((flags & IFF_BROADCAST) && !copyaddr(&ifi->ifi_brdaddr, 116 ifa->ifa_broadaddr, sa->sa_len)) 117 goto gotError; 118 if ((flags & IFF_POINTOPOINT) && !copyaddr(&ifi->ifi_dstaddr, 119 ifa->ifa_dstaddr, sa->sa_len)) 120 goto gotError; 121 } 122 123 goto done; 124 125 gotError: 126 warn("can't allocate memory"); 127 if (ifihead != NULL) { 128 free_ifi_info(ifihead); 129 ifihead = NULL; 130 } 131 132 freeifaddrs(ifal); 133 done: 134 return ifihead; /* pointer to first structure in linked list */ 135 } 136 137 void 138 free_ifi_info(struct ifi_info *ifihead) 139 { 140 struct ifi_info *ifi, *ififree; 141 142 for (ifi = ifihead; (ififree = ifi) != NULL;) { 143 free(ifi->ifi_addr); 144 free(ifi->ifi_netmask); 145 free(ifi->ifi_brdaddr); 146 free(ifi->ifi_dstaddr); 147 ifi = ifi->ifi_next; 148 free(ififree); 149 } 150 } 151 152 ssize_t 153 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp, 154 struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, 155 u_char *ttl) 156 { 157 struct msghdr msg; 158 struct iovec iov[1]; 159 ssize_t n; 160 161 #ifdef CMSG_FIRSTHDR 162 struct cmsghdr *cmptr; 163 union { 164 struct cmsghdr cm; 165 char control[1024]; 166 } control_un; 167 168 *ttl = 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be 169 170 msg.msg_control = control_un.control; 171 msg.msg_controllen = sizeof(control_un.control); 172 msg.msg_flags = 0; 173 #else 174 memset(&msg, 0, sizeof(msg)); /* make certain msg_accrightslen = 0 */ 175 #endif /* CMSG_FIRSTHDR */ 176 177 msg.msg_name = (char *) sa; 178 msg.msg_namelen = *salenptr; 179 iov[0].iov_base = (char *)ptr; 180 iov[0].iov_len = nbytes; 181 msg.msg_iov = iov; 182 msg.msg_iovlen = 1; 183 184 if ( (n = recvmsg(fd, &msg, *flagsp)) < 0) 185 return(n); 186 187 *salenptr = msg.msg_namelen; /* pass back results */ 188 if (pktp) { 189 /* 0.0.0.0, i/f = -1 */ 190 /* We set the interface to -1 so that the caller can 191 tell whether we returned a meaningful value or 192 just some default. Previously this code just 193 set the value to 0, but I'm concerned that 0 194 might be a valid interface value. 195 */ 196 memset(pktp, 0, sizeof(struct my_in_pktinfo)); 197 pktp->ipi_ifindex = -1; 198 } 199 /* end recvfrom_flags1 */ 200 201 /* include recvfrom_flags2 */ 202 #ifndef CMSG_FIRSTHDR 203 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc. 204 *flagsp = 0; /* pass back results */ 205 return(n); 206 #else 207 208 *flagsp = msg.msg_flags; /* pass back results */ 209 if (msg.msg_controllen < (socklen_t)sizeof(struct cmsghdr) || 210 (msg.msg_flags & MSG_CTRUNC) || pktp == NULL) 211 return(n); 212 213 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL; 214 cmptr = CMSG_NXTHDR(&msg, cmptr)) { 215 216 #ifdef IP_PKTINFO 217 #if in_pktinfo_definition_is_missing 218 struct in_pktinfo 219 { 220 int ipi_ifindex; 221 struct in_addr ipi_spec_dst; 222 struct in_addr ipi_addr; 223 }; 224 #endif 225 if (cmptr->cmsg_level == IPPROTO_IP && 226 cmptr->cmsg_type == IP_PKTINFO) { 227 struct in_pktinfo *tmp; 228 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 229 230 tmp = (struct in_pktinfo *) CMSG_DATA(cmptr); 231 sin->sin_family = AF_INET; 232 sin->sin_addr = tmp->ipi_addr; 233 sin->sin_port = 0; 234 pktp->ipi_ifindex = tmp->ipi_ifindex; 235 continue; 236 } 237 #endif 238 239 #ifdef IP_RECVDSTADDR 240 if (cmptr->cmsg_level == IPPROTO_IP && 241 cmptr->cmsg_type == IP_RECVDSTADDR) { 242 struct sockaddr_in *sin = (struct sockaddr_in*)&pktp->ipi_addr; 243 244 sin->sin_family = AF_INET; 245 sin->sin_addr = *(struct in_addr*)CMSG_DATA(cmptr); 246 sin->sin_port = 0; 247 continue; 248 } 249 #endif 250 251 #ifdef IP_RECVIF 252 if (cmptr->cmsg_level == IPPROTO_IP && 253 cmptr->cmsg_type == IP_RECVIF) { 254 struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA(cmptr); 255 #ifndef HAVE_BROKEN_RECVIF_NAME 256 int nameLen = (sdl->sdl_nlen < IFI_NAME - 1) ? sdl->sdl_nlen : (IFI_NAME - 1); 257 strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen); 258 #endif 259 pktp->ipi_ifindex = sdl->sdl_index; 260 #ifdef HAVE_BROKEN_RECVIF_NAME 261 if (sdl->sdl_index == 0) { 262 pktp->ipi_ifindex = *(uint_t*)sdl; 263 } 264 #endif 265 assert(pktp->ipi_ifname[IFI_NAME - 1] == 0); 266 // null terminated because of memset above 267 continue; 268 } 269 #endif 270 271 #ifdef IP_RECVTTL 272 if (cmptr->cmsg_level == IPPROTO_IP && 273 cmptr->cmsg_type == IP_RECVTTL) { 274 *ttl = *(u_char*)CMSG_DATA(cmptr); 275 continue; 276 } 277 else if (cmptr->cmsg_level == IPPROTO_IP && 278 cmptr->cmsg_type == IP_TTL) { // some implementations seem to send IP_TTL instead of IP_RECVTTL 279 *ttl = *(int*)CMSG_DATA(cmptr); 280 continue; 281 } 282 #endif 283 284 #if defined(IPV6_PKTINFO) && HAVE_IPV6 285 if (cmptr->cmsg_level == IPPROTO_IPV6 && 286 cmptr->cmsg_type == IPV6_2292_PKTINFO) { 287 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&pktp->ipi_addr; 288 struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmptr); 289 290 sin6->sin6_family = AF_INET6; 291 #ifndef NOT_HAVE_SA_LEN 292 sin6->sin6_len = sizeof(*sin6); 293 #endif 294 sin6->sin6_addr = ip6_info->ipi6_addr; 295 sin6->sin6_flowinfo = 0; 296 sin6->sin6_scope_id = 0; 297 sin6->sin6_port = 0; 298 pktp->ipi_ifindex = ip6_info->ipi6_ifindex; 299 continue; 300 } 301 #endif 302 303 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6 304 if (cmptr->cmsg_level == IPPROTO_IPV6 && 305 cmptr->cmsg_type == IPV6_2292_HOPLIMIT) { 306 *ttl = *(int*)CMSG_DATA(cmptr); 307 continue; 308 } 309 #endif 310 assert(0); // unknown ancillary data 311 } 312 return(n); 313 #endif /* CMSG_FIRSTHDR */ 314 } 315