iodine/src/read.c

215 lines
3.7 KiB
C
Raw Normal View History

/*
* Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
2006-08-25 01:04:27 +03:00
static int
readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)
{
char *dummy;
2006-08-25 01:18:24 +03:00
char *s;
char *d;
int len;
2006-11-07 12:07:53 +02:00
int offset;
char c;
2006-08-25 01:04:27 +03:00
if (loop <= 0)
return 0;
len = 0;
2006-08-25 01:18:24 +03:00
s = *src;
d = dst;
while(*s && len < length - 2) {
c = *s++;
/* is this a compressed label? */
if((c & 0xc0) == 0xc0) {
2006-11-07 12:07:53 +02:00
offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
if (offset > packetlen) {
if (len == 0) {
// Bad jump first in packet
return 0;
} else {
// Bad jump after some data
break;
}
}
dummy = packet + offset;
len += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);
2006-08-25 01:56:19 +03:00
goto end;
}
2006-08-25 01:21:32 +03:00
while(c && len < length - 1) {
2006-08-25 01:18:24 +03:00
*d++ = *s++;
len++;
c--;
}
2006-08-25 01:36:06 +03:00
2006-08-25 01:56:19 +03:00
if (len >= length - 1) {
2006-08-25 01:36:06 +03:00
break; /* We used up all space */
}
2006-08-25 01:56:19 +03:00
if (*s != 0) {
2006-08-25 01:18:24 +03:00
*d++ = '.';
2006-08-25 01:56:19 +03:00
len++;
}
}
2006-08-25 01:21:32 +03:00
dst[len++] = '\0';
2006-08-25 01:56:19 +03:00
end:
(*src) = s+1;
2006-08-25 01:18:24 +03:00
return len;
}
2006-08-25 01:04:27 +03:00
int
readname(char *packet, int packetlen, char **src, char *dst, size_t length)
2006-08-25 01:04:27 +03:00
{
return readname_loop(packet, packetlen, src, dst, length, 10);
2006-08-25 01:04:27 +03:00
}
int
readshort(char *packet, char **src, short *dst)
{
2006-08-23 19:03:24 +03:00
unsigned char *p;
2007-01-28 14:58:23 +02:00
p = (unsigned char *) *src;
2006-08-23 19:03:24 +03:00
*dst = (p[0] << 8) | p[1];
(*src) += sizeof(short);
return sizeof(short);
}
int
readlong(char *packet, char **src, uint32_t *dst)
{
// A long as described in dns protocol is always 32 bits
2006-08-23 19:03:24 +03:00
unsigned char *p;
2007-01-28 14:58:23 +02:00
p = (unsigned char *) *src;
*dst = ((uint32_t)p[0] << 24)
| ((uint32_t)p[1] << 16)
| ((uint32_t)p[2] << 8)
| ((uint32_t)p[3]);
(*src) += sizeof(uint32_t);
return sizeof(uint32_t);
}
int
readdata(char *packet, char **src, char *dst, size_t len)
{
2006-08-23 19:03:24 +03:00
if (len < 0)
2006-08-23 19:38:58 +03:00
return 0;
2006-08-23 19:03:24 +03:00
memcpy(dst, *src, len);
(*src) += len;
return len;
}
int
putname(char **buf, size_t buflen, const char *host)
{
char *word;
int left;
char *h;
char *p;
h = strdup(host);
left = buflen;
p = *buf;
word = strtok(h, ".");
while(word) {
if (strlen(word) > 63 || strlen(word) > left) {
free(h);
return -1;
}
left -= (strlen(word) + 1);
*p++ = (char)strlen(word);
memcpy(p, word, strlen(word));
p += strlen(word);
word = strtok(NULL, ".");
}
*p++ = 0;
free(h);
*buf = p;
return buflen - left;
}
int
putbyte(char **dst, char value)
{
**dst = value;
(*dst)++;
return sizeof(char);
}
int
putshort(char **dst, short value)
{
2006-08-23 19:03:24 +03:00
unsigned char *p;
2007-01-28 14:58:23 +02:00
p = (unsigned char *) *dst;
*p++ = (value >> 8);
*p++ = value;
2007-01-28 14:58:23 +02:00
(*dst) = (char *) p;
return sizeof(short);
}
int
putlong(char **dst, uint32_t value)
{
// A long as described in dns protocol is always 32 bits
2006-08-23 19:03:24 +03:00
unsigned char *p;
2007-01-28 14:58:23 +02:00
p = (unsigned char *) *dst;
*p++ = (value >> 24);
*p++ = (value >> 16);
*p++ = (value >> 8);
*p++ = (value);
2007-01-28 14:58:23 +02:00
(*dst) = (char *) p;
return sizeof(uint32_t);
}
int
putdata(char **dst, char *data, size_t len)
{
2006-08-23 19:03:24 +03:00
if (len < 0)
2006-08-23 19:38:58 +03:00
return 0;
2006-08-23 19:03:24 +03:00
memcpy(*dst, data, len);
(*dst) += len;
return len;
}