- uint32_t setup_retries; /* How many times to send setup packets */
- uint32_t setup_timeout; /* Initial timeout for setup packets */
- uint32_t wait_timeout; /* How long to wait if setup unsuccessful */
- uint32_t key_lifetime; /* How long a key lasts once set up */
- uint32_t key_renegotiate_time; /* If we see traffic (or a keepalive)
+ uint32_t index; /* Index of this site */
+ int32_t setup_retries; /* How many times to send setup packets */
+ int32_t setup_timeout; /* Initial timeout for setup packets */
+ int32_t wait_timeout; /* How long to wait if setup unsuccessful */
+ int32_t key_lifetime; /* How long a key lasts once set up */
+ int32_t key_renegotiate_time; /* If we see traffic (or a keepalive)
uint8_t localN[NONCELEN]; /* Nonces for key exchange */
uint8_t remoteN[NONCELEN];
struct buffer_if buffer; /* Current outgoing key exchange packet */
uint8_t localN[NONCELEN]; /* Nonces for key exchange */
uint8_t remoteN[NONCELEN];
struct buffer_if buffer; /* Current outgoing key exchange packet */
uint64_t timeout; /* Timeout for current state */
uint8_t *dhsecret;
uint8_t *sharedsecret;
struct transform_inst_if *new_transform; /* For key setup/verify */
};
uint64_t timeout; /* Timeout for current state */
uint8_t *dhsecret;
uint8_t *sharedsecret;
struct transform_inst_if *new_transform; /* For key setup/verify */
};
-static void slog(struct site *st, uint32_t event, string_t msg, ...)
+static void slog(struct site *st, uint32_t event, cstring_t msg, ...)
- vsnprintf(buf,240,msg,ap);
+ vsnprintf(buf,sizeof(buf),msg,ap);
st->log->log(st->log->st,class,"%s: %s",st->tunname,buf);
}
va_end(ap);
}
static void set_link_quality(struct site *st);
st->log->log(st->log->st,class,"%s: %s",st->tunname,buf);
}
va_end(ap);
}
static void set_link_quality(struct site *st);
-static void delete_key(struct site *st, string_t reason, uint32_t loglevel);
-static bool_t initiate_key_setup(struct site *st, string_t reason);
+static void delete_key(struct site *st, cstring_t reason, uint32_t loglevel);
+static bool_t initiate_key_setup(struct site *st, cstring_t reason);
static void enter_state_run(struct site *st);
static bool_t enter_state_resolve(struct site *st);
static bool_t enter_new_state(struct site *st,uint32_t next);
static void enter_state_run(struct site *st);
static bool_t enter_state_resolve(struct site *st);
static bool_t enter_new_state(struct site *st,uint32_t next);
};
/* Build any of msg1 to msg4. msg5 and msg6 are built from the inside
out using a transform of config data supplied by netlink */
};
/* Build any of msg1 to msg4. msg5 and msg6 are built from the inside
out using a transform of config data supplied by netlink */
buffer_init(&st->buffer,0);
buf_append_uint32(&st->buffer,
(type==LABEL_MSG1?0:st->setup_session_id));
buffer_init(&st->buffer,0);
buf_append_uint32(&st->buffer,
(type==LABEL_MSG1?0:st->setup_session_id));
buf_append_uint32(&st->buffer,type);
buf_append_string(&st->buffer,st->localname);
buf_append_string(&st->buffer,st->remotename);
buf_append_uint32(&st->buffer,type);
buf_append_string(&st->buffer,st->localname);
buf_append_string(&st->buffer,st->remotename);
if (type==LABEL_MSG1) return True;
memcpy(buf_append(&st->buffer,NONCELEN),st->remoteN,NONCELEN);
if (type==LABEL_MSG2) return True;
if (type==LABEL_MSG1) return True;
memcpy(buf_append(&st->buffer,NONCELEN),st->remoteN,NONCELEN);
if (type==LABEL_MSG2) return True;
dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->len);
buf_append_string(&st->buffer,dhpub);
free(dhpub);
dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->len);
buf_append_string(&st->buffer,dhpub);
free(dhpub);
hst=st->hash->init();
st->hash->update(hst,st->buffer.start,st->buffer.size);
st->hash->final(hst,hash);
sig=st->privkey->sign(st->privkey->st,hash,st->hash->len);
buf_append_string(&st->buffer,sig);
free(sig);
hst=st->hash->init();
st->hash->update(hst,st->buffer.start,st->buffer.size);
st->hash->final(hst,hash);
sig=st->privkey->sign(st->privkey->st,hash,st->hash->len);
buf_append_string(&st->buffer,sig);
free(sig);
}
static bool_t check_msg(struct site *st, uint32_t type, struct msg *m,
}
static bool_t check_msg(struct site *st, uint32_t type, struct msg *m,
if (!unpick_msg(st,LABEL_MSG2,msg2,&m)) return False;
if (!check_msg(st,LABEL_MSG2,&m,&err)) {
if (!unpick_msg(st,LABEL_MSG2,msg2,&m)) return False;
if (!check_msg(st,LABEL_MSG2,&m,&err)) {
if (!unpick_msg(st,LABEL_MSG3,msg3,&m)) return False;
if (!check_msg(st,LABEL_MSG3,&m,&err)) {
if (!unpick_msg(st,LABEL_MSG3,msg3,&m)) return False;
if (!check_msg(st,LABEL_MSG3,&m,&err)) {
hst=st->hash->init();
st->hash->update(hst,m.hashstart,m.hashlen);
st->hash->final(hst,hash);
hst=st->hash->init();
st->hash->update(hst,m.hashstart,m.hashlen);
st->hash->final(hst,hash);
m.sig[m.siglen]=0;
if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m.sig)) {
slog(st,LOG_SEC,"msg3 signature failed check!");
m.sig[m.siglen]=0;
if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m.sig)) {
slog(st,LOG_SEC,"msg3 signature failed check!");
if (!unpick_msg(st,LABEL_MSG4,msg4,&m)) return False;
if (!check_msg(st,LABEL_MSG4,&m,&err)) {
if (!unpick_msg(st,LABEL_MSG4,msg4,&m)) return False;
if (!check_msg(st,LABEL_MSG4,&m,&err)) {
hst=st->hash->init();
st->hash->update(hst,m.hashstart,m.hashlen);
st->hash->final(hst,hash);
hst=st->hash->init();
st->hash->update(hst,m.hashstart,m.hashlen);
st->hash->final(hst,hash);
m.sig[m.siglen]=0;
if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m.sig)) {
slog(st,LOG_SEC,"msg4 signature failed check!");
m.sig[m.siglen]=0;
if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m.sig)) {
slog(st,LOG_SEC,"msg4 signature failed check!");
BUF_ALLOC(&st->buffer,"site:MSG5");
/* We are going to add four words to the message */
BUF_ALLOC(&st->buffer,"site:MSG5");
/* We are going to add four words to the message */
st->new_transform->forwards(st->new_transform->st,&st->buffer,
&transform_err);
buf_prepend_uint32(&st->buffer,LABEL_MSG5);
st->new_transform->forwards(st->new_transform->st,&st->buffer,
&transform_err);
buf_prepend_uint32(&st->buffer,LABEL_MSG5);
buf_prepend_uint32(&st->buffer,st->setup_session_id);
st->retries=st->setup_retries;
buf_prepend_uint32(&st->buffer,st->setup_session_id);
st->retries=st->setup_retries;
BUF_ALLOC(&st->buffer,"site:MSG6");
/* We are going to add four words to the message */
BUF_ALLOC(&st->buffer,"site:MSG6");
/* We are going to add four words to the message */
st->new_transform->forwards(st->new_transform->st,&st->buffer,
&transform_err);
buf_prepend_uint32(&st->buffer,LABEL_MSG6);
st->new_transform->forwards(st->new_transform->st,&st->buffer,
&transform_err);
buf_prepend_uint32(&st->buffer,LABEL_MSG6);
buf_prepend_uint32(&st->buffer,st->setup_session_id);
st->retries=1; /* Peer will retransmit MSG5 if this packet gets lost */
buf_prepend_uint32(&st->buffer,st->setup_session_id);
st->retries=1; /* Peer will retransmit MSG5 if this packet gets lost */
/* We must forget about the current session. */
delete_key(st,"request from peer",LOG_SEC);
return True;
/* We must forget about the current session. */
delete_key(st,"request from peer",LOG_SEC);
return True;
case LABEL_MSG9:
/* Deliver to netlink layer */
st->netlink->deliver(st->netlink->st,msg0);
return True;
case LABEL_MSG9:
/* Deliver to netlink layer */
st->netlink->deliver(st->netlink->st,msg0);
return True;
- log(st->log,M_DEBUG,"%s: %s: %08x<-%08x: %08x:",
- st->tunname,incoming?"incoming":"outgoing",
- dest,source,msgtype);
+ slilog(st->log,M_DEBUG,"%s: %s: %08x<-%08x: %08x:",
+ st->tunname,incoming?"incoming":"outgoing",
+ dest,source,msgtype);
{
if (st->state!=SITE_RUN) return False;
slog(st,LOG_SETUP_INIT,"initiating key exchange (%s)",reason);
{
if (st->state!=SITE_RUN) return False;
slog(st,LOG_SETUP_INIT,"initiating key exchange (%s)",reason);
{
if (st->current_valid) {
slog(st,loglevel,"session closed (%s)",reason);
{
if (st->current_valid) {
slog(st,loglevel,"session closed (%s)",reason);
static bool_t enter_new_state(struct site *st, uint32_t next)
{
bool_t (*gen)(struct site *st);
static bool_t enter_new_state(struct site *st, uint32_t next)
{
bool_t (*gen)(struct site *st);
slog(st,LOG_STATE,"entering state %s",state_name(next));
switch(next) {
case SITE_SENTMSG1:
slog(st,LOG_STATE,"entering state %s",state_name(next));
switch(next) {
case SITE_SENTMSG1:
- if (gen(st) && send_msg(st)) {
+ if (hacky_par_start_failnow()) return False;
+
+ r= gen(st) && send_msg(st);
+
+ hacky_par_end(&r,
+ st->setup_retries, st->setup_timeout,
+ send_msg, st);
+
+ if (r) {
if (st->current_valid && st->peer_valid && st->buffer.free) {
BUF_ALLOC(&st->buffer,"site:MSG7");
if (st->current_valid && st->peer_valid && st->buffer.free) {
BUF_ALLOC(&st->buffer,"site:MSG7");
st->current_transform->forwards(st->current_transform->st,
&st->buffer, &transform_err);
buf_prepend_uint32(&st->buffer,LABEL_MSG0);
st->current_transform->forwards(st->current_transform->st,
&st->buffer, &transform_err);
buf_prepend_uint32(&st->buffer,LABEL_MSG0);
buf_prepend_uint32(&st->buffer,st->remote_session_id);
st->comm->sendmsg(st->comm->st,&st->buffer,&st->peer);
BUF_FREE(&st->buffer);
buf_prepend_uint32(&st->buffer,st->remote_session_id);
st->comm->sendmsg(st->comm->st,&st->buffer,&st->peer);
BUF_FREE(&st->buffer);
slog(st,LOG_STATE,"entering state WAIT");
st->timeout=st->now+st->wait_timeout;
st->state=SITE_WAIT;
slog(st,LOG_STATE,"entering state WAIT");
st->timeout=st->now+st->wait_timeout;
st->state=SITE_WAIT;
+static inline void site_settimeout(uint64_t timeout, int *timeout_io)
+{
+ if (timeout) {
+ int64_t offset=timeout-*now;
+ if (offset<0) offset=0;
+ if (offset>INT_MAX) offset=INT_MAX;
+ if (*timeout_io<0 || offset<*timeout_io)
+ *timeout_io=offset;
+ }
+}
+
static int site_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
static int site_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
/* Work out when our next timeout is. The earlier of 'timeout' or
'current_key_timeout'. A stored value of '0' indicates no timeout
active. */
/* Work out when our next timeout is. The earlier of 'timeout' or
'current_key_timeout'. A stored value of '0' indicates no timeout
active. */
- if (st->timeout && st->timeout-*now < *timeout_io) {
- *timeout_io=st->timeout-*now;
- }
-
- if (st->current_key_timeout && st->current_key_timeout-*now < *timeout_io)
- *timeout_io=st->current_key_timeout-*now;
+ site_settimeout(st->timeout, timeout_io);
+ site_settimeout(st->current_key_timeout, timeout_io);
-static void site_afterpoll(void *sst, struct pollfd *fds, int nfds,
- const struct timeval *tv_now, uint64_t *now)
+static void site_afterpoll(void *sst, struct pollfd *fds, int nfds)
- if (st->state>=SITE_SENTMSG1 && st->state<=SITE_SENTMSG5)
- send_msg(st);
- else if (st->state==SITE_WAIT) {
+ if (st->state>=SITE_SENTMSG1 && st->state<=SITE_SENTMSG5) {
+ if (!hacky_par_start_failnow())
+ send_msg(st);
+ } else if (st->state==SITE_WAIT) {
enter_state_run(st);
} else {
slog(st,LOG_ERROR,"site_afterpoll: unexpected timeout, state=%d",
enter_state_run(st);
} else {
slog(st,LOG_ERROR,"site_afterpoll: unexpected timeout, state=%d",
st->current_transform->forwards(st->current_transform->st,
buf, &transform_err);
buf_prepend_uint32(buf,LABEL_MSG0);
st->current_transform->forwards(st->current_transform->st,
buf, &transform_err);
buf_prepend_uint32(buf,LABEL_MSG0);
buf_prepend_uint32(buf,st->remote_session_id);
st->comm->sendmsg(st->comm->st,buf,&st->peer);
}
buf_prepend_uint32(buf,st->remote_session_id);
st->comm->sendmsg(st->comm->st,buf,&st->peer);
}
/* Explicitly addressed to us */
uint32_t msgtype=ntohl(get_uint32(buf->start+8));
if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True);
/* Explicitly addressed to us */
uint32_t msgtype=ntohl(get_uint32(buf->start+8));
if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True);
static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
list_t *args)
{
static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
list_t *args)
{
st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc);
st->comm=find_cl_if(dict,"comm",CL_COMM,True,"site",loc);
st->resolver=find_cl_if(dict,"resolver",CL_RESOLVER,True,"site",loc);
st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc);
st->comm=find_cl_if(dict,"comm",CL_COMM,True,"site",loc);
st->resolver=find_cl_if(dict,"resolver",CL_RESOLVER,True,"site",loc);
st->key_lifetime=dict_read_number(
dict,"key-lifetime",False,"site",loc,DEFAULT_KEY_LIFETIME);
st->key_lifetime=dict_read_number(
dict,"key-lifetime",False,"site",loc,DEFAULT_KEY_LIFETIME);
st->setup_retries=dict_read_number(
dict,"setup-retries",False,"site",loc,DEFAULT_SETUP_RETRIES);
st->setup_timeout=dict_read_number(
dict,"setup-timeout",False,"site",loc,DEFAULT_SETUP_TIMEOUT);
st->wait_timeout=dict_read_number(
dict,"wait-time",False,"site",loc,DEFAULT_WAIT_TIME);
st->setup_retries=dict_read_number(
dict,"setup-retries",False,"site",loc,DEFAULT_SETUP_RETRIES);
st->setup_timeout=dict_read_number(
dict,"setup-timeout",False,"site",loc,DEFAULT_SETUP_TIMEOUT);
st->wait_timeout=dict_read_number(
dict,"wait-time",False,"site",loc,DEFAULT_WAIT_TIME);
- dict,"renegotiate-time",False,"site",loc,st->key_lifetime);
+ dict,"renegotiate-time",False,"site",loc,st->key_renegotiate_time);
if (st->key_renegotiate_time > st->key_lifetime) {
cfgfatal(loc,"site",
"renegotiate-time must be less than key-lifetime\n");
}
if (st->key_renegotiate_time > st->key_lifetime) {
cfgfatal(loc,"site",
"renegotiate-time must be less than key-lifetime\n");
}
sprintf(st->tunname,"%s<->%s",st->localname,st->remotename);
/* The information we expect to see in incoming messages of type 1 */
sprintf(st->tunname,"%s<->%s",st->localname,st->remotename);
/* The information we expect to see in incoming messages of type 1 */
st->setupsiglen=strlen(st->remotename)+strlen(st->localname)+8;
st->setupsig=safe_malloc(st->setupsiglen,"site_apply");
put_uint32(st->setupsig+0,LABEL_MSG1);
st->setupsiglen=strlen(st->remotename)+strlen(st->localname)+8;
st->setupsig=safe_malloc(st->setupsiglen,"site_apply");
put_uint32(st->setupsig+0,LABEL_MSG1);
void site_module(dict_t *dict)
{
add_closure(dict,"site",site_apply);
void site_module(dict_t *dict)
{
add_closure(dict,"site",site_apply);