/**************************************************************************** * libs/libc/netdb/lib_dn.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include /* RFC 1035 message compression */ /**************************************************************************** * Private Functions ****************************************************************************/ /* label start offsets of a compressed domain name s */ static int getoffs(FAR short *offs, FAR const unsigned char *base, FAR const unsigned char *s) { int i = 0; for (; ; ) { while ((*s & 0xc0) != 0) { if ((*s & 0xc0) != 0xc0) { return 0; } s = base + ((s[0] & 0x3f) << 8 | s[1]); } if (*s == 0) { return i; } if (s - base >= 0x4000) { return 0; } offs[i++] = s - base; s += *s + 1; } } /* label lengths of an ascii domain name s */ static int getlens(FAR unsigned char *lens, FAR const char *s, int l) { int i = 0; int j = 0; int k = 0; for (; ; ) { for (; j < l && s[j] != '.'; j++); if (j - k - 1 > 62) { return 0; } lens[i++] = j - k; if (j == l) { return i; } k = ++j; } } /* longest suffix match of an ascii domain with a compressed domain name dn */ static int match(FAR int *offset, FAR const unsigned char *base, FAR const unsigned char *dn, FAR const char *end, FAR const unsigned char *lens, int nlen) { int l; int o; int m = 0; short offs[128]; int noff = getoffs(offs, base, dn); if (noff == 0) { return 0; } for (; ; ) { l = lens[--nlen]; o = offs[--noff]; end -= l; if (l != base[o] || memcmp(base + o + 1, end, l) != 0) { return m; } *offset = o; m += l; if (nlen > 0) { m++; } if (nlen == 0 || noff == 0) { return m; } end--; } } /**************************************************************************** * Public Functions ****************************************************************************/ int dn_comp(FAR const char *src, FAR unsigned char *dst, int space, FAR unsigned char **dnptrs, FAR unsigned char **lastdnptr) { int i; int j; int n; int m = 0; int offset = 0; int bestlen = 0; int bestoff = 0; unsigned char lens[127]; FAR unsigned char **p = dnptrs; FAR const char *end; size_t l = strnlen(src, 255); if (l > 0 && src[l - 1] == '.') { l--; } if (l > 253 || space <= 0) { return -1; } if (l == 0) { *dst = 0; return 1; } end = src + l; n = getlens(lens, src, l); if (n == 0) { return -1; } if (dnptrs != NULL && *dnptrs != NULL) { for (p = dnptrs + 1 ; *p != NULL; p++) { m = match(&offset, *dnptrs, *p, end, lens, n); if (m > bestlen) { bestlen = m; bestoff = offset; if (m == l) { break; } } } } /* encode unmatched part */ if (space < l - bestlen + 2 + (bestlen - 1 < l - 1)) { return -1; } memcpy(dst + 1, src, l - bestlen); for (i = j = 0; i < l - bestlen; i += lens[j++] + 1) { dst[i] = lens[j]; } /* add tail */ if (bestlen > 0) { dst[i++] = 0xc0 | bestoff >> 8; dst[i++] = bestoff; } else { dst[i++] = 0; } /* save dst pointer */ if (i > 2 && lastdnptr != NULL && dnptrs != NULL && *dnptrs != NULL) { while (*p != NULL) { p++; } if (p + 1 < lastdnptr) { *p++ = dst; *p = 0; } } return i; } int dn_expand(FAR const unsigned char *base, FAR const unsigned char *end, FAR const unsigned char *src, FAR char *dest, int space) { FAR const unsigned char *p = src; FAR char *dend; FAR char *dbegin = dest; int len = -1; int i; int j; if (p == end || space <= 0) { return -1; } dend = dest + (space > 254 ? 254 : space); /* detect reference loop using an iteration counter */ for (i = 0; i < end - base; i += 2) { /* loop invariants: p= end - base) { return -1; } p = base + j; } else if (*p) { if (dest != dbegin) { *dest++ = '.'; } j = *p++; if (j >= end - p || j >= dend - dest) { return -1; } while (j--) { *dest++ = *p++; } } else { *dest = 0; if (len < 0) { len = p + 1 - src; } return len; } } return -1; }