1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include "dns.h" 5 6 /* 7 * a dictionary of domain names for packing messages 8 */ 9 enum 10 { 11 Ndict= 64, 12 }; 13 typedef struct Dict Dict; 14 struct Dict 15 { 16 struct { 17 ushort offset; /* pointer to packed name in message */ 18 char *name; /* pointer to unpacked name in buf */ 19 } x[Ndict]; 20 int n; /* size of dictionary */ 21 uchar *start; /* start of packed message */ 22 char buf[16*1024]; /* buffer for unpacked names (was 4k) */ 23 char *ep; /* first free char in buf */ 24 }; 25 26 #define NAME(x) p = pname(p, ep, x, dp) 27 #define SYMBOL(x) p = psym(p, ep, x) 28 #define STRING(x) p = pstr(p, ep, x) 29 #define BYTES(x, n) p = pbytes(p, ep, x, n) 30 #define USHORT(x) p = pushort(p, ep, x) 31 #define UCHAR(x) p = puchar(p, ep, x) 32 #define ULONG(x) p = pulong(p, ep, x) 33 #define V4ADDR(x) p = pv4addr(p, ep, x) 34 #define V6ADDR(x) p = pv6addr(p, ep, x) 35 36 static uchar* 37 psym(uchar *p, uchar *ep, char *np) 38 { 39 int n; 40 41 n = strlen(np); 42 if(n >= Strlen) /* DNS maximum length string */ 43 n = Strlen - 1; 44 if(ep - p < n+1) /* see if it fits in the buffer */ 45 return ep+1; 46 *p++ = n; 47 memmove(p, np, n); 48 return p + n; 49 } 50 51 static uchar* 52 pstr(uchar *p, uchar *ep, char *np) 53 { 54 return psym(p, ep, np); 55 } 56 57 static uchar* 58 pbytes(uchar *p, uchar *ep, uchar *np, int n) 59 { 60 if(ep - p < n) 61 return ep+1; 62 memmove(p, np, n); 63 return p + n; 64 } 65 66 static uchar* 67 puchar(uchar *p, uchar *ep, int val) 68 { 69 if(ep - p < 1) 70 return ep+1; 71 *p++ = val; 72 return p; 73 } 74 75 static uchar* 76 pushort(uchar *p, uchar *ep, int val) 77 { 78 if(ep - p < 2) 79 return ep+1; 80 *p++ = val>>8; 81 *p++ = val; 82 return p; 83 } 84 85 static uchar* 86 pulong(uchar *p, uchar *ep, int val) 87 { 88 if(ep - p < 4) 89 return ep+1; 90 *p++ = val>>24; 91 *p++ = val>>16; 92 *p++ = val>>8; 93 *p++ = val; 94 return p; 95 } 96 97 static uchar* 98 pv4addr(uchar *p, uchar *ep, char *name) 99 { 100 uchar ip[IPaddrlen]; 101 102 if(ep - p < 4) 103 return ep+1; 104 parseip(ip, name); 105 v6tov4(p, ip); 106 return p + 4; 107 } 108 109 static uchar* 110 pv6addr(uchar *p, uchar *ep, char *name) 111 { 112 if(ep - p < IPaddrlen) 113 return ep+1; 114 parseip(p, name); 115 return p + IPaddrlen; 116 } 117 118 static uchar* 119 pname(uchar *p, uchar *ep, char *np, Dict *dp) 120 { 121 int i; 122 char *cp; 123 char *last; /* last component packed */ 124 125 if(strlen(np) >= Domlen) /* make sure we don't exceed DNS limits */ 126 return ep+1; 127 128 last = 0; 129 while(*np){ 130 /* look through every component in the dictionary for a match */ 131 for(i = 0; i < dp->n; i++) 132 if(strcmp(np, dp->x[i].name) == 0){ 133 if(ep - p < 2) 134 return ep+1; 135 if ((dp->x[i].offset>>8) & 0xc0) 136 dnslog("convDNS2M: offset too big for " 137 "DNS packet format"); 138 *p++ = dp->x[i].offset>>8 | 0xc0; 139 *p++ = dp->x[i].offset; 140 return p; 141 } 142 143 /* if there's room, enter this name in dictionary */ 144 if(dp->n < Ndict) 145 if(last){ 146 /* the whole name is already in dp->buf */ 147 last = strchr(last, '.') + 1; 148 dp->x[dp->n].name = last; 149 dp->x[dp->n].offset = p - dp->start; 150 dp->n++; 151 } else { 152 /* add to dp->buf */ 153 i = strlen(np); 154 if(dp->ep + i + 1 < &dp->buf[sizeof dp->buf]){ 155 strcpy(dp->ep, np); 156 dp->x[dp->n].name = dp->ep; 157 last = dp->ep; 158 dp->x[dp->n].offset = p - dp->start; 159 dp->ep += i + 1; 160 dp->n++; 161 } 162 } 163 164 /* put next component into message */ 165 cp = strchr(np, '.'); 166 if(cp == nil){ 167 i = strlen(np); 168 cp = np + i; /* point to null terminator */ 169 } else { 170 i = cp - np; 171 cp++; /* point past '.' */ 172 } 173 if(ep-p < i+1) 174 return ep+1; 175 if (i > Labellen) 176 return ep+1; 177 *p++ = i; /* count of chars in label */ 178 memmove(p, np, i); 179 np = cp; 180 p += i; 181 } 182 183 if(p >= ep) 184 return ep+1; 185 *p++ = 0; /* add top level domain */ 186 187 return p; 188 } 189 190 static uchar* 191 convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp) 192 { 193 uchar *lp, *data; 194 int len, ttl; 195 Txt *t; 196 197 NAME(rp->owner->name); 198 USHORT(rp->type); 199 USHORT(rp->owner->class); 200 201 /* egregious overuse of ttl (it's absolute time in the cache) */ 202 if(rp->db) 203 ttl = rp->ttl; 204 else 205 ttl = rp->ttl - now; 206 if(ttl < 0) 207 ttl = 0; 208 ULONG(ttl); 209 210 lp = p; /* leave room for the rdata length */ 211 p += 2; 212 data = p; 213 214 if(data >= ep) 215 return p+1; 216 217 switch(rp->type){ 218 case Thinfo: 219 SYMBOL(rp->cpu->name); 220 SYMBOL(rp->os->name); 221 break; 222 case Tcname: 223 case Tmb: 224 case Tmd: 225 case Tmf: 226 case Tns: 227 NAME(rp->host->name); 228 break; 229 case Tmg: 230 case Tmr: 231 NAME(rp->mb->name); 232 break; 233 case Tminfo: 234 NAME(rp->rmb->name); 235 NAME(rp->mb->name); 236 break; 237 case Tmx: 238 USHORT(rp->pref); 239 NAME(rp->host->name); 240 break; 241 case Ta: 242 V4ADDR(rp->ip->name); 243 break; 244 case Taaaa: 245 V6ADDR(rp->ip->name); 246 break; 247 case Tptr: 248 NAME(rp->ptr->name); 249 break; 250 case Tsoa: 251 NAME(rp->host->name); 252 NAME(rp->rmb->name); 253 ULONG(rp->soa->serial); 254 ULONG(rp->soa->refresh); 255 ULONG(rp->soa->retry); 256 ULONG(rp->soa->expire); 257 ULONG(rp->soa->minttl); 258 break; 259 case Tsrv: 260 USHORT(rp->srv->pri); 261 USHORT(rp->srv->weight); 262 USHORT(rp->port); 263 STRING(rp->host->name); /* rfc2782 sez no name compression */ 264 break; 265 case Ttxt: 266 for(t = rp->txt; t != nil; t = t->next) 267 STRING(t->p); 268 break; 269 case Tnull: 270 BYTES(rp->null->data, rp->null->dlen); 271 break; 272 case Trp: 273 NAME(rp->rmb->name); 274 NAME(rp->rp->name); 275 break; 276 case Tkey: 277 USHORT(rp->key->flags); 278 UCHAR(rp->key->proto); 279 UCHAR(rp->key->alg); 280 BYTES(rp->key->data, rp->key->dlen); 281 break; 282 case Tsig: 283 USHORT(rp->sig->type); 284 UCHAR(rp->sig->alg); 285 UCHAR(rp->sig->labels); 286 ULONG(rp->sig->ttl); 287 ULONG(rp->sig->exp); 288 ULONG(rp->sig->incep); 289 USHORT(rp->sig->tag); 290 NAME(rp->sig->signer->name); 291 BYTES(rp->sig->data, rp->sig->dlen); 292 break; 293 case Tcert: 294 USHORT(rp->cert->type); 295 USHORT(rp->cert->tag); 296 UCHAR(rp->cert->alg); 297 BYTES(rp->cert->data, rp->cert->dlen); 298 break; 299 } 300 301 /* stuff in the rdata section length */ 302 len = p - data; 303 *lp++ = len >> 8; 304 *lp = len; 305 306 return p; 307 } 308 309 static uchar* 310 convQ2M(RR *rp, uchar *p, uchar *ep, Dict *dp) 311 { 312 NAME(rp->owner->name); 313 USHORT(rp->type); 314 USHORT(rp->owner->class); 315 return p; 316 } 317 318 static uchar* 319 rrloop(RR *rp, int *countp, uchar *p, uchar *ep, Dict *dp, int quest) 320 { 321 uchar *np; 322 323 *countp = 0; 324 for(; rp && p < ep; rp = rp->next){ 325 if(quest) 326 np = convQ2M(rp, p, ep, dp); 327 else 328 np = convRR2M(rp, p, ep, dp); 329 if(np > ep) 330 break; 331 p = np; 332 (*countp)++; 333 } 334 return p; 335 } 336 337 /* 338 * convert into a message 339 */ 340 int 341 convDNS2M(DNSmsg *m, uchar *buf, int len) 342 { 343 ulong trunc = 0; 344 uchar *p, *ep, *np; 345 Dict d; 346 347 d.n = 0; 348 d.start = buf; 349 d.ep = d.buf; 350 memset(buf, 0, len); 351 m->qdcount = m->ancount = m->nscount = m->arcount = 0; 352 353 /* first pack in the RR's so we can get real counts */ 354 p = buf + 12; 355 ep = buf + len; 356 p = rrloop(m->qd, &m->qdcount, p, ep, &d, 1); 357 p = rrloop(m->an, &m->ancount, p, ep, &d, 0); 358 p = rrloop(m->ns, &m->nscount, p, ep, &d, 0); 359 p = rrloop(m->ar, &m->arcount, p, ep, &d, 0); 360 if(p > ep) { 361 trunc = Ftrunc; 362 dnslog("udp packet full; truncating my reply"); 363 p = ep; 364 } 365 366 /* now pack the rest */ 367 np = p; 368 p = buf; 369 ep = buf + len; 370 USHORT(m->id); 371 USHORT(m->flags | trunc); 372 USHORT(m->qdcount); 373 USHORT(m->ancount); 374 USHORT(m->nscount); 375 USHORT(m->arcount); 376 USED(p); 377 return np - buf; 378 } 379