|
@@ -344,6 +344,139 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, int len, int decorate)
|
|
|
return ptr;
|
|
|
}
|
|
|
|
|
|
+/** Parse an .in-addr.arpa or .ip6.arpa address from <b>address</b>. Return 0
|
|
|
+ * if this is not an .in-addr.arpa address or an .ip6.arpa address. Return -1
|
|
|
+ * if this is an ill-formed .in-addr.arpa address or an .ip6.arpa address.
|
|
|
+ * Also return -1 if <b>family</b> is not AF_UNSPEC, and the parsed address
|
|
|
+ * family does not match <b>family</b>. On success, return 1, and store the
|
|
|
+ * result, if any, into <b>result</b>, if provided.
|
|
|
+ *
|
|
|
+ * If <b>accept_regular</b> is set and the address is in neither recognized
|
|
|
+ * reverse lookup hostname format, try parsing the address as a regular
|
|
|
+ * IPv4 or IPv6 address too.
|
|
|
+ */
|
|
|
+int
|
|
|
+tor_addr_parse_reverse_lookup_name(tor_addr_t *result, const char *address,
|
|
|
+ int family, int accept_regular)
|
|
|
+{
|
|
|
+ if (!strcasecmpend(address, ".in-addr.arpa")) {
|
|
|
+ /* We have an in-addr.arpa address. */
|
|
|
+ char buf[INET_NTOA_BUF_LEN];
|
|
|
+ size_t len;
|
|
|
+ struct in_addr inaddr;
|
|
|
+ if (family == AF_INET6)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ len = strlen(address) - strlen(".in-addr.arpa");
|
|
|
+ if (len >= INET_NTOA_BUF_LEN)
|
|
|
+ return -1; /* Too long. */
|
|
|
+
|
|
|
+ memcpy(buf, address, len);
|
|
|
+ buf[len] = '\0';
|
|
|
+ if (tor_inet_aton(buf, &inaddr) == 0)
|
|
|
+ return -1; /* malformed. */
|
|
|
+
|
|
|
+ /* reverse the bytes */
|
|
|
+ inaddr.s_addr = (((inaddr.s_addr & 0x000000fful) << 24)
|
|
|
+ |((inaddr.s_addr & 0x0000ff00ul) << 8)
|
|
|
+ |((inaddr.s_addr & 0x00ff0000ul) >> 8)
|
|
|
+ |((inaddr.s_addr & 0xff000000ul) >> 24));
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ memset(result, 0, sizeof(tor_addr_t));
|
|
|
+ result->family = AF_INET;
|
|
|
+ result->addr.in_addr.s_addr = inaddr.s_addr;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!strcasecmpend(address, ".ip6.arpa")) {
|
|
|
+ const char *cp;
|
|
|
+ int i;
|
|
|
+ int n0, n1;
|
|
|
+ struct in6_addr in6;
|
|
|
+
|
|
|
+ if (family == AF_INET)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ cp = address;
|
|
|
+ for (i = 0; i < 16; ++i) {
|
|
|
+ n0 = hex_decode_digit(*cp++); /* The low-order nybble appears first. */
|
|
|
+ if (*cp++ != '.') return -1; /* Then a dot. */
|
|
|
+ n1 = hex_decode_digit(*cp++); /* The high-order nybble appears first. */
|
|
|
+ if (*cp++ != '.') return -1; /* Then another dot. */
|
|
|
+ if (n0<0 || n1 < 0) /* Both nybbles must be hex. */
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ /* We don't check the length of the string in here. But that's okay,
|
|
|
+ * since we already know that the string ends with ".ip6.arpa", and
|
|
|
+ * there is no way to frameshift .ip6.arpa so it fits into the pattern
|
|
|
+ * of hexdigit, period, hexdigit, period that we enforce above.
|
|
|
+ */
|
|
|
+
|
|
|
+ /* Assign from low-byte to high-byte. */
|
|
|
+ in6.s6_addr[15-i] = n0 | (n1 << 4);
|
|
|
+ }
|
|
|
+ if (strcasecmp(cp, "ip6.arpa"))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ result->family = AF_INET6;
|
|
|
+ memcpy(&result->addr.in6_addr, &in6, sizeof(in6));
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (accept_regular) {
|
|
|
+ tor_addr_t tmp;
|
|
|
+ int r = tor_addr_from_str(&tmp, address);
|
|
|
+ if (r < 0)
|
|
|
+ return 0;
|
|
|
+ if (r != family && family != AF_UNSPEC)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (result)
|
|
|
+ memcpy(result, &tmp, sizeof(tor_addr_t));
|
|
|
+
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/** Convert <b>addr</b> to an in-addr.arpa name or a .ip6.arpa name, and store
|
|
|
+ * the result in the <b>outlen</b>-byte buffer at <b>out</b>. Return 0 on
|
|
|
+ * success, -1 on failure. */
|
|
|
+int
|
|
|
+tor_addr_to_reverse_lookup_name(char *out, size_t outlen,
|
|
|
+ const tor_addr_t *addr)
|
|
|
+{
|
|
|
+ if (addr->family == AF_INET) {
|
|
|
+ uint32_t a = tor_addr_to_ipv4h(addr);
|
|
|
+
|
|
|
+ return tor_snprintf(out, outlen, "%d.%d.%d.%d.in-addr.arpa",
|
|
|
+ (int)(uint8_t)((a )&0xff),
|
|
|
+ (int)(uint8_t)((a>>8 )&0xff),
|
|
|
+ (int)(uint8_t)((a>>16)&0xff),
|
|
|
+ (int)(uint8_t)((a>>24)&0xff));
|
|
|
+ } else if (addr->family == AF_INET6) {
|
|
|
+ int i;
|
|
|
+ char *cp = out;
|
|
|
+ if (outlen < REVERSE_LOOKUP_NAME_BUF_LEN)
|
|
|
+ return -1;
|
|
|
+ for (i = 15; i >= 0; --i) {
|
|
|
+ uint8_t byte = addr->addr.in6_addr.s6_addr[i];
|
|
|
+ *cp++ = "0123456789abcdef"[byte & 0x0f];
|
|
|
+ *cp++ = '.';
|
|
|
+ *cp++ = "0123456789abcdef"[byte >> 4];
|
|
|
+ *cp++ = '.';
|
|
|
+ }
|
|
|
+ memcpy(cp, "ip6.arpa", 9); /* 8 characters plus nul */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
/** Parse a string <b>s</b> containing an IPv4/IPv6 address, and possibly
|
|
|
* a mask and port or port range. Store the parsed address in
|
|
|
* <b>addr_out</b>, a mask (if any) in <b>mask_out</b>, and port(s) (if any)
|
|
@@ -831,6 +964,13 @@ tor_dup_addr(const tor_addr_t *addr)
|
|
|
return tor_strdup(buf);
|
|
|
}
|
|
|
|
|
|
+/** Copy the address in <b>src</b> to <b>dest</b> */
|
|
|
+void
|
|
|
+tor_addr_assign(tor_addr_t *dest, const tor_addr_t *src)
|
|
|
+{
|
|
|
+ memcpy(dest, src, sizeof(tor_addr_t));
|
|
|
+}
|
|
|
+
|
|
|
/** Return a string representing the address <b>addr</b>. This string is
|
|
|
* statically allocated, and must not be freed. Each call to
|
|
|
* <b>fmt_addr</b> invalidates the last result of the function. This
|