1 #include <u.h> 2 #include <libc.h> 3 #include "dns.h" 4 5 typedef struct Scan Scan; 6 struct Scan 7 { 8 uchar *base; 9 uchar *p; 10 uchar *ep; 11 char *err; 12 }; 13 14 #define NAME(x) gname(x, sp) 15 #define STRING(x) (x = gstr(sp)) 16 #define USHORT(x) (x = gshort(sp)) 17 #define ULONG(x) (x = glong(sp)) 18 #define ADDR(x) (x = gaddr(sp)) 19 20 static char *toolong = "too long"; 21 22 /* 23 * get a ushort/ulong 24 */ 25 static ushort 26 gshort(Scan *sp) 27 { 28 ushort x; 29 30 if(sp->err) 31 return 0; 32 if(sp->ep - sp->p < 2){ 33 sp->err = toolong; 34 return 0; 35 } 36 x = (sp->p[0]<<8) | sp->p[1]; 37 sp->p += 2; 38 return x; 39 } 40 static ulong 41 glong(Scan *sp) 42 { 43 ulong x; 44 45 if(sp->err) 46 return 0; 47 if(sp->ep - sp->p < 4){ 48 sp->err = toolong; 49 return 0; 50 } 51 x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3]; 52 sp->p += 4; 53 return x; 54 } 55 56 /* 57 * get an ip address 58 */ 59 static DN* 60 gaddr(Scan *sp) 61 { 62 char addr[32]; 63 64 if(sp->err) 65 return 0; 66 if(sp->ep - sp->p < 4){ 67 sp->err = toolong; 68 return 0; 69 } 70 snprint(addr, sizeof(addr), "%I", sp->p); 71 sp->p += 4; 72 73 return dnlookup(addr, Cin, 1); 74 } 75 76 /* 77 * get a string. make it an internal symbol. 78 */ 79 static DN* 80 gstr(Scan *sp) 81 { 82 int n; 83 char sym[Strlen+1]; 84 85 if(sp->err) 86 return 0; 87 n = *(sp->p++); 88 if(sp->p+n > sp->ep){ 89 sp->err = toolong; 90 return 0; 91 } 92 93 if(n > Strlen){ 94 sp->err = "illegal string"; 95 return 0; 96 } 97 strncpy(sym, (char*)sp->p, n); 98 sym[n] = 0; 99 sp->p += n; 100 101 return dnlookup(sym, Csym, 1); 102 } 103 104 /* 105 * get a domain name. 'to' must point to a buffer at least Domlen+1 long. 106 */ 107 static char* 108 gname(char *to, Scan *sp) 109 { 110 int len, off; 111 int pointer; 112 int n; 113 char *tostart; 114 char *toend; 115 uchar *p; 116 117 tostart = to; 118 if(sp->err) 119 goto err; 120 pointer = 0; 121 p = sp->p; 122 toend = to + Domlen; 123 for(len = 0; *p; len += pointer ? 0 : (n+1)){ 124 if((*p & 0xc0) == 0xc0){ 125 /* pointer to other spot in message */ 126 if(pointer++ > 10){ 127 sp->err = "pointer loop"; 128 goto err; 129 } 130 off = ((p[0]<<8) + p[1]) & 0x3ff; 131 p = sp->base + off; 132 if(p >= sp->ep){ 133 sp->err = "bad pointer"; 134 goto err; 135 } 136 n = 0; 137 continue; 138 } 139 n = *p++; 140 if(len + n < Domlen - 1){ 141 if(to + n > toend){ 142 sp->err = toolong; 143 goto err; 144 } 145 memmove(to, p, n); 146 to += n; 147 } 148 p += n; 149 if(*p){ 150 if(to >= toend){ 151 sp->err = toolong; 152 goto err; 153 } 154 *to++ = '.'; 155 } 156 } 157 *to = 0; 158 if(pointer) 159 sp->p += len + 2; /* + 2 for pointer */ 160 else 161 sp->p += len + 1; /* + 1 for the null domain */ 162 return tostart; 163 err: 164 *tostart = 0; 165 return tostart; 166 } 167 168 /* 169 * convert the next RR from a message 170 */ 171 static RR* 172 convM2RR(Scan *sp) 173 { 174 RR *rp; 175 int type; 176 int class; 177 uchar *data; 178 int len; 179 char dname[Domlen+1]; 180 181 NAME(dname); 182 USHORT(type); 183 USHORT(class); 184 185 rp = rralloc(type); 186 rp->owner = dnlookup(dname, class, 1); 187 rp->type = type; 188 189 ULONG(rp->ttl); 190 USHORT(len); 191 data = sp->p; 192 switch(type){ 193 case Thinfo: 194 STRING(rp->cpu); 195 STRING(rp->os); 196 break; 197 case Tcname: 198 case Tmb: 199 case Tmd: 200 case Tmf: 201 case Tns: 202 rp->host = dnlookup(NAME(dname), Cin, 1); 203 break; 204 case Tmg: 205 case Tmr: 206 rp->mb = dnlookup(NAME(dname), Cin, 1); 207 break; 208 case Tminfo: 209 rp->rmb = dnlookup(NAME(dname), Cin, 1); 210 rp->mb = dnlookup(NAME(dname), Cin, 1); 211 break; 212 case Tmx: 213 USHORT(rp->pref); 214 rp->host = dnlookup(NAME(dname), Cin, 1); 215 break; 216 case Ta: 217 ADDR(rp->ip); 218 break; 219 case Tptr: 220 rp->ptr = dnlookup(NAME(dname), Cin, 1); 221 break; 222 case Tsoa: 223 rp->host = dnlookup(NAME(dname), Cin, 1); 224 rp->rmb = dnlookup(NAME(dname), Cin, 1); 225 ULONG(rp->soa->serial); 226 ULONG(rp->soa->refresh); 227 ULONG(rp->soa->retry); 228 ULONG(rp->soa->expire); 229 ULONG(rp->soa->minttl); 230 break; 231 } 232 if(sp->p - data != len) 233 sp->err = "bad RR len"; 234 return rp; 235 } 236 237 /* 238 * convert the next question from a message 239 */ 240 static RR* 241 convM2Q(Scan *sp) 242 { 243 char dname[Domlen+1]; 244 int type; 245 int class; 246 RR *rp; 247 248 NAME(dname); 249 USHORT(type); 250 USHORT(class); 251 if(sp->err) 252 return 0; 253 254 rp = rralloc(type); 255 rp->owner = dnlookup(dname, class, 1); 256 257 return rp; 258 } 259 260 static RR* 261 rrloop(Scan *sp, int count, int quest) 262 { 263 int i; 264 static char errbuf[64]; 265 RR *first, *rp, **l; 266 267 if(sp->err) 268 return 0; 269 l = &first; 270 first = 0; 271 for(i = 0; i < count; i++){ 272 rp = quest ? convM2Q(sp) : convM2RR(sp); 273 if(rp == 0) 274 break; 275 if(sp->err){ 276 rrfree(rp); 277 break; 278 } 279 *l = rp; 280 l = &rp->next; 281 } 282 return first; 283 } 284 285 /* 286 * convert the next DNS from a message stream 287 */ 288 char* 289 convM2DNS(uchar *buf, int len, DNSmsg *m) 290 { 291 Scan scan; 292 Scan *sp; 293 294 scan.base = buf; 295 scan.p = buf; 296 scan.ep = buf + len; 297 scan.err = 0; 298 sp = &scan; 299 memset(m, 0, sizeof(DNSmsg)); 300 USHORT(m->id); 301 USHORT(m->flags); 302 USHORT(m->qdcount); 303 USHORT(m->ancount); 304 USHORT(m->nscount); 305 USHORT(m->arcount); 306 m->qd = rrloop(sp, m->qdcount, 1); 307 m->an = rrloop(sp, m->ancount, 0); 308 m->ns = rrloop(sp, m->nscount, 0); 309 m->ar = rrloop(sp, m->arcount, 0); 310 return scan.err; 311 } 312