📄 util.c
字号:
case '\\':
if ((cp[1] == 'x' || cp[1] == 'X')
&& TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3])) {
cp += 4;
} else if (TOR_ISODIGIT(cp[1])) {
cp += 2;
if (TOR_ISODIGIT(*cp)) ++cp;
if (TOR_ISODIGIT(*cp)) ++cp;
} else if (cp[1]) {
cp += 2;
} else {
return NULL;
}
break;
default:
++cp;
break;
}
}
end_of_loop:
out = *result = tor_malloc(cp-s + 1);
cp = s+1;
while (1) {
switch (*cp)
{
case '\"':
*out = '\0';
if (size_out) *size_out = out - *result;
return cp+1;
case '\0':
tor_fragile_assert();
tor_free(*result);
return NULL;
case '\\':
switch (cp[1])
{
case 'n': *out++ = '\n'; cp += 2; break;
case 'r': *out++ = '\r'; cp += 2; break;
case 't': *out++ = '\t'; cp += 2; break;
case 'x': case 'X':
*out++ = ((hex_decode_digit(cp[2])<<4) +
hex_decode_digit(cp[3]));
cp += 4;
break;
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7':
{
int n = cp[1]-'0';
cp += 2;
if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
if (n > 255) { tor_free(*result); return NULL; }
*out++ = (char)n;
}
break;
case '\'':
case '\"':
case '\\':
case '\?':
*out++ = cp[1];
cp += 2;
break;
default:
tor_free(*result); return NULL;
}
break;
default:
*out++ = *cp++;
}
}
}
/** Given a string containing part of a configuration file or similar format,
* advance past comments and whitespace and try to parse a single line. If we
* parse a line successfully, set *<b>key_out</b> to a new string holding the
* key portion and *<b>value_out</b> to a new string holding the value portion
* of the line, and return a pointer to the start of the next line. If we run
* out of data, return a pointer to the end of the string. If we encounter an
* error, return NULL.
*/
const char *
parse_config_line_from_str(const char *line, char **key_out, char **value_out)
{
const char *key, *val, *cp;
tor_assert(key_out);
tor_assert(value_out);
*key_out = *value_out = NULL;
key = val = NULL;
/* Skip until the first keyword. */
while (1) {
while (TOR_ISSPACE(*line))
++line;
if (*line == '#') {
while (*line && *line != '\n')
++line;
} else {
break;
}
}
if (!*line) { /* End of string? */
*key_out = *value_out = NULL;
return line;
}
/* Skip until the next space. */
key = line;
while (*line && !TOR_ISSPACE(*line) && *line != '#')
++line;
*key_out = tor_strndup(key, line-key);
/* Skip until the value. */
while (*line == ' ' || *line == '\t')
++line;
val = line;
/* Find the end of the line. */
if (*line == '\"') {
if (!(line = unescape_string(line, value_out, NULL)))
return NULL;
while (*line == ' ' || *line == '\t')
++line;
if (*line && *line != '#' && *line != '\n')
return NULL;
} else {
while (*line && *line != '\n' && *line != '#')
++line;
if (*line == '\n') {
cp = line++;
} else {
cp = line;
}
while (cp>val && TOR_ISSPACE(*(cp-1)))
--cp;
tor_assert(cp >= val);
*value_out = tor_strndup(val, cp-val);
}
if (*line == '#') {
do {
++line;
} while (*line && *line != '\n');
}
while (TOR_ISSPACE(*line)) ++line;
return line;
}
/** Expand any homedir prefix on <b>filename</b>; return a newly allocated
* string. */
char *
expand_filename(const char *filename)
{
tor_assert(filename);
if (*filename == '~') {
size_t len;
char *home, *result;
const char *rest;
if (filename[1] == '/' || filename[1] == '\0') {
home = getenv("HOME");
if (!home) {
log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while "
"expanding \"%s\"", filename);
return NULL;
}
home = tor_strdup(home);
rest = strlen(filename)>=2?(filename+2):"";
} else {
#ifdef HAVE_PWD_H
char *username, *slash;
slash = strchr(filename, '/');
if (slash)
username = tor_strndup(filename+1,slash-filename-1);
else
username = tor_strdup(filename+1);
if (!(home = get_user_homedir(username))) {
log_warn(LD_CONFIG,"Couldn't get homedir for \"%s\"",username);
tor_free(username);
return NULL;
}
tor_free(username);
rest = slash ? (slash+1) : "";
#else
log_warn(LD_CONFIG, "Couldn't expend homedir on system without pwd.h");
return tor_strdup(filename);
#endif
}
tor_assert(home);
/* Remove trailing slash. */
if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) {
home[strlen(home)-1] = '\0';
}
/* Plus one for /, plus one for NUL.
* Round up to 16 in case we can't do math. */
len = strlen(home)+strlen(rest)+16;
result = tor_malloc(len);
tor_snprintf(result,len,"%s"PATH_SEPARATOR"%s",home,rest);
tor_free(home);
return result;
} else {
return tor_strdup(filename);
}
}
/** Return a new list containing the filenames in the directory <b>dirname</b>.
* Return NULL on error or if <b>dirname</b> is not a directory.
*/
smartlist_t *
tor_listdir(const char *dirname)
{
smartlist_t *result;
#ifdef MS_WINDOWS
char *pattern;
HANDLE handle;
WIN32_FIND_DATA findData;
size_t pattern_len = strlen(dirname)+16;
pattern = tor_malloc(pattern_len);
tor_snprintf(pattern, pattern_len, "%s\\*", dirname);
if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(pattern, &findData))) {
tor_free(pattern);
return NULL;
}
result = smartlist_create();
while (1) {
if (strcmp(findData.cFileName, ".") &&
strcmp(findData.cFileName, "..")) {
smartlist_add(result, tor_strdup(findData.cFileName));
}
if (!FindNextFile(handle, &findData)) {
if (GetLastError() != ERROR_NO_MORE_FILES) {
/* XXX021 can we say what the error is? */
log_warn(LD_FS, "Error reading directory '%s'.", dirname);
}
break;
}
}
FindClose(handle);
tor_free(pattern);
#else
DIR *d;
struct dirent *de;
if (!(d = opendir(dirname)))
return NULL;
result = smartlist_create();
while ((de = readdir(d))) {
if (!strcmp(de->d_name, ".") ||
!strcmp(de->d_name, ".."))
continue;
smartlist_add(result, tor_strdup(de->d_name));
}
closedir(d);
#endif
return result;
}
/** Return true iff <b>filename</b> is a relative path. */
int
path_is_relative(const char *filename)
{
if (filename && filename[0] == '/')
return 0;
#ifdef MS_WINDOWS
else if (filename && filename[0] == '\\')
return 0;
else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) &&
filename[1] == ':' && filename[2] == '\\')
return 0;
#endif
else
return 1;
}
/* =====
* Net helpers
* ===== */
/** Return true iff <b>ip</b> (in host order) is an IP reserved to localhost,
* or reserved for local networks by RFC 1918.
*/
int
is_internal_IP(uint32_t ip, int for_listening)
{
tor_addr_t myaddr;
myaddr.family = AF_INET;
myaddr.addr.in_addr.s_addr = htonl(ip);
return tor_addr_is_internal(&myaddr, for_listening);
}
/** Return true iff <b>ip</b> is an IP reserved to localhost or local networks
* in RFC1918 or RFC4193 or RFC4291. (fec0::/10, deprecated by RFC3879, is
* also treated as internal for now.)
*/
int
tor_addr_is_internal(const tor_addr_t *addr, int for_listening)
{
uint32_t iph4 = 0;
uint32_t iph6[4];
sa_family_t v_family;
v_family = IN_FAMILY(addr);
if (v_family == AF_INET) {
iph4 = IPV4IPh(addr);
} else if (v_family == AF_INET6) {
if (tor_addr_is_v4(addr)) { /* v4-mapped */
v_family = AF_INET;
iph4 = ntohl(IN6_ADDRESS32(addr)[3]);
}
}
if (v_family == AF_INET6) {
iph6[0] = ntohl(IN6_ADDRESS32(addr)[0]);
iph6[1] = ntohl(IN6_ADDRESS32(addr)[1]);
iph6[2] = ntohl(IN6_ADDRESS32(addr)[2]);
iph6[3] = ntohl(IN6_ADDRESS32(addr)[3]);
if (for_listening && !iph6[0] && !iph6[1] && !iph6[2] && !iph6[3]) /* :: */
return 0;
if (((iph6[0] & 0xfe000000) == 0xfc000000) || /* fc00/7 - RFC4193 */
((iph6[0] & 0xffc00000) == 0xfe800000) || /* fe80/10 - RFC4291 */
((iph6[0] & 0xffc00000) == 0xfec00000)) /* fec0/10 D- RFC3879 */
return 1;
if (!iph6[0] && !iph6[1] && !iph6[2] &&
((iph6[3] & 0xfffffffe) == 0x00000000)) /* ::/127 */
return 1;
return 0;
} else if (v_family == AF_INET) {
if (for_listening && !iph4) /* special case for binding to 0.0.0.0 */
return 0;
if (((iph4 & 0xff000000) == 0x0a000000) || /* 10/8 */
((iph4 & 0xff000000) == 0x00000000) || /* 0/8 */
((iph4 & 0xff000000) == 0x7f000000) || /* 127/8 */
((iph4 & 0xffff0000) == 0xa9fe0000) || /* 169.254/16 */
((iph4 & 0xfff00000) == 0xac100000) || /* 172.16/12 */
((iph4 & 0xffff0000) == 0xc0a80000)) /* 192.168/16 */
return 1;
return 0;
}
/* unknown address family... assume it's not safe for external use */
/* rather than tor_assert(0) */
log_warn(LD_BUG, "tor_addr_is_internal() called with a non-IP address.");
return 1;
}
#if 0
/** Convert a tor_addr_t <b>addr</b> into a string, and store it in
* <b>dest</b> of size <b>len</b>. Returns a pointer to dest on success,
* or NULL on failure.
*/
void
tor_addr_to_str(char *dest, const tor_addr_t *addr, int len)
{
const char *ptr;
tor_assert(addr && dest);
switch (IN_FAMILY(addr)) {
case AF_INET:
ptr = tor_inet_ntop(AF_INET, &addr->sa.sin_addr, dest, len);
break;
case AF_INET6:
ptr = tor_inet_ntop(AF_INET6, &addr->sa6.sin6_addr, dest, len);
break;
default:
return NULL;
}
return ptr;
}
#endif
/** Parse a string of the form "host[:port]" from <b>addrport</b>. If
* <b>address</b> is provided, set *<b>address</b> to a copy of the
* host portion of the string. If <b>addr</b> is provided, try to
* resolve the host portion of the string and store it into
* *<b>addr</b> (in host byte order). If <b>port_out</b> is provided,
* store the port number into *<b>port_out</b>, or 0 if no port is given.
* If <b>port_out</b> is NULL, then there must be no port number in
* <b>addrport</b>.
* Return 0 on success, -1 on failure.
*/
int
parse_addr_port(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out)
{
const char *colon;
char *_address = NULL;
int _port;
int ok = 1;
tor_assert(addrport);
colon = strchr(addrport, ':');
if (colon) {
_address = tor_strndup(addrport, colon-addrport);
_port = (int) tor_parse_long(colon+1,10,1,65535,NULL,NULL);
if (!_port) {
log_fn(severity, LD_GENERAL, "Port %s out of range", escaped(colon+1));
ok = 0;
}
if (!port_out) {
char *esc_addrport = esc_for_log(addrport);
log_fn(severity, LD_GENERAL,
"Port %s given on %s when not required",
escaped(colon+1), esc_addrport);
tor_free(esc_addrport);
ok = 0;
}
} else {
_address = tor_strdup(addrport);
_port = 0;
}
if (addr) {
/* There's an addr pointer, so we need to resolve the hostname. */
if (tor_lookup_hostname(_address,addr)) {
log_fn(severity, LD_NET, "Couldn't look up %s", escaped(_address));
ok = 0;
*addr = 0;
}
}
if (address && ok) {
*address = _address;
} else {
if (address)
*address = NULL;
tor_free(_address);
}
if (port_out)
*port_out = ok ? ((uint16_t) _port) : 0;
return ok ? 0 : -1;
}
/** If <b>mask</b> is an address mask for a bit-prefix, return the number of
* bits. Otherwise, return -1. */
int
addr_mask_get_bits(uint32_t mask)
{
int i;
if (mask == 0)
return 0;
if (mask == 0xFFFFFFFFu)
return 32;
for (i=0; i<=32; ++i) {
if (mask == (uint32_t) ~((1u<<(32-i))-1)) {
return i;
}
}
return -1;
}
/** Compare two addresses <b>a1</b> and <b>a2</b> for equality under a
* etmask of <b>mbits</b> bits. Return -1, 0, or 1.
*
* XXXX_IP6 Temporary function to allow masks as bitcounts everywhere. This
* will be replaced with an IPv6-aware version as soon as 32-bit addresses are
* no lo
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -