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