Support responding to unicast queries: initially just legacy queries and multicast responses.

This commit is contained in:
df 2020-07-26 21:02:43 +01:00
parent 2ce1bb8ae4
commit 0aa116dbce

115
mdnsd.c
View File

@ -554,6 +554,32 @@ static int create_recv_sock(int domain)
return sd;
}
static ssize_t send_packet_to(int fd, const void *data, size_t len, struct sockaddr_in *toaddr) {
return sendto(fd, data, len, 0, (struct sockaddr *) toaddr, sizeof(struct sockaddr_in));
}
// populate the specified list which matches the RR name and type
static int populate_query(struct mdnsd *svr, struct rr_list **rr_head)
{
int num_qns = 0;
// check if we have the records
pthread_mutex_lock(&svr->data_lock);
while (svr->query) {
struct rr_entry *qn_e = rr_list_remove(&svr->query, svr->query->e);
if (qn_e == NULL) {
break;
}
num_qns += rr_list_append(rr_head, qn_e);
}
pthread_mutex_unlock(&svr->data_lock);
return num_qns;
}
static ssize_t send_packet(int fd, const void *data, size_t len, int domain) {
static struct sockaddr_in toaddr;
char *addr;
@ -578,28 +604,7 @@ static ssize_t send_packet(int fd, const void *data, size_t len, int domain) {
toaddr.sin_port = htons(port);
toaddr.sin_addr.s_addr = inet_addr(addr);
return sendto(fd, data, len, 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in));
}
// populate the specified list which matches the RR name and type
static int populate_query(struct mdnsd *svr, struct rr_list **rr_head)
{
int num_qns = 0;
// check if we have the records
pthread_mutex_lock(&svr->data_lock);
while (svr->query) {
struct rr_entry *qn_e = rr_list_remove(&svr->query, svr->query->e);
if (qn_e == NULL) {
break;
}
num_qns += rr_list_append(rr_head, qn_e);
}
pthread_mutex_unlock(&svr->data_lock);
return num_qns;
return send_packet_to( fd, data, len, &toaddr);
}
#ifndef MDNS_NO_RESPONDER_SUPPORT
@ -902,7 +907,7 @@ out_with_mutex:
// processes the incoming MDNS packet
// returns >0 if processed, 0 otherwise
static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns_pkt *reply) {
static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct sockaddr_in *fromtoaddr, struct mdns_pkt *reply) {
int result;
assert(pkt != NULL);
@ -919,6 +924,15 @@ static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns
pkt->num_ans_rr,
pkt->num_add_rr);
int unicast = 0; /* 0, 1, 2, 4 = no, direct unicast, legacy, unicast-response */
if (fromtoaddr->sin_port != htons(MDNS_PORT)) {
/* legacy query */
unicast |= 2;
} else if (fromtoaddr->sin_addr.s_addr != inet_addr(MDNS_ADDR)) {
/* direct unicast - send back to same addr:port */
unicast |= 1;
}
// loop through questions
struct rr_list *qnl = pkt->rr_qn;
for (int i = 0; i < pkt->num_qn; i++, qnl = qnl->next) {
@ -929,10 +943,10 @@ static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns
DEBUG_PRINTF("qn #%d: type %s (%02x) %s - ", i, rr_get_type_name(qn->type), qn->type, namestr);
MDNS_FREE(namestr);
// check if it's a unicast query - we ignore those
// check if it's a unicast query - we don't treat those differently
if (qn->unicast_query) {
DEBUG_PRINTF("skipping unicast query\n");
continue;
DEBUG_PRINTF("treating unicast query as multicast\n");
unicast |= 4;
}
num_ans_added = populate_answers(svr, &reply->rr_ans, qn->name, qn->type);
@ -943,7 +957,7 @@ static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns
// remove our replies if they were already in their answers
struct rr_list *prev_ans = NULL;
for (struct rr_list *ans = reply->rr_ans; ans; ) {
for (struct rr_list *ans = reply->rr_ans; ans;) {
struct rr_list *next_ans = ans->next;
struct rr_entry *known_ans = rr_entry_match(pkt->rr_ans, ans->e);
@ -965,12 +979,11 @@ static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns
// adjust answer count
reply->num_ans_rr--;
}
prev_ans = ans;
ans = next_ans;
}
// see if we can match additional records for answers
add_related_rr(svr, reply->rr_ans, reply);
@ -979,6 +992,29 @@ static int process_mdns_pkt(struct mdnsd *svr, struct mdns_pkt *pkt, struct mdns
DEBUG_PRINTF("\n");
/* specific processing for unicast, ... or not */
if (unicast & 2) {
/* legacy: (rfc6762#section-5.4) send back to same addr:port, no cache flush, TTL -> 10s */
struct rr_list *rr_grps[] = { reply->rr_ans, reply->rr_add, NULL };
for (struct rr_list **rrl = rr_grps; *rrl; ++rrl) {
for (struct rr_list *ans = *rrl; ans; ans = ans->next) {
ans->e->cache_flush = 0;
ans->e->ttl = DEFAULT_TTL_LEGACY;
}
}
} else if (unicast & 1) {
/* direct: (rfc6762#section-5.5) should be sending answers to same addr:5353 if on LAN, then multicast */
/* let's pretend the first reply got lost ... */
fromtoaddr->sin_port = 0;
} else if (unicast & 4) {
/* unicast-response: (rfc6762#section-5.4) should be sending answers to QUs to same addr:5353 if on LAN, then multicast */
/* let's pretend the first reply got lost ... */
fromtoaddr->sin_port = 0;
} else {
/* send usual multicast response */
fromtoaddr->sin_port = 0;
}
return reply->num_ans_rr;
} else {
result = 0;
@ -1162,6 +1198,9 @@ static void main_loop(struct mdnsd *svr) {
max_fd = svr->notify_pipe[0];
while (1) {
struct sockaddr_in fromaddr;
socklen_t sockaddr_size = sizeof(struct sockaddr_in);
svr->sendmsg_requested = 0;
FD_ZERO(&sockfd_set);
@ -1176,9 +1215,6 @@ static void main_loop(struct mdnsd *svr) {
if (read_pipe(svr->notify_pipe[0], (char *)&notify_buf, 1) == -1)
log_message(LOG_ERR, "read_pipe() failed; %s\n", strerror(errno));
} else if (FD_ISSET(svr->sockfd, &sockfd_set)) {
struct sockaddr_in fromaddr;
socklen_t sockaddr_size = sizeof(struct sockaddr_in);
ssize_t recvsize = recvfrom(svr->sockfd, pkt_buffer, PACKET_SIZE, 0,
(struct sockaddr *) &fromaddr, &sockaddr_size);
if (recvsize < 0) {
@ -1198,7 +1234,7 @@ static void main_loop(struct mdnsd *svr) {
if (svr->sockfd != -1) {
/* succeed to create recv socket */
break;
}
}
remaining_cnt--;
}
if (svr->sockfd == -1) {
@ -1216,13 +1252,20 @@ static void main_loop(struct mdnsd *svr) {
continue;
}
DEBUG_PRINTF("data from=%s size=%ld\n", inet_ntoa(fromaddr.sin_addr), (long) recvsize);
DEBUG_PRINTF("data from=%s:%d size=%ld\n", inet_ntoa(fromaddr.sin_addr), (long) recvsize);
struct mdns_pkt *mdns = mdns_parse_pkt(pkt_buffer, recvsize);
if (mdns != NULL) {
if (process_mdns_pkt(svr, mdns, mdns_packet)) {
struct sockaddr_in toaddr = fromaddr;
if (process_mdns_pkt(svr, mdns, &toaddr, mdns_packet)) {
#ifndef MDNS_NO_RESPONDER_SUPPORT
size_t replylen = mdns_encode_pkt(mdns_packet, pkt_buffer, PACKET_SIZE);
if (send_packet(svr->sockfd, pkt_buffer, replylen, svr->domain) == -1)
ssize_t ret = -1;
if (toaddr.sin_port != 0) {
ret = send_packet_to(svr->sockfd, pkt_buffer, replylen, &toaddr);
} else {
ret = send_packet(svr->sockfd, pkt_buffer, replylen, svr->domain);
}
if (ret == -1)
log_message(LOG_ERR, "send_packet() failed; %s\n", strerror(errno));
#endif
} else if (mdns->num_qn == 0) {