xref: /freebsd/contrib/ldns/host2wire.c (revision 5afab0e5e56fe90a378fb57249600e7924e1cab2)
17b5038d7SDag-Erling Smørgrav /*
27b5038d7SDag-Erling Smørgrav  * host2wire.c
37b5038d7SDag-Erling Smørgrav  *
47b5038d7SDag-Erling Smørgrav  * conversion routines from the host to the wire format.
57b5038d7SDag-Erling Smørgrav  * This will usually just a re-ordering of the
67b5038d7SDag-Erling Smørgrav  * data (as we store it in network format)
77b5038d7SDag-Erling Smørgrav  *
87b5038d7SDag-Erling Smørgrav  * a Net::DNS like library for C
97b5038d7SDag-Erling Smørgrav  *
107b5038d7SDag-Erling Smørgrav  * (c) NLnet Labs, 2004-2006
117b5038d7SDag-Erling Smørgrav  *
127b5038d7SDag-Erling Smørgrav  * See the file LICENSE for the license
137b5038d7SDag-Erling Smørgrav  */
147b5038d7SDag-Erling Smørgrav 
157b5038d7SDag-Erling Smørgrav #include <ldns/config.h>
167b5038d7SDag-Erling Smørgrav 
177b5038d7SDag-Erling Smørgrav #include <ldns/ldns.h>
187b5038d7SDag-Erling Smørgrav 
197b5038d7SDag-Erling Smørgrav ldns_status
ldns_dname2buffer_wire(ldns_buffer * buffer,const ldns_rdf * name)207b5038d7SDag-Erling Smørgrav ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
217b5038d7SDag-Erling Smørgrav {
22986ba33cSDag-Erling Smørgrav 	return ldns_dname2buffer_wire_compress(buffer, name, NULL);
23986ba33cSDag-Erling Smørgrav }
24986ba33cSDag-Erling Smørgrav 
25986ba33cSDag-Erling Smørgrav ldns_status
ldns_dname2buffer_wire_compress(ldns_buffer * buffer,const ldns_rdf * name,ldns_rbtree_t * compression_data)26986ba33cSDag-Erling Smørgrav ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data)
27986ba33cSDag-Erling Smørgrav {
28986ba33cSDag-Erling Smørgrav 	ldns_rbnode_t *node;
29986ba33cSDag-Erling Smørgrav 	uint8_t *data;
30986ba33cSDag-Erling Smørgrav 	size_t size;
31986ba33cSDag-Erling Smørgrav 	ldns_rdf *label;
32986ba33cSDag-Erling Smørgrav 	ldns_rdf *rest;
33986ba33cSDag-Erling Smørgrav 	ldns_status s;
34986ba33cSDag-Erling Smørgrav 
35986ba33cSDag-Erling Smørgrav 	/* If no tree, just add the data */
36986ba33cSDag-Erling Smørgrav 	if(!compression_data)
37986ba33cSDag-Erling Smørgrav 	{
38986ba33cSDag-Erling Smørgrav 		if (ldns_buffer_reserve(buffer, ldns_rdf_size(name)))
39986ba33cSDag-Erling Smørgrav 		{
407b5038d7SDag-Erling Smørgrav 			ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name));
417b5038d7SDag-Erling Smørgrav 		}
427b5038d7SDag-Erling Smørgrav 		return ldns_buffer_status(buffer);
437b5038d7SDag-Erling Smørgrav 	}
447b5038d7SDag-Erling Smørgrav 
45986ba33cSDag-Erling Smørgrav 	/* No labels left, write final zero */
46986ba33cSDag-Erling Smørgrav 	if(ldns_dname_label_count(name)==0)
47986ba33cSDag-Erling Smørgrav 	{
48986ba33cSDag-Erling Smørgrav 		if(ldns_buffer_reserve(buffer,1))
49986ba33cSDag-Erling Smørgrav 		{
50986ba33cSDag-Erling Smørgrav 			ldns_buffer_write_u8(buffer, 0);
51986ba33cSDag-Erling Smørgrav 		}
52986ba33cSDag-Erling Smørgrav 		return ldns_buffer_status(buffer);
53986ba33cSDag-Erling Smørgrav 	}
54986ba33cSDag-Erling Smørgrav 
55986ba33cSDag-Erling Smørgrav 	/* Can we find the name in the tree? */
56986ba33cSDag-Erling Smørgrav 	if((node = ldns_rbtree_search(compression_data, name)) != NULL)
57986ba33cSDag-Erling Smørgrav 	{
58986ba33cSDag-Erling Smørgrav 		/* Found */
59986ba33cSDag-Erling Smørgrav 		uint16_t position = (uint16_t) (intptr_t) node->data | 0xC000;
60986ba33cSDag-Erling Smørgrav 		if (ldns_buffer_reserve(buffer, 2))
61986ba33cSDag-Erling Smørgrav 		{
62986ba33cSDag-Erling Smørgrav 			ldns_buffer_write_u16(buffer, position);
63986ba33cSDag-Erling Smørgrav 		}
64986ba33cSDag-Erling Smørgrav 		return ldns_buffer_status(buffer);
65986ba33cSDag-Erling Smørgrav 	}
66986ba33cSDag-Erling Smørgrav 	else
67986ba33cSDag-Erling Smørgrav 	{
68986ba33cSDag-Erling Smørgrav 		/* Not found. Write cache entry, take off first label, write it, */
69986ba33cSDag-Erling Smørgrav 		/* try again with the rest of the name. */
70*5afab0e5SDag-Erling Smørgrav 		if (ldns_buffer_position(buffer) < 16384) {
71*5afab0e5SDag-Erling Smørgrav 			ldns_rdf *key;
72*5afab0e5SDag-Erling Smørgrav 
73986ba33cSDag-Erling Smørgrav 			node = LDNS_MALLOC(ldns_rbnode_t);
74986ba33cSDag-Erling Smørgrav 			if(!node)
75986ba33cSDag-Erling Smørgrav 			{
76986ba33cSDag-Erling Smørgrav 				return LDNS_STATUS_MEM_ERR;
77986ba33cSDag-Erling Smørgrav 			}
78*5afab0e5SDag-Erling Smørgrav 
79*5afab0e5SDag-Erling Smørgrav 			key = ldns_rdf_clone(name);
80*5afab0e5SDag-Erling Smørgrav 			if (!key) {
81*5afab0e5SDag-Erling Smørgrav 				LDNS_FREE(node);
82*5afab0e5SDag-Erling Smørgrav 				return LDNS_STATUS_MEM_ERR;
83*5afab0e5SDag-Erling Smørgrav 			}
84*5afab0e5SDag-Erling Smørgrav 			node->key = key;
85986ba33cSDag-Erling Smørgrav 			node->data = (void *) (intptr_t) ldns_buffer_position(buffer);
86986ba33cSDag-Erling Smørgrav 			if(!ldns_rbtree_insert(compression_data,node))
87986ba33cSDag-Erling Smørgrav 			{
88986ba33cSDag-Erling Smørgrav 				/* fprintf(stderr,"Name not found but now it's there?\n"); */
89*5afab0e5SDag-Erling Smørgrav 				ldns_rdf_deep_free(key);
90*5afab0e5SDag-Erling Smørgrav 				LDNS_FREE(node);
91986ba33cSDag-Erling Smørgrav 			}
92986ba33cSDag-Erling Smørgrav 		}
93986ba33cSDag-Erling Smørgrav 		label = ldns_dname_label(name, 0);
94986ba33cSDag-Erling Smørgrav 		rest = ldns_dname_left_chop(name);
95986ba33cSDag-Erling Smørgrav 		size = ldns_rdf_size(label) - 1; /* Don't want the final zero */
96986ba33cSDag-Erling Smørgrav 		data = ldns_rdf_data(label);
97986ba33cSDag-Erling Smørgrav 		if(ldns_buffer_reserve(buffer, size))
98986ba33cSDag-Erling Smørgrav 		{
99986ba33cSDag-Erling Smørgrav 			ldns_buffer_write(buffer, data, size);
100986ba33cSDag-Erling Smørgrav 		}
101986ba33cSDag-Erling Smørgrav 		ldns_rdf_deep_free(label);
102986ba33cSDag-Erling Smørgrav 		s = ldns_dname2buffer_wire_compress(buffer, rest, compression_data);
103986ba33cSDag-Erling Smørgrav 		ldns_rdf_deep_free(rest);
104986ba33cSDag-Erling Smørgrav 		return s;
105986ba33cSDag-Erling Smørgrav 	}
106986ba33cSDag-Erling Smørgrav }
107986ba33cSDag-Erling Smørgrav 
1087b5038d7SDag-Erling Smørgrav ldns_status
ldns_rdf2buffer_wire(ldns_buffer * buffer,const ldns_rdf * rdf)1097b5038d7SDag-Erling Smørgrav ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
1107b5038d7SDag-Erling Smørgrav {
111986ba33cSDag-Erling Smørgrav 	return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL);
112986ba33cSDag-Erling Smørgrav }
113986ba33cSDag-Erling Smørgrav 
114986ba33cSDag-Erling Smørgrav ldns_status
ldns_rdf2buffer_wire_compress(ldns_buffer * buffer,const ldns_rdf * rdf,ldns_rbtree_t * compression_data)115986ba33cSDag-Erling Smørgrav ldns_rdf2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *rdf, ldns_rbtree_t *compression_data)
116986ba33cSDag-Erling Smørgrav {
117986ba33cSDag-Erling Smørgrav 	/* If it's a DNAME, call that function to get compression */
118986ba33cSDag-Erling Smørgrav 	if(compression_data && ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME)
119986ba33cSDag-Erling Smørgrav 	{
120986ba33cSDag-Erling Smørgrav 		return ldns_dname2buffer_wire_compress(buffer,rdf,compression_data);
121986ba33cSDag-Erling Smørgrav 	}
122986ba33cSDag-Erling Smørgrav 
1237b5038d7SDag-Erling Smørgrav 	if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
1247b5038d7SDag-Erling Smørgrav 		ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf));
1257b5038d7SDag-Erling Smørgrav 	}
1267b5038d7SDag-Erling Smørgrav 	return ldns_buffer_status(buffer);
1277b5038d7SDag-Erling Smørgrav }
1287b5038d7SDag-Erling Smørgrav 
1297b5038d7SDag-Erling Smørgrav ldns_status
ldns_rdf2buffer_wire_canonical(ldns_buffer * buffer,const ldns_rdf * rdf)1307b5038d7SDag-Erling Smørgrav ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf)
1317b5038d7SDag-Erling Smørgrav {
1327b5038d7SDag-Erling Smørgrav 	size_t i;
1337b5038d7SDag-Erling Smørgrav 	uint8_t *rdf_data;
1347b5038d7SDag-Erling Smørgrav 
1357b5038d7SDag-Erling Smørgrav 	if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) {
1367b5038d7SDag-Erling Smørgrav 		if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
1377b5038d7SDag-Erling Smørgrav 			rdf_data = ldns_rdf_data(rdf);
1387b5038d7SDag-Erling Smørgrav 			for (i = 0; i < ldns_rdf_size(rdf); i++) {
1397b5038d7SDag-Erling Smørgrav 				ldns_buffer_write_u8(buffer,
1407b5038d7SDag-Erling Smørgrav 				    (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i]));
1417b5038d7SDag-Erling Smørgrav 			}
1427b5038d7SDag-Erling Smørgrav 		}
1437b5038d7SDag-Erling Smørgrav 	} else {
1447b5038d7SDag-Erling Smørgrav 		/* direct copy for all other types */
1457b5038d7SDag-Erling Smørgrav 		if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
1467b5038d7SDag-Erling Smørgrav 			ldns_buffer_write(buffer,
1477b5038d7SDag-Erling Smørgrav 						   ldns_rdf_data(rdf),
1487b5038d7SDag-Erling Smørgrav 						   ldns_rdf_size(rdf));
1497b5038d7SDag-Erling Smørgrav 		}
1507b5038d7SDag-Erling Smørgrav 	}
1517b5038d7SDag-Erling Smørgrav 	return ldns_buffer_status(buffer);
1527b5038d7SDag-Erling Smørgrav }
1537b5038d7SDag-Erling Smørgrav 
1547b5038d7SDag-Erling Smørgrav /* convert a rr list to wireformat */
1557b5038d7SDag-Erling Smørgrav ldns_status
ldns_rr_list2buffer_wire(ldns_buffer * buffer,const ldns_rr_list * rr_list)1567b5038d7SDag-Erling Smørgrav ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list)
1577b5038d7SDag-Erling Smørgrav {
1587b5038d7SDag-Erling Smørgrav 	uint16_t rr_count;
1597b5038d7SDag-Erling Smørgrav 	uint16_t i;
1607b5038d7SDag-Erling Smørgrav 
1617b5038d7SDag-Erling Smørgrav 	rr_count = ldns_rr_list_rr_count(rr_list);
1627b5038d7SDag-Erling Smørgrav 	for(i = 0; i < rr_count; i++) {
1637b5038d7SDag-Erling Smørgrav 		(void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i),
1647b5038d7SDag-Erling Smørgrav 					  LDNS_SECTION_ANY);
1657b5038d7SDag-Erling Smørgrav 	}
1667b5038d7SDag-Erling Smørgrav 	return ldns_buffer_status(buffer);
1677b5038d7SDag-Erling Smørgrav }
1687b5038d7SDag-Erling Smørgrav 
16917d15b25SDag-Erling Smørgrav 
1707b5038d7SDag-Erling Smørgrav ldns_status
ldns_rr2buffer_wire_canonical(ldns_buffer * buffer,const ldns_rr * rr,int section)1717b5038d7SDag-Erling Smørgrav ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
1727b5038d7SDag-Erling Smørgrav 						const ldns_rr *rr,
1737b5038d7SDag-Erling Smørgrav 						int section)
1747b5038d7SDag-Erling Smørgrav {
1757b5038d7SDag-Erling Smørgrav 	uint16_t i;
1767b5038d7SDag-Erling Smørgrav 	uint16_t rdl_pos = 0;
1777b5038d7SDag-Erling Smørgrav 	bool pre_rfc3597 = false;
1787b5038d7SDag-Erling Smørgrav 	switch (ldns_rr_get_type(rr)) {
1797b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_NS:
1807b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_MD:
1817b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_MF:
1827b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_CNAME:
1837b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_SOA:
1847b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_MB:
1857b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_MG:
1867b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_MR:
1877b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_PTR:
1887b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_HINFO:
1897b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_MINFO:
1907b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_MX:
1917b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_RP:
1927b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_AFSDB:
1937b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_RT:
1947b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_SIG:
1957b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_PX:
1967b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_NXT:
1977b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_NAPTR:
1987b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_KX:
1997b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_SRV:
2007b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_DNAME:
2017b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_A6:
2027b5038d7SDag-Erling Smørgrav 	case LDNS_RR_TYPE_RRSIG:
2037b5038d7SDag-Erling Smørgrav 		pre_rfc3597 = true;
2047b5038d7SDag-Erling Smørgrav 		break;
2057b5038d7SDag-Erling Smørgrav 	default:
2067b5038d7SDag-Erling Smørgrav 		break;
2077b5038d7SDag-Erling Smørgrav 	}
2087b5038d7SDag-Erling Smørgrav 
2097b5038d7SDag-Erling Smørgrav 	if (ldns_rr_owner(rr)) {
2107b5038d7SDag-Erling Smørgrav 		(void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr));
2117b5038d7SDag-Erling Smørgrav 	}
2127b5038d7SDag-Erling Smørgrav 
2137b5038d7SDag-Erling Smørgrav 	if (ldns_buffer_reserve(buffer, 4)) {
2147b5038d7SDag-Erling Smørgrav 		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
2157b5038d7SDag-Erling Smørgrav 		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
2167b5038d7SDag-Erling Smørgrav 	}
2177b5038d7SDag-Erling Smørgrav 
2187b5038d7SDag-Erling Smørgrav 	if (section != LDNS_SECTION_QUESTION) {
2197b5038d7SDag-Erling Smørgrav 		if (ldns_buffer_reserve(buffer, 6)) {
2207b5038d7SDag-Erling Smørgrav 			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
2217b5038d7SDag-Erling Smørgrav 			/* remember pos for later */
2227b5038d7SDag-Erling Smørgrav 			rdl_pos = ldns_buffer_position(buffer);
2237b5038d7SDag-Erling Smørgrav 			ldns_buffer_write_u16(buffer, 0);
2247b5038d7SDag-Erling Smørgrav 		}
2257b5038d7SDag-Erling Smørgrav 		for (i = 0; i < ldns_rr_rd_count(rr); i++) {
2267b5038d7SDag-Erling Smørgrav 			if (pre_rfc3597) {
2277b5038d7SDag-Erling Smørgrav 				(void) ldns_rdf2buffer_wire_canonical(
2287b5038d7SDag-Erling Smørgrav 					buffer, ldns_rr_rdf(rr, i));
2297b5038d7SDag-Erling Smørgrav 			} else {
2307b5038d7SDag-Erling Smørgrav 				(void) ldns_rdf2buffer_wire(
2317b5038d7SDag-Erling Smørgrav 					buffer, ldns_rr_rdf(rr, i));
2327b5038d7SDag-Erling Smørgrav 			}
2337b5038d7SDag-Erling Smørgrav 		}
2347b5038d7SDag-Erling Smørgrav 		if (rdl_pos != 0) {
2357b5038d7SDag-Erling Smørgrav 			ldns_buffer_write_u16_at(buffer, rdl_pos,
2367b5038d7SDag-Erling Smørgrav 			                         ldns_buffer_position(buffer)
2377b5038d7SDag-Erling Smørgrav 		        	                   - rdl_pos - 2);
2387b5038d7SDag-Erling Smørgrav 		}
2397b5038d7SDag-Erling Smørgrav 	}
2407b5038d7SDag-Erling Smørgrav 	return ldns_buffer_status(buffer);
2417b5038d7SDag-Erling Smørgrav }
2427b5038d7SDag-Erling Smørgrav 
2437b5038d7SDag-Erling Smørgrav ldns_status
ldns_rr2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr,int section)2447b5038d7SDag-Erling Smørgrav ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
2457b5038d7SDag-Erling Smørgrav {
246986ba33cSDag-Erling Smørgrav 	return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL);
247986ba33cSDag-Erling Smørgrav }
248986ba33cSDag-Erling Smørgrav 
249986ba33cSDag-Erling Smørgrav ldns_status
ldns_rr2buffer_wire_compress(ldns_buffer * buffer,const ldns_rr * rr,int section,ldns_rbtree_t * compression_data)250986ba33cSDag-Erling Smørgrav ldns_rr2buffer_wire_compress(ldns_buffer *buffer, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data)
251986ba33cSDag-Erling Smørgrav {
2527b5038d7SDag-Erling Smørgrav 	uint16_t i;
2537b5038d7SDag-Erling Smørgrav 	uint16_t rdl_pos = 0;
2547b5038d7SDag-Erling Smørgrav 
2557b5038d7SDag-Erling Smørgrav 	if (ldns_rr_owner(rr)) {
256986ba33cSDag-Erling Smørgrav 		(void) ldns_dname2buffer_wire_compress(buffer, ldns_rr_owner(rr), compression_data);
2577b5038d7SDag-Erling Smørgrav 	}
2587b5038d7SDag-Erling Smørgrav 
2597b5038d7SDag-Erling Smørgrav 	if (ldns_buffer_reserve(buffer, 4)) {
2607b5038d7SDag-Erling Smørgrav 		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr));
2617b5038d7SDag-Erling Smørgrav 		(void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr));
2627b5038d7SDag-Erling Smørgrav 	}
2637b5038d7SDag-Erling Smørgrav 
2647b5038d7SDag-Erling Smørgrav 	if (section != LDNS_SECTION_QUESTION) {
2657b5038d7SDag-Erling Smørgrav 		if (ldns_buffer_reserve(buffer, 6)) {
2667b5038d7SDag-Erling Smørgrav 			ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr));
2677b5038d7SDag-Erling Smørgrav 			/* remember pos for later */
2687b5038d7SDag-Erling Smørgrav 			rdl_pos = ldns_buffer_position(buffer);
2697b5038d7SDag-Erling Smørgrav 			ldns_buffer_write_u16(buffer, 0);
2707b5038d7SDag-Erling Smørgrav 		}
271986ba33cSDag-Erling Smørgrav 		if (LDNS_RR_COMPRESS ==
272986ba33cSDag-Erling Smørgrav 		    ldns_rr_descript(ldns_rr_get_type(rr))->_compress) {
273986ba33cSDag-Erling Smørgrav 
274986ba33cSDag-Erling Smørgrav 			for (i = 0; i < ldns_rr_rd_count(rr); i++) {
275986ba33cSDag-Erling Smørgrav 				(void) ldns_rdf2buffer_wire_compress(buffer,
276986ba33cSDag-Erling Smørgrav 				    ldns_rr_rdf(rr, i), compression_data);
277986ba33cSDag-Erling Smørgrav 			}
278986ba33cSDag-Erling Smørgrav 		} else {
2797b5038d7SDag-Erling Smørgrav 			for (i = 0; i < ldns_rr_rd_count(rr); i++) {
2807b5038d7SDag-Erling Smørgrav 				(void) ldns_rdf2buffer_wire(
2817b5038d7SDag-Erling Smørgrav 				    buffer, ldns_rr_rdf(rr, i));
2827b5038d7SDag-Erling Smørgrav 			}
283986ba33cSDag-Erling Smørgrav 		}
2847b5038d7SDag-Erling Smørgrav 		if (rdl_pos != 0) {
2857b5038d7SDag-Erling Smørgrav 			ldns_buffer_write_u16_at(buffer, rdl_pos,
2867b5038d7SDag-Erling Smørgrav 			                         ldns_buffer_position(buffer)
2877b5038d7SDag-Erling Smørgrav 		        	                   - rdl_pos - 2);
2887b5038d7SDag-Erling Smørgrav 		}
2897b5038d7SDag-Erling Smørgrav 	}
2907b5038d7SDag-Erling Smørgrav 	return ldns_buffer_status(buffer);
2917b5038d7SDag-Erling Smørgrav }
2927b5038d7SDag-Erling Smørgrav 
2937b5038d7SDag-Erling Smørgrav ldns_status
ldns_rrsig2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr)2947b5038d7SDag-Erling Smørgrav ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
2957b5038d7SDag-Erling Smørgrav {
2967b5038d7SDag-Erling Smørgrav 	uint16_t i;
2977b5038d7SDag-Erling Smørgrav 
2987b5038d7SDag-Erling Smørgrav 	/* it must be a sig RR */
2997b5038d7SDag-Erling Smørgrav 	if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
3007b5038d7SDag-Erling Smørgrav 		return LDNS_STATUS_ERR;
3017b5038d7SDag-Erling Smørgrav 	}
3027b5038d7SDag-Erling Smørgrav 
3037b5038d7SDag-Erling Smørgrav 	/* Convert all the rdfs, except the actual signature data
3047b5038d7SDag-Erling Smørgrav 	 * rdf number 8  - the last, hence: -1 */
3057b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) {
30617d15b25SDag-Erling Smørgrav 		(void) ldns_rdf2buffer_wire_canonical(buffer,
30717d15b25SDag-Erling Smørgrav 				ldns_rr_rdf(rr, i));
3087b5038d7SDag-Erling Smørgrav 	}
3097b5038d7SDag-Erling Smørgrav 
3107b5038d7SDag-Erling Smørgrav 	return ldns_buffer_status(buffer);
3117b5038d7SDag-Erling Smørgrav }
3127b5038d7SDag-Erling Smørgrav 
3137b5038d7SDag-Erling Smørgrav ldns_status
ldns_rr_rdata2buffer_wire(ldns_buffer * buffer,const ldns_rr * rr)3147b5038d7SDag-Erling Smørgrav ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
3157b5038d7SDag-Erling Smørgrav {
3167b5038d7SDag-Erling Smørgrav 	uint16_t i;
317986ba33cSDag-Erling Smørgrav 
3187b5038d7SDag-Erling Smørgrav 	/* convert all the rdf's */
3197b5038d7SDag-Erling Smørgrav 	for (i = 0; i < ldns_rr_rd_count(rr); i++) {
3207b5038d7SDag-Erling Smørgrav 		(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr,i));
3217b5038d7SDag-Erling Smørgrav 	}
3227b5038d7SDag-Erling Smørgrav 	return ldns_buffer_status(buffer);
3237b5038d7SDag-Erling Smørgrav }
3247b5038d7SDag-Erling Smørgrav 
3257b5038d7SDag-Erling Smørgrav /*
3267b5038d7SDag-Erling Smørgrav  * Copies the packet header data to the buffer in wire format
3277b5038d7SDag-Erling Smørgrav  */
3287b5038d7SDag-Erling Smørgrav static ldns_status
ldns_hdr2buffer_wire(ldns_buffer * buffer,const ldns_pkt * packet)3297b5038d7SDag-Erling Smørgrav ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
3307b5038d7SDag-Erling Smørgrav {
3317b5038d7SDag-Erling Smørgrav 	uint8_t flags;
3327b5038d7SDag-Erling Smørgrav 	uint16_t arcount;
3337b5038d7SDag-Erling Smørgrav 
3347b5038d7SDag-Erling Smørgrav 	if (ldns_buffer_reserve(buffer, 12)) {
3357b5038d7SDag-Erling Smørgrav 		ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
3367b5038d7SDag-Erling Smørgrav 
3377b5038d7SDag-Erling Smørgrav 		flags = ldns_pkt_qr(packet) << 7
3387b5038d7SDag-Erling Smørgrav 		        | ldns_pkt_get_opcode(packet) << 3
3397b5038d7SDag-Erling Smørgrav 		        | ldns_pkt_aa(packet) << 2
3407b5038d7SDag-Erling Smørgrav 		        | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet);
3417b5038d7SDag-Erling Smørgrav 		ldns_buffer_write_u8(buffer, flags);
3427b5038d7SDag-Erling Smørgrav 
3437b5038d7SDag-Erling Smørgrav 		flags = ldns_pkt_ra(packet) << 7
3447b5038d7SDag-Erling Smørgrav 		        /*| ldns_pkt_z(packet) << 6*/
3457b5038d7SDag-Erling Smørgrav 		        | ldns_pkt_ad(packet) << 5
34617d15b25SDag-Erling Smørgrav 		        | ldns_pkt_cd(packet) << 4
34717d15b25SDag-Erling Smørgrav 			| ldns_pkt_get_rcode(packet);
3487b5038d7SDag-Erling Smørgrav 		ldns_buffer_write_u8(buffer, flags);
3497b5038d7SDag-Erling Smørgrav 
3507b5038d7SDag-Erling Smørgrav 		ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet));
3517b5038d7SDag-Erling Smørgrav 		ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet));
3527b5038d7SDag-Erling Smørgrav 		ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet));
3537b5038d7SDag-Erling Smørgrav 		/* add EDNS0 and TSIG to additional if they are there */
3547b5038d7SDag-Erling Smørgrav 		arcount = ldns_pkt_arcount(packet);
3557b5038d7SDag-Erling Smørgrav 		if (ldns_pkt_tsig(packet)) {
3567b5038d7SDag-Erling Smørgrav 			arcount++;
3577b5038d7SDag-Erling Smørgrav 		}
3587b5038d7SDag-Erling Smørgrav 		if (ldns_pkt_edns(packet)) {
3597b5038d7SDag-Erling Smørgrav 			arcount++;
3607b5038d7SDag-Erling Smørgrav 		}
3617b5038d7SDag-Erling Smørgrav 		ldns_buffer_write_u16(buffer, arcount);
3627b5038d7SDag-Erling Smørgrav 	}
3637b5038d7SDag-Erling Smørgrav 
3647b5038d7SDag-Erling Smørgrav 	return ldns_buffer_status(buffer);
3657b5038d7SDag-Erling Smørgrav }
3667b5038d7SDag-Erling Smørgrav 
367986ba33cSDag-Erling Smørgrav static void
compression_node_free(ldns_rbnode_t * node,void * arg)368986ba33cSDag-Erling Smørgrav compression_node_free(ldns_rbnode_t *node, void *arg)
369986ba33cSDag-Erling Smørgrav {
370986ba33cSDag-Erling Smørgrav 	(void)arg; /* Yes, dear compiler, it is used */
371986ba33cSDag-Erling Smørgrav 	ldns_rdf_deep_free((ldns_rdf *)node->key);
372986ba33cSDag-Erling Smørgrav 	LDNS_FREE(node);
373986ba33cSDag-Erling Smørgrav }
374986ba33cSDag-Erling Smørgrav 
3757b5038d7SDag-Erling Smørgrav ldns_status
ldns_pkt2buffer_wire(ldns_buffer * buffer,const ldns_pkt * packet)3767b5038d7SDag-Erling Smørgrav ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
3777b5038d7SDag-Erling Smørgrav {
378*5afab0e5SDag-Erling Smørgrav 	ldns_status status;
379*5afab0e5SDag-Erling Smørgrav 	ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare);
380*5afab0e5SDag-Erling Smørgrav 
381*5afab0e5SDag-Erling Smørgrav 	status = ldns_pkt2buffer_wire_compress(buffer, packet, compression_data);
382*5afab0e5SDag-Erling Smørgrav 
383*5afab0e5SDag-Erling Smørgrav 	ldns_traverse_postorder(compression_data,compression_node_free,NULL);
384*5afab0e5SDag-Erling Smørgrav 	ldns_rbtree_free(compression_data);
385*5afab0e5SDag-Erling Smørgrav 
386*5afab0e5SDag-Erling Smørgrav 	return status;
387*5afab0e5SDag-Erling Smørgrav }
388*5afab0e5SDag-Erling Smørgrav 
389*5afab0e5SDag-Erling Smørgrav ldns_status
ldns_pkt2buffer_wire_compress(ldns_buffer * buffer,const ldns_pkt * packet,ldns_rbtree_t * compression_data)390*5afab0e5SDag-Erling Smørgrav ldns_pkt2buffer_wire_compress(ldns_buffer *buffer, const ldns_pkt *packet, ldns_rbtree_t *compression_data)
391*5afab0e5SDag-Erling Smørgrav {
3927b5038d7SDag-Erling Smørgrav 	ldns_rr_list *rr_list;
3937b5038d7SDag-Erling Smørgrav 	uint16_t i;
3947b5038d7SDag-Erling Smørgrav 
3957b5038d7SDag-Erling Smørgrav 	/* edns tmp vars */
3967b5038d7SDag-Erling Smørgrav 	ldns_rr *edns_rr;
3977b5038d7SDag-Erling Smørgrav 	uint8_t edata[4];
3987b5038d7SDag-Erling Smørgrav 
399*5afab0e5SDag-Erling Smørgrav 	ldns_buffer *edns_buf = NULL;
400*5afab0e5SDag-Erling Smørgrav 	ldns_rdf    *edns_rdf = NULL;
401986ba33cSDag-Erling Smørgrav 
4027b5038d7SDag-Erling Smørgrav 	(void) ldns_hdr2buffer_wire(buffer, packet);
4037b5038d7SDag-Erling Smørgrav 
4047b5038d7SDag-Erling Smørgrav 	rr_list = ldns_pkt_question(packet);
4057b5038d7SDag-Erling Smørgrav 	if (rr_list) {
4067b5038d7SDag-Erling Smørgrav 		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
407986ba33cSDag-Erling Smørgrav 			(void) ldns_rr2buffer_wire_compress(buffer,
408986ba33cSDag-Erling Smørgrav 			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION, compression_data);
4097b5038d7SDag-Erling Smørgrav 		}
4107b5038d7SDag-Erling Smørgrav 	}
4117b5038d7SDag-Erling Smørgrav 	rr_list = ldns_pkt_answer(packet);
4127b5038d7SDag-Erling Smørgrav 	if (rr_list) {
4137b5038d7SDag-Erling Smørgrav 		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
414986ba33cSDag-Erling Smørgrav 			(void) ldns_rr2buffer_wire_compress(buffer,
415986ba33cSDag-Erling Smørgrav 			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER, compression_data);
4167b5038d7SDag-Erling Smørgrav 		}
4177b5038d7SDag-Erling Smørgrav 	}
4187b5038d7SDag-Erling Smørgrav 	rr_list = ldns_pkt_authority(packet);
4197b5038d7SDag-Erling Smørgrav 	if (rr_list) {
4207b5038d7SDag-Erling Smørgrav 		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
421986ba33cSDag-Erling Smørgrav 			(void) ldns_rr2buffer_wire_compress(buffer,
422986ba33cSDag-Erling Smørgrav 			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY, compression_data);
4237b5038d7SDag-Erling Smørgrav 		}
4247b5038d7SDag-Erling Smørgrav 	}
4257b5038d7SDag-Erling Smørgrav 	rr_list = ldns_pkt_additional(packet);
4267b5038d7SDag-Erling Smørgrav 	if (rr_list) {
4277b5038d7SDag-Erling Smørgrav 		for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
428986ba33cSDag-Erling Smørgrav 			(void) ldns_rr2buffer_wire_compress(buffer,
429986ba33cSDag-Erling Smørgrav 			             ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL, compression_data);
4307b5038d7SDag-Erling Smørgrav 		}
4317b5038d7SDag-Erling Smørgrav 	}
4327b5038d7SDag-Erling Smørgrav 
4337b5038d7SDag-Erling Smørgrav 	/* add EDNS to additional if it is needed */
4347b5038d7SDag-Erling Smørgrav 	if (ldns_pkt_edns(packet)) {
4357b5038d7SDag-Erling Smørgrav 		edns_rr = ldns_rr_new();
4367b5038d7SDag-Erling Smørgrav 		if(!edns_rr) return LDNS_STATUS_MEM_ERR;
4377b5038d7SDag-Erling Smørgrav 		ldns_rr_set_owner(edns_rr,
4387b5038d7SDag-Erling Smørgrav 				ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "."));
4397b5038d7SDag-Erling Smørgrav 		ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT);
4407b5038d7SDag-Erling Smørgrav 		ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet));
4417b5038d7SDag-Erling Smørgrav 		edata[0] = ldns_pkt_edns_extended_rcode(packet);
4427b5038d7SDag-Erling Smørgrav 		edata[1] = ldns_pkt_edns_version(packet);
4437b5038d7SDag-Erling Smørgrav 		ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet));
4447b5038d7SDag-Erling Smørgrav 		ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata));
4457b5038d7SDag-Erling Smørgrav 		/* don't forget to add the edns rdata (if any) */
446*5afab0e5SDag-Erling Smørgrav 		if ((edns_buf = ldns_edns_option_list2wireformat_buffer(packet->_edns_list))) {
447*5afab0e5SDag-Erling Smørgrav 			edns_rdf = ldns_rdf_new( LDNS_RDF_TYPE_UNKNOWN
448*5afab0e5SDag-Erling Smørgrav 			                       , ldns_buffer_limit(edns_buf)
449*5afab0e5SDag-Erling Smørgrav 			                       , ldns_buffer_export(edns_buf));
450*5afab0e5SDag-Erling Smørgrav 			ldns_buffer_free(edns_buf);
451*5afab0e5SDag-Erling Smørgrav 		}
452*5afab0e5SDag-Erling Smørgrav 		if (edns_rdf)
453*5afab0e5SDag-Erling Smørgrav 			ldns_rr_push_rdf(edns_rr, edns_rdf);
454*5afab0e5SDag-Erling Smørgrav 		else if (packet->_edns_data)
4557b5038d7SDag-Erling Smørgrav 			ldns_rr_push_rdf(edns_rr, packet->_edns_data);
456986ba33cSDag-Erling Smørgrav 		(void)ldns_rr2buffer_wire_compress(buffer, edns_rr, LDNS_SECTION_ADDITIONAL, compression_data);
457*5afab0e5SDag-Erling Smørgrav 		/* if the rdata of the OPT came from packet->_edns_data
458*5afab0e5SDag-Erling Smørgrav 		 * we need to take it back out of the edns_rr before we free it
459*5afab0e5SDag-Erling Smørgrav 		 * so packet->_edns_data doesn't get freed
460*5afab0e5SDag-Erling Smørgrav 		 */
461*5afab0e5SDag-Erling Smørgrav 		if (!edns_rdf && packet->_edns_data)
4627b5038d7SDag-Erling Smørgrav 			(void)ldns_rr_pop_rdf (edns_rr);
4637b5038d7SDag-Erling Smørgrav 		ldns_rr_free(edns_rr);
4647b5038d7SDag-Erling Smørgrav 	}
4657b5038d7SDag-Erling Smørgrav 
4667b5038d7SDag-Erling Smørgrav 	/* add TSIG to additional if it is there */
4677b5038d7SDag-Erling Smørgrav 	if (ldns_pkt_tsig(packet)) {
468986ba33cSDag-Erling Smørgrav 		(void) ldns_rr2buffer_wire_compress(buffer,
469986ba33cSDag-Erling Smørgrav 		                           ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL, compression_data);
4707b5038d7SDag-Erling Smørgrav 	}
4717b5038d7SDag-Erling Smørgrav 
4727b5038d7SDag-Erling Smørgrav 	return LDNS_STATUS_OK;
4737b5038d7SDag-Erling Smørgrav }
4747b5038d7SDag-Erling Smørgrav 
4757b5038d7SDag-Erling Smørgrav ldns_status
ldns_rdf2wire(uint8_t ** dest,const ldns_rdf * rdf,size_t * result_size)4767b5038d7SDag-Erling Smørgrav ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size)
4777b5038d7SDag-Erling Smørgrav {
4787b5038d7SDag-Erling Smørgrav 	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
4797b5038d7SDag-Erling Smørgrav 	ldns_status status;
4807b5038d7SDag-Erling Smørgrav 	*result_size = 0;
4817b5038d7SDag-Erling Smørgrav 	*dest = NULL;
4827b5038d7SDag-Erling Smørgrav 	if(!buffer) return LDNS_STATUS_MEM_ERR;
4837b5038d7SDag-Erling Smørgrav 
4847b5038d7SDag-Erling Smørgrav 	status = ldns_rdf2buffer_wire(buffer, rdf);
4857b5038d7SDag-Erling Smørgrav 	if (status == LDNS_STATUS_OK) {
4867b5038d7SDag-Erling Smørgrav 		*result_size =  ldns_buffer_position(buffer);
4872787e39aSDag-Erling Smørgrav 		*dest = (uint8_t *) ldns_buffer_export(buffer);
4887b5038d7SDag-Erling Smørgrav 	}
4897b5038d7SDag-Erling Smørgrav 	ldns_buffer_free(buffer);
4907b5038d7SDag-Erling Smørgrav 	return status;
4917b5038d7SDag-Erling Smørgrav }
4927b5038d7SDag-Erling Smørgrav 
4937b5038d7SDag-Erling Smørgrav ldns_status
ldns_rr2wire(uint8_t ** dest,const ldns_rr * rr,int section,size_t * result_size)4947b5038d7SDag-Erling Smørgrav ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size)
4957b5038d7SDag-Erling Smørgrav {
4967b5038d7SDag-Erling Smørgrav 	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
4977b5038d7SDag-Erling Smørgrav 	ldns_status status;
4987b5038d7SDag-Erling Smørgrav 	*result_size = 0;
4997b5038d7SDag-Erling Smørgrav 	*dest = NULL;
5007b5038d7SDag-Erling Smørgrav 	if(!buffer) return LDNS_STATUS_MEM_ERR;
5017b5038d7SDag-Erling Smørgrav 
5027b5038d7SDag-Erling Smørgrav 	status = ldns_rr2buffer_wire(buffer, rr, section);
5037b5038d7SDag-Erling Smørgrav 	if (status == LDNS_STATUS_OK) {
5047b5038d7SDag-Erling Smørgrav 		*result_size =  ldns_buffer_position(buffer);
5052787e39aSDag-Erling Smørgrav 		*dest = (uint8_t *) ldns_buffer_export(buffer);
5067b5038d7SDag-Erling Smørgrav 	}
5077b5038d7SDag-Erling Smørgrav 	ldns_buffer_free(buffer);
5087b5038d7SDag-Erling Smørgrav 	return status;
5097b5038d7SDag-Erling Smørgrav }
5107b5038d7SDag-Erling Smørgrav 
5117b5038d7SDag-Erling Smørgrav ldns_status
ldns_pkt2wire(uint8_t ** dest,const ldns_pkt * packet,size_t * result_size)5127b5038d7SDag-Erling Smørgrav ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size)
5137b5038d7SDag-Erling Smørgrav {
5147b5038d7SDag-Erling Smørgrav 	ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN);
5157b5038d7SDag-Erling Smørgrav 	ldns_status status;
5167b5038d7SDag-Erling Smørgrav 	*result_size = 0;
5177b5038d7SDag-Erling Smørgrav 	*dest = NULL;
5187b5038d7SDag-Erling Smørgrav 	if(!buffer) return LDNS_STATUS_MEM_ERR;
5197b5038d7SDag-Erling Smørgrav 
5207b5038d7SDag-Erling Smørgrav 	status = ldns_pkt2buffer_wire(buffer, packet);
5217b5038d7SDag-Erling Smørgrav 	if (status == LDNS_STATUS_OK) {
5227b5038d7SDag-Erling Smørgrav 		*result_size =  ldns_buffer_position(buffer);
5232787e39aSDag-Erling Smørgrav 		*dest = (uint8_t *) ldns_buffer_export(buffer);
5247b5038d7SDag-Erling Smørgrav 	}
5257b5038d7SDag-Erling Smørgrav 	ldns_buffer_free(buffer);
5267b5038d7SDag-Erling Smørgrav 	return status;
5277b5038d7SDag-Erling Smørgrav }
528