PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/usr.sbin/smtpd/pack.c

https://github.com/chrissicool/l4openbsd
C | 469 lines | 365 code | 83 blank | 21 comment | 64 complexity | 1ff40ca565b35c50041ae4a0333f3893 MD5 | raw file
  1. /*
  2. * Copyright (c) 2009,2010 Eric Faurot <eric@faurot.net>
  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. #include <string.h>
  17. #include "dnsutil.h"
  18. int dname_check_label(const char*, size_t);
  19. const char* dname_nthlabel(int, const unsigned char*, size_t, size_t);
  20. ssize_t dname_count_labels(const unsigned char*, size_t, size_t);
  21. ssize_t dname_expand(const unsigned char*, size_t, size_t,
  22. size_t*, char *, size_t);
  23. void
  24. packed_init(struct packed *pack, char *data, size_t len)
  25. {
  26. pack->data = data;
  27. pack->len = len;
  28. pack->offset = 0;
  29. pack->err = NULL;
  30. }
  31. ssize_t
  32. dname_expand(const unsigned char *data, size_t len, size_t offset,
  33. size_t *newoffset, char *dst, size_t max)
  34. {
  35. size_t n, count, end, ptr, start;
  36. ssize_t res;
  37. if (offset >= len)
  38. return (-1);
  39. res = 0;
  40. end = start = offset;
  41. for(; (n = data[offset]); ) {
  42. if ((n & 0xc0) == 0xc0) {
  43. if (offset + 2 > len)
  44. return (-1);
  45. ptr = 256 * (n & ~0xc0) + data[offset + 1];
  46. if (ptr >= start)
  47. return (-1);
  48. if (end < offset + 2)
  49. end = offset + 2;
  50. offset = ptr;
  51. continue;
  52. }
  53. if (offset + n + 1 > len)
  54. return (-1);
  55. if (dname_check_label(data + offset + 1, n) == -1)
  56. return (-1);
  57. /* copy n + at offset+1 */
  58. if (dst != NULL && max != 0) {
  59. count = (max < n + 1) ? (max) : (n + 1);
  60. memmove(dst, data + offset, count);
  61. dst += count;
  62. max -= count;
  63. }
  64. res += n + 1;
  65. offset += n + 1;
  66. if (end < offset)
  67. end = offset;
  68. }
  69. if (end < offset + 1)
  70. end = offset + 1;
  71. if (dst != NULL && max != 0)
  72. dst[0] = 0;
  73. if (newoffset)
  74. *newoffset = end;
  75. return (res + 1);
  76. }
  77. const char *
  78. dname_nthlabel(int n, const unsigned char *data, size_t len, size_t offset)
  79. {
  80. int i;
  81. size_t c, ptr, start;
  82. start = offset;
  83. for(i = 0;;) {
  84. c = data[offset];
  85. if (c == 0)
  86. return (NULL);
  87. if ((c & 0xc0) == 0xc0) {
  88. if (len < offset + 2)
  89. return (NULL);
  90. ptr = 256 * (c & ~0xc0) + data[offset + 1];
  91. if (ptr >= start)
  92. return (NULL);
  93. offset = ptr;
  94. continue;
  95. }
  96. if (i == n)
  97. break;
  98. offset += c + 1;
  99. i++;
  100. }
  101. return (data + offset);
  102. }
  103. ssize_t
  104. dname_count_labels(const unsigned char *data, size_t len, size_t offset)
  105. {
  106. size_t c, n, ptr, start;
  107. start = offset;
  108. for(n = 0; (c = data[offset]); ) {
  109. if ((c & 0xc0) == 0xc0) {
  110. if (len < offset + 2)
  111. return (-1);
  112. ptr = 256 * (c & ~0xc0) + data[offset + 1];
  113. if (ptr >= start)
  114. return (-1);
  115. offset = ptr;
  116. continue;
  117. }
  118. offset += c + 1;
  119. n += 1;
  120. }
  121. return (n);
  122. }
  123. int
  124. unpack_data(struct packed *p, void *data, size_t len)
  125. {
  126. if (p->err)
  127. return (-1);
  128. if (p->len - p->offset < len) {
  129. p->err = "too short";
  130. return (-1);
  131. }
  132. memmove(data, p->data + p->offset, len);
  133. p->offset += len;
  134. return (0);
  135. }
  136. int
  137. unpack_u16(struct packed *p, uint16_t *u16)
  138. {
  139. if (unpack_data(p, u16, 2) == -1)
  140. return (-1);
  141. *u16 = ntohs(*u16);
  142. return (0);
  143. }
  144. int
  145. unpack_u32(struct packed *p, uint32_t *u32)
  146. {
  147. if (unpack_data(p, u32, 4) == -1)
  148. return (-1);
  149. *u32 = ntohl(*u32);
  150. return (0);
  151. }
  152. int
  153. unpack_inaddr(struct packed *p, struct in_addr *a)
  154. {
  155. return (unpack_data(p, a, 4));
  156. }
  157. int
  158. unpack_in6addr(struct packed *p, struct in6_addr *a6)
  159. {
  160. return (unpack_data(p, a6, 16));
  161. }
  162. int
  163. unpack_dname(struct packed *p, char *dst, size_t max)
  164. {
  165. ssize_t e;
  166. if (p->err)
  167. return (-1);
  168. e = dname_expand(p->data, p->len, p->offset, &p->offset, dst, max);
  169. if (e == -1) {
  170. p->err = "bad domain name";
  171. return (-1);
  172. }
  173. if (e < 0 || e > DOMAIN_MAXLEN) {
  174. p->err = "domain name too long";
  175. return (-1);
  176. }
  177. return (0);
  178. }
  179. int
  180. unpack_header(struct packed *p, struct header *h)
  181. {
  182. if (unpack_data(p, h, HEADER_LEN) == -1)
  183. return (-1);
  184. h->flags = ntohs(h->flags);
  185. h->qdcount = ntohs(h->qdcount);
  186. h->ancount = ntohs(h->ancount);
  187. h->nscount = ntohs(h->nscount);
  188. h->arcount = ntohs(h->arcount);
  189. return (0);
  190. }
  191. int
  192. unpack_query(struct packed *p, struct query *q)
  193. {
  194. unpack_dname(p, q->q_dname, sizeof(q->q_dname));
  195. unpack_u16(p, &q->q_type);
  196. unpack_u16(p, &q->q_class);
  197. return (p->err) ? (-1) : (0);
  198. }
  199. int
  200. unpack_rr(struct packed *p, struct rr *rr)
  201. {
  202. uint16_t rdlen;
  203. size_t save_offset;
  204. unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
  205. unpack_u16(p, &rr->rr_type);
  206. unpack_u16(p, &rr->rr_class);
  207. unpack_u32(p, &rr->rr_ttl);
  208. unpack_u16(p, &rdlen);
  209. if (p->err)
  210. return (-1);
  211. if (p->len - p->offset < rdlen) {
  212. p->err = "too short";
  213. return (-1);
  214. }
  215. save_offset = p->offset;
  216. switch(rr->rr_type) {
  217. case T_CNAME:
  218. unpack_dname(p, rr->rr.cname.cname,
  219. sizeof(rr->rr.cname.cname));
  220. break;
  221. case T_MX:
  222. unpack_u16(p, &rr->rr.mx.preference);
  223. unpack_dname(p, rr->rr.mx.exchange,
  224. sizeof(rr->rr.mx.exchange));
  225. break;
  226. case T_NS:
  227. unpack_dname(p, rr->rr.ns.nsname,
  228. sizeof(rr->rr.ns.nsname));
  229. break;
  230. case T_PTR:
  231. unpack_dname(p, rr->rr.ptr.ptrname,
  232. sizeof(rr->rr.ptr.ptrname));
  233. break;
  234. case T_SOA:
  235. unpack_dname(p, rr->rr.soa.mname,
  236. sizeof(rr->rr.soa.mname));
  237. unpack_dname(p, rr->rr.soa.rname,
  238. sizeof(rr->rr.soa.rname));
  239. unpack_u32(p, &rr->rr.soa.serial);
  240. unpack_u32(p, &rr->rr.soa.refresh);
  241. unpack_u32(p, &rr->rr.soa.retry);
  242. unpack_u32(p, &rr->rr.soa.expire);
  243. unpack_u32(p, &rr->rr.soa.minimum);
  244. break;
  245. case T_A:
  246. if (rr->rr_class != C_IN)
  247. goto other;
  248. unpack_inaddr(p, &rr->rr.in_a.addr);
  249. break;
  250. case T_AAAA:
  251. if (rr->rr_class != C_IN)
  252. goto other;
  253. unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
  254. break;
  255. default:
  256. other:
  257. rr->rr.other.rdata = p->data + p->offset;
  258. rr->rr.other.rdlen = rdlen;
  259. p->offset += rdlen;
  260. }
  261. if (p->err)
  262. return (-1);
  263. /* make sure that the advertised rdlen is really ok */
  264. if (p->offset - save_offset != rdlen)
  265. p->err = "bad dlen";
  266. return (p->err) ? (-1) : (0);
  267. }
  268. int
  269. pack_data(struct packed *p, const void *data, size_t len)
  270. {
  271. if (p->err)
  272. return (-1);
  273. if (p->len < p->offset + len) {
  274. p->err = "no space";
  275. return (-1);
  276. }
  277. memmove(p->data + p->offset, data, len);
  278. p->offset += len;
  279. return (0);
  280. }
  281. int
  282. pack_u16(struct packed *p, uint16_t v)
  283. {
  284. v = htons(v);
  285. return (pack_data(p, &v, 2));
  286. }
  287. int
  288. pack_u32(struct packed *p, uint32_t v)
  289. {
  290. v = htonl(v);
  291. return (pack_data(p, &v, 4));
  292. }
  293. int
  294. pack_inaddr(struct packed *p, struct in_addr a)
  295. {
  296. return (pack_data(p, &a, 4));
  297. }
  298. int
  299. pack_in6addr(struct packed *p, struct in6_addr a6)
  300. {
  301. return (pack_data(p, &a6, 16));
  302. }
  303. int
  304. pack_dname(struct packed *p, const char *dname)
  305. {
  306. /* dname compression would be nice to have here.
  307. * need additionnal context.
  308. */
  309. return (pack_data(p, dname, strlen(dname) + 1));
  310. }
  311. int
  312. pack_header(struct packed *p, const struct header *h)
  313. {
  314. struct header c;
  315. c.id = h->id;
  316. c.flags = htons(h->flags);
  317. c.qdcount = htons(h->qdcount);
  318. c.ancount = htons(h->ancount);
  319. c.nscount = htons(h->nscount);
  320. c.arcount = htons(h->arcount);
  321. return (pack_data(p, &c, HEADER_LEN));
  322. }
  323. int
  324. pack_query(struct packed *p, uint16_t type, uint16_t class, const char *dname)
  325. {
  326. pack_dname(p, dname);
  327. pack_u16(p, type);
  328. pack_u16(p, class);
  329. return (p->err) ? (-1) : (0);
  330. }
  331. int
  332. pack_rrdynamic(struct packed *p, const struct rr_dynamic *rd)
  333. {
  334. const union rr_subtype *rr;
  335. struct packed save;
  336. pack_dname(p, rd->rd_dname);
  337. pack_u16(p, rd->rd_type);
  338. pack_u16(p, rd->rd_class);
  339. pack_u32(p, rd->rd_ttl);
  340. save = *p;
  341. pack_u16(p, 0); /* rdlen */
  342. rr = &rd->rd;
  343. switch(rd->rd_type) {
  344. case T_CNAME:
  345. pack_dname(p, rr->cname.cname);
  346. break;
  347. case T_MX:
  348. pack_u16(p, rr->mx.preference);
  349. pack_dname(p, rr->mx.exchange);
  350. break;
  351. case T_NS:
  352. pack_dname(p, rr->ns.nsname);
  353. break;
  354. case T_PTR:
  355. pack_dname(p, rr->ptr.ptrname);
  356. break;
  357. case T_SOA:
  358. pack_dname(p, rr->soa.mname);
  359. pack_dname(p, rr->soa.rname);
  360. pack_u32(p, rr->soa.serial);
  361. pack_u32(p, rr->soa.refresh);
  362. pack_u32(p, rr->soa.retry);
  363. pack_u32(p, rr->soa.expire);
  364. pack_u32(p, rr->soa.minimum);
  365. break;
  366. case T_A:
  367. if (rd->rd_class != C_IN)
  368. goto other;
  369. pack_inaddr(p, rr->in_a.addr);
  370. break;
  371. case T_AAAA:
  372. if (rd->rd_class != C_IN)
  373. goto other;
  374. pack_in6addr(p, rr->in_aaaa.addr6);
  375. break;
  376. default:
  377. other:
  378. pack_data(p, rr->other.rdata, rr->other.rdlen);
  379. }
  380. if (p->err)
  381. return (-1);
  382. /* rewrite rdlen */
  383. pack_u16(&save, p->offset - save.offset - 2);
  384. p->err = save.err;
  385. return (p->err) ? (-1) : (0);
  386. }