Home | History | Annotate | Download | only in avahi-core
      1 /***
      2   This file is part of avahi.
      3 
      4   avahi is free software; you can redistribute it and/or modify it
      5   under the terms of the GNU Lesser General Public License as
      6   published by the Free Software Foundation; either version 2.1 of the
      7   License, or (at your option) any later version.
      8 
      9   avahi is distributed in the hope that it will be useful, but WITHOUT
     10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
     12   Public License for more details.
     13 
     14   You should have received a copy of the GNU Lesser General Public
     15   License along with avahi; if not, write to the Free Software
     16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
     17   USA.
     18 ***/
     19 
     20 #ifdef HAVE_CONFIG_H
     21 #include <config.h>
     22 #endif
     23 
     24 #include <inttypes.h>
     25 #include <errno.h>
     26 #include <string.h>
     27 #include <stdio.h>
     28 #include <unistd.h>
     29 #include <fcntl.h>
     30 #include <sys/time.h>
     31 #include <sys/ioctl.h>
     32 #ifdef HAVE_SYS_FILIO_H
     33 #include <sys/filio.h>
     34 #endif
     35 #include <assert.h>
     36 
     37 #include <sys/types.h>
     38 #include <sys/socket.h>
     39 #include <netinet/in.h>
     40 #include <arpa/inet.h>
     41 #include <net/if.h>
     42 #include <sys/uio.h>
     43 
     44 #ifdef IP_RECVIF
     45 #include <net/if_dl.h>
     46 #endif
     47 
     48 #include "dns.h"
     49 #include "fdutil.h"
     50 #include "socket.h"
     51 #include "log.h"
     52 #include "addr-util.h"
     53 
     54 /* this is a portability hack */
     55 #ifndef IPV6_ADD_MEMBERSHIP
     56 #ifdef  IPV6_JOIN_GROUP
     57 #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
     58 #endif
     59 #endif
     60 
     61 #ifndef IPV6_DROP_MEMBERSHIP
     62 #ifdef  IPV6_LEAVE_GROUP
     63 #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
     64 #endif
     65 #endif
     66 
     67 static void mdns_mcast_group_ipv4(struct sockaddr_in *ret_sa) {
     68     assert(ret_sa);
     69 
     70     memset(ret_sa, 0, sizeof(struct sockaddr_in));
     71     ret_sa->sin_family = AF_INET;
     72     ret_sa->sin_port = htons(AVAHI_MDNS_PORT);
     73     inet_pton(AF_INET, AVAHI_IPV4_MCAST_GROUP, &ret_sa->sin_addr);
     74 }
     75 
     76 static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
     77     assert(ret_sa);
     78 
     79     memset(ret_sa, 0, sizeof(struct sockaddr_in6));
     80     ret_sa->sin6_family = AF_INET6;
     81     ret_sa->sin6_port = htons(AVAHI_MDNS_PORT);
     82     inet_pton(AF_INET6, AVAHI_IPV6_MCAST_GROUP, &ret_sa->sin6_addr);
     83 }
     84 
     85 static void ipv4_address_to_sockaddr(struct sockaddr_in *ret_sa, const AvahiIPv4Address *a, uint16_t port) {
     86     assert(ret_sa);
     87     assert(a);
     88     assert(port > 0);
     89 
     90     memset(ret_sa, 0, sizeof(struct sockaddr_in));
     91     ret_sa->sin_family = AF_INET;
     92     ret_sa->sin_port = htons(port);
     93     memcpy(&ret_sa->sin_addr, a, sizeof(AvahiIPv4Address));
     94 }
     95 
     96 static void ipv6_address_to_sockaddr(struct sockaddr_in6 *ret_sa, const AvahiIPv6Address *a, uint16_t port) {
     97     assert(ret_sa);
     98     assert(a);
     99     assert(port > 0);
    100 
    101     memset(ret_sa, 0, sizeof(struct sockaddr_in6));
    102     ret_sa->sin6_family = AF_INET6;
    103     ret_sa->sin6_port = htons(port);
    104     memcpy(&ret_sa->sin6_addr, a, sizeof(AvahiIPv6Address));
    105 }
    106 
    107 int avahi_mdns_mcast_join_ipv4(int fd, const AvahiIPv4Address *a, int idx, int join) {
    108 #ifdef HAVE_STRUCT_IP_MREQN
    109     struct ip_mreqn mreq;
    110 #else
    111     struct ip_mreq mreq;
    112 #endif
    113     struct sockaddr_in sa;
    114 
    115     assert(fd >= 0);
    116     assert(idx >= 0);
    117     assert(a);
    118 
    119     memset(&mreq, 0, sizeof(mreq));
    120 #ifdef HAVE_STRUCT_IP_MREQN
    121     mreq.imr_ifindex = idx;
    122     mreq.imr_address.s_addr = a->address;
    123 #else
    124     mreq.imr_interface.s_addr = a->address;
    125 #endif
    126     mdns_mcast_group_ipv4(&sa);
    127     mreq.imr_multiaddr = sa.sin_addr;
    128 
    129     /* Some network drivers have issues with dropping membership of
    130      * mcast groups when the iface is down, but don't allow rejoining
    131      * when it comes back up. This is an ugly workaround */
    132     if (join)
    133         setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
    134 
    135     if (setsockopt(fd, IPPROTO_IP, join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
    136         avahi_log_warn("%s failed: %s", join ? "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP", strerror(errno));
    137         return -1;
    138     }
    139 
    140     return 0;
    141 }
    142 
    143 int avahi_mdns_mcast_join_ipv6(int fd, const AvahiIPv6Address *a, int idx, int join) {
    144     struct ipv6_mreq mreq6;
    145     struct sockaddr_in6 sa6;
    146 
    147     assert(fd >= 0);
    148     assert(idx >= 0);
    149     assert(a);
    150 
    151     memset(&mreq6, 0, sizeof(mreq6));
    152     mdns_mcast_group_ipv6 (&sa6);
    153     mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
    154     mreq6.ipv6mr_interface = idx;
    155 
    156     if (join)
    157         setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6));
    158 
    159     if (setsockopt(fd, IPPROTO_IPV6, join ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
    160         avahi_log_warn("%s failed: %s", join ? "IPV6_ADD_MEMBERSHIP" : "IPV6_DROP_MEMBERSHIP", strerror(errno));
    161         return -1;
    162     }
    163 
    164     return 0;
    165 }
    166 
    167 static int reuseaddr(int fd) {
    168     int yes;
    169 
    170     yes = 1;
    171     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
    172         avahi_log_warn("SO_REUSEADDR failed: %s", strerror(errno));
    173         return -1;
    174     }
    175 
    176 #ifdef SO_REUSEPORT
    177     yes = 1;
    178     if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0) {
    179         avahi_log_warn("SO_REUSEPORT failed: %s", strerror(errno));
    180         return -1;
    181     }
    182 #endif
    183 
    184     return 0;
    185 }
    186 
    187 static int bind_with_warn(int fd, const struct sockaddr *sa, socklen_t l) {
    188 
    189     assert(fd >= 0);
    190     assert(sa);
    191     assert(l > 0);
    192 
    193     if (bind(fd, sa, l) < 0) {
    194 
    195         if (errno != EADDRINUSE) {
    196             avahi_log_warn("bind() failed: %s", strerror(errno));
    197             return -1;
    198         }
    199 
    200         avahi_log_warn("*** WARNING: Detected another %s mDNS stack running on this host. This makes mDNS unreliable and is thus not recommended. ***",
    201                        sa->sa_family == AF_INET ? "IPv4" : "IPv6");
    202 
    203         /* Try again, this time with SO_REUSEADDR set */
    204         if (reuseaddr(fd) < 0)
    205             return -1;
    206 
    207         if (bind(fd, sa, l) < 0) {
    208             avahi_log_warn("bind() failed: %s", strerror(errno));
    209             return -1;
    210         }
    211     } else {
    212 
    213         /* We enable SO_REUSEADDR afterwards, to make sure that the
    214          * user may run other mDNS implementations if he really
    215          * wants. */
    216 
    217         if (reuseaddr(fd) < 0)
    218             return -1;
    219     }
    220 
    221     return 0;
    222 }
    223 
    224 static int ipv4_pktinfo(int fd) {
    225     int yes;
    226 
    227 #ifdef IP_PKTINFO
    228     yes = 1;
    229     if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
    230         avahi_log_warn("IP_PKTINFO failed: %s", strerror(errno));
    231         return -1;
    232     }
    233 #else
    234 
    235 #ifdef IP_RECVINTERFACE
    236     yes = 1;
    237     if (setsockopt (fd, IPPROTO_IP, IP_RECVINTERFACE, &yes, sizeof(yes)) < 0) {
    238         avahi_log_warn("IP_RECVINTERFACE failed: %s", strerror(errno));
    239         return -1;
    240     }
    241 #elif defined(IP_RECVIF)
    242     yes = 1;
    243     if (setsockopt (fd, IPPROTO_IP, IP_RECVIF, &yes, sizeof(yes)) < 0) {
    244         avahi_log_warn("IP_RECVIF failed: %s", strerror(errno));
    245         return -1;
    246     }
    247 #endif
    248 
    249 #ifdef IP_RECVDSTADDR
    250     yes = 1;
    251     if (setsockopt (fd, IPPROTO_IP, IP_RECVDSTADDR, &yes, sizeof(yes)) < 0) {
    252         avahi_log_warn("IP_RECVDSTADDR failed: %s", strerror(errno));
    253         return -1;
    254     }
    255 #endif
    256 
    257 #endif /* IP_PKTINFO */
    258 
    259 #ifdef IP_RECVTTL
    260     yes = 1;
    261     if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
    262         avahi_log_warn("IP_RECVTTL failed: %s", strerror(errno));
    263         return -1;
    264     }
    265 #endif
    266 
    267     return 0;
    268 }
    269 
    270 static int ipv6_pktinfo(int fd) {
    271     int yes;
    272 
    273 #ifdef IPV6_RECVPKTINFO
    274     yes = 1;
    275     if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)) < 0) {
    276         avahi_log_warn("IPV6_RECVPKTINFO failed: %s", strerror(errno));
    277         return -1;
    278     }
    279 #elif defined(IPV6_PKTINFO)
    280     yes = 1;
    281     if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
    282         avahi_log_warn("IPV6_PKTINFO failed: %s", strerror(errno));
    283         return -1;
    284     }
    285 #endif
    286 
    287 #ifdef IPV6_RECVHOPS
    288     yes = 1;
    289     if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPS, &yes, sizeof(yes)) < 0) {
    290         avahi_log_warn("IPV6_RECVHOPS failed: %s", strerror(errno));
    291         return -1;
    292     }
    293 #elif defined(IPV6_RECVHOPLIMIT)
    294     yes = 1;
    295     if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &yes, sizeof(yes)) < 0) {
    296         avahi_log_warn("IPV6_RECVHOPLIMIT failed: %s", strerror(errno));
    297         return -1;
    298     }
    299 #elif defined(IPV6_HOPLIMIT)
    300     yes = 1;
    301     if (setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
    302         avahi_log_warn("IPV6_HOPLIMIT failed: %s", strerror(errno));
    303         return -1;
    304     }
    305 #endif
    306 
    307     return 0;
    308 }
    309 
    310 int avahi_open_socket_ipv4(int no_reuse) {
    311     struct sockaddr_in local;
    312     int fd = -1, r, ittl;
    313     uint8_t ttl, cyes;
    314 
    315     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    316         avahi_log_warn("socket() failed: %s", strerror(errno));
    317         goto fail;
    318     }
    319 
    320     ttl = 255;
    321     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
    322         avahi_log_warn("IP_MULTICAST_TTL failed: %s", strerror(errno));
    323         goto fail;
    324     }
    325 
    326     ittl = 255;
    327     if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)) < 0) {
    328         avahi_log_warn("IP_TTL failed: %s", strerror(errno));
    329         goto fail;
    330     }
    331 
    332     cyes = 1;
    333     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &cyes, sizeof(cyes)) < 0) {
    334         avahi_log_warn("IP_MULTICAST_LOOP failed: %s", strerror(errno));
    335         goto fail;
    336     }
    337 
    338     memset(&local, 0, sizeof(local));
    339     local.sin_family = AF_INET;
    340     local.sin_port = htons(AVAHI_MDNS_PORT);
    341 
    342     if (no_reuse)
    343         r = bind(fd, (struct sockaddr*) &local, sizeof(local));
    344     else
    345         r = bind_with_warn(fd, (struct sockaddr*) &local, sizeof(local));
    346 
    347     if (r < 0)
    348         goto fail;
    349 
    350     if (ipv4_pktinfo (fd) < 0)
    351          goto fail;
    352 
    353     if (avahi_set_cloexec(fd) < 0) {
    354         avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
    355         goto fail;
    356     }
    357 
    358     if (avahi_set_nonblock(fd) < 0) {
    359         avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
    360         goto fail;
    361     }
    362 
    363     return fd;
    364 
    365 fail:
    366     if (fd >= 0)
    367         close(fd);
    368 
    369     return -1;
    370 }
    371 
    372 int avahi_open_socket_ipv6(int no_reuse) {
    373     struct sockaddr_in6 sa, local;
    374     int fd = -1, yes, r;
    375     int ttl;
    376 
    377     mdns_mcast_group_ipv6(&sa);
    378 
    379     if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    380         avahi_log_warn("socket() failed: %s", strerror(errno));
    381         goto fail;
    382     }
    383 
    384     ttl = 255;
    385     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
    386         avahi_log_warn("IPV6_MULTICAST_HOPS failed: %s", strerror(errno));
    387         goto fail;
    388     }
    389 
    390     ttl = 255;
    391     if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
    392         avahi_log_warn("IPV6_UNICAST_HOPS failed: %s", strerror(errno));
    393         goto fail;
    394     }
    395 
    396     yes = 1;
    397     if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
    398         avahi_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
    399         goto fail;
    400     }
    401 
    402     yes = 1;
    403     if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
    404         avahi_log_warn("IPV6_MULTICAST_LOOP failed: %s", strerror(errno));
    405         goto fail;
    406     }
    407 
    408     memset(&local, 0, sizeof(local));
    409     local.sin6_family = AF_INET6;
    410     local.sin6_port = htons(AVAHI_MDNS_PORT);
    411 
    412     if (no_reuse)
    413         r = bind(fd, (struct sockaddr*) &local, sizeof(local));
    414     else
    415         r = bind_with_warn(fd, (struct sockaddr*) &local, sizeof(local));
    416 
    417     if (r < 0)
    418         goto fail;
    419 
    420     if (ipv6_pktinfo(fd) < 0)
    421         goto fail;
    422 
    423     if (avahi_set_cloexec(fd) < 0) {
    424         avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
    425         goto fail;
    426     }
    427 
    428     if (avahi_set_nonblock(fd) < 0) {
    429         avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
    430         goto fail;
    431     }
    432 
    433     return fd;
    434 
    435 fail:
    436     if (fd >= 0)
    437         close(fd);
    438 
    439     return -1;
    440 }
    441 
    442 static int sendmsg_loop(int fd, struct msghdr *msg, int flags) {
    443     assert(fd >= 0);
    444     assert(msg);
    445 
    446     for (;;) {
    447 
    448         if (sendmsg(fd, msg, flags) >= 0)
    449             break;
    450 
    451         if (errno == EINTR)
    452             continue;
    453 
    454         if (errno != EAGAIN) {
    455             char where[64];
    456             struct sockaddr_in *sin = msg->msg_name;
    457 
    458             inet_ntop(sin->sin_family, &sin->sin_addr, where, sizeof(where));
    459             avahi_log_debug("sendmsg() to %s failed: %s", where, strerror(errno));
    460             return -1;
    461         }
    462 
    463         if (avahi_wait_for_write(fd) < 0)
    464             return -1;
    465     }
    466 
    467     return 0;
    468 }
    469 
    470 int avahi_send_dns_packet_ipv4(
    471         int fd,
    472         AvahiIfIndex interface,
    473         AvahiDnsPacket *p,
    474         const AvahiIPv4Address *src_address,
    475         const AvahiIPv4Address *dst_address,
    476         uint16_t dst_port) {
    477 
    478     struct sockaddr_in sa;
    479     struct msghdr msg;
    480     struct iovec io;
    481 #ifdef IP_PKTINFO
    482     struct cmsghdr *cmsg;
    483     size_t cmsg_data[( CMSG_SPACE(sizeof(struct in_pktinfo)) / sizeof(size_t)) + 1];
    484 #elif !defined(IP_MULTICAST_IF) && defined(IP_SENDSRCADDR)
    485     struct cmsghdr *cmsg;
    486     size_t cmsg_data[( CMSG_SPACE(sizeof(struct in_addr)) / sizeof(size_t)) + 1];
    487 #endif
    488 
    489     assert(fd >= 0);
    490     assert(p);
    491     assert(avahi_dns_packet_check_valid(p) >= 0);
    492     assert(!dst_address || dst_port > 0);
    493 
    494     if (!dst_address)
    495         mdns_mcast_group_ipv4(&sa);
    496     else
    497         ipv4_address_to_sockaddr(&sa, dst_address, dst_port);
    498 
    499     memset(&io, 0, sizeof(io));
    500     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
    501     io.iov_len = p->size;
    502 
    503     memset(&msg, 0, sizeof(msg));
    504     msg.msg_name = &sa;
    505     msg.msg_namelen = sizeof(sa);
    506     msg.msg_iov = &io;
    507     msg.msg_iovlen = 1;
    508     msg.msg_flags = 0;
    509     msg.msg_control = NULL;
    510     msg.msg_controllen = 0;
    511 
    512 #ifdef IP_PKTINFO
    513     if (interface > 0 || src_address) {
    514         struct in_pktinfo *pkti;
    515 
    516         memset(cmsg_data, 0, sizeof(cmsg_data));
    517         msg.msg_control = cmsg_data;
    518         msg.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo));
    519 
    520         cmsg = CMSG_FIRSTHDR(&msg);
    521         cmsg->cmsg_len = msg.msg_controllen;
    522         cmsg->cmsg_level = IPPROTO_IP;
    523         cmsg->cmsg_type = IP_PKTINFO;
    524 
    525         pkti = (struct in_pktinfo*) CMSG_DATA(cmsg);
    526 
    527         if (interface > 0)
    528             pkti->ipi_ifindex = interface;
    529 
    530         if (src_address)
    531             pkti->ipi_spec_dst.s_addr = src_address->address;
    532     }
    533 #elif defined(IP_MULTICAST_IF)
    534     if (src_address) {
    535         struct in_addr any = { INADDR_ANY };
    536         if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, src_address ? &src_address->address : &any, sizeof(struct in_addr)) < 0) {
    537             avahi_log_warn("IP_MULTICAST_IF failed: %s", strerror(errno));
    538             return -1;
    539         }
    540     }
    541 #elif defined(IP_SENDSRCADDR)
    542     if (src_address) {
    543         struct in_addr *addr;
    544 
    545         memset(cmsg_data, 0, sizeof(cmsg_data));
    546         msg.msg_control = cmsg_data;
    547         msg.msg_controllen = CMSG_LEN(sizeof(struct in_addr));
    548 
    549         cmsg = CMSG_FIRSTHDR(&msg);
    550         cmsg->cmsg_len = msg.msg_controllen;
    551         cmsg->cmsg_level = IPPROTO_IP;
    552         cmsg->cmsg_type = IP_SENDSRCADDR;
    553 
    554         addr = (struct in_addr *)CMSG_DATA(cmsg);
    555         addr->s_addr =  src_address->address;
    556     }
    557 #elif defined(__GNUC__)
    558 #warning "FIXME: We need some code to set the outgoing interface/local address here if IP_PKTINFO/IP_MULTICAST_IF is not available"
    559 #endif
    560 
    561     return sendmsg_loop(fd, &msg, 0);
    562 }
    563 
    564 int avahi_send_dns_packet_ipv6(
    565         int fd,
    566         AvahiIfIndex interface,
    567         AvahiDnsPacket *p,
    568         const AvahiIPv6Address *src_address,
    569         const AvahiIPv6Address *dst_address,
    570         uint16_t dst_port) {
    571 
    572     struct sockaddr_in6 sa;
    573     struct msghdr msg;
    574     struct iovec io;
    575     struct cmsghdr *cmsg;
    576     size_t cmsg_data[(CMSG_SPACE(sizeof(struct in6_pktinfo))/sizeof(size_t)) + 1];
    577 
    578     assert(fd >= 0);
    579     assert(p);
    580     assert(avahi_dns_packet_check_valid(p) >= 0);
    581     assert(!dst_address || dst_port > 0);
    582 
    583     if (!dst_address)
    584         mdns_mcast_group_ipv6(&sa);
    585     else
    586         ipv6_address_to_sockaddr(&sa, dst_address, dst_port);
    587 
    588     memset(&io, 0, sizeof(io));
    589     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
    590     io.iov_len = p->size;
    591 
    592     memset(&msg, 0, sizeof(msg));
    593     msg.msg_name = &sa;
    594     msg.msg_namelen = sizeof(sa);
    595     msg.msg_iov = &io;
    596     msg.msg_iovlen = 1;
    597     msg.msg_flags = 0;
    598 
    599     if (interface > 0 || src_address) {
    600         struct in6_pktinfo *pkti;
    601 
    602         memset(cmsg_data, 0, sizeof(cmsg_data));
    603         msg.msg_control = cmsg_data;
    604         msg.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo));
    605 
    606         cmsg = CMSG_FIRSTHDR(&msg);
    607         cmsg->cmsg_len = msg.msg_controllen;
    608         cmsg->cmsg_level = IPPROTO_IPV6;
    609         cmsg->cmsg_type = IPV6_PKTINFO;
    610 
    611         pkti = (struct in6_pktinfo*) CMSG_DATA(cmsg);
    612 
    613         if (interface > 0)
    614             pkti->ipi6_ifindex = interface;
    615 
    616         if (src_address)
    617             memcpy(&pkti->ipi6_addr, src_address->address, sizeof(src_address->address));
    618     } else {
    619         msg.msg_control = NULL;
    620         msg.msg_controllen = 0;
    621     }
    622 
    623     return sendmsg_loop(fd, &msg, 0);
    624 }
    625 
    626 AvahiDnsPacket *avahi_recv_dns_packet_ipv4(
    627         int fd,
    628         AvahiIPv4Address *ret_src_address,
    629         uint16_t *ret_src_port,
    630         AvahiIPv4Address *ret_dst_address,
    631         AvahiIfIndex *ret_iface,
    632         uint8_t *ret_ttl) {
    633 
    634     AvahiDnsPacket *p= NULL;
    635     struct msghdr msg;
    636     struct iovec io;
    637     size_t aux[1024 / sizeof(size_t)]; /* for alignment on ia64 ! */
    638     ssize_t l;
    639     struct cmsghdr *cmsg;
    640     int found_addr = 0;
    641     int ms;
    642     struct sockaddr_in sa;
    643 
    644     assert(fd >= 0);
    645 
    646     if (ioctl(fd, FIONREAD, &ms) < 0) {
    647         avahi_log_warn("ioctl(): %s", strerror(errno));
    648         goto fail;
    649     }
    650 
    651     if (ms < 0) {
    652         avahi_log_warn("FIONREAD returned negative value.");
    653         goto fail;
    654     }
    655 
    656     p = avahi_dns_packet_new(ms + AVAHI_DNS_PACKET_EXTRA_SIZE);
    657 
    658     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
    659     io.iov_len = p->max_size;
    660 
    661     memset(&msg, 0, sizeof(msg));
    662     msg.msg_name = &sa;
    663     msg.msg_namelen = sizeof(sa);
    664     msg.msg_iov = &io;
    665     msg.msg_iovlen = 1;
    666     msg.msg_control = aux;
    667     msg.msg_controllen = sizeof(aux);
    668     msg.msg_flags = 0;
    669 
    670     if ((l = recvmsg(fd, &msg, 0)) < 0) {
    671         /* Linux returns EAGAIN when an invalid IP packet has been
    672         received. We suppress warnings in this case because this might
    673         create quite a bit of log traffic on machines with unstable
    674         links. (See #60) */
    675 
    676         if (errno != EAGAIN)
    677             avahi_log_warn("recvmsg(): %s", strerror(errno));
    678 
    679         goto fail;
    680     }
    681 
    682     /* For corrupt packets FIONREAD returns zero size (See rhbz #607297). So
    683      * fail after having read them. */
    684     if (!ms)
    685         goto fail;
    686 
    687     if (sa.sin_addr.s_addr == INADDR_ANY)
    688         /* Linux 2.4 behaves very strangely sometimes! */
    689         goto fail;
    690 
    691     assert(!(msg.msg_flags & MSG_CTRUNC));
    692     assert(!(msg.msg_flags & MSG_TRUNC));
    693 
    694     p->size = (size_t) l;
    695 
    696     if (ret_src_port)
    697         *ret_src_port = avahi_port_from_sockaddr((struct sockaddr*) &sa);
    698 
    699     if (ret_src_address) {
    700         AvahiAddress a;
    701         avahi_address_from_sockaddr((struct sockaddr*) &sa, &a);
    702         *ret_src_address = a.data.ipv4;
    703     }
    704 
    705     if (ret_ttl)
    706         *ret_ttl = 255;
    707 
    708     if (ret_iface)
    709         *ret_iface = AVAHI_IF_UNSPEC;
    710 
    711     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
    712 
    713         if (cmsg->cmsg_level == IPPROTO_IP) {
    714 
    715             switch (cmsg->cmsg_type) {
    716 #ifdef IP_RECVTTL
    717                 case IP_RECVTTL:
    718 #endif
    719                 case IP_TTL:
    720                     if (ret_ttl)
    721                         *ret_ttl = (uint8_t) (*(int *) CMSG_DATA(cmsg));
    722 
    723                     break;
    724 
    725 #ifdef IP_PKTINFO
    726                 case IP_PKTINFO: {
    727                     struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg);
    728 
    729                     if (ret_iface && i->ipi_ifindex > 0)
    730                         *ret_iface = (int) i->ipi_ifindex;
    731 
    732                     if (ret_dst_address)
    733                         ret_dst_address->address = i->ipi_addr.s_addr;
    734 
    735                     found_addr = 1;
    736 
    737                     break;
    738                 }
    739 #endif
    740 
    741 #ifdef IP_RECVIF
    742                 case IP_RECVIF: {
    743                     struct sockaddr_dl *sdl = (struct sockaddr_dl *) CMSG_DATA (cmsg);
    744 
    745                     if (ret_iface) {
    746 #ifdef __sun
    747                         if (*(uint_t*) sdl > 0)
    748                             *ret_iface = *(uint_t*) sdl;
    749 #else
    750 
    751                         if (sdl->sdl_index > 0)
    752                             *ret_iface = (int) sdl->sdl_index;
    753 #endif
    754                     }
    755 
    756                     break;
    757                 }
    758 #endif
    759 
    760 #ifdef IP_RECVDSTADDR
    761                 case IP_RECVDSTADDR:
    762                     if (ret_dst_address)
    763                         memcpy(&ret_dst_address->address, CMSG_DATA (cmsg), 4);
    764 
    765                     found_addr = 1;
    766                     break;
    767 #endif
    768 
    769                 default:
    770                     avahi_log_warn("Unhandled cmsg_type: %d", cmsg->cmsg_type);
    771                     break;
    772             }
    773         }
    774     }
    775 
    776     assert(found_addr);
    777 
    778     return p;
    779 
    780 fail:
    781     if (p)
    782         avahi_dns_packet_free(p);
    783 
    784     return NULL;
    785 }
    786 
    787 AvahiDnsPacket *avahi_recv_dns_packet_ipv6(
    788         int fd,
    789         AvahiIPv6Address *ret_src_address,
    790         uint16_t *ret_src_port,
    791         AvahiIPv6Address *ret_dst_address,
    792         AvahiIfIndex *ret_iface,
    793         uint8_t *ret_ttl) {
    794 
    795     AvahiDnsPacket *p = NULL;
    796     struct msghdr msg;
    797     struct iovec io;
    798     size_t aux[1024 / sizeof(size_t)];
    799     ssize_t l;
    800     int ms;
    801     struct cmsghdr *cmsg;
    802     int found_ttl = 0, found_iface = 0;
    803     struct sockaddr_in6 sa;
    804 
    805     assert(fd >= 0);
    806 
    807     if (ioctl(fd, FIONREAD, &ms) < 0) {
    808         avahi_log_warn("ioctl(): %s", strerror(errno));
    809         goto fail;
    810     }
    811 
    812     if (ms < 0) {
    813         avahi_log_warn("FIONREAD returned negative value.");
    814         goto fail;
    815     }
    816 
    817     p = avahi_dns_packet_new(ms + AVAHI_DNS_PACKET_EXTRA_SIZE);
    818 
    819     io.iov_base = AVAHI_DNS_PACKET_DATA(p);
    820     io.iov_len = p->max_size;
    821 
    822     memset(&msg, 0, sizeof(msg));
    823     msg.msg_name = (struct sockaddr*) &sa;
    824     msg.msg_namelen = sizeof(sa);
    825 
    826     msg.msg_iov = &io;
    827     msg.msg_iovlen = 1;
    828     msg.msg_control = aux;
    829     msg.msg_controllen = sizeof(aux);
    830     msg.msg_flags = 0;
    831 
    832     if ((l = recvmsg(fd, &msg, 0)) < 0) {
    833         /* Linux returns EAGAIN when an invalid IP packet has been
    834         received. We suppress warnings in this case because this might
    835         create quite a bit of log traffic on machines with unstable
    836         links. (See #60) */
    837 
    838         if (errno != EAGAIN)
    839             avahi_log_warn("recvmsg(): %s", strerror(errno));
    840 
    841         goto fail;
    842     }
    843 
    844     /* For corrupt packets FIONREAD returns zero size (See rhbz #607297). So
    845      * fail after having read them. */
    846     if (!ms)
    847         goto fail;
    848 
    849     assert(!(msg.msg_flags & MSG_CTRUNC));
    850     assert(!(msg.msg_flags & MSG_TRUNC));
    851 
    852     p->size = (size_t) l;
    853 
    854     if (ret_src_port)
    855         *ret_src_port = avahi_port_from_sockaddr((struct sockaddr*) &sa);
    856 
    857     if (ret_src_address) {
    858         AvahiAddress a;
    859         avahi_address_from_sockaddr((struct sockaddr*) &sa, &a);
    860         *ret_src_address = a.data.ipv6;
    861     }
    862 
    863     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
    864 
    865         if (cmsg->cmsg_level == IPPROTO_IPV6) {
    866 
    867             switch (cmsg->cmsg_type) {
    868 
    869                 case IPV6_HOPLIMIT:
    870 
    871                     if (ret_ttl)
    872                         *ret_ttl = (uint8_t) (*(int *) CMSG_DATA(cmsg));
    873 
    874                     found_ttl = 1;
    875 
    876                     break;
    877 
    878                 case IPV6_PKTINFO: {
    879                     struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg);
    880 
    881                     if (ret_iface && i->ipi6_ifindex > 0)
    882                         *ret_iface = i->ipi6_ifindex;
    883 
    884                     if (ret_dst_address)
    885                         memcpy(ret_dst_address->address, i->ipi6_addr.s6_addr, 16);
    886 
    887                     found_iface = 1;
    888                     break;
    889                 }
    890 
    891                 default:
    892                     avahi_log_warn("Unhandled cmsg_type: %d", cmsg->cmsg_type);
    893                     break;
    894             }
    895         }
    896     }
    897 
    898     assert(found_iface);
    899     assert(found_ttl);
    900 
    901     return p;
    902 
    903 fail:
    904     if (p)
    905         avahi_dns_packet_free(p);
    906 
    907     return NULL;
    908 }
    909 
    910 int avahi_open_unicast_socket_ipv4(void) {
    911     struct sockaddr_in local;
    912     int fd = -1;
    913 
    914     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    915         avahi_log_warn("socket() failed: %s", strerror(errno));
    916         goto fail;
    917     }
    918 
    919     memset(&local, 0, sizeof(local));
    920     local.sin_family = AF_INET;
    921 
    922     if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
    923         avahi_log_warn("bind() failed: %s", strerror(errno));
    924         goto fail;
    925     }
    926 
    927     if (ipv4_pktinfo(fd) < 0) {
    928          goto fail;
    929     }
    930 
    931     if (avahi_set_cloexec(fd) < 0) {
    932         avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
    933         goto fail;
    934     }
    935 
    936     if (avahi_set_nonblock(fd) < 0) {
    937         avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
    938         goto fail;
    939     }
    940 
    941     return fd;
    942 
    943 fail:
    944     if (fd >= 0)
    945         close(fd);
    946 
    947     return -1;
    948 }
    949 
    950 int avahi_open_unicast_socket_ipv6(void) {
    951     struct sockaddr_in6 local;
    952     int fd = -1, yes;
    953 
    954     if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    955         avahi_log_warn("socket() failed: %s", strerror(errno));
    956         goto fail;
    957     }
    958 
    959     yes = 1;
    960     if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
    961         avahi_log_warn("IPV6_V6ONLY failed: %s", strerror(errno));
    962         goto fail;
    963     }
    964 
    965     memset(&local, 0, sizeof(local));
    966     local.sin6_family = AF_INET6;
    967 
    968     if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
    969         avahi_log_warn("bind() failed: %s", strerror(errno));
    970         goto fail;
    971     }
    972 
    973     if (ipv6_pktinfo(fd) < 0)
    974         goto fail;
    975 
    976     if (avahi_set_cloexec(fd) < 0) {
    977         avahi_log_warn("FD_CLOEXEC failed: %s", strerror(errno));
    978         goto fail;
    979     }
    980 
    981     if (avahi_set_nonblock(fd) < 0) {
    982         avahi_log_warn("O_NONBLOCK failed: %s", strerror(errno));
    983         goto fail;
    984     }
    985 
    986     return fd;
    987 
    988 fail:
    989     if (fd >= 0)
    990         close(fd);
    991 
    992     return -1;
    993 }
    994