New upstream release.
[debian/iodine.git] / src / read.c
1 /*
2  * Copyright (c) 2006-2009 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 #include <stdlib.h>
20
21 static int
22 readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, size_t loop)
23 {
24         char *dummy;
25         char *s;
26         char *d;
27         int len;
28         int offset;
29         char c;
30
31         if (loop <= 0)
32                 return 0;
33
34         len = 0;
35         s = *src;
36         d = dst;
37         while(*s && len < length - 2) {
38                 c = *s++;
39
40                 /* is this a compressed label? */
41                 if((c & 0xc0) == 0xc0) {
42                         offset = (((s[-1] & 0x3f) << 8) | (s[0] & 0xff));
43                         if (offset > packetlen) {
44                                 if (len == 0) {
45                                         /* Bad jump first in packet */
46                                         return 0;
47                                 } else {
48                                         /* Bad jump after some data */
49                                         break;
50                                 }
51                         }
52                         dummy = packet + offset;
53                         len += readname_loop(packet, packetlen, &dummy, d, length - len, loop - 1);
54                         goto end;
55                 }
56
57                 while(c && len < length - 1) {
58                         *d++ = *s++;
59                         len++;
60
61                         c--;
62                 }
63                 
64                 if (len >= length - 1) {
65                         break; /* We used up all space */
66                 }
67
68                 if (*s != 0) {
69                         *d++ = '.';
70                         len++;
71                 }
72         }
73         dst[len++] = '\0';
74
75 end:
76         (*src) = s+1;
77         return len;
78 }
79
80 int
81 readname(char *packet, int packetlen, char **src, char *dst, size_t length)
82 {
83         return readname_loop(packet, packetlen, src, dst, length, 10);
84 }
85
86 int
87 readshort(char *packet, char **src, short *dst)
88 {
89         unsigned char *p;
90
91         p = (unsigned char *) *src;
92         *dst = (p[0] << 8) | p[1];
93
94         (*src) += sizeof(short);
95         return sizeof(short);
96 }
97
98 int
99 readlong(char *packet, char **src, uint32_t *dst)
100 {
101         /* A long as described in dns protocol is always 32 bits */
102         unsigned char *p;
103
104         p = (unsigned char *) *src;
105
106         *dst = ((uint32_t)p[0] << 24) 
107                  | ((uint32_t)p[1] << 16) 
108                  | ((uint32_t)p[2] << 8)
109                  | ((uint32_t)p[3]);
110
111         (*src) += sizeof(uint32_t);
112         return sizeof(uint32_t);
113 }
114
115 int
116 readdata(char *packet, char **src, char *dst, size_t len)
117 {
118         if (len < 0)
119                 return 0;
120
121         memcpy(dst, *src, len);
122
123         (*src) += len;
124
125         return len;
126 }
127
128 int
129 putname(char **buf, size_t buflen, const char *host)
130 {
131         char *word;
132         int left;
133         char *h;
134         char *p;
135
136         h = strdup(host);
137         left = buflen;
138         p = *buf;
139         
140         word = strtok(h, ".");
141         while(word) {
142                 if (strlen(word) > 63 || strlen(word) > left) {
143                         free(h);
144                         return -1;
145                 }
146
147                 left -= (strlen(word) + 1);
148                 *p++ = (char)strlen(word);
149                 memcpy(p, word, strlen(word));
150                 p += strlen(word);
151
152                 word = strtok(NULL, ".");
153         }
154
155         *p++ = 0;
156
157         free(h);
158
159         *buf = p;
160         return buflen - left;
161 }
162
163 int
164 putbyte(char **dst, unsigned char value)
165 {
166         **dst = value;
167         (*dst)++;
168
169         return sizeof(char);
170 }
171
172 int
173 putshort(char **dst, unsigned short value)
174 {
175         unsigned char *p;
176
177         p = (unsigned char *) *dst;
178
179         *p++ = (value >> 8);
180         *p++ = value;
181
182         (*dst) = (char *) p;
183         return sizeof(short);
184 }
185
186 int
187 putlong(char **dst, uint32_t value)
188 {
189         /* A long as described in dns protocol is always 32 bits */
190         unsigned char *p;
191
192         p = (unsigned char *) *dst;
193
194         *p++ = (value >> 24);
195         *p++ = (value >> 16);
196         *p++ = (value >> 8);
197         *p++ = (value);
198
199         (*dst) = (char *) p;
200         return sizeof(uint32_t);
201 }
202
203 int
204 putdata(char **dst, char *data, size_t len)
205 {
206         if (len < 0)
207                 return 0;
208
209         memcpy(*dst, data, len);
210         
211         (*dst) += len;
212         return len;
213 }
214