1 /**
2  * @file dns/hdr.c  DNS header encoding
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <re_types.h>
7 #include <re_fmt.h>
8 #include <re_list.h>
9 #include <re_mbuf.h>
10 #include <re_net.h>
11 #include <re_dns.h>
12 
13 
14 enum {
15 	QUERY_RESPONSE      = 15,
16 	OPCODE              = 11,
17 	AUTH_ANSWER         = 10,
18 	TRUNCATED           =  9,
19 	RECURSION_DESIRED   =  8,
20 	RECURSION_AVAILABLE =  7,
21 	ZERO                =  4
22 };
23 
24 
25 /**
26  * Encode a DNS header
27  *
28  * @param mb  Memory buffer to encode header into
29  * @param hdr DNS header
30  *
31  * @return 0 if success, otherwise errorcode
32  */
33 int dns_hdr_encode(struct mbuf *mb, const struct dnshdr *hdr)
34 {
35 	uint16_t flags = 0;
36 	int err = 0;
37 
38 	if (!mb || !hdr)
39 		return EINVAL;
40 
41 	flags |= hdr->qr     <<QUERY_RESPONSE;
42 	flags |= hdr->opcode <<OPCODE;
43 	flags |= hdr->aa     <<AUTH_ANSWER;
44 	flags |= hdr->tc     <<TRUNCATED;
45 	flags |= hdr->rd     <<RECURSION_DESIRED;
46 	flags |= hdr->ra     <<RECURSION_AVAILABLE;
47 	flags |= hdr->z      <<ZERO;
48 	flags |= hdr->rcode;
49 
50 	err |= mbuf_write_u16(mb, htons(hdr->id));
51 	err |= mbuf_write_u16(mb, htons(flags));
52 	err |= mbuf_write_u16(mb, htons(hdr->nq));
53 	err |= mbuf_write_u16(mb, htons(hdr->nans));
54 	err |= mbuf_write_u16(mb, htons(hdr->nauth));
55 	err |= mbuf_write_u16(mb, htons(hdr->nadd));
56 
57 	return err;
58 }
59 
60 
61 /**
62  * Decode a DNS header from a memory buffer
63  *
64  * @param mb  Memory buffer to decode header from
65  * @param hdr DNS header (output)
66  *
67  * @return 0 if success, otherwise errorcode
68  */
69 int dns_hdr_decode(struct mbuf *mb, struct dnshdr *hdr)
70 {
71 	uint16_t flags = 0;
72 
73 	if (!mb || !hdr || (mbuf_get_left(mb) < DNS_HEADER_SIZE))
74 		return EINVAL;
75 
76 	hdr->id = ntohs(mbuf_read_u16(mb));
77 	flags   = ntohs(mbuf_read_u16(mb));
78 
79 	hdr->qr     = 0x1 & (flags >> QUERY_RESPONSE);
80 	hdr->opcode = 0xf & (flags >> OPCODE);
81 	hdr->aa     = 0x1 & (flags >> AUTH_ANSWER);
82 	hdr->tc     = 0x1 & (flags >> TRUNCATED);
83 	hdr->rd     = 0x1 & (flags >> RECURSION_DESIRED);
84 	hdr->ra     = 0x1 & (flags >> RECURSION_AVAILABLE);
85 	hdr->z      = 0x7 & (flags >> ZERO);
86 	hdr->rcode  = 0xf & (flags >> 0);
87 
88 	hdr->nq    = ntohs(mbuf_read_u16(mb));
89 	hdr->nans  = ntohs(mbuf_read_u16(mb));
90 	hdr->nauth = ntohs(mbuf_read_u16(mb));
91 	hdr->nadd  = ntohs(mbuf_read_u16(mb));
92 
93 	return 0;
94 }
95 
96 
97 /**
98  * Get the string of a DNS opcode
99  *
100  * @param opcode DNS opcode
101  *
102  * @return Opcode string
103  */
104 const char *dns_hdr_opcodename(uint8_t opcode)
105 {
106 	switch (opcode) {
107 
108 	case DNS_OPCODE_QUERY:  return "QUERY";
109 	case DNS_OPCODE_IQUERY: return "IQUERY";
110 	case DNS_OPCODE_STATUS: return "STATUS";
111 	case DNS_OPCODE_NOTIFY: return "NOTIFY";
112 	default:                return "??";
113 	}
114 }
115 
116 
117 /**
118  * Get the string of a DNS response code
119  *
120  * @param rcode Response code
121  *
122  * @return Response code string
123  */
124 const char *dns_hdr_rcodename(uint8_t rcode)
125 {
126 	switch (rcode) {
127 
128 	case DNS_RCODE_OK:       return "OK";
129 	case DNS_RCODE_FMT_ERR:  return "Format Error";
130 	case DNS_RCODE_SRV_FAIL: return "Server Failure";
131 	case DNS_RCODE_NAME_ERR: return "Name Error";
132 	case DNS_RCODE_NOT_IMPL: return "Not Implemented";
133 	case DNS_RCODE_REFUSED:  return "Refused";
134 	case DNS_RCODE_NOT_AUTH: return "Server Not Authoritative for zone";
135 	default:                 return "??";
136 	}
137 }
138