diff options
Diffstat (limited to 'networking/udhcp/domain_codec.c')
-rw-r--r-- | networking/udhcp/domain_codec.c | 73 |
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 | */ |
26 | char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre) | 26 | char* 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 |