string_t tunname; /* localname<->remotename by default, used in logs */
string_t address; /* DNS name for bootstrapping, optional */
int remoteport; /* Port for bootstrapping, optional */
+ uint32_t mtu_target;
struct netlink_if *netlink;
struct comm_if **comms;
int ncomms;
timeout before we can listen for another setup packet); perhaps
we should keep a list of 'bad' sources for setup packets. */
uint32_t remote_capabilities;
+ uint16_t remote_adv_mtu;
struct transform_if *chosen_transform;
uint32_t setup_session_id;
transport_peers setup_peers;
struct transform_inst_if *new_transform; /* For key setup/verify */
};
+static uint32_t event_log_priority(struct site *st, uint32_t event)
+{
+ if (!(event&st->log_events))
+ return 0;
+ switch(event) {
+ case LOG_UNEXPECTED: return M_INFO;
+ case LOG_SETUP_INIT: return M_INFO;
+ case LOG_SETUP_TIMEOUT: return M_NOTICE;
+ case LOG_ACTIVATE_KEY: return M_INFO;
+ case LOG_TIMEOUT_KEY: return M_INFO;
+ case LOG_SEC: return M_SECURITY;
+ case LOG_STATE: return M_DEBUG;
+ case LOG_DROP: return M_DEBUG;
+ case LOG_DUMP: return M_DEBUG;
+ case LOG_ERROR: return M_ERR;
+ case LOG_PEER_ADDRS: return M_DEBUG;
+ default: return M_ERR;
+ }
+}
+
static void slog(struct site *st, uint32_t event, cstring_t msg, ...)
FORMAT(printf,3,4);
static void slog(struct site *st, uint32_t event, cstring_t msg, ...)
char buf[240];
uint32_t class;
- va_start(ap,msg);
-
- if (event&st->log_events) {
- switch(event) {
- case LOG_UNEXPECTED: class=M_INFO; break;
- case LOG_SETUP_INIT: class=M_INFO; break;
- case LOG_SETUP_TIMEOUT: class=M_NOTICE; break;
- case LOG_ACTIVATE_KEY: class=M_INFO; break;
- case LOG_TIMEOUT_KEY: class=M_INFO; break;
- case LOG_SEC: class=M_SECURITY; break;
- case LOG_STATE: class=M_DEBUG; break;
- case LOG_DROP: class=M_DEBUG; break;
- case LOG_DUMP: class=M_DEBUG; break;
- case LOG_ERROR: class=M_ERR; break;
- case LOG_PEER_ADDRS: class=M_DEBUG; break;
- default: class=M_ERR; break;
- }
-
+ class=event_log_priority(st, event);
+ if (class) {
+ va_start(ap,msg);
vsnprintf(buf,sizeof(buf),msg,ap);
slilog(st->log,class,"%s: %s",st->tunname,buf);
+ va_end(ap);
}
- va_end(ap);
}
static void set_link_quality(struct site *st);
type=buf_unprepend_uint32((b)); \
if (type!=(t)) return False; } while(0)
+static _Bool type_is_msg34(uint32_t type)
+{
+ return
+ type == LABEL_MSG3 ||
+ type == LABEL_MSG3BIS ||
+ type == LABEL_MSG4;
+}
+
struct parsedname {
int32_t len;
uint8_t *name;
struct parsedname remote;
struct parsedname local;
uint32_t remote_capabilities;
+ uint16_t remote_mtu;
int capab_transformnum;
uint8_t *nR;
uint8_t *nL;
if ((st->local_capabilities & CAPAB_EARLY) || (type != LABEL_MSG1)) {
buf_append_uint32(&st->buffer,st->local_capabilities);
}
+ if (type_is_msg34(type)) {
+ buf_append_uint16(&st->buffer,st->mtu_target);
+ }
append_string_xinfo_done(&st->buffer,&xia);
buf_append_string(&st->buffer,st->remotename);
CHECK_TYPE(msg,type);
if (!unpick_name(msg,&m->remote)) return False;
m->remote_capabilities=0;
+ m->remote_mtu=0;
if (m->remote.extrainfo.size) {
CHECK_AVAIL(&m->remote.extrainfo,4);
m->remote_capabilities=buf_unprepend_uint32(&m->remote.extrainfo);
}
+ if (type_is_msg34(type) && m->remote.extrainfo.size) {
+ CHECK_AVAIL(&m->remote.extrainfo,2);
+ m->remote_mtu=buf_unprepend_uint16(&m->remote.extrainfo);
+ }
if (!unpick_name(msg,&m->local)) return False;
if (type==LABEL_PROD) {
CHECK_EMPTY(msg);
"site:MSG3");
}
+static bool_t process_msg3_msg4(struct site *st, struct msg *m)
+{
+ uint8_t *hash;
+ void *hst;
+
+ /* Check signature and store g^x mod m */
+ hash=safe_malloc(st->hash->len, "process_msg3_msg4");
+ hst=st->hash->init();
+ st->hash->update(hst,m->hashstart,m->hashlen);
+ st->hash->final(hst,hash);
+ /* Terminate signature with a '0' - cheating, but should be ok */
+ m->sig[m->siglen]=0;
+ if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m->sig)) {
+ slog(st,LOG_SEC,"msg3/msg4 signature failed check!");
+ free(hash);
+ return False;
+ }
+ free(hash);
+
+ st->remote_adv_mtu=m->remote_mtu;
+
+ return True;
+}
+
static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
const struct comm_addr *src, uint32_t msgtype)
{
struct msg m;
- uint8_t *hash;
- void *hst;
cstring_t err;
assert(msgtype==LABEL_MSG3 || msgtype==LABEL_MSG3BIS);
transform_found:
st->chosen_transform=ti;
- /* Check signature and store g^x mod m */
- hash=safe_malloc(st->hash->len, "process_msg3");
- hst=st->hash->init();
- st->hash->update(hst,m.hashstart,m.hashlen);
- st->hash->final(hst,hash);
- /* Terminate signature with a '0' - cheating, but should be ok */
- 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!");
- free(hash);
+ if (!process_msg3_msg4(st,&m))
return False;
- }
- free(hash);
/* Terminate their DH public key with a '0' */
m.pk[m.pklen]=0;
const struct comm_addr *src)
{
struct msg m;
- uint8_t *hash;
- void *hst;
cstring_t err;
if (!unpick_msg(st,LABEL_MSG4,msg4,&m)) return False;
return False;
}
- /* Check signature and store g^x mod m */
- hash=safe_malloc(st->hash->len, "process_msg4");
- hst=st->hash->init();
- st->hash->update(hst,m.hashstart,m.hashlen);
- st->hash->final(hst,hash);
- /* Terminate signature with a '0' - cheating, but should be ok */
- 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!");
- free(hash);
+ if (!process_msg3_msg4(st,&m))
return False;
- }
- free(hash);
/* Terminate their DH public key with a '0' */
m.pk[m.pklen]=0;
transport_peers_copy(st,&st->peers,&st->setup_peers);
st->current.remote_session_id=st->setup_session_id;
- slog(st,LOG_ACTIVATE_KEY,"new key activated");
+ /* Compute the inter-site MTU. This is min( our_mtu, their_mtu ).
+ * But their mtu be unspecified, in which case we just use ours. */
+ uint32_t intersite_mtu=
+ MIN(st->mtu_target, st->remote_adv_mtu ?: ~(uint32_t)0);
+ st->netlink->set_mtu(st->netlink->st,intersite_mtu);
+
+ slog(st,LOG_ACTIVATE_KEY,"new key activated"
+ " (mtu ours=%"PRId32" theirs=%"PRId32" intersite=%"PRId32")",
+ st->mtu_target, st->remote_adv_mtu, intersite_mtu);
enter_state_run(st);
}
st->setup_retries= CFG_NUMBER("setup-retries", SETUP_RETRIES);
st->setup_retry_interval= CFG_NUMBER("setup-timeout", SETUP_RETRY_INTERVAL);
st->wait_timeout= CFG_NUMBER("wait-time", WAIT_TIME);
+ st->mtu_target= dict_read_number(dict,"mtu-target",False,"site",loc,0);
st->mobile_peer_expiry= dict_read_number(
dict,"mobile-peer-expiry",False,"site",loc,DEFAULT_MOBILE_PEER_EXPIRY);
}
/* We need to register the remote networks with the netlink device */
- st->netlink->reg(st->netlink->st, site_outgoing, st);
+ uint32_t netlink_mtu; /* local virtual interface mtu */
+ st->netlink->reg(st->netlink->st, site_outgoing, st, &netlink_mtu);
+ if (!st->mtu_target)
+ st->mtu_target=netlink_mtu;
for (i=0; i<st->ncomms; i++)
st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming);
changed=1;
if (peers->npeers==st->transport_peers_max)
- slot=st->transport_peers_max;
+ slot=st->transport_peers_max-1;
else
slot=peers->npeers++;