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; 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 ssize_t send_packet(int fd, const void *data, size_t len, int domain) {
static struct sockaddr_in toaddr; static struct sockaddr_in toaddr;
char *addr; 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_port = htons(port);
toaddr.sin_addr.s_addr = inet_addr(addr); toaddr.sin_addr.s_addr = inet_addr(addr);
return sendto(fd, data, len, 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr_in)); return send_packet_to( fd, data, len, &toaddr);
}
// 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;
} }
#ifndef MDNS_NO_RESPONDER_SUPPORT #ifndef MDNS_NO_RESPONDER_SUPPORT
@@ -902,7 +907,7 @@ out_with_mutex:
// processes the incoming MDNS packet // processes the incoming MDNS packet
// returns >0 if processed, 0 otherwise // 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; int result;
assert(pkt != NULL); 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_ans_rr,
pkt->num_add_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 // loop through questions
struct rr_list *qnl = pkt->rr_qn; struct rr_list *qnl = pkt->rr_qn;
for (int i = 0; i < pkt->num_qn; i++, qnl = qnl->next) { 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); DEBUG_PRINTF("qn #%d: type %s (%02x) %s - ", i, rr_get_type_name(qn->type), qn->type, namestr);
MDNS_FREE(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) { if (qn->unicast_query) {
DEBUG_PRINTF("skipping unicast query\n"); DEBUG_PRINTF("treating unicast query as multicast\n");
continue; unicast |= 4;
} }
num_ans_added = populate_answers(svr, &reply->rr_ans, qn->name, qn->type); 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 // remove our replies if they were already in their answers
struct rr_list *prev_ans = NULL; 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_list *next_ans = ans->next;
struct rr_entry *known_ans = rr_entry_match(pkt->rr_ans, ans->e); 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 // adjust answer count
reply->num_ans_rr--; reply->num_ans_rr--;
} }
prev_ans = ans; prev_ans = ans;
ans = next_ans; ans = next_ans;
} }
// see if we can match additional records for answers // see if we can match additional records for answers
add_related_rr(svr, reply->rr_ans, reply); 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"); 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; return reply->num_ans_rr;
} else { } else {
result = 0; result = 0;
@@ -1162,6 +1198,9 @@ static void main_loop(struct mdnsd *svr) {
max_fd = svr->notify_pipe[0]; max_fd = svr->notify_pipe[0];
while (1) { while (1) {
struct sockaddr_in fromaddr;
socklen_t sockaddr_size = sizeof(struct sockaddr_in);
svr->sendmsg_requested = 0; svr->sendmsg_requested = 0;
FD_ZERO(&sockfd_set); 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) if (read_pipe(svr->notify_pipe[0], (char *)&notify_buf, 1) == -1)
log_message(LOG_ERR, "read_pipe() failed; %s\n", strerror(errno)); log_message(LOG_ERR, "read_pipe() failed; %s\n", strerror(errno));
} else if (FD_ISSET(svr->sockfd, &sockfd_set)) { } 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, ssize_t recvsize = recvfrom(svr->sockfd, pkt_buffer, PACKET_SIZE, 0,
(struct sockaddr *) &fromaddr, &sockaddr_size); (struct sockaddr *) &fromaddr, &sockaddr_size);
if (recvsize < 0) { if (recvsize < 0) {
@@ -1198,7 +1234,7 @@ static void main_loop(struct mdnsd *svr) {
if (svr->sockfd != -1) { if (svr->sockfd != -1) {
/* succeed to create recv socket */ /* succeed to create recv socket */
break; break;
} }
remaining_cnt--; remaining_cnt--;
} }
if (svr->sockfd == -1) { if (svr->sockfd == -1) {
@@ -1216,13 +1252,20 @@ static void main_loop(struct mdnsd *svr) {
continue; 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); struct mdns_pkt *mdns = mdns_parse_pkt(pkt_buffer, recvsize);
if (mdns != NULL) { 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 #ifndef MDNS_NO_RESPONDER_SUPPORT
size_t replylen = mdns_encode_pkt(mdns_packet, pkt_buffer, PACKET_SIZE); 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)); log_message(LOG_ERR, "send_packet() failed; %s\n", strerror(errno));
#endif #endif
} else if (mdns->num_qn == 0) { } else if (mdns->num_qn == 0) {