1 /* 2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org> 3 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU Lesser General Public License version 2.1 7 * as published by the Free Software Foundation 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15 #define _GNU_SOURCE 16 #include <sys/socket.h> 17 #include <sys/ioctl.h> 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <sys/utsname.h> 21 #include <net/if.h> 22 #include <netinet/in.h> 23 #include <arpa/inet.h> 24 #include <sys/types.h> 25 26 #include <ifaddrs.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include <stdio.h> 31 #include <errno.h> 32 33 #include <libubox/usock.h> 34 #include <libubox/uloop.h> 35 #include <libubox/avl-cmp.h> 36 #include <libubox/utils.h> 37 #include "cache.h" 38 #include "interface.h" 39 #include "util.h" 40 #include "dns.h" 41 #include "announce.h" 42 #include "service.h" 43 44 static struct uloop_fd ufd[] = { 45 [SOCK_UC_IPV4] = { .fd = -1 }, 46 [SOCK_UC_IPV6] = { .fd = -1 }, 47 [SOCK_MC_IPV4] = { .fd = -1 }, 48 [SOCK_MC_IPV6] = { .fd = -1 }, 49 }; 50 51 static int 52 interface_send_packet4(struct interface *iface, struct sockaddr_in *to, struct iovec *iov, int iov_len) 53 { 54 static size_t cmsg_data[( CMSG_SPACE(sizeof(struct in_pktinfo)) / sizeof(size_t)) + 1]; 55 static struct sockaddr_in a = {}; 56 static struct msghdr m = { 57 .msg_name = (struct sockaddr *) &a, 58 .msg_namelen = sizeof(a), 59 .msg_control = cmsg_data, 60 .msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo)), 61 }; 62 struct in_pktinfo *pkti; 63 struct cmsghdr *cmsg; 64 int fd; 65 66 a.sin_family = AF_INET; 67 a.sin_port = htons(MCAST_PORT); 68 m.msg_iov = iov; 69 m.msg_iovlen = iov_len; 70 71 memset(cmsg_data, 0, sizeof(cmsg_data)); 72 cmsg = CMSG_FIRSTHDR(&m); 73 cmsg->cmsg_len = m.msg_controllen; 74 cmsg->cmsg_level = IPPROTO_IP; 75 cmsg->cmsg_type = IP_PKTINFO; 76 77 pkti = (struct in_pktinfo*) CMSG_DATA(cmsg); 78 pkti->ipi_ifindex = iface->ifindex; 79 80 fd = ufd[iface->type].fd; 81 if (interface_multicast(iface)) { 82 a.sin_addr.s_addr = inet_addr(MCAST_ADDR); 83 if (to) 84 fprintf(stderr, "Ignoring IPv4 address for multicast interface\n"); 85 } else { 86 a.sin_addr.s_addr = to->sin_addr.s_addr; 87 a.sin_port = to->sin_port; 88 } 89 90 return sendmsg(fd, &m, 0); 91 } 92 93 static int 94 interface_send_packet6(struct interface *iface, struct sockaddr_in6 *to, struct iovec *iov, int iov_len) 95 { 96 static size_t cmsg_data[( CMSG_SPACE(sizeof(struct in6_pktinfo)) / sizeof(size_t)) + 1]; 97 static struct sockaddr_in6 a = {}; 98 static struct msghdr m = { 99 .msg_name = (struct sockaddr *) &a, 100 .msg_namelen = sizeof(a), 101 .msg_control = cmsg_data, 102 .msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo)), 103 }; 104 struct in6_pktinfo *pkti; 105 struct cmsghdr *cmsg; 106 int fd; 107 108 a.sin6_family = AF_INET6; 109 a.sin6_port = htons(MCAST_PORT); 110 a.sin6_scope_id = iface->ifindex; 111 m.msg_iov = iov; 112 m.msg_iovlen = iov_len; 113 114 memset(cmsg_data, 0, sizeof(cmsg_data)); 115 cmsg = CMSG_FIRSTHDR(&m); 116 cmsg->cmsg_len = m.msg_controllen; 117 cmsg->cmsg_level = IPPROTO_IPV6; 118 cmsg->cmsg_type = IPV6_PKTINFO; 119 120 pkti = (struct in6_pktinfo*) CMSG_DATA(cmsg); 121 pkti->ipi6_ifindex = iface->ifindex; 122 123 fd = ufd[iface->type].fd; 124 if (interface_multicast(iface)) { 125 inet_pton(AF_INET6, MCAST_ADDR6, &a.sin6_addr); 126 if (to) 127 fprintf(stderr, "Ignoring IPv6 address for multicast interface\n"); 128 } else { 129 a.sin6_addr = to->sin6_addr; 130 } 131 132 return sendmsg(fd, &m, 0); 133 } 134 135 int 136 interface_send_packet(struct interface *iface, struct sockaddr *to, struct iovec *iov, int iov_len) 137 { 138 if (!interface_multicast(iface) && !to) { 139 fprintf(stderr, "No IP address specified for unicast interface\n"); 140 errno = EINVAL; 141 return -1; 142 } 143 144 if (debug > 1) { 145 fprintf(stderr, "TX ipv%d: %s\n", interface_ipv6(iface) ? 6 : 4, iface->name); 146 fprintf(stderr, " multicast: %d\n", interface_multicast(iface)); 147 } 148 149 if (interface_ipv6(iface)) 150 return interface_send_packet6(iface, (struct sockaddr_in6 *)to, iov, iov_len); 151 152 return interface_send_packet4(iface, (struct sockaddr_in *)to, iov, iov_len); 153 } 154 155 static struct interface *interface_lookup(unsigned int ifindex, enum umdns_socket_type type) 156 { 157 struct interface *iface; 158 159 vlist_for_each_element(&interfaces, iface, node) 160 if (iface->ifindex == ifindex && iface->type == type) 161 return iface; 162 163 return NULL; 164 } 165 166 static void interface_free(struct interface *iface) 167 { 168 cache_cleanup(iface); 169 announce_free(iface); 170 free(iface->addrs.v4); 171 free(iface); 172 } 173 174 static int 175 interface_valid_src(void *ip1, void *mask, void *ip2, int len) 176 { 177 uint8_t *i1 = ip1; 178 uint8_t *i2 = ip2; 179 uint8_t *m = mask; 180 int i; 181 182 if (cfg_no_subnet) 183 return 0; 184 185 for (i = 0; i < len; i++, i1++, i2++, m++) { 186 if ((*i1 & *m) != (*i2 & *m)) 187 return -1; 188 } 189 190 return 0; 191 } 192 193 static void 194 read_socket4(struct uloop_fd *u, unsigned int events) 195 { 196 enum umdns_socket_type type = (enum umdns_socket_type)(u - ufd); 197 struct interface *iface; 198 static uint8_t buffer[8 * 1024]; 199 struct iovec iov[1]; 200 char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int)) + 1]; 201 struct cmsghdr *cmsgptr; 202 struct msghdr msg; 203 socklen_t len; 204 struct sockaddr_in from; 205 int flags = 0; 206 uint8_t ttl = 0; 207 struct in_pktinfo *inp = NULL; 208 bool valid_src = false; 209 210 if (u->eof) { 211 uloop_end(); 212 return; 213 } 214 215 iov[0].iov_base = buffer; 216 iov[0].iov_len = sizeof(buffer); 217 218 memset(&msg, 0, sizeof(msg)); 219 msg.msg_name = (struct sockaddr *) &from; 220 msg.msg_namelen = sizeof(struct sockaddr_in); 221 msg.msg_iov = iov; 222 msg.msg_iovlen = 1; 223 msg.msg_control = &cmsg; 224 msg.msg_controllen = sizeof(cmsg); 225 226 len = recvmsg(u->fd, &msg, flags); 227 if (len == -1) { 228 perror("read failed"); 229 return; 230 } 231 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { 232 void *c = CMSG_DATA(cmsgptr); 233 234 switch (cmsgptr->cmsg_type) { 235 case IP_PKTINFO: 236 inp = ((struct in_pktinfo *) c); 237 break; 238 239 case IP_TTL: 240 ttl = (uint8_t) *((int *) c); 241 break; 242 243 default: 244 fprintf(stderr, "unknown cmsg %x\n", cmsgptr->cmsg_type); 245 return; 246 } 247 } 248 249 if (!inp) 250 return; 251 252 iface = interface_lookup(inp->ipi_ifindex, type); 253 if (!iface) 254 return; 255 256 if (debug > 1) { 257 char buf[256]; 258 259 fprintf(stderr, "RX ipv4: %s\n", iface->name); 260 fprintf(stderr, " multicast: %d\n", interface_multicast(iface)); 261 inet_ntop(AF_INET, &from.sin_addr, buf, 256); 262 fprintf(stderr, " src %s:%d\n", buf, ntohs(from.sin_port)); 263 inet_ntop(AF_INET, &inp->ipi_spec_dst, buf, 256); 264 fprintf(stderr, " dst %s\n", buf); 265 inet_ntop(AF_INET, &inp->ipi_addr, buf, 256); 266 fprintf(stderr, " real %s\n", buf); 267 fprintf(stderr, " ttl %u\n", ttl); 268 } 269 270 for (size_t i = 0; i < iface->addrs.n_addr; i++) { 271 if (!interface_valid_src((void *)&iface->addrs.v4[i].addr, 272 (void *)&iface->addrs.v4[i].mask, 273 (void *) &from.sin_addr, 4)) { 274 valid_src = true; 275 break; 276 } 277 } 278 279 if (!valid_src) 280 return; 281 282 dns_handle_packet(iface, (struct sockaddr *) &from, ntohs(from.sin_port), buffer, len); 283 } 284 285 static void 286 read_socket6(struct uloop_fd *u, unsigned int events) 287 { 288 enum umdns_socket_type type = (enum umdns_socket_type)(u - ufd); 289 struct interface *iface; 290 static uint8_t buffer[8 * 1024]; 291 struct iovec iov[1]; 292 char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) + 1]; 293 struct cmsghdr *cmsgptr; 294 struct msghdr msg; 295 socklen_t len; 296 struct sockaddr_in6 from; 297 int flags = 0; 298 int ttl = 0; 299 struct in6_pktinfo *inp = NULL; 300 bool valid_src = false; 301 302 if (u->eof) { 303 uloop_end(); 304 return; 305 } 306 307 iov[0].iov_base = buffer; 308 iov[0].iov_len = sizeof(buffer); 309 310 memset(&msg, 0, sizeof(msg)); 311 msg.msg_name = (struct sockaddr *) &from; 312 msg.msg_namelen = sizeof(struct sockaddr_in6); 313 msg.msg_iov = iov; 314 msg.msg_iovlen = 1; 315 msg.msg_control = &cmsg6; 316 msg.msg_controllen = sizeof(cmsg6); 317 318 len = recvmsg(u->fd, &msg, flags); 319 if (len == -1) { 320 perror("read failed"); 321 return; 322 } 323 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { 324 void *c = CMSG_DATA(cmsgptr); 325 326 switch (cmsgptr->cmsg_type) { 327 case IPV6_PKTINFO: 328 inp = ((struct in6_pktinfo *) c); 329 break; 330 331 case IPV6_HOPLIMIT: 332 ttl = (uint8_t) *((int *) c); 333 break; 334 335 default: 336 fprintf(stderr, "unknown cmsg %x\n", cmsgptr->cmsg_type); 337 return; 338 } 339 } 340 341 if (!inp) 342 return; 343 344 iface = interface_lookup(inp->ipi6_ifindex, type); 345 if (!iface) 346 return; 347 348 if (debug > 1) { 349 char buf[256]; 350 351 fprintf(stderr, "RX ipv6: %s\n", iface->name); 352 fprintf(stderr, " multicast: %d\n", interface_multicast(iface)); 353 inet_ntop(AF_INET6, &from.sin6_addr, buf, 256); 354 fprintf(stderr, " src %s:%d\n", buf, ntohs(from.sin6_port)); 355 inet_ntop(AF_INET6, &inp->ipi6_addr, buf, 256); 356 fprintf(stderr, " dst %s\n", buf); 357 fprintf(stderr, " ttl %u\n", ttl); 358 } 359 360 for (size_t i = 0; i < iface->addrs.n_addr; i++) { 361 if (!interface_valid_src((void *)&iface->addrs.v6[i].addr, 362 (void *)&iface->addrs.v6[i].mask, 363 (void *)&from.sin6_addr, 6)) { 364 valid_src = true; 365 break; 366 } 367 } 368 369 if (!valid_src) 370 return; 371 372 dns_handle_packet(iface, (struct sockaddr *) &from, ntohs(from.sin6_port), buffer, len); 373 } 374 375 static int 376 interface_mcast_setup4(struct interface *iface) 377 { 378 struct ip_mreqn mreq; 379 struct sockaddr_in sa = {}; 380 int fd = ufd[SOCK_MC_IPV4].fd; 381 382 sa.sin_family = AF_INET; 383 sa.sin_port = htons(MCAST_PORT); 384 inet_pton(AF_INET, MCAST_ADDR, &sa.sin_addr); 385 386 memset(&mreq, 0, sizeof(mreq)); 387 mreq.imr_multiaddr = sa.sin_addr; 388 mreq.imr_ifindex = iface->ifindex; 389 mreq.imr_address.s_addr = iface->addrs.v4[0].addr.s_addr; 390 391 /* Some network drivers have issues with dropping membership of 392 * mcast groups when the iface is down, but don't allow rejoining 393 * when it comes back up. This is an ugly workaround 394 * -- this was copied from avahi -- 395 */ 396 setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); 397 setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); 398 399 return 0; 400 } 401 402 static int 403 interface_mcast_setup6(struct interface *iface) 404 { 405 struct ipv6_mreq mreq; 406 struct sockaddr_in6 sa = {}; 407 int fd = ufd[SOCK_MC_IPV6].fd; 408 409 sa.sin6_family = AF_INET6; 410 sa.sin6_port = htons(MCAST_PORT); 411 inet_pton(AF_INET6, MCAST_ADDR6, &sa.sin6_addr); 412 413 memset(&mreq, 0, sizeof(mreq)); 414 mreq.ipv6mr_multiaddr = sa.sin6_addr; 415 mreq.ipv6mr_interface = iface->ifindex; 416 417 setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)); 418 setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); 419 420 return 0; 421 } 422 423 static void interface_start(struct interface *iface) 424 { 425 if (iface->type & SOCKTYPE_BIT_UNICAST) 426 return; 427 428 if (iface->type & SOCKTYPE_BIT_IPV6) 429 interface_mcast_setup6(iface); 430 else 431 interface_mcast_setup4(iface); 432 433 dns_send_question(iface, NULL, C_DNS_SD, TYPE_PTR, 0); 434 announce_init(iface); 435 } 436 437 static bool 438 iface_equal(struct interface *if_old, struct interface *if_new) 439 { 440 size_t addr_size; 441 442 if (if_old->ifindex != if_new->ifindex || 443 if_old->addrs.n_addr != if_new->addrs.n_addr) 444 return false; 445 446 if (if_old->type & SOCKTYPE_BIT_IPV6) 447 addr_size = sizeof(*if_old->addrs.v6); 448 else 449 addr_size = sizeof(*if_old->addrs.v4); 450 addr_size *= if_old->addrs.n_addr; 451 if (memcmp(if_old->addrs.v4, if_new->addrs.v4, addr_size) != 0) 452 return false; 453 454 return true; 455 } 456 457 static void 458 iface_update_cb(struct vlist_tree *tree, struct vlist_node *node_new, 459 struct vlist_node *node_old) 460 { 461 struct interface *if_old = container_of_safe(node_old, struct interface, node); 462 struct interface *if_new = container_of_safe(node_new, struct interface, node); 463 464 if (if_old && if_new) { 465 bool equal = iface_equal(if_old, if_new); 466 if (!equal) 467 cache_cleanup(if_old); 468 free(if_old->addrs.v4); 469 if_old->addrs = if_new->addrs; 470 if_old->ifindex = if_new->ifindex; 471 free(if_new); 472 473 if (!equal) 474 interface_start(if_old); 475 return; 476 } 477 478 if (if_old) 479 interface_free(if_old); 480 481 if (if_new) 482 interface_start(if_new); 483 } 484 485 static int interface_init_socket(enum umdns_socket_type type, bool *mcast) 486 { 487 struct sockaddr_in6 local6 = { 488 .sin6_family = AF_INET6 489 }; 490 struct sockaddr_in local = { 491 .sin_family = AF_INET 492 }; 493 uint8_t ttl = 255; 494 int ittl = 255; 495 int yes = 1; 496 int no = 0; 497 int fd; 498 int af = (type & SOCKTYPE_BIT_IPV6) ? AF_INET6 : AF_INET; 499 bool reuseport = false; 500 501 if (ufd[type].fd >= 0) 502 return 0; 503 504 ufd[type].fd = fd = socket(af, SOCK_DGRAM, 0); 505 if (fd < 0) 506 return -1; 507 508 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); 509 510 switch (type) { 511 case SOCK_UC_IPV4: 512 case SOCK_UC_IPV6: 513 break; 514 case SOCK_MC_IPV4: 515 setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); 516 setsockopt(fd, IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)); 517 setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no, sizeof(no)); 518 local.sin_port = htons(MCAST_PORT); 519 break; 520 case SOCK_MC_IPV6: 521 setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); 522 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); 523 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)); 524 setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no, sizeof(no)); 525 local6.sin6_port = htons(MCAST_PORT); 526 break; 527 } 528 529 retry: 530 if (type & SOCKTYPE_BIT_IPV6) { 531 ufd[type].cb = read_socket6; 532 if (bind(fd, (struct sockaddr *)&local6, sizeof(local6)) < 0) 533 goto error; 534 535 setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)); 536 setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &yes, sizeof(yes)); 537 } else { 538 ufd[type].cb = read_socket4; 539 if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0) 540 goto error; 541 542 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)); 543 setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)); 544 } 545 546 uloop_fd_add(&ufd[type], ULOOP_READ); 547 548 return 0; 549 550 error: 551 if (!reuseport) { 552 #ifdef SO_REUSEPORT 553 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)); 554 #endif 555 reuseport = true; 556 *mcast = true; 557 goto retry; 558 } 559 close(ufd[type].fd); 560 return -1; 561 } 562 563 static void 564 __interface_add(const char *name, enum umdns_socket_type type, 565 struct interface_addr_list *list) 566 { 567 struct interface *iface; 568 unsigned int ifindex; 569 bool mcast = false; 570 char *id_buf; 571 572 if (interface_init_socket(type, &mcast)) 573 goto error; 574 575 ifindex = if_nametoindex(name); 576 if (!ifindex) 577 goto error; 578 579 iface = calloc_a(sizeof(*iface), 580 &id_buf, strlen(name) + 3); 581 582 sprintf(id_buf, "%d_%s", type, name); 583 iface->name = id_buf + 2; 584 iface->ifindex = ifindex; 585 iface->type = type; 586 iface->addrs = *list; 587 iface->need_multicast = mcast; 588 589 vlist_add(&interfaces, &iface->node, id_buf); 590 return; 591 592 error: 593 free(list->v4); 594 } 595 596 int interface_add(const char *name) 597 { 598 struct ifaddrs *ifap, *ifa; 599 struct interface_addr_list addr4 = {}, addr6 = {}; 600 601 getifaddrs(&ifap); 602 603 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 604 if (strcmp(ifa->ifa_name, name)) 605 continue; 606 if (ifa->ifa_addr->sa_family == AF_INET) { 607 struct sockaddr_in *sin; 608 609 if (cfg_proto && (cfg_proto != 4)) 610 continue; 611 612 addr4.v4 = realloc(addr4.v4, (addr4.n_addr + 1) * sizeof(*addr4.v4)); 613 sin = (struct sockaddr_in *) ifa->ifa_addr; 614 addr4.v4[addr4.n_addr].addr = sin->sin_addr; 615 sin = (struct sockaddr_in *) ifa->ifa_netmask; 616 addr4.v4[addr4.n_addr++].mask = sin->sin_addr; 617 } 618 619 if (ifa->ifa_addr->sa_family == AF_INET6) { 620 uint8_t ll_prefix[] = {0xfe, 0x80 }; 621 struct sockaddr_in6 *sin6; 622 623 if (cfg_proto && (cfg_proto != 6)) 624 continue; 625 626 sin6 = (struct sockaddr_in6 *) ifa->ifa_addr; 627 if (memcmp(&sin6->sin6_addr, &ll_prefix, 2)) 628 continue; 629 630 addr6.v6 = realloc(addr6.v6, (addr6.n_addr + 1) * sizeof(*addr6.v6)); 631 sin6 = (struct sockaddr_in6 *) ifa->ifa_addr; 632 addr6.v6[addr6.n_addr].addr = sin6->sin6_addr; 633 sin6 = (struct sockaddr_in6 *) ifa->ifa_netmask; 634 addr6.v6[addr6.n_addr++].mask = sin6->sin6_addr; 635 } 636 } 637 638 freeifaddrs(ifap); 639 640 if (addr4.n_addr) { 641 size_t addr_size = addr4.n_addr * sizeof(*addr4.v4); 642 void *addr_dup = malloc(addr_size); 643 644 memcpy(addr_dup, addr4.v4, addr_size); 645 __interface_add(name, SOCK_UC_IPV4, &addr4); 646 addr4.v4 = addr_dup; 647 __interface_add(name, SOCK_MC_IPV4, &addr4); 648 } 649 650 if (addr6.n_addr) { 651 size_t addr_size = addr6.n_addr * sizeof(*addr6.v6); 652 void *addr_dup = malloc(addr_size); 653 654 memcpy(addr_dup, addr6.v6, addr_size); 655 __interface_add(name, SOCK_UC_IPV6, &addr6); 656 addr6.v6 = addr_dup; 657 __interface_add(name, SOCK_MC_IPV6, &addr6); 658 } 659 660 return !addr4.n_addr && !addr6.n_addr; 661 } 662 663 void interface_shutdown(void) 664 { 665 struct interface *iface; 666 667 vlist_for_each_element(&interfaces, iface, node) 668 if (interface_multicast(iface)) { 669 dns_reply_a(iface, NULL, 0, NULL); 670 dns_reply_a_additional(iface, NULL, 0); 671 service_announce_services(iface, NULL, 0); 672 } 673 674 for (size_t i = 0; i < ARRAY_SIZE(ufd); i++) { 675 uloop_fd_delete(&ufd[i]); 676 close(ufd[i].fd); 677 ufd[i].fd = -1; 678 } 679 } 680 681 struct interface *interface_get(const char *name, enum umdns_socket_type type) 682 { 683 char id_buf[32]; 684 snprintf(id_buf, sizeof(id_buf), "%d_%s", type, name); 685 struct interface *iface = vlist_find(&interfaces, id_buf, iface, node); 686 return iface; 687 } 688 689 VLIST_TREE(interfaces, avl_strcmp, iface_update_cb, true, false); 690
This page was automatically generated by LXR 0.3.1. • OpenWrt