Support responding to unicast queries: initially just legacy queries and multicast responses.
This commit is contained in:
115
mdnsd.c
115
mdnsd.c
@@ -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 *)¬ify_buf, 1) == -1)
|
if (read_pipe(svr->notify_pipe[0], (char *)¬ify_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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user