diff options
author | Lennart Poettering <lennart@poettering.net> | 2004-12-05 17:33:51 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2004-12-05 17:33:51 +0000 |
commit | 8d4fd94fc8332b23f757443841a5c19c104a9bb8 (patch) | |
tree | 4763b4cdbdd13f28efbe07ebfc0486536713c577 /query.c | |
parent | a3b571996ea5cb0227b36a20f3fc0986f7ab1b7d (diff) |
move source files to src/
git-svn-id: file:///home/lennart/svn/public/nss-mdns/trunk@51 0ee8848e-81ea-0310-a63a-f631d1a40d77
Diffstat (limited to 'query.c')
-rw-r--r-- | query.c | 541 |
1 files changed, 0 insertions, 541 deletions
diff --git a/query.c b/query.c deleted file mode 100644 index 5673c3e..0000000 --- a/query.c +++ /dev/null @@ -1,541 +0,0 @@ -#include <inttypes.h> -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <unistd.h> -#include <fcntl.h> -#include <assert.h> -#include <sys/time.h> - -#include "dns.h" -#include "util.h" -#include "query.h" - -static const usec_t retry_ms[] = { 200000, 500000, 900000, 1400000, 0 }; - -static void mdns_mcast_group(struct sockaddr_in *ret_sa) { - assert(ret_sa); - - ret_sa->sin_family = AF_INET; - ret_sa->sin_port = htons(5353); - ret_sa->sin_addr.s_addr = inet_addr("224.0.0.251"); -} - -int mdns_open_socket(void) { - struct ip_mreqn mreq; - struct sockaddr_in sa; - int fd = -1, ttl, yes; - - mdns_mcast_group(&sa); - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - fprintf(stderr, "socket() failed: %s\n", strerror(errno)); - goto fail; - } - - ttl = 255; - if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) { - fprintf(stderr, "IP_MULTICAST_TTL failed: %s\n", strerror(errno)); - goto fail; - } - - yes = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { - fprintf(stderr, "SO_REUSEADDR failed: %s\n", strerror(errno)); - goto fail; - } - - if (bind(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { - fprintf(stderr, "bind() failed: %s\n", strerror(errno)); - goto fail; - } - - memset(&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr = sa.sin_addr; - mreq.imr_address.s_addr = htonl(INADDR_ANY); - mreq.imr_ifindex = 0; - - if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { - fprintf(stderr, "IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno)); - goto fail; - } - - if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) { - fprintf(stderr, "O_RECVTTL failed: %s\n", strerror(errno)); - goto fail; - } - - if (set_cloexec(fd) < 0) { - fprintf(stderr, "FD_CLOEXEC failed: %s\n", strerror(errno)); - goto fail; - } - - if (set_nonblock(fd) < 0) { - fprintf(stderr, "O_ONONBLOCK failed: %s\n", strerror(errno)); - goto fail; - } - - return fd; - -fail: - if (fd >= 0) - close(fd); - - return -1; -} - -static int send_dns_packet(int fd, struct dns_packet *p) { - struct sockaddr_in sa; - assert(fd >= 0 && p); - - assert(dns_packet_check_valid(p) >= 0); - - mdns_mcast_group(&sa); - - for (;;) { - if (sendto(fd, p->data, p->size, 0, (struct sockaddr*) &sa, sizeof(sa)) >= 0) - return 0; - - if (errno != EAGAIN) { - fprintf(stderr, "sendto() failed: %s\n", strerror(errno)); - return -1; - } - - if (wait_for_write(fd, NULL) < 0) - return -1; - } -} - -static int recv_dns_packet(int fd, struct dns_packet **ret_packet, uint8_t* ret_ttl, struct timeval *end) { - struct dns_packet *p= NULL; - struct msghdr msg; - struct iovec io; - int ret = -1; - uint8_t aux[16]; - assert(fd >= 0); - - p = dns_packet_new(); - - io.iov_base = p->data; - io.iov_len = sizeof(p->data); - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &io; - msg.msg_iovlen = 1; - msg.msg_control = aux; - msg.msg_controllen = sizeof(aux); - msg.msg_flags = 0; - - for (;;) { - ssize_t l; - int r; - - if ((l = recvmsg(fd, &msg, 0)) >= 0) { - struct cmsghdr *cmsg; - *ret_ttl = 0; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) { - if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) { - *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg); - break; - } - } - - if (cmsg == NULL) { - fprintf(stderr, "Didn't recieve TTL\n"); - goto fail; - } - - p->size = (size_t) l; - - *ret_packet = p; - return 0; - } - - if (errno != EAGAIN) { - fprintf(stderr, "recvfrom() failed: %s\n", strerror(errno)); - goto fail; - } - - if ((r = wait_for_read(fd, end)) < 0) - goto fail; - else if (r > 0) { /* timeout */ - ret = 1; - goto fail; - } - } - -fail: - if (p) - dns_packet_free(p); - - return ret; -} - -static int send_name_query(int fd, const char *name, int query_ipv4, int query_ipv6) { - int ret = -1; - struct dns_packet *p = NULL; - uint8_t *prev_name = NULL; - int qdcount = 0; - - assert(fd >= 0 && name && (query_ipv4 || query_ipv6)); - - if (!(p = dns_packet_new())) { - fprintf(stderr, "Failed to allocate DNS packet.\n"); - goto finish; - } - - dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - - if (query_ipv4) { - if (!(prev_name = dns_packet_append_name(p, name))) { - fprintf(stderr, "Bad host name\n"); - goto finish; - - } - dns_packet_append_uint16(p, DNS_TYPE_A); - dns_packet_append_uint16(p, DNS_CLASS_IN); - qdcount++; - } - - if (query_ipv6) { - if (!dns_packet_append_name_compressed(p, name, prev_name)) { - fprintf(stderr, "Bad host name\n"); - goto finish; - } - - dns_packet_append_uint16(p, DNS_TYPE_AAAA); - dns_packet_append_uint16(p, DNS_CLASS_IN); - qdcount++; - } - - dns_packet_set_field(p, DNS_FIELD_QDCOUNT, qdcount); - - if (send_dns_packet(fd, p) < 0) - goto finish; - - ret = 0; - -finish: - if (p) - dns_packet_free(p); - - return ret; -} - -static int domain_cmp(const char *a, const char *b) { - size_t al, bl; - - al = strlen(a); - bl = strlen(b); - - if (al > 0 && a[al-1] == '.') - al --; - - if (bl > 0 && b[bl-1] == '.') - bl --; - - if (al != bl) - return al > bl ? 1 : (al < bl ? -1 : 0); - - return strncasecmp(a, b, al); -} - -static int process_name_response(int fd, const char *name, usec_t timeout, void (*ipv4_func)(const ipv4_address_t *ipv4, void *userdata), void (*ipv6_func)(const ipv6_address_t *ipv6, void *userdata), void *userdata) { - assert(fd >= 0 && name && (ipv4_func || ipv6_func)); - struct dns_packet *p = NULL; - int done = 0; - struct timeval end; - - gettimeofday(&end, NULL); - timeval_add(&end, timeout); - - while (!done) { - uint8_t ttl; - int r; - - if ((r = recv_dns_packet(fd, &p, &ttl, &end)) < 0) - return -1; - else if (r > 0) /* timeout */ - return 1; - - /* Ignore packets with RFC != 255 */ - if (ttl == 255) { - - /* Ignore corrupt packets */ - if (dns_packet_check_valid_response(p) >= 0) { - - for (;;) { - char pname[256]; - uint16_t type, class; - uint32_t rr_ttl; - uint16_t rdlength; - - if (dns_packet_consume_name(p, pname, sizeof(pname)) < 0 || - dns_packet_consume_uint16(p, &type) < 0 || - dns_packet_consume_uint16(p, &class) < 0 || - dns_packet_consume_uint32(p, &rr_ttl) < 0 || - dns_packet_consume_uint16(p, &rdlength) < 0) { - break; - } - - /* Remove mDNS cache flush bit */ - class &= ~0x8000; - - if (ipv4_func && - type == DNS_TYPE_A && - class == DNS_CLASS_IN && - !domain_cmp(name, pname) && - rdlength == sizeof(ipv4_address_t)) { - - ipv4_address_t ipv4; - - if (dns_packet_consume_bytes(p, &ipv4, sizeof(ipv4)) < 0) - break; - - ipv4_func(&ipv4, userdata); - done = 1; - - } else if (ipv6_func && - type == DNS_TYPE_AAAA && - class == DNS_CLASS_IN && - !domain_cmp(name, pname) && - rdlength == sizeof(ipv6_address_t)) { - - ipv6_address_t ipv6; - - if (dns_packet_consume_bytes(p, &ipv6, sizeof(ipv6_address_t)) < 0) - break; - - ipv6_func(&ipv6, userdata); - done = 1; - } else { - - /* Step over */ - - if (dns_packet_consume_seek(p, rdlength) < 0) - break; - } - } - } - } - - if (p) - dns_packet_free(p); - } - - return 0; -} - -int mdns_query_name(int fd, const char *name, void (*ipv4_func)(const ipv4_address_t *ipv4, void *userdata), void (*ipv6_func)(const ipv6_address_t *ipv6, void *userdata), void *userdata) { - const usec_t *timeout = retry_ms; - assert(fd >= 0 && name && (ipv4_func || ipv6_func)); - - while (*timeout > 0) { - int n; - - if (send_name_query(fd, name, !!ipv4_func, !!ipv6_func) < 0) - return -1; - - if ((n = process_name_response(fd, name, *timeout, ipv4_func, ipv6_func, userdata)) < 0) - return -1; - - if (n == 0) - return 0; - - /* Timeout */ - - timeout++; - } - - return -1; -} - -static int send_reverse_query(int fd, const char *name) { - int ret = -1; - struct dns_packet *p = NULL; - - assert(fd >= 0 && name); - - if (!(p = dns_packet_new())) { - fprintf(stderr, "Failed to allocate DNS packet.\n"); - goto finish; - } - - dns_packet_set_field(p, DNS_FIELD_FLAGS, DNS_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - - if (!dns_packet_append_name(p, name)) { - fprintf(stderr, "Bad host name\n"); - goto finish; - } - - dns_packet_append_uint16(p, DNS_TYPE_PTR); - dns_packet_append_uint16(p, DNS_CLASS_IN); - - dns_packet_set_field(p, DNS_FIELD_QDCOUNT, 1); - - if (send_dns_packet(fd, p) < 0) - goto finish; - - ret = 0; - -finish: - if (p) - dns_packet_free(p); - - return ret; -} - -static int process_reverse_response(int fd, const char *name, usec_t timeout, void (*name_func)(const char *name, void *userdata), void *userdata) { - assert(fd >= 0 && name && name_func); - struct dns_packet *p = NULL; - int done = 0; - struct timeval end; - - gettimeofday(&end, NULL); - timeval_add(&end, timeout); - - while (!done) { - uint8_t ttl; - int r; - - if ((r = recv_dns_packet(fd, &p, &ttl, &end)) < 0) - return -1; - else if (r > 0) /* timeout */ - return 1; - - /* Ignore packets with RFC != 255 */ - if (ttl == 255) { - - /* Ignore corrupt packets */ - if (dns_packet_check_valid_response(p) >= 0) { - - for (;;) { - char pname[256]; - uint16_t type, class; - uint32_t rr_ttl; - uint16_t rdlength; - - if (dns_packet_consume_name(p, pname, sizeof(pname)) < 0 || - dns_packet_consume_uint16(p, &type) < 0 || - dns_packet_consume_uint16(p, &class) < 0 || - dns_packet_consume_uint32(p, &rr_ttl) < 0 || - dns_packet_consume_uint16(p, &rdlength) < 0) { - break; - } - - /* Remove mDNS cache flush bit */ - class &= ~0x8000; - - if (type == DNS_TYPE_PTR && - class == DNS_CLASS_IN && - !domain_cmp(name, pname)) { - - char rname[256]; - - if (dns_packet_consume_name(p, rname, sizeof(rname)) < 0) - break; - - name_func(rname, userdata); - done = 1; - - } else { - - /* Step over */ - - if (dns_packet_consume_seek(p, rdlength) < 0) - break; - } - } - } - } - - if (p) - dns_packet_free(p); - } - - return 0; -} - -static int query_reverse(int fd, const char *name, void (*name_func)(const char *name, void *userdata), void *userdata) { - const usec_t *timeout = retry_ms; - assert(fd >= 0 && name && name_func); - - while (*timeout > 0) { - int n; - - if (send_reverse_query(fd, name) < 0) - return -1; - - if ((n = process_reverse_response(fd, name, *timeout, name_func, userdata)) < 0) - return -1; - - if (n == 0) - return 0; - - /* Timeout */ - - timeout++; - } - - return -1; -} - - -int mdns_query_ipv4(int fd, const ipv4_address_t *ipv4, void (*name_func)(const char *name, void *userdata), void *userdata) { - char name[256]; - uint32_t a; - assert(fd >= 0 && ipv4 && name_func); - - a = ntohl(ipv4->address); - snprintf(name, sizeof(name), "%u.%u.%u.%u.in-addr.arpa", a & 0xFF, (a >> 8) & 0xFF, (a >> 16) & 0xFF, a >> 24); - - return query_reverse(fd, name, name_func, userdata); -} - -int mdns_query_ipv6(int fd, const ipv6_address_t *ipv6, void (*name_func)(const char *name, void *userdata), void *userdata) { - char name[256]; - assert(fd >= 0 && ipv6 && name_func); - - snprintf(name, sizeof(name), "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.int", - ipv6->address[15] & 0xF, - ipv6->address[15] >> 4, - ipv6->address[14] & 0xF, - ipv6->address[14] >> 4, - ipv6->address[13] & 0xF, - ipv6->address[13] >> 4, - ipv6->address[12] & 0xF, - ipv6->address[12] >> 4, - ipv6->address[11] & 0xF, - ipv6->address[11] >> 4, - ipv6->address[10] & 0xF, - ipv6->address[10] >> 4, - ipv6->address[9] & 0xF, - ipv6->address[9] >> 4, - ipv6->address[8] & 0xF, - ipv6->address[8] >> 4, - ipv6->address[7] & 0xF, - ipv6->address[7] >> 4, - ipv6->address[6] & 0xF, - ipv6->address[6] >> 4, - ipv6->address[5] & 0xF, - ipv6->address[5] >> 4, - ipv6->address[4] & 0xF, - ipv6->address[4] >> 4, - ipv6->address[3] & 0xF, - ipv6->address[3] >> 4, - ipv6->address[2] & 0xF, - ipv6->address[2] >> 4, - ipv6->address[1] & 0xF, - ipv6->address[1] >> 4, - ipv6->address[0] & 0xF, - ipv6->address[0] >> 4); - - return query_reverse(fd, name, name_func, userdata); -} - |