iodine/src/read.c

276 lines
4.9 KiB
C
Raw Normal View History

/*
2009-01-03 23:27:21 +00:00
* Copyright (c) 2006-2009 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-24 22:04:27 +00:00
static int
readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)
{
char *dummy;
2006-08-24 22:18:24 +00:00
char *s;
char *d;
int len;
2006-11-07 10:07:53 +00:00
int offset;
char c;
2006-08-24 22:04:27 +00:00
if (loop <= 0)
return 0;
len = 0;
2006-08-24 22:18:24 +00:00
s = *src;
d = dst;
while(*s && len < length - 2) {
c = *s++;
/* is this a compressed label? */
if((c & 0xc0) == 0xc0) {
2006-11-07 10:07:53 +00:00
offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
if (offset > packetlen) {
if (len == 0) {
2007-02-11 13:54:40 +00:00
/* Bad jump first in packet */
return 0;
} else {
2007-02-11 13:54:40 +00:00
/* Bad jump after some data */
break;
}
}
dummy = packet + offset;
len += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);
2006-08-24 22:56:19 +00:00
goto end;
}
2006-08-24 22:21:32 +00:00
while(c && len < length - 1) {
2006-08-24 22:18:24 +00:00
*d++ = *s++;
len++;
c--;
}
2006-08-24 22:36:06 +00:00
2006-08-24 22:56:19 +00:00
if (len >= length - 1) {
2006-08-24 22:36:06 +00:00
break; /* We used up all space */
}
2006-08-24 22:56:19 +00:00
if (*s != 0) {
2006-08-24 22:18:24 +00:00
*d++ = '.';
2006-08-24 22:56:19 +00:00
len++;
}
}
2006-08-24 22:21:32 +00:00
dst[len++] = '\0';
2006-08-24 22:56:19 +00:00
end:
(*src) = s+1;
2006-08-24 22:18:24 +00:00
return len;
}
2006-08-24 22:04:27 +00:00
int
readname(char *packet, int packetlen, char **src, char *dst, size_t length)
2006-08-24 22:04:27 +00:00
{
return readname_loop(packet, packetlen, src, dst, length, 10);
2006-08-24 22:04:27 +00:00
}
int
readshort(char *packet, char **src, short *dst)
{
2006-08-23 16:03:24 +00:00
unsigned char *p;
2007-01-28 12:58:23 +00:00
p = (unsigned char *) *src;
2006-08-23 16:03:24 +00:00
*dst = (p[0] << 8) | p[1];
(*src) += sizeof(short);
return sizeof(short);
}
int
readlong(char *packet, char **src, uint32_t *dst)
{
2007-02-11 13:54:40 +00:00
/* A long as described in dns protocol is always 32 bits */
2006-08-23 16:03:24 +00:00
unsigned char *p;
2007-01-28 12:58:23 +00: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 16:03:24 +00:00
if (len < 0)
2006-08-23 16:38:58 +00:00
return 0;
2006-08-23 16:03:24 +00:00
memcpy(dst, *src, len);
(*src) += len;
return len;
}
2009-09-20 15:11:04 +00:00
int
readtxtbin(char *packet, char **src, size_t srcremain, char *dst, size_t dstremain)
{
unsigned char *uc;
int tocopy;
int dstused = 0;
while (srcremain > 0)
{
uc = (unsigned char*) (*src);
tocopy = *uc;
(*src)++;
srcremain--;
if (tocopy > srcremain)
return 0; /* illegal, better have nothing */
if (tocopy > dstremain)
return 0; /* doesn't fit, better have nothing */
memcpy(dst, *src, tocopy);
dst += tocopy;
(*src) += tocopy;
srcremain -= tocopy;
dstremain -= tocopy;
dstused += tocopy;
}
return dstused;
}
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
2007-02-11 13:54:40 +00:00
putbyte(char **dst, unsigned char value)
{
**dst = value;
(*dst)++;
return sizeof(char);
}
int
2007-02-11 13:54:40 +00:00
putshort(char **dst, unsigned short value)
{
2006-08-23 16:03:24 +00:00
unsigned char *p;
2007-01-28 12:58:23 +00:00
p = (unsigned char *) *dst;
*p++ = (value >> 8);
*p++ = value;
2007-01-28 12:58:23 +00:00
(*dst) = (char *) p;
return sizeof(short);
}
int
putlong(char **dst, uint32_t value)
{
2007-02-11 13:54:40 +00:00
/* A long as described in dns protocol is always 32 bits */
2006-08-23 16:03:24 +00:00
unsigned char *p;
2007-01-28 12:58:23 +00:00
p = (unsigned char *) *dst;
*p++ = (value >> 24);
*p++ = (value >> 16);
*p++ = (value >> 8);
*p++ = (value);
2007-01-28 12:58:23 +00:00
(*dst) = (char *) p;
return sizeof(uint32_t);
}
int
putdata(char **dst, char *data, size_t len)
{
2006-08-23 16:03:24 +00:00
if (len < 0)
2006-08-23 16:38:58 +00:00
return 0;
2006-08-23 16:03:24 +00:00
memcpy(*dst, data, len);
(*dst) += len;
return len;
}
2009-09-20 15:11:04 +00:00
int
puttxtbin(char **buf, size_t bufremain, char *from, size_t fromremain)
{
unsigned char uc;
unsigned char *ucp = &uc;
char *cp = (char *) ucp;
int tocopy;
int bufused = 0;
while (fromremain > 0)
{
tocopy = fromremain;
if (tocopy > 252)
tocopy = 252; /* allow off-by-1s in caches etc */
if (tocopy + 1 > bufremain)
return -1; /* doesn't fit, better have nothing */
uc = tocopy;
**buf = *cp;
(*buf)++;
bufremain--;
bufused++;
memcpy(*buf, from, tocopy);
(*buf) += tocopy;
from += tocopy;
bufremain -= tocopy;
fromremain -= tocopy;
bufused += tocopy;
}
return bufused;
}