iface.c revision e4583f74180a1a334ce2591316a6a63d74aafd97
1/* $Id$ */ 2 3/*** 4 This file is part of avahi. 5 6 avahi is free software; you can redistribute it and/or modify it 7 under the terms of the GNU Lesser General Public License as 8 published by the Free Software Foundation; either version 2.1 of the 9 License, or (at your option) any later version. 10 11 avahi is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 14 Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with avahi; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 19 USA. 20***/ 21 22#ifdef HAVE_CONFIG_H 23#include <config.h> 24#endif 25 26#include <string.h> 27#include <sys/socket.h> 28#include <asm/types.h> 29#include <linux/netlink.h> 30#include <linux/rtnetlink.h> 31#include <errno.h> 32#include <net/if.h> 33#include <stdio.h> 34 35#include <avahi-common/error.h> 36#include <avahi-common/malloc.h> 37 38#include "iface.h" 39#include "netlink.h" 40#include "dns.h" 41#include "socket.h" 42#include "announce.h" 43#include "util.h" 44#include "log.h" 45 46static void update_address_rr(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a, int remove_rrs) { 47 assert(m); 48 assert(a); 49 50 if (a->interface->announcing && 51 m->list == LIST_DONE && 52 avahi_interface_address_relevant(a) && 53 !remove_rrs && 54 m->server->config.publish_addresses && 55 (m->server->state == AVAHI_SERVER_RUNNING || 56 m->server->state == AVAHI_SERVER_REGISTERING)) { 57 58 /* Fill the entry group */ 59 if (!a->entry_group) 60 a->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL); 61 62 if (!a->entry_group) /* OOM */ 63 return; 64 65 if (avahi_s_entry_group_is_empty(a->entry_group)) { 66 char t[64]; 67 avahi_address_snprint(t, sizeof(t), &a->address); 68 69 avahi_log_info("Registering new address %s on %s.", t, a->interface->hardware->name); 70 71 if (avahi_server_add_address(m->server, a->entry_group, a->interface->hardware->index, a->interface->protocol, 0, NULL, &a->address) < 0) { 72 avahi_log_warn(__FILE__": avahi_server_add_address() failed: %s", avahi_strerror(m->server->error)); 73 avahi_s_entry_group_free(a->entry_group); 74 a->entry_group = NULL; 75 return; 76 } 77 78 avahi_s_entry_group_commit(a->entry_group); 79 } 80 } else { 81 82 /* Clear the entry group */ 83 84 if (a->entry_group && !avahi_s_entry_group_is_empty(a->entry_group)) { 85 char t[64]; 86 avahi_address_snprint(t, sizeof(t), &a->address); 87 88 if (avahi_s_entry_group_get_state(a->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING) 89 avahi_server_decrease_host_rr_pending(m->server); 90 91 avahi_log_info("Withdrawing address %s on %s.", t, a->interface->hardware->name); 92 93 avahi_s_entry_group_reset(a->entry_group); 94 } 95 } 96} 97 98static void update_interface_rr(AvahiInterfaceMonitor *m, AvahiInterface *i, int remove_rrs) { 99 AvahiInterfaceAddress *a; 100 101 assert(m); 102 assert(i); 103 104 for (a = i->addresses; a; a = a->address_next) 105 update_address_rr(m, a, remove_rrs); 106} 107 108static void update_hw_interface_rr(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, int remove_rrs) { 109 AvahiInterface *i; 110 111 assert(m); 112 assert(hw); 113 114 for (i = hw->interfaces; i; i = i->by_hardware_next) 115 update_interface_rr(m, i, remove_rrs); 116 117 if (m->list == LIST_DONE && 118 !remove_rrs && 119 m->server->config.publish_workstation && 120 (m->server->state == AVAHI_SERVER_RUNNING || 121 m->server->state == AVAHI_SERVER_REGISTERING)) { 122 123 if (!hw->entry_group) 124 hw->entry_group = avahi_s_entry_group_new(m->server, avahi_host_rr_entry_group_callback, NULL); 125 126 if (!hw->entry_group) 127 return; /* OOM */ 128 129 if (avahi_s_entry_group_is_empty(hw->entry_group)) { 130 char *name; 131 char *t; 132 133 if (!(t = avahi_format_mac_address(hw->mac_address, hw->mac_address_size))) 134 return; /* OOM */ 135 136 name = avahi_strdup_printf("%s [%s]", m->server->host_name, t); 137 avahi_free(t); 138 139 if (!name) 140 return; /* OOM */ 141 142 if (avahi_server_add_service(m->server, hw->entry_group, hw->index, AVAHI_PROTO_UNSPEC, name, "_workstation._tcp", NULL, NULL, 9, NULL) < 0) { 143 avahi_log_warn(__FILE__": avahi_server_add_service() failed."); 144 avahi_s_entry_group_free(hw->entry_group); 145 hw->entry_group = NULL; 146 } else 147 avahi_s_entry_group_commit(hw->entry_group); 148 149 avahi_free(name); 150 } 151 152 } else { 153 154 if (hw->entry_group && !avahi_s_entry_group_is_empty(hw->entry_group)) { 155 156 if (avahi_s_entry_group_get_state(hw->entry_group) == AVAHI_ENTRY_GROUP_REGISTERING) 157 avahi_server_decrease_host_rr_pending(m->server); 158 159 avahi_s_entry_group_reset(hw->entry_group); 160 } 161 } 162} 163 164static void free_address(AvahiInterfaceMonitor *m, AvahiInterfaceAddress *a) { 165 assert(m); 166 assert(a); 167 assert(a->interface); 168 169 update_address_rr(m, a, 1); 170 AVAHI_LLIST_REMOVE(AvahiInterfaceAddress, address, a->interface->addresses, a); 171 172 if (a->entry_group) 173 avahi_s_entry_group_free(a->entry_group); 174 175 avahi_free(a); 176} 177 178static void free_interface(AvahiInterfaceMonitor *m, AvahiInterface *i, int send_goodbye) { 179 assert(m); 180 assert(i); 181 182 avahi_goodbye_interface(m->server, i, send_goodbye); 183 avahi_response_scheduler_force(i->response_scheduler); 184 185 assert(!i->announcements); 186 187 update_interface_rr(m, i, 1); 188 189 while (i->addresses) 190 free_address(m, i->addresses); 191 192 avahi_response_scheduler_free(i->response_scheduler); 193 avahi_query_scheduler_free(i->query_scheduler); 194 avahi_probe_scheduler_free(i->probe_scheduler); 195 avahi_cache_free(i->cache); 196 197 AVAHI_LLIST_REMOVE(AvahiInterface, interface, m->interfaces, i); 198 AVAHI_LLIST_REMOVE(AvahiInterface, by_hardware, i->hardware->interfaces, i); 199 200 avahi_free(i); 201} 202 203static void free_hw_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, int send_goodbye) { 204 assert(m); 205 assert(hw); 206 207 update_hw_interface_rr(m, hw, 1); 208 209 while (hw->interfaces) 210 free_interface(m, hw->interfaces, send_goodbye); 211 212 if (hw->entry_group) 213 avahi_s_entry_group_free(hw->entry_group); 214 215 AVAHI_LLIST_REMOVE(AvahiHwInterface, hardware, m->hw_interfaces, hw); 216 avahi_hashmap_remove(m->hashmap, &hw->index); 217 218 avahi_free(hw->name); 219 avahi_free(hw); 220} 221 222static AvahiInterfaceAddress* get_address(AvahiInterfaceMonitor *m, AvahiInterface *i, const AvahiAddress *raddr) { 223 AvahiInterfaceAddress *ia; 224 225 assert(m); 226 assert(i); 227 assert(raddr); 228 229 for (ia = i->addresses; ia; ia = ia->address_next) 230 if (avahi_address_cmp(&ia->address, raddr) == 0) 231 return ia; 232 233 return NULL; 234} 235 236static int netlink_list_items(AvahiNetlink *nl, uint16_t type, unsigned *ret_seq) { 237 struct nlmsghdr *n; 238 struct rtgenmsg *gen; 239 uint8_t req[1024]; 240 241 memset(&req, 0, sizeof(req)); 242 n = (struct nlmsghdr*) req; 243 n->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); 244 n->nlmsg_type = type; 245 n->nlmsg_flags = NLM_F_ROOT/*|NLM_F_MATCH*/|NLM_F_REQUEST; 246 n->nlmsg_pid = 0; 247 248 gen = NLMSG_DATA(n); 249 memset(gen, 0, sizeof(struct rtgenmsg)); 250 gen->rtgen_family = AF_UNSPEC; 251 252 return avahi_netlink_send(nl, n, ret_seq); 253} 254 255static void new_interface(AvahiInterfaceMonitor *m, AvahiHwInterface *hw, AvahiProtocol protocol) { 256 AvahiInterface *i; 257 258 assert(m); 259 assert(hw); 260 assert(protocol != AVAHI_PROTO_UNSPEC); 261 262 if (!(i = avahi_new(AvahiInterface, 1))) 263 goto fail; /* OOM */ 264 265 i->monitor = m; 266 i->hardware = hw; 267 i->protocol = protocol; 268 i->announcing = 0; 269 270 AVAHI_LLIST_HEAD_INIT(AvahiInterfaceAddress, i->addresses); 271 AVAHI_LLIST_HEAD_INIT(AvahiAnnouncement, i->announcements); 272 273 i->cache = avahi_cache_new(m->server, i); 274 i->response_scheduler = avahi_response_scheduler_new(i); 275 i->query_scheduler = avahi_query_scheduler_new(i); 276 i->probe_scheduler = avahi_probe_scheduler_new(i); 277 278 if (!i->cache || !i->response_scheduler || !i->query_scheduler || !i->probe_scheduler) 279 goto fail; /* OOM */ 280 281 AVAHI_LLIST_PREPEND(AvahiInterface, by_hardware, hw->interfaces, i); 282 AVAHI_LLIST_PREPEND(AvahiInterface, interface, m->interfaces, i); 283 284 return; 285fail: 286 287 if (i) { 288 if (i->cache) 289 avahi_cache_free(i->cache); 290 if (i->response_scheduler) 291 avahi_response_scheduler_free(i->response_scheduler); 292 if (i->query_scheduler) 293 avahi_query_scheduler_free(i->query_scheduler); 294 if (i->probe_scheduler) 295 avahi_probe_scheduler_free(i->probe_scheduler); 296 } 297 298} 299 300static void check_interface_relevant(AvahiInterfaceMonitor *m, AvahiInterface *i) { 301 int b; 302 303 assert(m); 304 assert(i); 305 306 b = avahi_interface_relevant(i); 307 308 if (m->list == LIST_DONE && b && !i->announcing) { 309 avahi_log_info("New relevant interface %s.%i.", i->hardware->name, i->protocol); 310 311 if (i->protocol == AVAHI_PROTO_INET) 312 avahi_mdns_mcast_join_ipv4(m->server->fd_ipv4, i->hardware->index); 313 if (i->protocol == AVAHI_PROTO_INET6) 314 avahi_mdns_mcast_join_ipv6(m->server->fd_ipv6, i->hardware->index); 315 316 i->announcing = 1; 317 avahi_announce_interface(m->server, i); 318 avahi_browser_new_interface(m->server, i); 319 } else if (!b && i->announcing) { 320 avahi_log_info("Interface %s.%i no longer relevant.", i->hardware->name, i->protocol); 321 322 if (i->protocol == AVAHI_PROTO_INET) 323 avahi_mdns_mcast_leave_ipv4(m->server->fd_ipv4, i->hardware->index); 324 if (i->protocol == AVAHI_PROTO_INET6) 325 avahi_mdns_mcast_leave_ipv6(m->server->fd_ipv6, i->hardware->index); 326 327 avahi_goodbye_interface(m->server, i, 0); 328 avahi_response_scheduler_clear(i->response_scheduler); 329 avahi_query_scheduler_clear(i->query_scheduler); 330 avahi_probe_scheduler_clear(i->probe_scheduler); 331 avahi_cache_flush(i->cache); 332 333 i->announcing = 0; 334 } 335} 336 337static void check_hw_interface_relevant(AvahiInterfaceMonitor *m, AvahiHwInterface *hw) { 338 AvahiInterface *i; 339 340 assert(m); 341 assert(hw); 342 343 for (i = hw->interfaces; i; i = i->by_hardware_next) 344 check_interface_relevant(m, i); 345} 346 347static void check_all_interfaces_relevant(AvahiInterfaceMonitor *m) { 348 AvahiInterface *i; 349 assert(m); 350 351 for (i = m->interfaces; i; i = i->interface_next) 352 check_interface_relevant(m, i); 353} 354 355static void netlink_callback(AvahiNetlink *nl, struct nlmsghdr *n, void* userdata) { 356 AvahiInterfaceMonitor *m = userdata; 357 358 assert(m); 359 assert(n); 360 assert(m->netlink == nl); 361 362 if (n->nlmsg_type == RTM_NEWLINK) { 363 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n); 364 AvahiHwInterface *hw; 365 struct rtattr *a = NULL; 366 size_t l; 367 368 if (ifinfomsg->ifi_family != AF_UNSPEC) 369 return; 370 371 if (!(hw = avahi_hashmap_lookup(m->hashmap, &ifinfomsg->ifi_index))) { 372 373 if (!(hw = avahi_new(AvahiHwInterface, 1))) 374 return; /* OOM */ 375 376 hw->monitor = m; 377 hw->name = NULL; 378 hw->flags = 0; 379 hw->mtu = 1500; 380 hw->index = (AvahiIfIndex) ifinfomsg->ifi_index; 381 hw->mac_address_size = 0; 382 hw->entry_group = NULL; 383 384 AVAHI_LLIST_HEAD_INIT(AvahiInterface, hw->interfaces); 385 AVAHI_LLIST_PREPEND(AvahiHwInterface, hardware, m->hw_interfaces, hw); 386 387 avahi_hashmap_insert(m->hashmap, &hw->index, hw); 388 389 if (m->server->fd_ipv4 >= 0) 390 new_interface(m, hw, AVAHI_PROTO_INET); 391 if (m->server->fd_ipv6 >= 0) 392 new_interface(m, hw, AVAHI_PROTO_INET6); 393 } 394 395 hw->flags = ifinfomsg->ifi_flags; 396 397 l = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg)); 398 a = IFLA_RTA(ifinfomsg); 399 400 while (RTA_OK(a, l)) { 401 switch(a->rta_type) { 402 case IFLA_IFNAME: 403 avahi_free(hw->name); 404 hw->name = avahi_strndup(RTA_DATA(a), RTA_PAYLOAD(a)); 405 break; 406 407 case IFLA_MTU: 408 assert(RTA_PAYLOAD(a) == sizeof(unsigned int)); 409 hw->mtu = *((unsigned int*) RTA_DATA(a)); 410 break; 411 412 case IFLA_ADDRESS: { 413 hw->mac_address_size = RTA_PAYLOAD(a); 414 if (hw->mac_address_size > AVAHI_MAX_MAC_ADDRESS) 415 hw->mac_address_size = AVAHI_MAX_MAC_ADDRESS; 416 417 memcpy(hw->mac_address, RTA_DATA(a), hw->mac_address_size); 418 break; 419 } 420 421 default: 422 ; 423 } 424 425 a = RTA_NEXT(a, l); 426 } 427 428 check_hw_interface_relevant(m, hw); 429 update_hw_interface_rr(m, hw, 0); 430 431 } else if (n->nlmsg_type == RTM_DELLINK) { 432 struct ifinfomsg *ifinfomsg = NLMSG_DATA(n); 433 AvahiHwInterface *hw; 434 435 if (ifinfomsg->ifi_family != AF_UNSPEC) 436 return; 437 438 if (!(hw = avahi_interface_monitor_get_hw_interface(m, (AvahiIfIndex) ifinfomsg->ifi_index))) 439 return; 440 441 free_hw_interface(m, hw, 0); 442 443 } else if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) { 444 445 struct ifaddrmsg *ifaddrmsg = NLMSG_DATA(n); 446 AvahiInterface *i; 447 struct rtattr *a = NULL; 448 size_t l; 449 AvahiAddress raddr; 450 int raddr_valid = 0; 451 452 if (ifaddrmsg->ifa_family != AVAHI_PROTO_INET && ifaddrmsg->ifa_family != AVAHI_PROTO_INET6) 453 return; 454 455 if (!(i = (AvahiInterface*) avahi_interface_monitor_get_interface(m, (AvahiIfIndex) ifaddrmsg->ifa_index, (AvahiProtocol) ifaddrmsg->ifa_family))) 456 return; 457 458 raddr.family = (AvahiProtocol) ifaddrmsg->ifa_family; 459 460 l = NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg)); 461 a = IFA_RTA(ifaddrmsg); 462 463 while (RTA_OK(a, l)) { 464 465 switch(a->rta_type) { 466 case IFA_ADDRESS: 467 if ((raddr.family == AVAHI_PROTO_INET6 && RTA_PAYLOAD(a) != 16) || 468 (raddr.family == AVAHI_PROTO_INET && RTA_PAYLOAD(a) != 4)) 469 return; 470 471 memcpy(raddr.data.data, RTA_DATA(a), RTA_PAYLOAD(a)); 472 raddr_valid = 1; 473 474 break; 475 476 default: 477 ; 478 } 479 480 a = RTA_NEXT(a, l); 481 } 482 483 if (!raddr_valid) 484 return; 485 486 if (n->nlmsg_type == RTM_NEWADDR) { 487 AvahiInterfaceAddress *addr; 488 489 if (!(addr = get_address(m, i, &raddr))) { 490 if (!(addr = avahi_new(AvahiInterfaceAddress, 1))) 491 return; /* OOM */ 492 493 addr->monitor = m; 494 addr->address = raddr; 495 addr->interface = i; 496 addr->entry_group = NULL; 497 498 AVAHI_LLIST_PREPEND(AvahiInterfaceAddress, address, i->addresses, addr); 499 } 500 501 addr->flags = ifaddrmsg->ifa_flags; 502 addr->scope = ifaddrmsg->ifa_scope; 503 addr->prefix_len = ifaddrmsg->ifa_prefixlen; 504 } else { 505 AvahiInterfaceAddress *addr; 506 507 if (!(addr = get_address(m, i, &raddr))) 508 return; 509 510 free_address(m, addr); 511 } 512 513 check_interface_relevant(m, i); 514 update_interface_rr(m, i, 0); 515 516 } else if (n->nlmsg_type == NLMSG_DONE) { 517 518 if (m->list == LIST_IFACE) { 519 520 if (netlink_list_items(m->netlink, RTM_GETADDR, &m->query_addr_seq) < 0) { 521 avahi_log_warn("NETLINK: Failed to list addrs: %s", strerror(errno)); 522 m->list = LIST_DONE; 523 } else 524 m->list = LIST_ADDR; 525 526 } else 527 /* We're through */ 528 m->list = LIST_DONE; 529 530 if (m->list == LIST_DONE) { 531 check_all_interfaces_relevant(m); 532 avahi_update_host_rrs(m, 0); 533 avahi_log_info("Network interface enumeration completed."); 534 } 535 536 } else if (n->nlmsg_type == NLMSG_ERROR && (n->nlmsg_seq == m->query_link_seq || n->nlmsg_seq == m->query_addr_seq)) { 537 struct nlmsgerr *e = NLMSG_DATA (n); 538 539 if (e->error) 540 avahi_log_warn("NETLINK: Failed to browse: %s", strerror(-e->error)); 541 } 542} 543 544AvahiInterfaceMonitor *avahi_interface_monitor_new(AvahiServer *s) { 545 AvahiInterfaceMonitor *m = NULL; 546 547 if (!(m = avahi_new0(AvahiInterfaceMonitor, 1))) 548 return NULL; /* OOM */ 549 550 m->server = s; 551 if (!(m->netlink = avahi_netlink_new(s->poll_api, RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR, netlink_callback, m))) 552 goto fail; 553 554 m->hashmap = avahi_hashmap_new(avahi_int_hash, avahi_int_equal, NULL, NULL); 555 556 AVAHI_LLIST_HEAD_INIT(AvahiInterface, m->interfaces); 557 AVAHI_LLIST_HEAD_INIT(AvahiHwInterface, m->hw_interfaces); 558 559 if (netlink_list_items(m->netlink, RTM_GETLINK, &m->query_link_seq) < 0) 560 goto fail; 561 562 m->list = LIST_IFACE; 563 564 return m; 565 566fail: 567 avahi_interface_monitor_free(m); 568 return NULL; 569} 570 571void avahi_interface_monitor_sync(AvahiInterfaceMonitor *m) { 572 assert(m); 573 574 while (m->list != LIST_DONE) { 575 if (!avahi_netlink_work(m->netlink, 1)) 576 break; 577 } 578} 579 580void avahi_interface_monitor_free(AvahiInterfaceMonitor *m) { 581 assert(m); 582 583 while (m->hw_interfaces) 584 free_hw_interface(m, m->hw_interfaces, 1); 585 586 assert(!m->interfaces); 587 588 589 if (m->netlink) 590 avahi_netlink_free(m->netlink); 591 592 if (m->hashmap) 593 avahi_hashmap_free(m->hashmap); 594 595 avahi_free(m); 596} 597 598 599AvahiInterface* avahi_interface_monitor_get_interface(AvahiInterfaceMonitor *m, AvahiIfIndex idx, AvahiProtocol protocol) { 600 AvahiHwInterface *hw; 601 AvahiInterface *i; 602 603 assert(m); 604 assert(idx > 0); 605 assert(protocol != AVAHI_PROTO_UNSPEC); 606 607 if (!(hw = avahi_interface_monitor_get_hw_interface(m, idx))) 608 return NULL; 609 610 for (i = hw->interfaces; i; i = i->by_hardware_next) 611 if (i->protocol == protocol) 612 return i; 613 614 return NULL; 615} 616 617AvahiHwInterface* avahi_interface_monitor_get_hw_interface(AvahiInterfaceMonitor *m, AvahiIfIndex idx) { 618 assert(m); 619 assert(idx > 0); 620 621 return avahi_hashmap_lookup(m->hashmap, &idx); 622} 623 624void avahi_interface_send_packet_unicast(AvahiInterface *i, AvahiDnsPacket *p, const AvahiAddress *a, uint16_t port) { 625 assert(i); 626 assert(p); 627/* char t[64]; */ 628 629 if (!avahi_interface_relevant(i)) 630 return; 631 632 assert(!a || a->family == i->protocol); 633 634/* if (a) */ 635/* avahi_log_debug("unicast sending on '%s.%i' to %s:%u", i->hardware->name, i->protocol, avahi_address_snprint(t, sizeof(t), a), port); */ 636/* else */ 637/* avahi_log_debug("multicast sending on '%s.%i'", i->hardware->name, i->protocol); */ 638 639 if (i->protocol == AVAHI_PROTO_INET && i->monitor->server->fd_ipv4 >= 0) 640 avahi_send_dns_packet_ipv4(i->monitor->server->fd_ipv4, i->hardware->index, p, a ? &a->data.ipv4 : NULL, port); 641 else if (i->protocol == AVAHI_PROTO_INET6 && i->monitor->server->fd_ipv6 >= 0) 642 avahi_send_dns_packet_ipv6(i->monitor->server->fd_ipv6, i->hardware->index, p, a ? &a->data.ipv6 : NULL, port); 643} 644 645void avahi_interface_send_packet(AvahiInterface *i, AvahiDnsPacket *p) { 646 assert(i); 647 assert(p); 648 649 avahi_interface_send_packet_unicast(i, p, NULL, 0); 650} 651 652int avahi_interface_post_query(AvahiInterface *i, AvahiKey *key, int immediately) { 653 assert(i); 654 assert(key); 655 656 if (avahi_interface_relevant(i)) 657 return avahi_query_scheduler_post(i->query_scheduler, key, immediately); 658 659 return 0; 660} 661 662int avahi_interface_post_response(AvahiInterface *i, AvahiRecord *record, int flush_cache, const AvahiAddress *querier, int immediately) { 663 assert(i); 664 assert(record); 665 666 if (avahi_interface_relevant(i)) 667 return avahi_response_scheduler_post(i->response_scheduler, record, flush_cache, querier, immediately); 668 669 return 0; 670} 671 672int avahi_interface_post_probe(AvahiInterface *i, AvahiRecord *record, int immediately) { 673 assert(i); 674 assert(record); 675 676 if (avahi_interface_relevant(i)) 677 return avahi_probe_scheduler_post(i->probe_scheduler, record, immediately); 678 679 return 0; 680} 681 682int avahi_dump_caches(AvahiInterfaceMonitor *m, AvahiDumpCallback callback, void* userdata) { 683 AvahiInterface *i; 684 assert(m); 685 686 for (i = m->interfaces; i; i = i->interface_next) { 687 if (avahi_interface_relevant(i)) { 688 char ln[256]; 689 snprintf(ln, sizeof(ln), ";;; INTERFACE %s.%i ;;;", i->hardware->name, i->protocol); 690 callback(ln, userdata); 691 if (avahi_cache_dump(i->cache, callback, userdata) < 0) 692 return -1; 693 } 694 } 695 696 return 0; 697} 698 699int avahi_interface_relevant(AvahiInterface *i) { 700 AvahiInterfaceAddress *a; 701 int relevant_address; 702 703 assert(i); 704 705 relevant_address = 0; 706 707 for (a = i->addresses; a; a = a->address_next) 708 if (avahi_interface_address_relevant(a)) { 709 relevant_address = 1; 710 break; 711 } 712 713/* avahi_log_debug("%p. iface-relevant: %i %i %i %i %i %i", i, relevant_address, */ 714/* (i->hardware->flags & IFF_UP), */ 715/* (i->hardware->flags & IFF_RUNNING), */ 716/* !(i->hardware->flags & IFF_LOOPBACK), */ 717/* (i->hardware->flags & IFF_MULTICAST), */ 718/* !(i->hardware->flags & IFF_POINTOPOINT)); */ 719 720 return 721 (i->hardware->flags & IFF_UP) && 722 (!i->monitor->server->config.use_iff_running || (i->hardware->flags & IFF_RUNNING)) && 723 !(i->hardware->flags & IFF_LOOPBACK) && 724 (i->hardware->flags & IFF_MULTICAST) && 725 !(i->hardware->flags & IFF_POINTOPOINT) && 726 relevant_address; 727} 728 729int avahi_interface_address_relevant(AvahiInterfaceAddress *a) { 730 AvahiInterfaceAddress *b; 731 assert(a); 732 733 /* Publish public IP addresses */ 734 if (a->scope == RT_SCOPE_UNIVERSE || 735 a->scope == RT_SCOPE_SITE) 736 return 1; 737 738 if (a->scope == RT_SCOPE_LINK) { 739 740 /* Publish link local IP addresses if they are the only ones on the link */ 741 for (b = a->interface->addresses; b; b = b->address_next) { 742 if (b == a) 743 continue; 744 745 if (b->scope == RT_SCOPE_UNIVERSE || 746 b->scope == RT_SCOPE_SITE) 747 return 0; 748 } 749 750 return 1; 751 } 752 753 return 0; 754} 755 756int avahi_interface_match(AvahiInterface *i, AvahiIfIndex idx, AvahiProtocol protocol) { 757 assert(i); 758 759 if (idx > 0 && idx != i->hardware->index) 760 return 0; 761 762 if (protocol != AVAHI_PROTO_UNSPEC && protocol != i->protocol) 763 return 0; 764 765 return 1; 766} 767 768void avahi_interface_monitor_walk(AvahiInterfaceMonitor *m, AvahiIfIndex interface, AvahiProtocol protocol, AvahiInterfaceMonitorWalkCallback callback, void* userdata) { 769 assert(m); 770 assert(callback); 771 772 if (interface > 0) { 773 if (protocol != AVAHI_PROTO_UNSPEC) { 774 AvahiInterface *i; 775 776 if ((i = avahi_interface_monitor_get_interface(m, interface, protocol))) 777 callback(m, i, userdata); 778 779 } else { 780 AvahiHwInterface *hw; 781 AvahiInterface *i; 782 783 if ((hw = avahi_interface_monitor_get_hw_interface(m, interface))) 784 for (i = hw->interfaces; i; i = i->by_hardware_next) 785 if (avahi_interface_match(i, interface, protocol)) 786 callback(m, i, userdata); 787 } 788 789 } else { 790 AvahiInterface *i; 791 792 for (i = m->interfaces; i; i = i->interface_next) 793 if (avahi_interface_match(i, interface, protocol)) 794 callback(m, i, userdata); 795 } 796} 797 798void avahi_update_host_rrs(AvahiInterfaceMonitor *m, int remove_rrs) { 799 AvahiHwInterface *hw; 800 801 assert(m); 802 803 for (hw = m->hw_interfaces; hw; hw = hw->hardware_next) 804 update_hw_interface_rr(m, hw, remove_rrs); 805} 806 807int avahi_address_is_local(AvahiInterfaceMonitor *m, const AvahiAddress *a) { 808 AvahiInterface *i; 809 AvahiInterfaceAddress *ia; 810 assert(m); 811 assert(a); 812 813 for (i = m->interfaces; i; i = i->interface_next) 814 for (ia = i->addresses; ia; ia = ia->address_next) 815 if (avahi_address_cmp(a, &ia->address) == 0) 816 return 1; 817 818 return 0; 819} 820 821int avahi_interface_address_on_link(AvahiInterface *i, const AvahiAddress *a) { 822 AvahiInterfaceAddress *ia; 823 824 assert(i); 825 assert(a); 826 827 if (a->family != i->protocol) 828 return 0; 829 830 for (ia = i->addresses; ia; ia = ia->address_next) { 831 832 if (a->family == AVAHI_PROTO_INET) { 833 uint32_t m; 834 835 m = ~(((uint32_t) -1) >> ia->prefix_len); 836 837 if ((ntohl(a->data.ipv4.address) & m) == (ntohl(ia->address.data.ipv4.address) & m)) 838 return 1; 839 } else { 840 unsigned j; 841 unsigned char pl; 842 assert(a->family == AVAHI_PROTO_INET6); 843 844 pl = ia->prefix_len; 845 846 for (j = 0; j < 16; j++) { 847 uint8_t m; 848 849 if (pl == 0) 850 return 1; 851 852 if (pl >= 8) { 853 m = 0xFF; 854 pl -= 8; 855 } else { 856 m = ~(0xFF >> pl); 857 pl = 0; 858 } 859 860 if ((a->data.ipv6.address[j] & m) != (ia->address.data.ipv6.address[j] & m)) 861 break; 862 } 863 } 864 } 865 866 return 0; 867} 868 869int avahi_interface_has_address(AvahiInterfaceMonitor *m, AvahiIfIndex iface, const AvahiAddress *a) { 870 AvahiInterface *i; 871 AvahiInterfaceAddress *j; 872 873 assert(m); 874 assert(iface != AVAHI_IF_UNSPEC); 875 assert(a); 876 877 if (!(i = avahi_interface_monitor_get_interface(m, iface, a->family))) 878 return 0; 879 880 for (j = i->addresses; j; j = j->address_next) 881 if (avahi_address_cmp(a, &j->address) == 0) 882 return 1; 883 884 return 0; 885} 886