2017-10-23 06:17:38 +02:00
|
|
|
#include <arpa/inet.h>
|
2017-10-23 06:16:38 +02:00
|
|
|
#include <assert.h>
|
2018-05-07 06:29:21 +02:00
|
|
|
#include <common/status.h>
|
|
|
|
#include <common/type_to_string.h>
|
2017-10-23 06:18:38 +02:00
|
|
|
#include <errno.h>
|
2018-05-07 06:29:21 +02:00
|
|
|
#include <gossipd/netaddress.h>
|
2017-10-23 06:16:38 +02:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <wire/wire.h>
|
|
|
|
|
|
|
|
/* Based on bitcoin's src/netaddress.cpp, hence different naming and styling!
|
|
|
|
version 7f31762cb6261806542cc6d1188ca07db98a6950:
|
|
|
|
|
|
|
|
Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
|
|
Copyright (c) 2009-2016 The Bitcoin Core developers
|
|
|
|
Distributed under the MIT software license, see the accompanying
|
|
|
|
file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* The common IPv4-in-IPv6 prefix */
|
|
|
|
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC6145(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
static const unsigned char pchRFC6145[] = {0,0,0,0,0,0,0,0,0xFF,0xFF,0,0};
|
|
|
|
return addr->type == ADDR_TYPE_IPV6
|
|
|
|
&& memcmp(addr->addr, pchRFC6145, sizeof(pchRFC6145)) == 0;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC6052(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
static const unsigned char pchRFC6052[] = {0,0x64,0xFF,0x9B,0,0,0,0,0,0,0,0};
|
|
|
|
return addr->type == ADDR_TYPE_IPV6
|
|
|
|
&& memcmp(addr->addr, pchRFC6052, sizeof(pchRFC6052)) == 0;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC3964(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return addr->type == ADDR_TYPE_IPV6
|
|
|
|
&& addr->addr[0] == 0x20 && addr->addr[1] == 0x02;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return offset of IPv4 address, or 0 == not an IPv4 */
|
2017-10-23 06:17:38 +02:00
|
|
|
static size_t IPv4In6(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
if (addr->type != ADDR_TYPE_IPV6)
|
|
|
|
return 0;
|
|
|
|
if (memcmp(addr->addr, pchIPv4, sizeof(pchIPv4)) == 0)
|
|
|
|
return sizeof(pchIPv4);
|
|
|
|
if (IsRFC6052(addr))
|
|
|
|
return 12;
|
|
|
|
if (IsRFC6145(addr))
|
|
|
|
return 12;
|
|
|
|
if (IsRFC3964(addr))
|
|
|
|
return 2;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is this an IPv4 address, or an IPv6-wrapped IPv4 */
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsIPv4(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return addr->type == ADDR_TYPE_IPV4 || IPv4In6(addr) != 0;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsIPv6(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return addr->type == ADDR_TYPE_IPV6 && IPv4In6(addr) == 0;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool RawEq(const struct wireaddr *addr, const void *cmp, size_t len)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
size_t off = IPv4In6(addr);
|
|
|
|
|
|
|
|
assert(off + len <= addr->addrlen);
|
|
|
|
return memcmp(addr->addr + off, cmp, len) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The bitcoin code packs addresses backwards, so we map it here. */
|
2017-10-23 06:17:38 +02:00
|
|
|
static unsigned int GetByte(const struct wireaddr *addr, int n)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
size_t off = IPv4In6(addr);
|
|
|
|
assert(off + n < addr->addrlen);
|
|
|
|
return addr->addr[addr->addrlen - 1 - off - n];
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC1918(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsIPv4(addr) && (
|
|
|
|
GetByte(addr, 3) == 10 ||
|
|
|
|
(GetByte(addr, 3) == 192 && GetByte(addr, 2) == 168) ||
|
|
|
|
(GetByte(addr, 3) == 172 && (GetByte(addr, 2) >= 16 && GetByte(addr, 2) <= 31)));
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC2544(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsIPv4(addr) && GetByte(addr, 3) == 198 && (GetByte(addr, 2) == 18 || GetByte(addr, 2) == 19);
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC3927(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsIPv4(addr) && (GetByte(addr, 3) == 169 && GetByte(addr, 2) == 254);
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC6598(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsIPv4(addr) && GetByte(addr, 3) == 100 && GetByte(addr, 2) >= 64 && GetByte(addr, 2) <= 127;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC5737(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsIPv4(addr) && ((GetByte(addr, 3) == 192 && GetByte(addr, 2) == 0 && GetByte(addr, 1) == 2) ||
|
|
|
|
(GetByte(addr, 3) == 198 && GetByte(addr, 2) == 51 && GetByte(addr, 1) == 100) ||
|
|
|
|
(GetByte(addr, 3) == 203 && GetByte(addr, 2) == 0 && GetByte(addr, 1) == 113));
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC3849(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsIPv6(addr) && GetByte(addr, 15) == 0x20 && GetByte(addr, 14) == 0x01 && GetByte(addr, 13) == 0x0D && GetByte(addr, 12) == 0xB8;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC4862(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
static const unsigned char pchRFC4862[] = {0xFE,0x80,0,0,0,0,0,0};
|
|
|
|
return IsIPv6(addr) && RawEq(addr, pchRFC4862, sizeof(pchRFC4862));
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC4193(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsIPv6(addr) && ((GetByte(addr, 15) & 0xFE) == 0xFC);
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRFC4843(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsIPv6(addr) && (GetByte(addr, 15) == 0x20 && GetByte(addr, 14) == 0x01 && GetByte(addr, 13) == 0x00 && (GetByte(addr, 12) & 0xF0) == 0x10);
|
|
|
|
}
|
|
|
|
|
2018-02-21 16:06:07 +01:00
|
|
|
static bool IsTor(const struct wireaddr *addr UNUSED)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
/* FIXME */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsLocal(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
// IPv4 loopback
|
|
|
|
if (IsIPv4(addr) && (GetByte(addr, 3) == 127 || GetByte(addr, 3) == 0))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// IPv6 loopback (::1/128)
|
|
|
|
static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
|
|
|
|
if (IsIPv6(addr) && RawEq(addr, pchLocal, sizeof(pchLocal)))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsInternal(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return addr->type == ADDR_TYPE_PADDING;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsValid(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
// unspecified IPv6 address (::/128)
|
|
|
|
unsigned char ipNone6[16] = {};
|
|
|
|
if (IsIPv6(addr) && RawEq(addr, ipNone6, sizeof(ipNone6)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// documentation IPv6 address
|
|
|
|
if (IsRFC3849(addr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (IsInternal(addr))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (IsIPv4(addr))
|
|
|
|
{
|
|
|
|
// INADDR_NONE
|
|
|
|
uint32_t ipNone = INADDR_NONE;
|
|
|
|
if (RawEq(addr, &ipNone, sizeof(ipNone)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// 0
|
|
|
|
ipNone = 0;
|
|
|
|
if (RawEq(addr, &ipNone, sizeof(ipNone)))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-10-23 06:17:38 +02:00
|
|
|
static bool IsRoutable(const struct wireaddr *addr)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
return IsValid(addr) && !(IsRFC1918(addr) || IsRFC2544(addr) || IsRFC3927(addr) || IsRFC4862(addr) || IsRFC6598(addr) || IsRFC5737(addr) || (IsRFC4193(addr) && !IsTor(addr)) || IsRFC4843(addr) || IsLocal(addr) || IsInternal(addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Trick I learned from Harald Welte: create UDP socket, connect() and
|
|
|
|
* then query address. */
|
2018-05-07 06:29:12 +02:00
|
|
|
/* Returns 0 if protocol completely unsupported, ADDR_LISTEN if we
|
|
|
|
* can't reach addr, ADDR_LISTEN_AND_ANNOUNCE if we can (and fill saddr). */
|
2018-05-07 06:29:21 +02:00
|
|
|
static enum addr_listen_announce get_local_sockname(int af, void *saddr,
|
2018-05-07 06:29:12 +02:00
|
|
|
socklen_t saddrlen)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
|
|
|
int fd = socket(af, SOCK_DGRAM, 0);
|
2017-10-23 06:18:38 +02:00
|
|
|
if (fd < 0) {
|
2018-05-07 06:29:21 +02:00
|
|
|
status_trace("Failed to create %u socket: %s",
|
|
|
|
af, strerror(errno));
|
2018-05-07 06:29:12 +02:00
|
|
|
return 0;
|
2017-10-23 06:18:38 +02:00
|
|
|
}
|
2017-10-23 06:16:38 +02:00
|
|
|
|
|
|
|
if (connect(fd, saddr, saddrlen) != 0) {
|
2018-05-07 06:29:21 +02:00
|
|
|
status_trace("Failed to connect %u socket: %s",
|
|
|
|
af, strerror(errno));
|
2017-10-23 06:16:38 +02:00
|
|
|
close(fd);
|
2018-05-07 06:29:12 +02:00
|
|
|
return ADDR_LISTEN;
|
2017-10-23 06:16:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (getsockname(fd, saddr, &saddrlen) != 0) {
|
2018-05-07 06:29:21 +02:00
|
|
|
status_trace("Failed to get %u socket name: %s",
|
|
|
|
af, strerror(errno));
|
2017-10-23 06:16:38 +02:00
|
|
|
close(fd);
|
2018-05-07 06:29:12 +02:00
|
|
|
return ADDR_LISTEN;
|
2017-10-23 06:16:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
2018-05-07 06:29:12 +02:00
|
|
|
return ADDR_LISTEN_AND_ANNOUNCE;
|
2017-10-23 06:16:38 +02:00
|
|
|
}
|
|
|
|
|
2018-05-07 06:28:12 +02:00
|
|
|
/* Return 0 if not available, or whether it's listenable-only or announceable.
|
|
|
|
* If it's listenable only, will set wireaddr to all-zero address for universal
|
|
|
|
* binding. */
|
2018-05-07 06:29:21 +02:00
|
|
|
static enum addr_listen_announce guess_one_address(struct wireaddr *addr,
|
2018-05-07 06:28:12 +02:00
|
|
|
u16 portnum,
|
|
|
|
enum wire_addr_type type)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
2018-05-07 06:29:12 +02:00
|
|
|
enum addr_listen_announce ret;
|
|
|
|
|
2017-10-23 06:16:38 +02:00
|
|
|
addr->type = type;
|
|
|
|
addr->port = portnum;
|
|
|
|
|
|
|
|
/* We point to Google nameservers, works unless you're inside Google :) */
|
|
|
|
switch (type) {
|
|
|
|
case ADDR_TYPE_IPV4: {
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
sin.sin_port = htons(53);
|
|
|
|
/* 8.8.8.8 */
|
|
|
|
sin.sin_addr.s_addr = 0x08080808;
|
2017-10-23 06:18:38 +02:00
|
|
|
sin.sin_family = AF_INET;
|
2018-05-07 06:29:21 +02:00
|
|
|
ret = get_local_sockname(AF_INET, &sin, sizeof(sin));
|
2017-10-23 06:16:38 +02:00
|
|
|
addr->addrlen = sizeof(sin.sin_addr);
|
|
|
|
memcpy(addr->addr, &sin.sin_addr, addr->addrlen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ADDR_TYPE_IPV6: {
|
|
|
|
struct sockaddr_in6 sin6;
|
|
|
|
/* 2001:4860:4860::8888 */
|
|
|
|
static const unsigned char pchGoogle[16]
|
|
|
|
= {0x20,0x01,0x48,0x60,0x48,0x60,0,0,0,0,0,0,8,8,8,8};
|
|
|
|
memset(&sin6, 0, sizeof(sin6));
|
|
|
|
sin6.sin6_port = htons(53);
|
2017-10-23 06:18:38 +02:00
|
|
|
sin6.sin6_family = AF_INET6;
|
2017-10-23 06:16:38 +02:00
|
|
|
memcpy(sin6.sin6_addr.s6_addr, pchGoogle, sizeof(pchGoogle));
|
2018-05-07 06:29:21 +02:00
|
|
|
ret = get_local_sockname(AF_INET6, &sin6, sizeof(sin6));
|
2017-10-23 06:16:38 +02:00
|
|
|
addr->addrlen = sizeof(sin6.sin6_addr);
|
|
|
|
memcpy(addr->addr, &sin6.sin6_addr, addr->addrlen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ADDR_TYPE_PADDING:
|
2018-05-07 06:29:21 +02:00
|
|
|
status_trace("Padding address, ignoring");
|
2018-05-07 06:28:12 +02:00
|
|
|
return 0;
|
2017-10-23 06:16:38 +02:00
|
|
|
}
|
|
|
|
|
2018-05-07 06:29:12 +02:00
|
|
|
if (ret == 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
/* If we can reach it, but resulting address is unroutable, listen only */
|
|
|
|
if (ret == ADDR_LISTEN_AND_ANNOUNCE && !IsRoutable(addr)) {
|
2018-05-07 06:29:21 +02:00
|
|
|
status_trace("Address %s is not routable",
|
|
|
|
type_to_string(tmpctx, struct wireaddr, addr));
|
2018-05-07 06:29:12 +02:00
|
|
|
ret = ADDR_LISTEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == ADDR_LISTEN) {
|
2018-05-07 06:28:12 +02:00
|
|
|
/* This corresponds to INADDR_ANY or in6addr_any */
|
|
|
|
memset(addr->addr, 0, addr->addrlen);
|
2018-05-07 06:29:12 +02:00
|
|
|
} else {
|
2018-05-07 06:29:21 +02:00
|
|
|
status_trace("Public address %s",
|
|
|
|
type_to_string(tmpctx, struct wireaddr, addr));
|
2017-10-23 06:18:38 +02:00
|
|
|
}
|
2018-05-07 06:29:12 +02:00
|
|
|
return ret;
|
2017-10-23 06:16:38 +02:00
|
|
|
}
|
|
|
|
|
2018-05-07 06:29:21 +02:00
|
|
|
void guess_addresses(struct wireaddr_internal **wireaddrs,
|
2018-05-07 06:29:21 +02:00
|
|
|
enum addr_listen_announce **listen_announce,
|
|
|
|
u16 portnum)
|
2017-10-23 06:16:38 +02:00
|
|
|
{
|
2018-05-07 06:29:21 +02:00
|
|
|
size_t n = tal_count(*wireaddrs);
|
2017-10-23 06:16:38 +02:00
|
|
|
|
2018-05-07 06:29:21 +02:00
|
|
|
status_trace("Trying to guess public addresses...");
|
2017-10-23 06:18:38 +02:00
|
|
|
|
2017-10-23 06:16:38 +02:00
|
|
|
/* We allocate an extra, then remove if it's not needed. */
|
2018-05-07 06:29:21 +02:00
|
|
|
tal_resize(wireaddrs, n+1);
|
|
|
|
tal_resize(listen_announce, n+1);
|
2018-05-07 06:29:21 +02:00
|
|
|
|
|
|
|
(*wireaddrs)[n].itype = ADDR_INTERNAL_WIREADDR;
|
2018-05-07 06:28:12 +02:00
|
|
|
/* We do IPv6 first: on Linux, that binds to IPv4 too. */
|
2018-05-07 06:29:21 +02:00
|
|
|
(*listen_announce)[n] = guess_one_address(&(*wireaddrs)[n].u.wireaddr,
|
2018-05-07 06:29:21 +02:00
|
|
|
portnum, ADDR_TYPE_IPV6);
|
|
|
|
if ((*listen_announce)[n] != 0) {
|
2017-10-23 06:16:38 +02:00
|
|
|
n++;
|
2018-05-07 06:29:21 +02:00
|
|
|
tal_resize(wireaddrs, n+1);
|
|
|
|
tal_resize(listen_announce, n+1);
|
2018-05-07 06:29:21 +02:00
|
|
|
(*wireaddrs)[n].itype = ADDR_INTERNAL_WIREADDR;
|
2017-10-23 06:16:38 +02:00
|
|
|
}
|
2018-05-07 06:29:21 +02:00
|
|
|
(*listen_announce)[n] = guess_one_address(&(*wireaddrs)[n].u.wireaddr,
|
2018-05-07 06:29:21 +02:00
|
|
|
portnum, ADDR_TYPE_IPV4);
|
|
|
|
if ((*listen_announce)[n] == 0) {
|
|
|
|
tal_resize(wireaddrs, n);
|
|
|
|
tal_resize(listen_announce, n);
|
2018-05-07 06:28:12 +02:00
|
|
|
}
|
2017-10-23 06:16:38 +02:00
|
|
|
}
|