chiark / gitweb /
Import release 0.09
[secnet.git] / site.c
diff --git a/site.c b/site.c
index 1a664ce30c0d6e52d5f3259e2579e746fb11bcd7..22f1575d365e134193af1d5517a25a43643a7388 100644 (file)
--- a/site.c
+++ b/site.c
@@ -1,16 +1,19 @@
 /* site.c - manage communication with a remote network site */
 
+#include "secnet.h"
 #include <stdio.h>
-#include <sys/mman.h>
+/* MBM asserts the next one is needed for compilation under BSD. */
+#include <sys/socket.h>
 
-#include "secnet.h"
+#include <sys/mman.h>
 #include "util.h"
+#include "unaligned.h"
 
 #define SETUP_BUFFER_LEN 2048
 
-#define DEFAULT_KEY_LIFETIME 15000
+#define DEFAULT_KEY_LIFETIME 3600000
 #define DEFAULT_SETUP_RETRIES 5
-#define DEFAULT_SETUP_TIMEOUT 500
+#define DEFAULT_SETUP_TIMEOUT 1000
 #define DEFAULT_WAIT_TIME 10000
 
 /* Each site can be in one of several possible states. */
@@ -60,6 +63,7 @@
 #define SITE_SENTMSG5 7
 #define SITE_WAIT     8
 
+#if 0
 static string_t state_name(uint32_t state)
 {
     switch (state) {
@@ -75,6 +79,7 @@ static string_t state_name(uint32_t state)
     default: return "*bad state*";
     }
 }
+#endif /* 0 */
 
 #define LABEL_MSG0 0x00020200
 #define LABEL_MSG1 0x01010101
@@ -94,7 +99,7 @@ static string_t state_name(uint32_t state)
 #define LOG_SETUP_TIMEOUT 0x00000004
 #define LOG_ACTIVATE_KEY  0x00000008
 #define LOG_TIMEOUT_KEY   0x00000010
-#define LOG_SECURITY      0x00000020
+#define LOG_SEC      0x00000020
 #define LOG_STATE         0x00000040
 #define LOG_DROP          0x00000080
 #define LOG_DUMP          0x00000100
@@ -186,7 +191,7 @@ static void enter_state_wait(struct site *st);
 #define CHECK_EMPTY(b) do { if ((b)->size!=0) return False; } while(0)
 #define CHECK_TYPE(b,t) do { uint32_t type; \
     CHECK_AVAIL((b),4); \
-    type=*(uint32_t *)buf_unprepend((b),4); \
+    type=buf_unprepend_uint32((b)); \
     if (type!=(t)) return False; } while(0)
 
 struct msg {
@@ -217,10 +222,10 @@ static bool_t generate_msg(struct site *st, uint32_t type, string_t what)
     st->retries=st->setup_retries;
     BUF_ALLOC(&st->buffer,what);
     buffer_init(&st->buffer,0);
-    *(uint32_t *)buf_append(&st->buffer,4)=
-       (type==LABEL_MSG1?0:st->setup_session_id);
-    *(uint32_t *)buf_append(&st->buffer,4)=(uint32_t)st;
-    *(uint32_t *)buf_append(&st->buffer,4)=type;
+    buf_append_uint32(&st->buffer,
+       (type==LABEL_MSG1?0:st->setup_session_id));
+    buf_append_uint32(&st->buffer,(uint32_t)st);
+    buf_append_uint32(&st->buffer,type);
     buf_append_string(&st->buffer,st->localname);
     buf_append_string(&st->buffer,st->remotename);
     memcpy(buf_append(&st->buffer,NONCELEN),st->localN,NONCELEN);
@@ -244,16 +249,16 @@ static bool_t unpick_msg(struct site *st, uint32_t type,
 {
     m->hashstart=msg->start;
     CHECK_AVAIL(msg,4);
-    m->dest=*(uint32_t *)buf_unprepend(msg,4);
+    m->dest=buf_unprepend_uint32(msg);
     CHECK_AVAIL(msg,4);
-    m->source=*(uint32_t *)buf_unprepend(msg,4);
+    m->source=buf_unprepend_uint32(msg);
     CHECK_TYPE(msg,type);
     CHECK_AVAIL(msg,2);
-    m->remlen=ntohs(*(uint16_t *)buf_unprepend(msg,2));
+    m->remlen=buf_unprepend_uint16(msg);
     CHECK_AVAIL(msg,m->remlen);
     m->remote=buf_unprepend(msg,m->remlen);
     CHECK_AVAIL(msg,2);
-    m->loclen=ntohs(*(uint16_t *)buf_unprepend(msg,2));
+    m->loclen=buf_unprepend_uint16(msg);
     CHECK_AVAIL(msg,m->loclen);
     m->local=buf_unprepend(msg,m->loclen);
     CHECK_AVAIL(msg,NONCELEN);
@@ -269,12 +274,12 @@ static bool_t unpick_msg(struct site *st, uint32_t type,
        return True;
     }
     CHECK_AVAIL(msg,2);
-    m->pklen=ntohs(*(uint16_t *)buf_unprepend(msg,2));
+    m->pklen=buf_unprepend_uint16(msg);
     CHECK_AVAIL(msg,m->pklen);
     m->pk=buf_unprepend(msg,m->pklen);
     m->hashlen=msg->start-m->hashstart;
     CHECK_AVAIL(msg,2);
-    m->siglen=ntohs(*(uint16_t *)buf_unprepend(msg,2));
+    m->siglen=buf_unprepend_uint16(msg);
     CHECK_AVAIL(msg,m->siglen);
     m->sig=buf_unprepend(msg,m->siglen);
     CHECK_EMPTY(msg);
@@ -322,15 +327,15 @@ static bool_t process_msg2(struct site *st, struct buffer_if *msg2,
     /* Check that the site names and our nonce have been sent
        back correctly, and then store our peer's nonce. */ 
     if (memcmp(m.remote,st->remotename,strlen(st->remotename)!=0)) {
-       slog(st,LOG_SECURITY,"msg2: bad B (remote site name)");
+       slog(st,LOG_SEC,"msg2: bad B (remote site name)");
        return False;
     }
     if (memcmp(m.local,st->localname,strlen(st->localname)!=0)) {
-       slog(st,LOG_SECURITY,"msg2: bad A (local site name)");
+       slog(st,LOG_SEC,"msg2: bad A (local site name)");
        return False;
     }
     if (memcmp(m.nL,st->localN,NONCELEN)!=0) {
-       slog(st,LOG_SECURITY,"msg2: bad nA (locally generated nonce)");
+       slog(st,LOG_SEC,"msg2: bad nA (locally generated nonce)");
        return False;
     }
     st->setup_session_id=m.source;
@@ -358,19 +363,19 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
     /* Check that the site names and nonces have been sent back
        correctly */
     if (memcmp(m.remote,st->remotename,strlen(st->remotename)!=0)) {
-       slog(st,LOG_SECURITY,"msg3: bad A (remote site name)");
+       slog(st,LOG_SEC,"msg3: bad A (remote site name)");
        return False;
     }
     if (memcmp(m.local,st->localname,strlen(st->localname)!=0)) {
-       slog(st,LOG_SECURITY,"msg3: bad B (local site name)");
+       slog(st,LOG_SEC,"msg3: bad B (local site name)");
        return False;
     }
     if (memcmp(m.nR,st->remoteN,NONCELEN)!=0) {
-       slog(st,LOG_SECURITY,"msg3: bad nA (remotely generated nonce)");
+       slog(st,LOG_SEC,"msg3: bad nA (remotely generated nonce)");
        return False;
     }
     if (memcmp(m.nL,st->localN,NONCELEN)!=0) {
-       slog(st,LOG_SECURITY,"msg3: bad nB (locally generated nonce)");
+       slog(st,LOG_SEC,"msg3: bad nB (locally generated nonce)");
        return False;
     }
     
@@ -381,7 +386,7 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
     /* 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_SECURITY,"msg3 signature failed check!");
+       slog(st,LOG_SEC,"msg3 signature failed check!");
        return False;
     }
 
@@ -420,19 +425,19 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4,
     /* Check that the site names and nonces have been sent back
        correctly */
     if (memcmp(m.remote,st->remotename,strlen(st->remotename)!=0)) {
-       slog(st,LOG_SECURITY,"msg4: bad B (remote site name)");
+       slog(st,LOG_SEC,"msg4: bad B (remote site name)");
        return False;
     }
     if (memcmp(m.local,st->localname,strlen(st->localname)!=0)) {
-       slog(st,LOG_SECURITY,"msg4: bad A (local site name)");
+       slog(st,LOG_SEC,"msg4: bad A (local site name)");
        return False;
     }
     if (memcmp(m.nR,st->remoteN,NONCELEN)!=0) {
-       slog(st,LOG_SECURITY,"msg4: bad nB (remotely generated nonce)");
+       slog(st,LOG_SEC,"msg4: bad nB (remotely generated nonce)");
        return False;
     }
     if (memcmp(m.nL,st->localN,NONCELEN)!=0) {
-       slog(st,LOG_SECURITY,"msg4: bad nA (locally generated nonce)");
+       slog(st,LOG_SEC,"msg4: bad nA (locally generated nonce)");
        return False;
     }
     
@@ -443,7 +448,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4,
     /* 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_SECURITY,"msg4 signature failed check!");
+       slog(st,LOG_SEC,"msg4 signature failed check!");
        return False;
     }
 
@@ -466,12 +471,12 @@ static bool_t generate_msg5(struct site *st)
     BUF_ALLOC(&st->buffer,"site:MSG5");
     /* We are going to add three words to the transformed message */
     buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
-    *(uint32_t *)buf_append(&st->buffer,4)=LABEL_MSG5;
+    buf_append_uint32(&st->buffer,LABEL_MSG5);
     st->new_transform->forwards(st->new_transform->st,&st->buffer,
                                &transform_err);
-    *(uint32_t *)buf_prepend(&st->buffer,4)=LABEL_MSG5;
-    *(uint32_t *)buf_prepend(&st->buffer,4)=(uint32_t)st;
-    *(uint32_t *)buf_prepend(&st->buffer,4)=st->setup_session_id;
+    buf_prepend_uint32(&st->buffer,LABEL_MSG5);
+    buf_prepend_uint32(&st->buffer,(uint32_t)st);
+    buf_prepend_uint32(&st->buffer,st->setup_session_id);
 
     st->retries=st->setup_retries;
     return True;
@@ -487,11 +492,11 @@ static bool_t unpick_msg0(struct site *st, struct buffer_if *msg0,
                          struct msg0 *m)
 {
     CHECK_AVAIL(msg0,4);
-    m->dest=*(uint32_t *)buf_unprepend(msg0,4);
+    m->dest=buf_unprepend_uint32(msg0);
     CHECK_AVAIL(msg0,4);
-    m->source=*(uint32_t *)buf_unprepend(msg0,4);
+    m->source=buf_unprepend_uint32(msg0);
     CHECK_AVAIL(msg0,4);
-    m->type=*(uint32_t *)buf_unprepend(msg0,4);
+    m->type=buf_unprepend_uint32(msg0);
     return True;
     /* Leaves transformed part of buffer untouched */
 }
@@ -507,13 +512,13 @@ static bool_t process_msg5(struct site *st, struct buffer_if *msg5,
     if (st->new_transform->reverse(st->new_transform->st,
                                   msg5,&transform_err)) {
        /* There's a problem */
-       slog(st,LOG_SECURITY,"process_msg5: transform: %s",transform_err);
+       slog(st,LOG_SEC,"process_msg5: transform: %s",transform_err);
        return False;
     }
     /* Buffer should now contain untransformed PING packet data */
     CHECK_AVAIL(msg5,4);
-    if ((*(uint32_t *)buf_unprepend(msg5,4))!=LABEL_MSG5) {
-       slog(st,LOG_SECURITY,"MSG5/PING packet contained invalid data");
+    if (buf_unprepend_uint32(msg5)!=LABEL_MSG5) {
+       slog(st,LOG_SEC,"MSG5/PING packet contained invalid data");
        return False;
     }
     CHECK_EMPTY(msg5);
@@ -527,12 +532,12 @@ static bool_t generate_msg6(struct site *st)
     BUF_ALLOC(&st->buffer,"site:MSG6");
     /* We are going to add three words to the transformed message */
     buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
-    *(uint32_t *)buf_append(&st->buffer,4)=LABEL_MSG6;
+    buf_append_uint32(&st->buffer,LABEL_MSG6);
     st->new_transform->forwards(st->new_transform->st,&st->buffer,
                                &transform_err);
-    *(uint32_t *)buf_prepend(&st->buffer,4)=LABEL_MSG6;
-    *(uint32_t *)buf_prepend(&st->buffer,4)=(uint32_t)st;
-    *(uint32_t *)buf_prepend(&st->buffer,4)=st->setup_session_id;
+    buf_prepend_uint32(&st->buffer,LABEL_MSG6);
+    buf_prepend_uint32(&st->buffer,(uint32_t)st);
+    buf_prepend_uint32(&st->buffer,st->setup_session_id);
 
     st->retries=1; /* Peer will retransmit MSG5 if necessary */
     return True;
@@ -549,13 +554,13 @@ static bool_t process_msg6(struct site *st, struct buffer_if *msg6,
     if (st->new_transform->reverse(st->new_transform->st,
                                   msg6,&transform_err)) {
        /* There's a problem */
-       slog(st,LOG_SECURITY,"process_msg6: transform: %s",transform_err);
+       slog(st,LOG_SEC,"process_msg6: transform: %s",transform_err);
        return False;
     }
     /* Buffer should now contain untransformed PING packet data */
     CHECK_AVAIL(msg6,4);
-    if ((*(uint32_t *)buf_unprepend(msg6,4))!=LABEL_MSG6) {
-       slog(st,LOG_SECURITY,"MSG6/PONG packet contained invalid data");
+    if (buf_unprepend_uint32(msg6)!=LABEL_MSG6) {
+       slog(st,LOG_SEC,"MSG6/PONG packet contained invalid data");
        return False;
     }
     CHECK_EMPTY(msg6);
@@ -584,11 +589,11 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0,
     if (st->current_transform->reverse(st->current_transform->st,
                                       msg0,&transform_err)) {
        /* There's a problem */
-       slog(st,LOG_SECURITY,"transform: %s",transform_err);
+       slog(st,LOG_SEC,"transform: %s",transform_err);
        return False;
     }
     CHECK_AVAIL(msg0,4);
-    type=*(uint32_t *)buf_unprepend(msg0,4);
+    type=buf_unprepend_uint32(msg0);
     switch(type) {
     case LABEL_MSG9:
        /* Deliver to netlink layer */
@@ -596,7 +601,7 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0,
        return True;
        break;
     default:
-       slog(st,LOG_SECURITY,"incoming message of type %08x (unknown)",type);
+       slog(st,LOG_SEC,"incoming message of type %08x (unknown)",type);
        break;
     }
     return False;
@@ -605,9 +610,9 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0,
 static void dump_packet(struct site *st, struct buffer_if *buf,
                        struct sockaddr_in *addr, bool_t incoming)
 {
-    uint32_t dest=*(uint32_t *)buf->start;
-    uint32_t source=*(uint32_t *)(buf->start+4);
-    uint32_t msgtype=*(uint32_t *)(buf->start+8);
+    uint32_t dest=ntohl(*(uint32_t *)buf->start);
+    uint32_t source=ntohl(*(uint32_t *)(buf->start+4));
+    uint32_t msgtype=ntohl(*(uint32_t *)(buf->start+8));
 
     if (st->log_events & LOG_DUMP)
        log(st->log,0,"(%s,%s): %s: %08x<-%08x: %08x:",
@@ -887,12 +892,12 @@ static void site_outgoing(void *sst, void *cid, struct buffer_if *buf)
        a valid key and a valid address to send it to. */
     if (st->current_valid && st->peer_valid) {
        /* Transform it and send it */
-       *(uint32_t *)buf_prepend(buf,4)=LABEL_MSG9;
+       buf_prepend_uint32(buf,LABEL_MSG9);
        st->current_transform->forwards(st->current_transform->st,
                                        buf, &transform_err);
-       *(uint32_t *)buf_prepend(buf,4)=LABEL_MSG0;
-       *(uint32_t *)buf_prepend(buf,4)=(uint32_t)st;
-       *(uint32_t *)buf_prepend(buf,4)=st->remote_session_id;
+       buf_prepend_uint32(buf,LABEL_MSG0);
+       buf_prepend_uint32(buf,(uint32_t)st);
+       buf_prepend_uint32(buf,st->remote_session_id);
        st->comm->sendmsg(st->comm->st,buf,&st->peer);
        BUF_FREE(buf);
        return;
@@ -918,7 +923,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
                            struct sockaddr_in *source)
 {
     struct site *st=sst;
-    uint32_t dest=*(uint32_t *)buf->start;
+    uint32_t dest=ntohl(*(uint32_t *)buf->start);
 
     if (dest==0) {
        if (buf->size<(st->setupsiglen+8+NONCELEN)) return False;
@@ -971,7 +976,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
        return False; /* Not for us. */
     }
     if (dest==(uint32_t)st) {
-       uint32_t msgtype=*(uint32_t *)(buf->start+8);
+       uint32_t msgtype=ntohl(*(uint32_t *)(buf->start+8));
        /* Explicitly addressed to us */
        if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True);
        switch (msgtype) {
@@ -981,7 +986,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
        case LABEL_MSG1:
            /* Setup packet: should not have been explicitly addressed
               to us */
-           slog(st,LOG_SECURITY,"incoming explicitly addressed msg1");
+           slog(st,LOG_SEC,"incoming explicitly addressed msg1");
            break;
        case LABEL_MSG2:
            /* Setup packet: expected only in state SENTMSG1 */
@@ -990,7 +995,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            } else if (process_msg2(st,buf,source))
                enter_state_sentmsg3(st);
            else {
-               slog(st,LOG_SECURITY,"invalid MSG2");
+               slog(st,LOG_SEC,"invalid MSG2");
            }
            break;
        case LABEL_MSG3:
@@ -1000,7 +1005,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            } else if (process_msg3(st,buf,source))
                enter_state_sentmsg4(st);
            else {
-               slog(st,LOG_SECURITY,"invalid MSG3");
+               slog(st,LOG_SEC,"invalid MSG3");
            }
            break;
        case LABEL_MSG4:
@@ -1010,7 +1015,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            } else if (process_msg4(st,buf,source))
                enter_state_sentmsg5(st);
            else {
-               slog(st,LOG_SECURITY,"invalid MSG4");
+               slog(st,LOG_SEC,"invalid MSG4");
            }
            break;
        case LABEL_MSG5:
@@ -1025,7 +1030,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            } else if (process_msg5(st,buf,source)) {
                send_msg6(st);
            } else {
-               slog(st,LOG_SECURITY,"invalid MSG5");
+               slog(st,LOG_SEC,"invalid MSG5");
            }
            break;
        case LABEL_MSG6:
@@ -1036,7 +1041,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
                BUF_FREE(&st->buffer); /* Free message 5 */
                activate_new_key(st);
            } else {
-               slog(st,LOG_SECURITY,"invalid MSG6");
+               slog(st,LOG_SEC,"invalid MSG6");
            }
            break;
        case LABEL_MSG8:
@@ -1044,7 +1049,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            slog(st,LOG_ERROR,"received a NAK");
            break;
        default:
-           slog(st,LOG_SECURITY,"received message of unknown type 0x%08x",
+           slog(st,LOG_SEC,"received message of unknown type 0x%08x",
                 msgtype);
            break;
        }
@@ -1085,17 +1090,25 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
        cfgfatal(loc,"site","parameter must be a dictionary\n");
     
     dict=item->data.dict;
+    st->localname=dict_read_string(dict, "local-name", True, "site", loc);
+    st->remotename=dict_read_string(dict, "name", True, "site", loc);
+    /* Sanity check (which also allows the 'sites' file to include
+       site() closures for all sites including our own): refuse to
+       talk to ourselves */
+    if (strcmp(st->localname,st->remotename)==0) {
+       Message(M_INFO,"site %s: talking to ourselves!\n",st->localname);
+       free(st);
+       return NULL;
+    }
     st->netlink=find_cl_if(dict,"netlink",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->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc);
     st->random=find_cl_if(dict,"random",CL_RANDOMSRC,True,"site",loc);
 
-    st->localname=dict_read_string(dict, "local-name", True, "site", loc);
     st->privkey=find_cl_if(dict,"local-key",CL_RSAPRIVKEY,True,"site",loc);
     st->remoteport=dict_read_number(dict,"port",True,"site",loc,0);
 
-    st->remotename=dict_read_string(dict, "name", True, "site", loc);
     st->address=dict_read_string(dict, "address", False, "site", loc);
     dict_read_subnet_list(dict, "networks", True, "site", loc,
                          &st->remotenets);
@@ -1116,7 +1129,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
     st->wait_timeout=dict_read_number(dict,"wait-time",
                                      False,"site",loc,DEFAULT_WAIT_TIME);
     /* XXX should be configurable */
-    st->log_events=LOG_SECURITY|LOG_ERROR|
+    st->log_events=LOG_SEC|LOG_ERROR|
        LOG_ACTIVATE_KEY|LOG_TIMEOUT_KEY|LOG_SETUP_INIT|LOG_SETUP_TIMEOUT;
 
     st->tunname=safe_malloc(strlen(st->localname)+strlen(st->remotename)+5,
@@ -1124,13 +1137,13 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
     sprintf(st->tunname,"%s<->%s",st->localname,st->remotename);
 
     /* The information we expect to see in incoming messages of type 1 */
+    /* XXX fix this bit for unaligned access */
     st->setupsiglen=strlen(st->remotename)+strlen(st->localname)+8;
     st->setupsig=safe_malloc(st->setupsiglen,"site_apply");
-    *(uint32_t *)&(st->setupsig[0])=LABEL_MSG1;
-    *(uint16_t *)&(st->setupsig[4])=htons(strlen(st->remotename));
+    put_uint32(st->setupsig+0,LABEL_MSG1);
+    put_uint16(st->setupsig+4,strlen(st->remotename));
     memcpy(&st->setupsig[6],st->remotename,strlen(st->remotename));
-    *(uint16_t *)&(st->setupsig[6+strlen(st->remotename)])=
-       htons(strlen(st->localname));
+    put_uint16(st->setupsig+(6+strlen(st->remotename)),strlen(st->localname));
     memcpy(&st->setupsig[8+strlen(st->remotename)],st->localname,
           strlen(st->localname));
     st->setup_priority=(strcmp(st->localname,st->remotename)>0);