📄 compat.c
字号:
#endif /* HAVE_GETRLIMIT */
if (limit < ULIMIT_BUFFER) {
log_warn(LD_CONFIG,
"ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER);
return -1;
}
if (limit > INT_MAX)
limit = INT_MAX;
tor_assert(max_out);
*max_out = (int)limit - ULIMIT_BUFFER;
return 0;
}
/** Call setuid and setgid to run as <b>user</b>:<b>group</b>. Return 0 on
* success. On failure, log and return -1.
*/
int
switch_id(const char *user, const char *group)
{
#ifndef MS_WINDOWS
struct passwd *pw = NULL;
struct group *gr = NULL;
if (user) {
pw = getpwnam(user);
if (pw == NULL) {
log_warn(LD_CONFIG,"User '%s' not found.", user);
return -1;
}
}
/* switch the group first, while we still have the privileges to do so */
if (group) {
gr = getgrnam(group);
if (gr == NULL) {
log_warn(LD_CONFIG,"Group '%s' not found.", group);
return -1;
}
if (setgid(gr->gr_gid) != 0) {
log_warn(LD_GENERAL,"Error setting to configured GID: %s",
strerror(errno));
return -1;
}
} else if (user) {
if (setgid(pw->pw_gid) != 0) {
log_warn(LD_GENERAL,"Error setting to user GID: %s", strerror(errno));
return -1;
}
}
/* now that the group is switched, we can switch users and lose
privileges */
if (user) {
if (setuid(pw->pw_uid) != 0) {
log_warn(LD_GENERAL,"Error setting UID: %s", strerror(errno));
return -1;
}
}
return 0;
#else
(void)user;
(void)group;
#endif
log_warn(LD_CONFIG,
"User or group specified, but switching users is not supported.");
return -1;
}
#ifdef HAVE_PWD_H
/** Allocate and return a string containing the home directory for the
* user <b>username</b>. Only works on posix-like systems. */
char *
get_user_homedir(const char *username)
{
struct passwd *pw;
tor_assert(username);
if (!(pw = getpwnam(username))) {
log_err(LD_CONFIG,"User \"%s\" not found.", username);
return NULL;
}
return tor_strdup(pw->pw_dir);
}
#endif
/** Set *addr to the IP address (in dotted-quad notation) stored in c.
* Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr),
* but works on Windows and Solaris.)
*/
int
tor_inet_aton(const char *c, struct in_addr* addr)
{
#ifdef HAVE_INET_ATON
return inet_aton(c, addr);
#else
uint32_t r;
tor_assert(c);
tor_assert(addr);
if (strcmp(c, "255.255.255.255") == 0) {
addr->s_addr = 0xFFFFFFFFu;
return 1;
}
r = inet_addr(c);
if (r == INADDR_NONE)
return 0;
addr->s_addr = r;
return 1;
#endif
}
/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or
* <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the
* address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns
* <b>dst</b> on success, NULL on failure.
*
* (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it:
* Tor sometimes needs to format ipv6 addresses even on platforms without ipv6
* support.) */
const char *
tor_inet_ntop(int af, const void *src, char *dst, size_t len)
{
if (af == AF_INET) {
if (tor_inet_ntoa(src, dst, len) < 0)
return NULL;
else
return dst;
} else if (af == AF_INET6) {
const struct in6_addr *addr = src;
char buf[64], *cp;
int longestGapLen = 0, longestGapPos = -1, i,
curGapPos = -1, curGapLen = 0;
uint16_t words[8];
for (i = 0; i < 8; ++i) {
words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
}
if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
(words[5] == 0xffff))) {
/* This is an IPv4 address. */
if (words[5] == 0) {
tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
addr->s6_addr[12], addr->s6_addr[13],
addr->s6_addr[14], addr->s6_addr[15]);
} else {
tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
addr->s6_addr[12], addr->s6_addr[13],
addr->s6_addr[14], addr->s6_addr[15]);
}
if (strlen(buf) > len)
return NULL;
strlcpy(dst, buf, len);
return dst;
}
i = 0;
while (i < 8) {
if (words[i] == 0) {
curGapPos = i++;
curGapLen = 1;
while (i<8 && words[i] == 0) {
++i; ++curGapLen;
}
if (curGapLen > longestGapLen) {
longestGapPos = curGapPos;
longestGapLen = curGapLen;
}
} else {
++i;
}
}
if (longestGapLen<=1)
longestGapPos = -1;
cp = buf;
for (i = 0; i < 8; ++i) {
if (words[i] == 0 && longestGapPos == i) {
if (i == 0)
*cp++ = ':';
*cp++ = ':';
while (i < 8 && words[i] == 0)
++i;
--i; /* to compensate for loop increment. */
} else {
tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
cp += strlen(cp);
if (i != 7)
*cp++ = ':';
}
}
*cp = '\0';
if (strlen(buf) > len)
return NULL;
strlcpy(dst, buf, len);
return dst;
} else {
return NULL;
}
}
/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b>
* encoding an IPv4 address or IPv6 address correspondingly, try to parse the
* address and store the result in <b>dst</b> (which must have space for a
* struct in_addr or a struct in6_addr, as appropriate). Return 1 on success,
* 0 on a bad parse, and -1 on a bad <b>af</b>.
*
* (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor
* sometimes needs to format ipv6 addresses even on platforms without ipv6
* support.) */
int
tor_inet_pton(int af, const char *src, void *dst)
{
if (af == AF_INET) {
return tor_inet_aton(src, dst);
} else if (af == AF_INET6) {
struct in6_addr *out = dst;
uint16_t words[8];
int gapPos = -1, i, setWords=0;
const char *dot = strchr(src, '.');
const char *eow; /* end of words. */
if (dot == src)
return 0;
else if (!dot)
eow = src+strlen(src);
else {
int byte1,byte2,byte3,byte4;
char more;
for (eow = dot-1; eow >= src && TOR_ISDIGIT(*eow); --eow)
;
++eow;
/* We use "scanf" because some platform inet_aton()s are too lax
* about IPv4 addresses of the form "1.2.3" */
if (sscanf(eow, "%d.%d.%d.%d%c", &byte1,&byte2,&byte3,&byte4,&more) != 4)
return 0;
if (byte1 > 255 || byte1 < 0 ||
byte2 > 255 || byte2 < 0 ||
byte3 > 255 || byte3 < 0 ||
byte4 > 255 || byte4 < 0)
return 0;
words[6] = (byte1<<8) | byte2;
words[7] = (byte3<<8) | byte4;
setWords += 2;
}
i = 0;
while (src < eow) {
if (i > 7)
return 0;
if (TOR_ISXDIGIT(*src)) {
char *next;
long r = strtol(src, &next, 16);
if (next > 4+src)
return 0;
if (next == src)
return 0;
if (r<0 || r>65536)
return 0;
words[i++] = (uint16_t)r;
setWords++;
src = next;
if (*src != ':' && src != eow)
return 0;
++src;
} else if (*src == ':' && i > 0 && gapPos==-1) {
gapPos = i;
++src;
} else if (*src == ':' && i == 0 && src[1] == ':' && gapPos==-1) {
gapPos = i;
src += 2;
} else {
return 0;
}
}
if (setWords > 8 ||
(setWords == 8 && gapPos != -1) ||
(setWords < 8 && gapPos == -1))
return 0;
if (gapPos >= 0) {
int nToMove = setWords - (dot ? 2 : 0) - gapPos;
int gapLen = 8 - setWords;
tor_assert(nToMove >= 0);
memmove(&words[gapPos+gapLen], &words[gapPos],
sizeof(uint16_t)*nToMove);
memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
}
for (i = 0; i < 8; ++i) {
out->s6_addr[2*i ] = words[i] >> 8;
out->s6_addr[2*i+1] = words[i] & 0xff;
}
return 1;
} else {
return -1;
}
}
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
* *<b>addr</b> to the proper IP address, in host byte order. Returns 0
* on success, -1 on failure; 1 on transient failure.
*
* (This function exists because standard windows gethostbyname
* doesn't treat raw IP addresses properly.)
*/
int
tor_lookup_hostname(const char *name, uint32_t *addr)
{
tor_addr_t myaddr;
int ret;
if ((ret = tor_addr_lookup(name, AF_INET, &myaddr)))
return ret;
if (IN_FAMILY(&myaddr) == AF_INET) {
*addr = IPV4IPh(&myaddr);
return ret;
}
return -1;
}
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
* *<b>addr</b> to the proper IP address and family. The <b>family</b>
* argument (which must be AF_INET, AF_INET6, or AF_UNSPEC) declares a
* <i>preferred</i> family, though another one may be returned if only one
* family is implemented for this address.
*
* Return 0 on success, -1 on failure; 1 on transient failure.
*/
int
tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr)
{
/* Perhaps eventually this should be replaced by a tor_getaddrinfo or
* something.
*/
struct in_addr iaddr;
struct in6_addr iaddr6;
tor_assert(name);
tor_assert(addr);
tor_assert(family == AF_INET || family == AF_UNSPEC);
memset(addr, 0, sizeof(addr)); /* Clear the extraneous fields. */
if (!*name) {
/* Empty address is an error. */
return -1;
} else if (tor_inet_pton(AF_INET, name, &iaddr)) {
/* It's an IPv4 IP. */
addr->family = AF_INET;
memcpy(&addr->addr.in_addr, &iaddr, sizeof(struct in_addr));
return 0;
} else if (tor_inet_pton(AF_INET6, name, &iaddr6)) {
addr->family = AF_INET6;
memcpy(&addr->addr.in6_addr, &iaddr6, sizeof(struct in6_addr));
return 0;
} else {
#ifdef HAVE_GETADDRINFO
int err;
struct addrinfo *res=NULL, *res_p;
struct addrinfo *best=NULL;
struct addrinfo hints;
int result = -1;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(name, NULL, &hints, &res);
if (!err) {
best = NULL;
for (res_p = res; res_p; res_p = res_p->ai_next) {
if (family == AF_UNSPEC) {
if (res_p->ai_family == AF_INET) {
best = res_p;
break;
} else if (res_p->ai_family == AF_INET6 && !best) {
best = res_p;
}
} else if (family == res_p->ai_family) {
best = res_p;
break;
}
}
if (!best)
best = res;
if (best->ai_family == AF_INET) {
addr->family = AF_INET;
memcpy(&addr->addr.in_addr,
&((struct sockaddr_in*)best->ai_addr)->sin_addr,
sizeof(struct in_addr));
result = 0;
} else if (best->ai_family == AF_INET6) {
addr->family = AF_INET6;
memcpy(&addr->addr.in6_addr,
&((struct sockaddr_in6*)best->ai_addr)->sin6_addr,
sizeof(struct in6_addr));
result = 0;
}
freeaddrinfo(res);
return result;
}
return (err == EAI_AGAIN) ? 1 : -1;
#else
struct hostent *ent;
int err;
#ifdef HAVE_GETHOSTBYNAME_R_6_ARG
char buf[2048];
struct hostent hostent;
int r;
r = gethostbyname_r(name, &hostent, buf, sizeof(buf), &ent, &err);
#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG)
char buf[2048];
struct hostent hostent;
ent = gethostbyname_r(name, &hostent, buf, sizeof(buf), &err);
#elif defined(HAVE_GETHOSTBYNAME_R_3_ARG)
struct hostent_data data;
struct hostent hent;
memset(&data, 0, sizeof(data));
err = gethostbyname_r(name, &hent, &data);
ent = err ? NULL : &hent;
#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -