blob: 2b9151dbb40e04fda605cff8b53e130440af91c2 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <stdint.h>
#include <stdlib.h>
/**
* This is a library that implements a subset of mDNS (RFC 6762) to support the
* Fuchsia boot process. The structure of an mDNS packet is largely borrowed
* from the DNS package structure (RFC 1035).
**/
#ifdef __cplusplus
extern "C" {
#endif
// The default IPv4 multicast address.
#define MDNS_IPV4_ADDRESS "224.0.0.251";
// The default IPv6 multicast address.
#define MDNS_IPV6_ADDRESS "ff02::fb";
// The maxinum number of characters in a domain name.
#define MAX_DOMAIN_LENGTH 255
#define MAX_DOMAIN_LABEL 63
// The number of bytes in a DNS message header.
#define MDNS_HEADER_SIZE 12
/**
* Resource record types.
*
* A record type communicates a given record's intended-use.
*
* This list is incomplete, since all record types are not necessarily useful to
* Zircon. Add to this list as needed.
**/
// A records contain 32-bit IPv4 host addresses. They are used to map hostnames
// to IP addresses of a given host.
#define RR_TYPE_A 0x01
// AAAA Records contain 128-bit IPv6 host addresses. Used to map hostnames IP
// addresses of a given host.
#define RR_TYPE_AAAA 0x1C
/**
* Resource record classes.
*
* These are DNS classes, which are individual namespaces that map to various
* DNS Zones.
*
* This list is incomplete, since all record classes are not necessarily useful
* to Zircon. Add to this list as needed.
**/
// IN is a class for common DNS records involving internet hostnames, servers
// or IP addresses.
#define RR_CLASS_IN 0x0001
// A DNS message header.
//
// The message header should not be modified by hand. When creating a message
// for sending, invalid changes, such as specifying a qd_count that differs from
// the actual number of questions in a message, are replaced with their correct
// values. When reading a received message, modifying the header can obviously
// lead to confusing inconsistencies between the header information and its
// corresponding message.
//
// id is a unique identifier used to match queries with responses.
//
// flags is a set of flags represented as a collection of sub-fields.
// The format of the flags section is as follows:
//
// Bit no. | Meaning
// -------------------
// 1 0 = query
// 1 = reply
//
// 2-5 0000 = standard query
// 0100 = inverse
// 0010 & 0001 not used.
//
// 6 0 = non-authoritative DNS answer
// 1 = authoritative DNS answer
//
// 7 0 = message not truncated
// 1 = message truncated
//
// 8 0 = non-recursive query
// 1 = recursive query
//
// 9 0 = recursion not available
// 1 = recursion available
//
// 10 & 12 reserved
//
// 11 0 = answer/authority portion was not authenticated by the
// server
// 1 = answer/authority portion was authenticated by the
// server
//
// 13 - 16 0000 = no error
// 0100 = Format error in query
// 0010 = Server failure
// 0001 = Name does not exist
typedef struct mdns_header_t {
uint16_t id;
uint16_t flags;
uint16_t qd_count; // Question count
uint16_t an_count; // Answer count
uint16_t ns_count; // Authoritative name server count
uint16_t ar_count; // Additional record count
} mdns_header;
// An mDNS question.
typedef struct mdns_question_t {
char domain[MAX_DOMAIN_LENGTH + 1];
uint16_t qtype;
uint16_t qclass;
struct mdns_question_t* next;
} mdns_question;
// An mDNS resource record
typedef struct mdns_rr_t {
char name[MAX_DOMAIN_LENGTH + 1];
uint16_t type;
uint16_t clazz;
uint32_t ttl;
uint16_t rdlength;
uint8_t* rdata;
struct mdns_rr_t* next;
} mdns_rr;
// An mDNS query packet.
typedef struct mdns_message_t {
mdns_header header;
mdns_question* questions;
mdns_rr* answers;
mdns_rr* authorities;
mdns_rr* additionals;
} mdns_message;
// Reads an mdns_message.
//
// buf_len is the number of bytes in buf. Data is unmarshalled into the given
// mdns_message container which is zeroed before writing via mdns_init_message.
// The message is zeroed even if unmarshalling fails.
//
// If buf_len is less than MDNS_HEADER_SIZE or the complete message is longer
// than buf_len bytes (data is missing), -1 is returned and errno is set to
// EBADMSG.
//
// Returns the number of bytes read from buf.
int mdns_unmarshal(const void* buf,
const size_t buf_len,
mdns_message* container);
// Zeroes the values contained in the given mdns_message.
void mdns_init_message(mdns_message* message);
// Appends a question to a message.
//
// Assumes mdns_init_message(&message) has been called.
//
// If domain is longer than MAX_DOMAIN_LENGTH bytes, a negative value is
// returned and errno is set to ENAMETOOLONG. The message header's question
// count is incremented by one. This count is guaranteed to be in-sync with
// the actual number of questions in the message. If memory cannot be
// allocated for the question, a negative value is returned and errno is set to
// ENOMEM.
//
// Returns 0 on success.
int mdns_add_question(mdns_message* message,
const char* domain,
uint16_t qtype,
uint16_t qclass);
// Appends an answer resource record to a message.
//
// Assumes mdns_init_message(&message) has been called.
//
// name is the domain name associated with this resource record, and is expected
// to be a null-terminated string. Type must be one of the RR_TYPE* constants
// and specifies the type of rdata. clazz must be one the RR_CLASS* constants
// and specifies the class of rdata. If type or clazz is invalid, a negative
// value is returned and errno is set to EINVAL. rdata and rdlenth are the data
// and its length, respectively. ttl specifies the time interval in seconds that
// the record may be cached before it should be discarded. A ttl of zero means
// that the record should not be cached.
//
// If memory cannot be allocated for the resource record, a negative value is
// returned and errno is set to ENOMEM.
//
// Returns 0 on success.
int mdns_add_answer(mdns_message*,
char* name,
uint16_t type,
uint16_t clazz,
uint8_t* rdata,
uint16_t rdlength,
uint32_t ttl);
// Appends an authority resource record to a message.
//
// See mdns_add_answer for documentation.
int mdns_add_authority(mdns_message*,
char* name,
uint16_t type,
uint16_t clazz,
uint8_t* rdata,
uint16_t rdlength,
uint32_t ttl);
// Appends an additional info resource record to a message.
//
// See mdns_add_answer for documentation.
int mdns_add_additional(mdns_message*,
char* name,
uint16_t type,
uint16_t clazz,
uint8_t* rdata,
uint16_t rdlength,
uint32_t ttl);
// Zeroes all pointers and values associated with the given message.
//
// Clients should free(message) after calling mdns_free_message(message) if the
// message was allocated on the heap.
void mdns_free_message(mdns_message* message);
#ifdef __cplusplus
} // extern "C"
#endif