e2114378b9
Signed-off-by: songlinzhang <songlinzhang@xiaomi.com>
315 lines
6.3 KiB
C
315 lines
6.3 KiB
C
/****************************************************************************
|
|
* 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 <string.h>
|
|
#include <resolv.h>
|
|
|
|
/* 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, dest<dend */
|
|
|
|
if ((*p & 0xc0) != 0)
|
|
{
|
|
if (p + 1 == end)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
j = ((p[0] & 0x3f) << 8) | p[1];
|
|
if (len < 0)
|
|
{
|
|
len = p + 2 - src;
|
|
}
|
|
|
|
if (j >= 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;
|
|
}
|