From 8381f595a6066f893cc24e8a161e27a10a140cf0 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 27 May 2014 18:16:10 +0100 Subject: [PATCH] make the code work for bridge interfaces Signed-off-by: John Crispin --- dns.c | 18 ++++++++++++++++++ main.c | 12 ++++++++++-- util.c | 37 +++++++++++++++++++++++++++++++++++-- util.h | 2 ++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/dns.c b/dns.c index 1d8a830..ecfaa63 100644 --- a/dns.c +++ b/dns.c @@ -67,12 +67,16 @@ dns_type_string(uint16_t type) void dns_send_question(struct uloop_fd *u, char *question, int type) { + size_t cmsg_data[( CMSG_SPACE(sizeof(struct in_pktinfo)) / sizeof(size_t)) + 1]; unsigned char buffer[MAX_NAME_LEN]; struct dns_header h = { 0 }; struct dns_question q = { 0 }; struct msghdr m = { 0 }; struct iovec iov[3] = { {0}, {0}, {0} }; struct sockaddr_in a = { 0 }; + struct in_pktinfo *pkti; + struct cmsghdr *cmsg; + struct in_addr in; int len; a.sin_family = AF_INET; @@ -92,6 +96,20 @@ dns_send_question(struct uloop_fd *u, char *question, int type) m.msg_iov = iov; m.msg_iovlen = 3; + memset(cmsg_data, 0, sizeof(cmsg_data)); + m.msg_control = cmsg_data; + m.msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo)); + + cmsg = CMSG_FIRSTHDR(&m); + cmsg->cmsg_len = m.msg_controllen; + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_PKTINFO; + + inet_aton(iface_ip, &in); + + pkti = (struct in_pktinfo*) CMSG_DATA(cmsg); + pkti->ipi_ifindex = iface_index; + iov[0].iov_base = &h; iov[0].iov_len = sizeof(struct dns_header); diff --git a/main.c b/main.c index a6c99b5..cc17903 100644 --- a/main.c +++ b/main.c @@ -42,6 +42,7 @@ static struct uloop_timeout reconnect; char *iface_name = "eth0"; const char *iface_ip; +int iface_index; static int parse_answer(struct uloop_fd *u, uint8_t *buffer, int len, uint8_t **b, int *rlen, int cache) @@ -185,7 +186,6 @@ reconnect_socket(struct uloop_timeout *timeout) uloop_fd_add(&listener, ULOOP_READ); sleep(5); - dns_send_question(&listener, "_services._dns-sd._tcp.local", TYPE_PTR); dns_send_question(&listener, "_services._dns-sd._udp.local", TYPE_PTR); announce_init(&listener); } @@ -226,7 +226,15 @@ main(int argc, char **argv) fprintf(stderr, "failed to read ip for %s\n", iface_name); return -1; } - fprintf(stderr, "interface %s has ip %s\n", iface_name, iface_ip); + + iface_index = get_iface_index(iface_name); + + if (!iface_index) { + fprintf(stderr, "failed to read index for %s\n", iface_name); + return -1; + } + + fprintf(stderr, "interface %s has ip %s and index %d\n", iface_name, iface_ip, iface_index); signal_setup(); if (dns_init()) diff --git a/util.c b/util.c index a4a117b..1708a40 100644 --- a/util.c +++ b/util.c @@ -98,6 +98,28 @@ get_iface_ipv4(const char *ifname) return ret; } +int +get_iface_index(const char *ifname) +{ + struct ifreq ir; + int sock; + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + return 0; + + memset(&ir, 0, sizeof(struct ifreq)); + + strncpy(ir.ifr_name, ifname, sizeof(ir.ifr_name)); + + if (ioctl(sock, SIOCGIFINDEX, &ir) < 0) + return 0; + + close(sock); + + return ir.ifr_ifindex; +} + char* get_hostname(void) { @@ -116,15 +138,19 @@ socket_setup(int fd, const char *ip) uint8_t ttl = 255; int yes = 1; int no = 0; - struct sockaddr_in sa; + struct sockaddr_in sa = { 0 }; + struct in_addr in; + + inet_aton(iface_ip, &in); sa.sin_family = AF_INET; sa.sin_port = htons(MCAST_PORT); inet_pton(AF_INET, MCAST_ADDR, &sa.sin_addr); memset(&mreq, 0, sizeof(mreq)); - mreq.imr_address.s_addr = htonl(INADDR_ANY); + mreq.imr_address.s_addr = in.s_addr; mreq.imr_multiaddr = sa.sin_addr; + mreq.imr_ifindex = iface_index; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) fprintf(stderr, "ioctl failed: IP_MULTICAST_TTL\n"); @@ -132,6 +158,13 @@ socket_setup(int fd, const char *ip) if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) fprintf(stderr, "ioctl failed: SO_REUSEADDR\n"); + /* Some network drivers have issues with dropping membership of + * mcast groups when the iface is down, but don't allow rejoining + * when it comes back up. This is an ugly workaround + * -- this was copied from avahi -- + */ + setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); + if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { fprintf(stderr, "failed to join multicast group: %s\n", strerror(errno)); close(fd); diff --git a/util.h b/util.h index 6c73904..fe9f1ea 100644 --- a/util.h +++ b/util.h @@ -22,6 +22,7 @@ extern int debug; extern struct uloop_fd listener; extern const char *iface_ip; +extern int iface_index; void *memdup(void *d, int l); @@ -29,6 +30,7 @@ extern void signal_setup(void); extern int socket_setup(int fd, const char *ip); extern char* get_hostname(void); extern const char* get_iface_ipv4(const char *ifname); +extern int get_iface_index(const char *ifname); extern uint32_t rand_time_delta(uint32_t t); #endif -- 2.30.2