aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/domain_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/domain_codec.c')
-rw-r--r--networking/udhcp/domain_codec.c73
1 files changed, 39 insertions, 34 deletions
diff --git a/networking/udhcp/domain_codec.c b/networking/udhcp/domain_codec.c
index 6f051c4b0..45354e727 100644
--- a/networking/udhcp/domain_codec.c
+++ b/networking/udhcp/domain_codec.c
@@ -25,16 +25,9 @@
25 */ 25 */
26char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre) 26char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
27{ 27{
28 const uint8_t *c; 28 char *ret = ret; /* for compiler */
29 int crtpos, retpos, depth, plen = 0, len = 0;
30 char *dst = NULL; 29 char *dst = NULL;
31 30
32 if (!cstr)
33 return NULL;
34
35 if (pre)
36 plen = strlen(pre);
37
38 /* We make two passes over the cstr string. First, we compute 31 /* We make two passes over the cstr string. First, we compute
39 * how long the resulting string would be. Then we allocate a 32 * how long the resulting string would be. Then we allocate a
40 * new buffer of the required length, and fill it in with the 33 * new buffer of the required length, and fill it in with the
@@ -42,59 +35,71 @@ char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
42 * having to deal with requiring callers to supply their own 35 * having to deal with requiring callers to supply their own
43 * buffer, then having to check if it's sufficiently large, etc. 36 * buffer, then having to check if it's sufficiently large, etc.
44 */ 37 */
45 38 while (1) {
46 while (!dst) { 39 /* note: "return NULL" below are leak-safe since
47 40 * dst isn't yet allocated */
48 if (len > 0) { /* second pass? allocate dst buffer and copy pre */ 41 const uint8_t *c;
49 dst = xmalloc(len + plen); 42 unsigned crtpos, retpos, depth, len;
50 memcpy(dst, pre, plen);
51 }
52 43
53 crtpos = retpos = depth = len = 0; 44 crtpos = retpos = depth = len = 0;
54
55 while (crtpos < clen) { 45 while (crtpos < clen) {
56 c = cstr + crtpos; 46 c = cstr + crtpos;
57 47
58 if ((*c & NS_CMPRSFLGS) != 0) { /* pointer */ 48 if (*c & NS_CMPRSFLGS) {
59 if (crtpos + 2 > clen) /* no offset to jump to? abort */ 49 /* pointer */
50 if (crtpos + 2 > clen) /* no offset to jump to? abort */
60 return NULL; 51 return NULL;
61 if (retpos == 0) /* toplevel? save return spot */ 52 if (retpos == 0) /* toplevel? save return spot */
62 retpos = crtpos + 2; 53 retpos = crtpos + 2;
63 depth++; 54 depth++;
64 crtpos = ((*c & 0x3f) << 8) | (*(c + 1) & 0xff); /* jump */ 55 crtpos = ((c[0] & 0x3f) << 8) | (c[1] & 0xff); /* jump */
65 } else if (*c) { /* label */ 56 } else if (*c) {
66 if (crtpos + *c + 1 > clen) /* label too long? abort */ 57 /* label */
58 if (crtpos + *c + 1 > clen) /* label too long? abort */
67 return NULL; 59 return NULL;
68 if (dst) 60 if (dst)
69 memcpy(dst + plen + len, c + 1, *c); 61 memcpy(dst + len, c + 1, *c);
70 len += *c + 1; 62 len += *c + 1;
71 crtpos += *c + 1; 63 crtpos += *c + 1;
72 if (dst) 64 if (dst)
73 *(dst + plen + len - 1) = '.'; 65 dst[len - 1] = '.';
74 } else { /* null: end of current domain name */ 66 } else {
75 if (retpos == 0) { /* toplevel? keep going */ 67 /* null: end of current domain name */
68 if (retpos == 0) {
69 /* toplevel? keep going */
76 crtpos++; 70 crtpos++;
77 } else { /* return to toplevel saved spot */ 71 } else {
72 /* return to toplevel saved spot */
78 crtpos = retpos; 73 crtpos = retpos;
79 retpos = depth = 0; 74 retpos = depth = 0;
80 } 75 }
81 if (dst) 76 if (dst)
82 *(dst + plen + len - 1) = ' '; 77 dst[len - 1] = ' ';
83 } 78 }
84 79
85 if (depth > NS_MAXDNSRCH || /* too many jumps? abort, it's a loop */ 80 if (depth > NS_MAXDNSRCH /* too many jumps? abort, it's a loop */
86 len > NS_MAXDNAME * NS_MAXDNSRCH) /* result too long? abort */ 81 || len > NS_MAXDNAME * NS_MAXDNSRCH /* result too long? abort */
82 ) {
87 return NULL; 83 return NULL;
84 }
88 } 85 }
89 86
90 if (!len) /* expanded string has 0 length? abort */ 87 if (!len) /* expanded string has 0 length? abort */
91 return NULL; 88 return NULL;
92 89
93 if (dst) 90 if (!dst) { /* first pass? */
94 *(dst + plen + len - 1) = '\0'; 91 /* allocate dst buffer and copy pre */
92 unsigned plen = strlen(pre);
93 ret = dst = xmalloc(plen + len);
94 memcpy(dst, pre, plen);
95 dst += plen;
96 } else {
97 dst[len - 1] = '\0';
98 break;
99 }
95 } 100 }
96 101
97 return dst; 102 return ret;
98} 103}
99 104
100/* Convert a domain name (src) from human-readable "foo.blah.com" format into 105/* Convert a domain name (src) from human-readable "foo.blah.com" format into