Make clients regenerate their keys when their IP address changes.
svn:r4688
This commit is contained in:
parent
ceb02cee2c
commit
11ff0aba80
|
@ -695,7 +695,8 @@ int parse_iso_time(const char *cp, time_t *t) {
|
|||
* must be 1 if fd was returned by socket() or accept(), and 0 if fd
|
||||
* was returned by open(). Return the number of bytes written, or -1
|
||||
* on error. Only use if fd is a blocking fd. */
|
||||
int write_all(int fd, const char *buf, size_t count, int isSocket) {
|
||||
int
|
||||
write_all(int fd, const char *buf, size_t count, int isSocket) {
|
||||
size_t written = 0;
|
||||
int result;
|
||||
|
||||
|
@ -716,7 +717,8 @@ int write_all(int fd, const char *buf, size_t count, int isSocket) {
|
|||
* was returned by socket() or accept(), and 0 if fd was returned by
|
||||
* open(). Return the number of bytes read, or -1 on error. Only use
|
||||
* if fd is a blocking fd. */
|
||||
int read_all(int fd, char *buf, size_t count, int isSocket) {
|
||||
int
|
||||
read_all(int fd, char *buf, size_t count, int isSocket) {
|
||||
size_t numread = 0;
|
||||
int result;
|
||||
|
||||
|
@ -1319,6 +1321,59 @@ is_plausible_address(const char *name)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set *<b>addr</b> to the host-order IPv4 address (if any) of whatever
|
||||
* interface connects to the internet. This address should only be used in
|
||||
* checking whether our address has changed. Return 0 on success, -1 on
|
||||
* failure.
|
||||
*/
|
||||
int
|
||||
get_interface_address(uint32_t *addr)
|
||||
{
|
||||
int sock=-1, r=-1;
|
||||
struct sockaddr_in target_addr, my_addr;
|
||||
socklen_t my_addr_len = sizeof(my_addr);
|
||||
|
||||
tor_assert(addr);
|
||||
*addr = 0;
|
||||
|
||||
sock = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
|
||||
if (sock < 0) {
|
||||
int e = tor_socket_errno(-1);
|
||||
log_fn(LOG_WARN, "unable to create socket: %s", tor_socket_strerror(e));
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset(&target_addr, 0, sizeof(target_addr));
|
||||
target_addr.sin_family = AF_INET;
|
||||
/* discard port */
|
||||
target_addr.sin_port = 9;
|
||||
/* 18.0.0.1 (Don't worry: no packets are sent. We just need a real address
|
||||
* on the internet.) */
|
||||
target_addr.sin_addr.s_addr = htonl(0x12000001);
|
||||
|
||||
if (connect(sock,(struct sockaddr *)&target_addr,sizeof(target_addr))<0) {
|
||||
int e = tor_socket_errno(sock);
|
||||
log_fn(LOG_WARN, "connnect() failed: %s", tor_socket_strerror(e));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* XXXX Can this be right on IPv6 clients? */
|
||||
if (getsockname(sock, &my_addr, &my_addr_len)) {
|
||||
int e = tor_socket_errno(sock);
|
||||
log_fn(LOG_WARN, "getsockname() failed: %s", tor_socket_strerror(e));
|
||||
goto err;
|
||||
}
|
||||
|
||||
*addr = ntohl(my_addr.sin_addr.s_addr);
|
||||
|
||||
r=0;
|
||||
err:
|
||||
if (sock >= 0)
|
||||
tor_close_socket(sock);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* =====
|
||||
* Process helpers
|
||||
* ===== */
|
||||
|
|
|
@ -135,6 +135,7 @@ int parse_addr_and_port_range(const char *s, uint32_t *addr_out,
|
|||
#define INET_NTOA_BUF_LEN 16
|
||||
int tor_inet_ntoa(struct in_addr *in, char *buf, size_t buf_len);
|
||||
int is_plausible_address(const char *name);
|
||||
int get_interface_address(uint32_t *addr);
|
||||
|
||||
/* Process helpers */
|
||||
void start_daemon(void);
|
||||
|
|
|
@ -24,6 +24,10 @@ static int connection_reached_eof(connection_t *conn);
|
|||
static int connection_read_to_buf(connection_t *conn, int *max_to_read);
|
||||
static int connection_process_inbuf(connection_t *conn, int package_partial);
|
||||
static int connection_bucket_read_limit(connection_t *conn);
|
||||
static void client_check_address_changed(int sock);
|
||||
|
||||
static uint32_t last_interface_ip = 0;
|
||||
static smartlist_t *outgoing_addrs = NULL;
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
|
@ -251,11 +255,16 @@ connection_free(connection_t *conn)
|
|||
}
|
||||
connection_unregister(conn);
|
||||
_connection_free(conn);
|
||||
|
||||
SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
|
||||
smartlist_free(outgoing_addrs);
|
||||
outgoing_addrs = NULL;
|
||||
}
|
||||
|
||||
/** Call _connection_free() on every connection in our array.
|
||||
* This is used by cpuworkers and dnsworkers when they fork,
|
||||
* so they don't keep resources held open (especially sockets).
|
||||
/** Call _connection_free() on every connection in our array, and release all
|
||||
* storage helpd by connection.c. This is used by cpuworkers and dnsworkers
|
||||
* when they fork, so they don't keep resources held open (especially
|
||||
* sockets).
|
||||
*
|
||||
* Don't do the checks in connection_free(), because they will
|
||||
* fail.
|
||||
|
@ -701,7 +710,7 @@ int
|
|||
connection_connect(connection_t *conn, char *address,
|
||||
uint32_t addr, uint16_t port)
|
||||
{
|
||||
int s;
|
||||
int s, inprogress = 0;
|
||||
struct sockaddr_in dest_addr;
|
||||
or_options_t *options = get_options();
|
||||
|
||||
|
@ -754,21 +763,21 @@ connection_connect(connection_t *conn, char *address,
|
|||
tor_close_socket(s);
|
||||
return -1;
|
||||
} else {
|
||||
/* it's in progress. set state appropriately and return. */
|
||||
conn->s = s;
|
||||
if (connection_add(conn) < 0) /* no space, forget it */
|
||||
return -1;
|
||||
log_fn(LOG_DEBUG,"connect in progress, socket %d.",s);
|
||||
return 0;
|
||||
inprogress = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!server_mode(options))
|
||||
client_check_address_changed(s);
|
||||
|
||||
/* it succeeded. we're connected. */
|
||||
log_fn(LOG_INFO,"Connection to %s:%u established.",safe_str(address),port);
|
||||
log_fn(inprogress?LOG_DEBUG:LOG_INFO,
|
||||
"Connection to %s:%u %s (sock %d).",safe_str(address),port,
|
||||
inprogress?"in progress":"established",s);
|
||||
conn->s = s;
|
||||
if (connection_add(conn) < 0) /* no space, forget it */
|
||||
return -1;
|
||||
return 1;
|
||||
return inprogress ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1680,6 +1689,57 @@ alloc_http_authenticator(const char *authenticator)
|
|||
return base64_authenticator;
|
||||
}
|
||||
|
||||
/** DOCDOC
|
||||
* XXXX ipv6 NM
|
||||
*/
|
||||
static void
|
||||
client_check_address_changed(int sock)
|
||||
{
|
||||
uint32_t iface_ip, ip_out;
|
||||
struct sockaddr_in out_addr;
|
||||
socklen_t out_addr_len = sizeof(out_addr);
|
||||
uint32_t *ip;
|
||||
|
||||
if (!last_interface_ip)
|
||||
get_interface_address(&last_interface_ip);
|
||||
if (!outgoing_addrs)
|
||||
outgoing_addrs = smartlist_create();
|
||||
|
||||
if (getsockname(sock, (struct sockaddr*)&out_addr, &out_addr_len)<0) {
|
||||
int e = tor_socket_errno(sock);
|
||||
log_fn(LOG_WARN, "getsockname() failed: %s", tor_socket_strerror(e));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Okay. If we've used this address previously, we're okay. */
|
||||
ip_out = ntohl(out_addr.sin_addr.s_addr);
|
||||
SMARTLIST_FOREACH(outgoing_addrs, uint32_t*, ip,
|
||||
if (*ip == ip_out) return;
|
||||
);
|
||||
|
||||
/* Uh-oh. We haven't connected from this address before. Has the interface
|
||||
* address changed? */
|
||||
if (get_interface_address(&iface_ip)<0)
|
||||
return;
|
||||
ip = tor_malloc(sizeof(uint32_t));
|
||||
*ip = ip_out;
|
||||
|
||||
if (iface_ip == last_interface_ip) {
|
||||
/* Nope, it hasn't changed. Add this address to the list. */
|
||||
smartlist_add(outgoing_addrs, ip);
|
||||
} else {
|
||||
/* The interface changed. We're a client, so we need to regenerate our
|
||||
* keys. First, reset the state. */
|
||||
log_fn(LOG_NOTICE, "Our IP has changed. Rotating keys...");
|
||||
last_interface_ip = iface_ip;
|
||||
SMARTLIST_FOREACH(outgoing_addrs, void*, ip, tor_free(ip));
|
||||
smartlist_clear(outgoing_addrs);
|
||||
smartlist_add(outgoing_addrs, ip);
|
||||
/* Okay, now change our keys. */
|
||||
init_keys(); /* XXXX NM return value-- safe to ignore? */
|
||||
}
|
||||
}
|
||||
|
||||
/** Process new bytes that have arrived on conn-\>inbuf.
|
||||
*
|
||||
* This function just passes conn to the connection-specific
|
||||
|
|
|
@ -245,8 +245,6 @@ init_keys(void)
|
|||
/* XXX009 Two problems with how this is called:
|
||||
* 1. It should be idempotent for servers, so we can call init_keys
|
||||
* as much as we need to.
|
||||
* 2. Clients should rotate their identity keys at least whenever
|
||||
* their IPs change.
|
||||
*/
|
||||
char keydir[512];
|
||||
char keydir2[512];
|
||||
|
|
Loading…
Reference in New Issue