[svn-inject] Applying Debian modifications to trunk
[debian/iodine.git] / read.c
1 /*
2  * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <string.h>
18 #include <stdint.h>
19
20 static int
21 readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)
22 {
23         char *dummy;
24         char *s;
25         char *d;
26         int len;
27         int offset;
28         char c;
29
30         if (loop <= 0)
31                 return 0;
32
33         len = 0;
34         s = *src;
35         d = dst;
36         while(*s && len < length - 2) {
37                 c = *s++;
38
39                 /* is this a compressed label? */
40                 if((c & 0xc0) == 0xc0) {
41                         offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
42                         if (offset > packetlen) {
43                                 if (len == 0) {
44                                         // Bad jump first in packet
45                                         return 0;
46                                 } else {
47                                         // Bad jump after some data
48                                         break;
49                                 }
50                         }
51                         dummy = packet + offset;
52                         len += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);
53                         goto end;
54                 }
55
56                 while(c && len < length - 1) {
57                         *d++ = *s++;
58                         len++;
59
60                         c--;
61                 }
62                 
63                 if (len >= length - 1) {
64                         break; /* We used up all space */
65                 }
66
67                 if (*s != 0) {
68                         *d++ = '.';
69                         len++;
70                 }
71         }
72         dst[len++] = '\0';
73
74 end:
75         (*src) = s+1;
76         return len;
77 }
78
79 int
80 readname(char *packet, int packetlen, char **src, char *dst, size_t length)
81 {
82         return readname_loop(packet, packetlen, src, dst, length, 10);
83 }
84
85 int
86 readshort(char *packet, char **src, short *dst)
87 {
88         unsigned char *p;
89
90         p = *src;
91         *dst = (p[0] << 8) | p[1];
92
93         (*src) += sizeof(short);
94         return sizeof(short);
95 }
96
97 int
98 readlong(char *packet, char **src, uint32_t *dst)
99 {
100         // A long as described in dns protocol is always 32 bits
101         unsigned char *p;
102
103         p = *src;
104
105         *dst = ((uint32_t)p[0] << 24) 
106                  | ((uint32_t)p[1] << 16) 
107                  | ((uint32_t)p[2] << 8)
108                  | ((uint32_t)p[3]);
109
110         (*src) += sizeof(uint32_t);
111         return sizeof(uint32_t);
112 }
113
114 int
115 readdata(char *packet, char **src, char *dst, size_t len)
116 {
117         if (len < 0)
118                 return 0;
119
120         memcpy(dst, *src, len);
121
122         (*src) += len;
123
124         return len;
125 }
126
127 int
128 putbyte(char **dst, char value)
129 {
130         **dst = value;
131         (*dst)++;
132
133         return sizeof(char);
134 }
135
136 int
137 putshort(char **dst, short value)
138 {
139         unsigned char *p;
140
141         p = *dst;
142
143         *p++ = (value >> 8);
144         *p++ = value;
145
146         (*dst) = p;
147         return sizeof(short);
148 }
149
150 int
151 putlong(char **dst, uint32_t value)
152 {
153         // A long as described in dns protocol is always 32 bits
154         unsigned char *p;
155
156         p = *dst;
157
158         *p++ = (value >> 24);
159         *p++ = (value >> 16);
160         *p++ = (value >> 8);
161         *p++ = (value);
162
163         (*dst) = p;
164         return sizeof(uint32_t);
165 }
166
167 int
168 putdata(char **dst, char *data, size_t len)
169 {
170         if (len < 0)
171                 return 0;
172
173         memcpy(*dst, data, len);
174         
175         (*dst) += len;
176         return len;
177 }
178