diff --git a/libmdnsd/mdnsd.c b/libmdnsd/mdnsd.c index c2ca7a9..c008276 100644 --- a/libmdnsd/mdnsd.c +++ b/libmdnsd/mdnsd.c @@ -52,6 +52,17 @@ * cached */ +/* Sockaddr structure with sin_addr and sin6_addr union, to save the + extra storage requirements of a sockaddr_storage in smaller systems. */ +struct sockaddr46 { + sa_family_t family; + in_port_t port; + union { + struct in_addr sin_addr; + struct in6_addr sin6_addr; + }; +}; + struct query { char *name; int type; @@ -64,8 +75,7 @@ struct query { struct unicast { int id; - struct in_addr to; - unsigned short port; + struct sockaddr46 to; mdns_record_t *r; struct unicast *next; }; @@ -320,7 +330,7 @@ static void _r_send(mdns_daemon_t *d, mdns_record_t *r) } /* Create generic unicast response struct */ -static void _u_push(mdns_daemon_t *d, mdns_record_t *r, int id, struct in_addr to, unsigned short port) +static void _u_push(mdns_daemon_t *d, mdns_record_t *r, int id, const struct sockaddr46 *to) { struct unicast *u; @@ -330,8 +340,7 @@ static void _u_push(mdns_daemon_t *d, mdns_record_t *r, int id, struct in_addr t u->r = r; u->id = id; - u->to = to; - u->port = port; + u->to = *to; u->next = d->uanswers; d->uanswers = u; } @@ -501,7 +510,7 @@ static void _gc(mdns_daemon_t *d) d->expireall = (unsigned long)(d->now.tv_sec + GC); } -static int _cache(mdns_daemon_t *d, struct resource *r, struct in_addr ip) +static int _cache(mdns_daemon_t *d, struct resource *r, const struct sockaddr46 *ips) { unsigned long int ttl; struct cached *c = 0; @@ -587,7 +596,11 @@ static int _cache(mdns_daemon_t *d, struct resource *r, struct in_addr ip) case QTYPE_CNAME: case QTYPE_PTR: c->rr.rdname = strdup(r->known.ns.name); - c->rr.ip = ip; + if (ips->family == AF_INET) { + c->rr.ip = ips->sin_addr; + } else { + c->rr.ip6 = ips->sin6_addr; + } break; case QTYPE_SRV: @@ -855,9 +868,10 @@ void mdnsd_register_receive_callback(mdns_daemon_t *d, mdnsd_record_received_cal d->received_callback_data = data; } -int mdnsd_in(mdns_daemon_t *d, struct message *m, struct in_addr ip, unsigned short port) +int mdnsd_in(mdns_daemon_t *d, struct message *m, const struct sockaddr_storage *ss_from) { mdns_record_t *r = NULL; + struct sockaddr46 from = { 0 }; int i, j; if (d->shutdown) @@ -865,6 +879,19 @@ int mdnsd_in(mdns_daemon_t *d, struct message *m, struct in_addr ip, unsigned sh gettimeofday(&d->now, 0); + if (ss_from->ss_family == AF_INET) { + from.family = AF_INET; + from.port = ((struct sockaddr_in*)ss_from)->sin_port; + from.sin_addr = ((struct sockaddr_in*)ss_from)->sin_addr; + } else if (ss_from->ss_family == AF_INET6) { + from.family = AF_INET6; + from.port = ((struct sockaddr_in6*)ss_from)->sin6_port; + from.sin6_addr = ((struct sockaddr_in6*)ss_from)->sin6_addr; + } else { + WARN("Unsupported protocol family in incoming packet: %d", ss_from->ss_family); + return -1; + } + if (m->header.qr == 0) { /* Process each query */ for (i = 0; i < m->qdcount; i++) { @@ -936,8 +963,8 @@ int mdnsd_in(mdns_daemon_t *d, struct message *m, struct in_addr ip, unsigned sh } /* Send the matching unicast reply */ - if (!has_conflict && port != 5353) - _u_push(d, r_start, m->id, ip, port); + if (!has_conflict && ntohs(from.port) != 5353) + _u_push(d, r_start, m->id, &from); } return 0; @@ -958,7 +985,8 @@ int mdnsd_in(mdns_daemon_t *d, struct message *m, struct in_addr ip, unsigned sh r = _r_next(d, NULL, m->an[i].name, m->an[i].type); if (r && r->unique && r->modified && _a_match(&m->an[i], &r->rr)) { /* double check, is this actually from us, looped back? */ - if (ip.s_addr == d->addr.s_addr) + if ((from.family == AF_INET && from.sin_addr.s_addr == d->addr.s_addr) || + (from.family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&(from.sin6_addr), &(d->addr_v6))) ) continue; _conflict(d, r); } @@ -966,7 +994,7 @@ int mdnsd_in(mdns_daemon_t *d, struct message *m, struct in_addr ip, unsigned sh if (d->received_callback) d->received_callback(&m->an[i], d->received_callback_data); - if (_cache(d, &m->an[i], ip) != 0) { + if (_cache(d, &m->an[i], &from) != 0) { ERR("Failed caching answer, possibly too long packet, skipping."); continue; } @@ -975,7 +1003,7 @@ int mdnsd_in(mdns_daemon_t *d, struct message *m, struct in_addr ip, unsigned sh return 0; } -int mdnsd_out(mdns_daemon_t *d, struct message *m, struct in_addr *ip, unsigned short *port) +int mdnsd_out(mdns_daemon_t *d, struct message *m, struct sockaddr_storage *to) { mdns_record_t *r; int ret = 0; @@ -984,28 +1012,56 @@ int mdnsd_out(mdns_daemon_t *d, struct message *m, struct in_addr *ip, unsigned memset(m, 0, sizeof(struct message)); /* Defaults, multicast */ - *port = htons(5353); - ip->s_addr = inet_addr("224.0.0.251"); + if (to->ss_family == AF_INET) { + ((struct sockaddr_in*)to)->sin_port = htons(5353); + inet_pton(AF_INET, "224.0.0.251", &(((struct sockaddr_in*)to)->sin_addr)); + } else if (to->ss_family == AF_INET6) { + ((struct sockaddr_in6*)to)->sin6_port = htons(5353); + inet_pton(AF_INET6, "FF02::FB", &(((struct sockaddr_in6*)to)->sin6_addr)); + } else { + WARN("Unsupported outgoing protocol family requested: %d", to->ss_family); + return -1; + } m->header.qr = 1; m->header.aa = 1; /* Send out individual unicast answers */ if (d->uanswers) { struct unicast *u = d->uanswers; + struct unicast *prev = d->uanswers; - INFO("Send Unicast Answer: Name: %s, Type: %d", u->r->rr.name, u->r->rr.type); + /* Find a unicast answer that matches the currently handled protocol. */ + while (u && u->to.family != to->ss_family) { + prev = u; + u = u->next; + } - d->uanswers = u->next; - *port = htons(u->port); - *ip = u->to; - m->id = u->id; - message_qd(m, u->r->rr.name, u->r->rr.type, d->class); - message_an(m, u->r->rr.name, u->r->rr.type, d->class, u->r->rr.ttl); - u->r->last_sent = d->now; - _a_copy(m, &u->r->rr); - free(u); + if (u != NULL) { + INFO("Send Unicast Answer: Name: %s, Type: %d", u->r->rr.name, u->r->rr.type); - return 1; + if (prev == d->uanswers) { + d->uanswers = u->next; + } else { + prev->next = u->next; + } + u->next = NULL; + + if (to->ss_family == AF_INET) { + ((struct sockaddr_in*)to)->sin_port = u->to.port; + ((struct sockaddr_in*)to)->sin_addr = u->to.sin_addr; + } else { + ((struct sockaddr_in6*)to)->sin6_port = u->to.port; + ((struct sockaddr_in6*)to)->sin6_addr = u->to.sin6_addr; + } + m->id = u->id; + message_qd(m, u->r->rr.name, u->r->rr.type, d->class); + message_an(m, u->r->rr.name, u->r->rr.type, d->class, u->r->rr.ttl); + u->r->last_sent = d->now; + _a_copy(m, &u->r->rr); + free(u); + + return 1; + } } /* Accumulate any immediate responses */ @@ -1131,8 +1187,10 @@ int mdnsd_out(mdns_daemon_t *d, struct message *m, struct in_addr *ip, unsigned /* Ask questions first, track nextbest time */ for (q = d->qlist; q != 0; q = q->list) { - if (q->nexttry > 0 && q->nexttry <= (unsigned long)d->now.tv_sec && q->tries < 3) + if (q->nexttry > 0 && q->nexttry <= (unsigned long)d->now.tv_sec && q->tries < 3) { + INFO("Send query for: Name: %s, Type: %d", q->name, q->type); message_qd(m, q->name, q->type, d->class); + } else if (q->nexttry > 0 && (nextbest == 0 || q->nexttry < nextbest)) nextbest = q->nexttry; } @@ -1460,8 +1518,8 @@ void mdnsd_set_srv(mdns_daemon_t *d, mdns_record_t *r, unsigned short priority, static int process_in(mdns_daemon_t *d, int sd) { static unsigned char buf[MAX_PACKET_LEN + 1]; - struct sockaddr_in from; - socklen_t ssize = sizeof(struct sockaddr_in); + struct sockaddr_storage from; + socklen_t ssize = sizeof(struct sockaddr_storage); ssize_t bsize; memset(buf, 0, sizeof(buf)); @@ -1476,9 +1534,7 @@ static int process_in(mdns_daemon_t *d, int sd) rc = message_parse(&m, buf); if (rc) continue; - rc = mdnsd_in(d, &m, from.sin_addr, ntohs(from.sin_port)); - if (rc) - continue; + mdnsd_in(d, &m, &from); } if (bsize < 0 && errno != EAGAIN) @@ -1489,25 +1545,25 @@ static int process_in(mdns_daemon_t *d, int sd) static int process_out(mdns_daemon_t *d, int sd) { - unsigned short int port; - struct sockaddr_in to; - struct in_addr ip; + struct sockaddr_storage to = { 0 }; + socklen_t ssize = sizeof(struct sockaddr_storage); struct message m; - while (mdnsd_out(d, &m, &ip, &port)) { + if (getsockname(sd, (struct sockaddr*)&to, &ssize) != 0) { + WARN("Unable to determine address family of socket %d: %s", sd, strerror(errno)); + return 1; + } + + DBG("Processing %s (%d) socket %d, ssize %d", to.ss_family == AF_INET ? "IPv4" : "IPv6", to.ss_family, sd, ssize); + while (mdnsd_out(d, &m, &to) > 0) { unsigned char *buf; ssize_t len; - memset(&to, 0, sizeof(to)); - to.sin_family = AF_INET; - to.sin_port = port; - to.sin_addr = ip; - len = message_packet_len(&m); buf = message_packet(&m); mdnsd_log_hex("Send Data:", buf, len); - if (sendto(sd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&to, sizeof(struct sockaddr_in)) != len) + if (sendto(sd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&to, ssize) != len) return 2; } diff --git a/libmdnsd/mdnsd.h b/libmdnsd/mdnsd.h index aa72881..3a4a258 100644 --- a/libmdnsd/mdnsd.h +++ b/libmdnsd/mdnsd.h @@ -153,13 +153,20 @@ void mdnsd_register_receive_callback(mdns_daemon_t *d, mdnsd_record_received_cal /** * Oncoming message from host (to be cached/processed) */ -int mdnsd_in(mdns_daemon_t *d, struct message *m, struct in_addr ip, unsigned short port); +int mdnsd_in(mdns_daemon_t *d, struct message *m, const struct sockaddr_storage *from); /** - * Outgoing messge to be delivered to host, returns >0 if one was - * returned and m/ip/port set - */ -int mdnsd_out(mdns_daemon_t *d, struct message *m, struct in_addr *ip, unsigned short *port); + * Outgoing message passed to the host for delivery to destination. + * + * @param[out] m Message filled in to be sent by teh host + * @param[in,out] to The sockaddr_storage needs to have the family member set to + * the protocol family over which the message should be sent. + * When processing a IPv4 socket it must be set to AF_INET and + * when processing a IPv6 socket it must be set to AF_INET6. + * The function fills in the destination port and IP address. + * @return >0 if a message was returned and m/ip/port set, <0 in case of error + */ +int mdnsd_out(mdns_daemon_t *d, struct message *m, struct sockaddr_storage *to); /** * returns the max wait-time until mdnsd_out() needs to be called again diff --git a/src/mcsock.c b/src/mcsock.c index fe54ec8..4d91a33 100644 --- a/src/mcsock.c +++ b/src/mcsock.c @@ -34,7 +34,9 @@ #include #include #include +#include +#include "config.h" #include "libmdnsd/mdnsd.h" #include "mcsock.h" @@ -64,31 +66,154 @@ static struct in_addr get_addr(const char *ifname) } -static int mc_socket(struct ifnfo *iface, unsigned char ttl) + +static int mc_socket_mcast_join_ipv4(int sd, struct ifnfo *iface, struct sockaddr_in *sin) { #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX struct ip_mreqn imr ={ 0 }; #else struct ip_mreq imr = { 0 }; - imr.imr_interface.s_addr = htonl(INADDR_ANY); #endif + + if (iface) { + if (iface->ifindex != 0 && iface->inaddr.s_addr == 0) { + iface->inaddr = get_addr(iface->ifname); + } + + /* Set interface for outbound multicast */ +#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX + imr.imr_ifindex = iface->ifindex; + imr.imr_address = iface->inaddr; + if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &imr, sizeof(imr))) + WARN("Failed setting IP_MULTICAST_IF to %d: %s", iface->ifindex, strerror(errno)); +#else + imr.imr_interface = iface->inaddr; + if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &(iface->inaddr), sizeof(struct in_addr))) + WARN("Failed setting IP_MULTICAST_IF to %s: %s", inet_ntoa(iface->inaddr), strerror(errno)); +#endif + } + + + /* Join link-local multicast group on the given interface. */ + imr.imr_multiaddr = sin->sin_addr; + if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr))) + WARN("Failed joining IPv4 multicast group %s: %s", inet_ntoa(imr.imr_multiaddr), strerror(errno)); + else + INFO("Joining mDNS IPv4 multicast group %s%s", iface?" on iface " : "", iface?iface->ifname:""); + + return sd; +} + + +static int mc_socket_mcast_join_ipv6(int sd, struct ifnfo *iface, struct sockaddr_in6 *sin6) +{ + struct ipv6_mreq i6mr = { 0 }; + + + if (iface) { + /* Set interface for outbound multicast */ + if (setsockopt(sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &(iface->ifindex), sizeof(iface->ifindex))) + WARN("Failed setting IPV6_MULTICAST_IF to %d: %s", iface->ifindex, strerror(errno)); + + i6mr.ipv6mr_interface = iface->ifindex; + } + + /* Join link-local multicast group on the given interface. */ + i6mr.ipv6mr_multiaddr = sin6->sin6_addr; + if (setsockopt(sd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &i6mr, sizeof(i6mr))) + WARN("Failed joining IPv6 multicast group: %s", strerror(errno)); + else + INFO("Joining mDNS IPv6 multicast group %s%s", iface?" on iface " : "", iface?iface->ifname:""); + + return sd; +} + + +static int mc_socket_setup_ipv4(int sd, struct ifnfo *iface, struct sockaddr_in *sin) +{ + struct sockaddr_in local_addr = { 0 }; + + if (iface) { + /* Filter inbound traffic from anyone (ANY) to port 5353 on ifname */ + if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &iface->ifname, strlen(iface->ifname))) + INFO("Failed setting SO_BINDTODEVICE on %s: %s", iface->ifname, strerror(errno)); + } + + + local_addr.sin_family = AF_INET; + local_addr.sin_port = sin->sin_port; + if (bind(sd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in))) { + close(sd); + ERR("Failed binding socket to *:%d: %s", ntohs(local_addr.sin_port), strerror(errno)); + return -1; + } + INFO("Bound to *:%d%s%s", ntohs(local_addr.sin_port), iface?" on iface " : "", iface?iface->ifname:""); + + + mc_socket_mcast_join_ipv4(sd, iface, sin); + + return sd; +} + + +static int mc_socket_setup_ipv6(int sd, struct ifnfo *iface, struct sockaddr_in6 *sin6) +{ + const int on = 1; + struct sockaddr_in6 local_addr = { 0 }; + + + if (iface) { + /* Filter inbound traffic from anyone (ANY) to port 5353 on ifname */ + if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &iface->ifname, strlen(iface->ifname))) + INFO("Failed setting SO_BINDTODEVICE on %s: %s", iface->ifname, strerror(errno)); + } + + if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on))) + WARN("Failed setting IPV6_V6ONLY: %s", strerror(errno)); + + + + local_addr.sin6_family = AF_INET6; + local_addr.sin6_port = sin6->sin6_port; + if (bind(sd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in6))) { + close(sd); + ERR("Failed binding socket to :: :%d: %s", ntohs(local_addr.sin6_port), strerror(errno)); + return -1; + } + INFO("Bound to *:%d%s%s", ntohs(local_addr.sin6_port), iface?" on iface " : "", iface?iface->ifname:""); + + + mc_socket_mcast_join_ipv6(sd, iface, sin6); + + return sd; +} + + +static int mc_socket(struct ifnfo *iface, unsigned char ttl, struct sockaddr *saddr) +{ const int on = 1; const int off = 0; - struct sockaddr_in sin; + const bool ipv6 = (saddr->sa_family == AF_INET6); + const int so_level = (saddr->sa_family == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP; + + int so_optname; socklen_t len; int unicast_ttl = 255; + int multicast_ttl = ttl; int bufsiz; int sd; - sd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); + + sd = socket(saddr->sa_family, SOCK_DGRAM | SOCK_NONBLOCK, 0); if (sd < 0) { ERR("Failed creating UDP socket: %s", strerror(errno)); return -1; } + /* Set IP independent socket options */ #ifdef SO_REUSEPORT if (setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on))) WARN("Failed setting SO_REUSEPORT: %s", strerror(errno)); @@ -103,74 +228,66 @@ static int mc_socket(struct ifnfo *iface, unsigned char ttl) INFO("Failed doubling the size of the receive buffer: %s", strerror(errno)); } - if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, &on, sizeof(on))) - WARN("Failed enabling IP_MULTICAST_LOOP on %s: %s", iface->ifname, strerror(errno)); - if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_ALL, &off, sizeof(off))) - WARN("Failed disabling IP_MULTICAST_ALL on %s: %s", iface->ifname, strerror(errno)); + + /* Set socket options on IP level */ + so_optname = (ipv6) ? IPV6_MULTICAST_LOOP : IP_MULTICAST_LOOP; + if (setsockopt(sd, so_level, so_optname, &on, sizeof(on))) + WARN("Failed enabling IP%s_MULTICAST_LOOP on %s: %s", (ipv6)?"V6":"", iface->ifname, strerror(errno)); + + if (! ipv6) { + if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_ALL, &off, sizeof(off))) + WARN("Failed disabling IP_MULTICAST_ALL on %s: %s", iface->ifname, strerror(errno)); + } /* * All traffic on mDNS is link-local only, so the default * TTL is set to 1. Some users may however want to route mDNS. */ - if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))) - WARN("Failed setting IP_MULTICAST_TTL to %d: %s", ttl, strerror(errno)); + so_optname = (ipv6) ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL; + if (setsockopt(sd, so_level, so_optname, &multicast_ttl, sizeof(multicast_ttl))) + WARN("Failed setting %s to %d: %s", (ipv6)?"IPV6_MULTICAST_HOPS":"IP_MULTICAST_TTL", multicast_ttl, strerror(errno)); /* mDNS also supports unicast, so we need a relevant TTL there too */ - if (setsockopt(sd, IPPROTO_IP, IP_TTL, &unicast_ttl, sizeof(unicast_ttl))) - WARN("Failed setting IP_TTL to %d: %s", unicast_ttl, strerror(errno)); + so_optname = (ipv6) ? IPV6_UNICAST_HOPS : IP_TTL; + if (setsockopt(sd, so_level, so_optname, &unicast_ttl, sizeof(unicast_ttl))) + WARN("Failed setting %s to %d: %s", (ipv6)?"IPV6_UNICAST_HOPS":"IP_TTL", unicast_ttl, strerror(errno)); - if (iface) { - if (iface->ifindex != 0 && iface->inaddr.s_addr == 0) { - iface->inaddr = get_addr(iface->ifname); - } - /* Set interface for outbound multicast */ -#ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX - imr.imr_ifindex = iface->ifindex; - if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &imr, sizeof(imr))) - WARN("Failed setting IP_MULTICAST_IF to %d: %s", iface->ifindex, strerror(errno)); -#else - imr.imr_interface = iface->inaddr; - if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &(iface->inaddr), sizeof(struct in_addr))) - WARN("Failed setting IP_MULTICAST_IF to %s: %s", inet_ntoa(iface->inaddr), strerror(errno)); -#endif - /* Filter inbound traffic from anyone (ANY) to port 5353 on ifname */ - if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &iface->ifname, strlen(iface->ifname))) - INFO("Failed setting SO_BINDTODEVICE on %s: %s", iface->ifname, strerror(errno)); - } + if (saddr->sa_family == AF_INET6) + return mc_socket_setup_ipv6(sd, iface, (struct sockaddr_in6*)saddr); + + return mc_socket_setup_ipv4(sd, iface, (struct sockaddr_in*)saddr); +} + - /* - * Join mDNS link-local group on the given interface, that way - * we can receive multicast without a proper net route (default - * route or a 224.0.0.0/24 net route). - */ - imr.imr_multiaddr.s_addr = inet_addr("224.0.0.251"); - if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr))) - WARN("Failed joining mDNS group 224.0.0.251: %s", strerror(errno)); +int mdns_ipv4_socket(struct ifnfo *iface, unsigned char ttl) +{ + /* Default to TTL of 1 for mDNS as it is link-local */ + if (ttl == 0) + ttl = 1; - memset(&sin, 0, sizeof(sin)); + struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(5353); - if (bind(sd, (struct sockaddr *)&sin, sizeof(sin))) { - close(sd); - ERR("Failed binding socket to *:5353: %s", strerror(errno)); - return -1; - } - INFO("Bound to *:5353 on iface %s", iface->ifname); + inet_pton(AF_INET, "224.0.0.251", &(sin.sin_addr)); - - return sd; + return mc_socket(iface, ttl, (struct sockaddr*)&sin); } -int mdns_socket(struct ifnfo *iface, unsigned char ttl) +int mdns_ipv6_socket(struct ifnfo *iface, unsigned char ttl) { /* Default to TTL of 1 for mDNS as it is link-local */ if (ttl == 0) ttl = 1; - return mc_socket(iface, ttl); + struct sockaddr_in6 sin6 = { 0 }; + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(5353); + inet_pton(AF_INET6, "ff02::fb", &(sin6.sin6_addr)); + + return mc_socket(iface, ttl, (struct sockaddr*)&sin6); } diff --git a/src/mcsock.h b/src/mcsock.h index e857c8c..53ae0e6 100644 --- a/src/mcsock.h +++ b/src/mcsock.h @@ -41,12 +41,22 @@ struct ifnfo { }; /** - * Create multicast socket for mDNS. + * Create IPv4 multicast socket for mDNS. * * @param iface Specify if socket should be bound to specific interface * @param ttl Multicast TTL, 0 for default (1) * @return socket file descriptor or <0 in case or error */ -int mdns_socket(struct ifnfo *iface, unsigned char ttl); +int mdns_ipv4_socket(struct ifnfo *iface, unsigned char ttl); + + +/** + * Create IPv6 multicast socket for mDNS. + * + * @param iface Specify if socket should be bound to specific interface + * @param ttl Multicast TTL, 0 for default (1) + * @return socket file descriptor or <0 in case or error + */ +int mdns_ipv6_socket(struct ifnfo *iface, unsigned char ttl); #endif /* MDNSD_MCSOCK_H_ */ diff --git a/src/mdnsd.c b/src/mdnsd.c index ad2fd64..4f2c33e 100644 --- a/src/mdnsd.c +++ b/src/mdnsd.c @@ -68,7 +68,7 @@ static int multicast_socket(struct iface *iface, unsigned char ttl) memcpy(ifa.ifname, iface->ifname, sizeof(ifa.ifname)); ifa.ifindex = iface->ifindex; ifa.inaddr = iface->inaddr; - return mdns_socket(&ifa, ttl); + return mdns_ipv4_socket(&ifa, ttl); } void mdnsd_conflict(char *name, int type, void *arg) diff --git a/src/mquery.c b/src/mquery.c index 686294a..37ddefc 100644 --- a/src/mquery.c +++ b/src/mquery.c @@ -188,10 +188,10 @@ static int msock(char *ifname) if (ifname) { memcpy(ifa.ifname, ifname, sizeof(ifa.ifname)); ifa.ifindex = if_nametoindex(ifname); - return mdns_socket(&ifa, 0); + return mdns_ipv4_socket(&ifa, 0); } - return mdns_socket(NULL, 0); + return mdns_ipv4_socket(NULL, 0); } @@ -205,13 +205,11 @@ static int usage(int code) int main(int argc, char *argv[]) { struct message m; - struct in_addr ip; - unsigned short port; ssize_t bsize; socklen_t ssize; unsigned char buf[MAX_PACKET_LEN]; char default_iface[IFNAMSIZ] = { 0 }; - struct sockaddr_in from, to; + struct sockaddr_storage from, to; char *name = DISCO_NAME; char *ifname = NULL; int type = QTYPE_PTR; /* 12 */ @@ -284,11 +282,11 @@ int main(int argc, char *argv[]) select(sd + 1, &fds, 0, 0, tv); if (FD_ISSET(sd, &fds)) { - ssize = sizeof(struct sockaddr_in); + ssize = sizeof(from); while ((bsize = recvfrom(sd, buf, MAX_PACKET_LEN, 0, (struct sockaddr *)&from, &ssize)) > 0) { memset(&m, 0, sizeof(struct message)); if (message_parse(&m, buf) == 0) - mdnsd_in(d, &m, from.sin_addr, from.sin_port); + mdnsd_in(d, &m, &from); } if (bsize < 0 && errno != EAGAIN) { printf("Failed reading from socket %d: %s\n", errno, strerror(errno)); @@ -296,17 +294,17 @@ int main(int argc, char *argv[]) } } - while (mdnsd_out(d, &m, &ip, &port)) { + memset(&to, 0, sizeof(to)); + to.ss_family = AF_INET; + while (mdnsd_out(d, &m, &to) > 0) { int len = message_packet_len(&m); - memset(&to, 0, sizeof(to)); - to.sin_family = AF_INET; - to.sin_port = port; - to.sin_addr = ip; if (sendto(sd, message_packet(&m), len, 0, (struct sockaddr *)&to, sizeof(struct sockaddr_in)) != len) { printf("Failed writing to socket: %s\n", strerror(errno)); return 1; } + memset(&to, 0, sizeof(to)); + to.ss_family = AF_INET; } if (wait && (time(NULL) - start >= wait))