1 /**********************************************************************
2  * packet.c                                                    May 2003
3  * Horms                                             horms@verge.net.au
4  *
5  * Packets for map queries
6  *
7  * perdition
8  * Mail retrieval proxy server
9  * Copyright (C) 1999-2005  Horms
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of the
14  * License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  **********************************************************************/
26 
27 #include "packet.h"
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <inttypes.h>
32 #include <netinet/in.h>
33 #include <vanessa_logger.h>
34 
35 
36 static int
37 perdition_packet_init_v1_head(perdition_packet_t **packet,
38 		uint16_t cs_type, uint16_t flags,
39 		uint32_t saddr, uint16_t sport,
40 		uint32_t daddr, uint16_t dport, size_t body_len);
41 
42 static int
43 perdition_packet_verify_v1_head(perdition_packet_t *packet, size_t len);
44 
45 static int
46 perdition_packet_verify_v1_tail(perdition_packet_t *packet, size_t body_len);
47 
48 
49 perdition_packet_t *
perdition_packet_create(void)50 perdition_packet_create(void)
51 {
52 	perdition_packet_t *packet;
53 
54 	packet = (perdition_packet_t *)
55 				calloc(1, sizeof(perdition_packet_t));
56 	if(!packet) {
57 		VANESSA_LOGGER_DEBUG_ERRNO("calloc");
58 		return(NULL);
59 	}
60 
61 	return(packet);
62 }
63 
64 void
perdition_packet_destroy(perdition_packet_t * packet)65 perdition_packet_destroy(perdition_packet_t *packet)
66 {
67 	if(!packet) {
68 		return;
69 	}
70 	free(packet);
71 }
72 
73 #define PACKET_STR_SET(buf, p_str)                                          \
74 {                                                                           \
75 	perdition_packet_str_t str;                                         \
76 	str.length =  p_str ? htons(p_str->length) : 0;                     \
77 	memcpy(buf, &(str.length), sizeof(str.length));                     \
78 	buf += sizeof(str.length);                                          \
79 	if (str.length) {                                                   \
80 		memcpy(buf, p_str->data, p_str->length);                    \
81 		buf += p_str->length;                                       \
82 	}                                                                   \
83 }
84 
85 
86 int
perdition_packet_init_v1_req(perdition_packet_t ** packet,uint16_t cs_type,uint32_t saddr,uint16_t sport,uint32_t daddr,uint16_t dport,perdition_packet_str_t * key,perdition_packet_str_t * domain_delimiter)87 perdition_packet_init_v1_req(perdition_packet_t **packet,
88 		uint16_t cs_type,
89 		uint32_t saddr, uint16_t sport,
90 		uint32_t daddr, uint16_t dport,
91 		perdition_packet_str_t *key,
92 		perdition_packet_str_t *domain_delimiter)
93 {
94 	char *buf;
95 	perdition_packet_str_t str;
96 	size_t body_len;
97 
98 	body_len = sizeof(str.length) + (key ? key->length : 0) +
99 		sizeof(str.length) +
100 		(domain_delimiter ? domain_delimiter->length : 0);
101 
102 	if(perdition_packet_init_v1_head(packet, cs_type, PERDITION_PACKET_REQ,
103 				saddr, sport, daddr, dport, body_len) < 0) {
104 		VANESSA_LOGGER_DEBUG("perdition_packet_init_v1_head");
105 		return(-1);
106 	}
107 
108 	buf = (*packet)->body;
109 
110 	/* Fill in Key */
111 	PACKET_STR_SET(buf, key);
112 	/* Fill in Domain Delimiter */
113 	PACKET_STR_SET(buf, domain_delimiter);
114 
115 	return(0);
116 }
117 
118 int
perdition_packet_init_v1_str_req(perdition_packet_t ** packet,uint16_t cs_type,perdition_packet_str_t * saddr,perdition_packet_str_t * sport,perdition_packet_str_t * daddr,perdition_packet_str_t * dport,perdition_packet_str_t * key,perdition_packet_str_t * domain_delimiter)119 perdition_packet_init_v1_str_req(perdition_packet_t **packet,
120 				 uint16_t cs_type,
121 				 perdition_packet_str_t *saddr,
122 				 perdition_packet_str_t *sport,
123 				 perdition_packet_str_t *daddr,
124 				 perdition_packet_str_t *dport,
125 				 perdition_packet_str_t *key,
126 				 perdition_packet_str_t *domain_delimiter)
127 {
128 	char *buf;
129 	perdition_packet_str_t str;
130 	size_t body_len;
131 
132 	body_len = sizeof(str.length) + (saddr ? saddr->length : 0) +
133 		   sizeof(str.length) + (sport ? sport->length : 0) +
134 		   sizeof(str.length) + (daddr ? daddr->length : 0) +
135 		   sizeof(str.length) + (dport ? dport->length : 0) +
136 		   sizeof(str.length) + (key ? key->length : 0) +
137 		   sizeof(str.length) + (domain_delimiter ?
138 					 domain_delimiter->length : 0);
139 
140 	if(perdition_packet_init_v1_head(packet, cs_type,
141 					 PERDITION_PACKET_STR_REQ,
142 					 0, 0, 0, 0, body_len) < 0) {
143 		VANESSA_LOGGER_DEBUG("perdition_packet_init_v1_head");
144 		return -1;
145 	}
146 
147 	buf = (*packet)->body;
148 
149 	/* Fill in Body */
150 	PACKET_STR_SET(buf, key);
151 	PACKET_STR_SET(buf, domain_delimiter);
152 	PACKET_STR_SET(buf, saddr);
153 	PACKET_STR_SET(buf, sport);
154 	PACKET_STR_SET(buf, daddr);
155 	PACKET_STR_SET(buf, dport);
156 
157 	return 0;
158 }
159 
160 int
perdition_packet_init_v1_rsp(perdition_packet_t ** packet,uint16_t cs_type,perdition_packet_str_t * user,perdition_packet_str_t * server,perdition_packet_str_t * port)161 perdition_packet_init_v1_rsp(perdition_packet_t **packet,
162 		uint16_t cs_type, perdition_packet_str_t *user,
163 		perdition_packet_str_t *server,
164 		perdition_packet_str_t *port)
165 {
166 	char *buf;
167 	perdition_packet_str_t str;
168 	size_t body_len;
169 
170 	body_len = sizeof(str.length) + (user ? user->length : 0) +
171 		sizeof(str.length) + (server ? server->length : 0) +
172 		sizeof(str.length) + (port ? port->length : 0);
173 
174 	if(perdition_packet_init_v1_head(packet, cs_type, PERDITION_PACKET_RSP,
175 				0, 0, 0, 0, body_len) < 0) {
176 		VANESSA_LOGGER_DEBUG("perdition_packet_init_v1_head");
177 		return(-1);
178 	}
179 	buf = (*packet)->body;
180 
181 	/* Fill in User */
182 	PACKET_STR_SET(buf, user);
183 	/* Fill in Server */
184 	PACKET_STR_SET(buf, server);
185 	/* Fill in Port */
186 	PACKET_STR_SET(buf, port);
187 
188 	return(0);
189 }
190 
191 static int
perdition_packet_init_v1_head(perdition_packet_t ** packet,uint16_t cs_type,uint16_t flags,uint32_t saddr,uint16_t sport,uint32_t daddr,uint16_t dport,size_t body_len)192 perdition_packet_init_v1_head(perdition_packet_t **packet,
193 		uint16_t cs_type, uint16_t flags,
194 		uint32_t saddr, uint16_t sport,
195 		uint32_t daddr, uint16_t dport, size_t body_len)
196 {
197 	if (cs_type != PERDITION_PACKET_CS_NONE) {
198 		VANESSA_LOGGER_DEBUG("Only checksum type none is implemented");
199 		return(-1);
200 	}
201 
202 	if (body_len > PERDITION_PACKET_MAX_BODY_LEN) {
203 		VANESSA_LOGGER_DEBUG("Strings supplied would overflow body");
204 		return(-1);
205 	}
206 
207 	if (!*packet) {
208 		*packet = perdition_packet_create();
209 		if (!*packet) {
210 			VANESSA_LOGGER_DEBUG("perdition_packet_create");
211 			return(-1);
212 		}
213 	}
214 	else {
215 		memset(*packet, 0, sizeof(perdition_packet_t));
216 	}
217 
218 	/* Fill in Head */
219 	(*packet)->head.magic = htonl(PERDITION_PACKET_MAGIC);
220 	(*packet)->head.version = htons(PERDITION_PACKET_VERSION);
221 	(*packet)->head.flags = htons(flags);
222 	(*packet)->head.length = htons(sizeof(perdition_packet_head_t) +
223 		body_len);
224 	(*packet)->head.cs_type = htons(cs_type);
225 	(*packet)->head.saddr = htonl(saddr);
226 	(*packet)->head.sport = htons(sport);
227 	(*packet)->head.daddr = htonl(daddr);
228 	(*packet)->head.dport = htons(dport);
229 
230 	return(0);
231 }
232 
packet_str_get(char * buf,perdition_packet_str_t * p_str)233 static size_t packet_str_get(char *buf, perdition_packet_str_t *p_str)
234 {
235 	perdition_packet_str_t str;
236 
237 	memcpy(&str.length, buf, sizeof(str.length));
238 	str.length = ntohs(str.length);
239 
240 	if (p_str) {
241 		p_str->length = str.length;
242 		if (p_str->length)
243 			p_str->data = (unsigned char *) buf +
244 				      sizeof(str.length);
245 		else
246 			p_str->data = NULL;
247 	}
248 
249 	return str.length + sizeof(str.length);
250 }
251 
252 #define PACKET_STR_GET(buf, p_str)					    \
253 do {									    \
254 	buf += packet_str_get(buf, p_str);				    \
255 } while (0)
256 
257 int
perdition_packet_verify_v1_req(perdition_packet_t * packet,size_t len,perdition_packet_str_t * key,perdition_packet_str_t * domain_delimiter)258 perdition_packet_verify_v1_req(perdition_packet_t *packet,
259 		size_t len, perdition_packet_str_t *key,
260 		perdition_packet_str_t *domain_delimiter)
261 {
262 	char *buf;
263 
264 	if(perdition_packet_verify_v1_head(packet, len) < 0) {
265 		VANESSA_LOGGER_DEBUG("perdition_packet_verify_v1_head");
266 		return(-1);
267 	}
268 
269 	if(ntohs(packet->head.flags) != PERDITION_PACKET_REQ) {
270 		VANESSA_LOGGER_DEBUG("Packet is not a request");
271 		return(-1);
272 	}
273 
274 	buf = packet->body;
275 
276 	/* Fill in Key */
277 	PACKET_STR_GET(buf, key);
278 	/* Fill in Domain Delimiter */
279 	PACKET_STR_GET(buf, domain_delimiter);
280 
281 	if(perdition_packet_verify_v1_tail(packet, buf - packet->body) < 0) {
282 		VANESSA_LOGGER_DEBUG("perdition_packet_verify_v1_head");
283 		return(-1);
284 	}
285 
286 	return(0);
287 }
288 
289 
290 
291 int
perdition_packet_verify_v1_str_req(perdition_packet_t * packet,size_t len,perdition_packet_str_t * saddr,perdition_packet_str_t * sport,perdition_packet_str_t * daddr,perdition_packet_str_t * dport,perdition_packet_str_t * key,perdition_packet_str_t * domain_delimiter)292 perdition_packet_verify_v1_str_req(perdition_packet_t *packet, size_t len,
293 				   perdition_packet_str_t *saddr,
294 				   perdition_packet_str_t *sport,
295 				   perdition_packet_str_t *daddr,
296 				   perdition_packet_str_t *dport,
297 				   perdition_packet_str_t *key,
298 				   perdition_packet_str_t *domain_delimiter)
299 {
300 	char *buf;
301 
302 	if (perdition_packet_verify_v1_head(packet, len) < 0) {
303 		VANESSA_LOGGER_DEBUG("perdition_packet_verify_v1_head");
304 		return -1;
305 	}
306 
307 	if (ntohs(packet->head.flags) != PERDITION_PACKET_STR_REQ) {
308 		VANESSA_LOGGER_DEBUG("Packet is not a string request");
309 		return -1;
310 	}
311 
312 	buf = packet->body;
313 
314 	PACKET_STR_GET(buf, key);
315 	PACKET_STR_GET(buf, domain_delimiter);
316 	PACKET_STR_GET(buf, saddr);
317 	PACKET_STR_GET(buf, sport);
318 	PACKET_STR_GET(buf, daddr);
319 	PACKET_STR_GET(buf, dport);
320 
321 	if(perdition_packet_verify_v1_tail(packet, buf - packet->body) < 0) {
322 		VANESSA_LOGGER_DEBUG("perdition_packet_verify_v1_head");
323 		return -1;
324 	}
325 
326 	return 0;
327 }
328 
329 
330 int
perdition_packet_verify_v1_rsp(perdition_packet_t * packet,size_t len,perdition_packet_str_t * user,perdition_packet_str_t * server,perdition_packet_str_t * port)331 perdition_packet_verify_v1_rsp(perdition_packet_t *packet,
332 		size_t len, perdition_packet_str_t *user,
333 		perdition_packet_str_t *server,
334 		perdition_packet_str_t *port)
335 {
336 	char *buf;
337 
338 	if(perdition_packet_verify_v1_head(packet, len) < 0) {
339 		VANESSA_LOGGER_DEBUG("perdition_packet_verify_v1_head");
340 		return(-1);
341 	}
342 
343 	if(ntohs(packet->head.flags) != PERDITION_PACKET_RSP) {
344 		VANESSA_LOGGER_DEBUG("Packet is not a response");
345 		return(-1);
346 	}
347 
348 	buf = packet->body;
349 
350 	/* Fill in Key */
351 	PACKET_STR_GET(buf, user);
352 	/* Fill in Server */
353 	PACKET_STR_GET(buf, server);
354 	/* Fill in Port */
355 	PACKET_STR_GET(buf, port);
356 
357 	if(perdition_packet_verify_v1_tail(packet, buf - packet->body) < 0) {
358 		VANESSA_LOGGER_DEBUG("perdition_packet_verify_v1_head");
359 		return(-1);
360 	}
361 
362 	return(0);
363 }
364 
365 
366 static int
perdition_packet_verify_v1_head(perdition_packet_t * packet,size_t len)367 perdition_packet_verify_v1_head(perdition_packet_t *packet, size_t len)
368 {
369 	if (len < sizeof(perdition_packet_head_t)) {
370 		VANESSA_LOGGER_DEBUG("Packet is too short to contain body");
371 		return(-1);
372 	}
373 
374 	if (packet->head.magic != htonl(PERDITION_PACKET_MAGIC)) {
375 		VANESSA_LOGGER_DEBUG("Magic number missmatch");
376 		return(-1);
377 	}
378 
379 	if (len > PERDITION_PACKET_MAX_PACKET_LEN) {
380 		VANESSA_LOGGER_DEBUG("Packet is too long");
381 		return(-1);
382 	}
383 
384 	if (len != ntohs(packet->head.length)) {
385 		VANESSA_LOGGER_DEBUG_UNSAFE("Packet length missmatch. "
386 				"Have %d bytes, header specifies %d bytes",
387 				len, ntohs(packet->head.length));
388 	}
389 
390 	if (packet->head.cs_type != PERDITION_PACKET_CS_NONE) {
391 		VANESSA_LOGGER_DEBUG("Only checksum type none is implemented");
392 		return(-1);
393 	}
394 
395 	return(0);
396 }
397 
398 static int
perdition_packet_verify_v1_tail(perdition_packet_t * packet,size_t body_len)399 perdition_packet_verify_v1_tail(perdition_packet_t *packet, size_t body_len)
400 {
401 	if (body_len > PERDITION_PACKET_MAX_BODY_LEN) {
402 		VANESSA_LOGGER_DEBUG("Strings supplied would overflow body");
403 		return(-1);
404 	}
405 
406 	if(body_len + sizeof(packet->head) != ntohs(packet->head.length)) {
407 		VANESSA_LOGGER_DEBUG_UNSAFE("Length of strings in body does "
408 				"not match length of packet."
409 				"strings (%d) + head (%d) != %d",
410 				body_len, sizeof(packet->head),
411 				ntohs(packet->head.length));
412 		return(-1);
413 	}
414 
415 	return(0);
416 }
417