chiark / gitweb /
Import release 0.1.1 v0.1.1
authorStephen Early <steve@greenend.org.uk>
Thu, 27 Sep 2001 18:10:00 +0000 (19:10 +0100)
committerStephen Early <steve@greenend.org.uk>
Wed, 18 May 2011 12:27:03 +0000 (13:27 +0100)
Makefile.in
TODO
conffile.c
dh.c
netlink.c
rsa.c
secnet.h
site.c
util.c

index a06fcae9966b55e87db441546f841b669995b861..881a726a4191a96cb0f20664045518be1588aecb 100644 (file)
@@ -18,7 +18,7 @@
 .PHONY:        all clean realclean dist install
 
 PACKAGE:=secnet
-VERSION:=0.1.0
+VERSION:=0.1.1
 
 @SET_MAKE@
 
diff --git a/TODO b/TODO
index 071a71609e82a4e29c4d63ea8701348c414446c1..811ee1a8e8e07e12cffc5e5333412fe186f73cef 100644 (file)
--- a/TODO
+++ b/TODO
@@ -8,6 +8,7 @@ dh.c: change format to binary from decimal string (without introducing
 endianness problems)
 
 netlink.c: done. jdamery reports tun-old code works on Linux-2.2
+Unresolved problem with ioctl(TUNSETIFF) sometimes return EINVAL.
 
 random.c: test
 
index 45889ba93de36d6c27699ee96bbde39393264e09..c9796fc11e2114a0d8f98f2e976118aa2ac5f742 100644 (file)
@@ -681,6 +681,7 @@ static struct subnet string_to_subnet(item_t *i, string_t desc)
     }
     s.prefix=(a<<24)|(b<<16)|(c<<8)|(d);
     s.mask=(~0UL << (32-n));
+    s.len=n;
     if (s.prefix & ~s.mask) {
        cfgfatal(i->loc,desc,"\"%s\": prefix not fully contained "
                 "in mask\n",i->data.string);
diff --git a/dh.c b/dh.c
index eb9ae21c7b75a7989bf77a13f1fe1d44ed51b199..67ebd5068bbff17d5ccabd885fd0c10931492c49 100644 (file)
--- a/dh.c
+++ b/dh.c
@@ -135,9 +135,15 @@ static list_t *dh_apply(closure_t *self, struct cloc loc, dict_t *context,
        cfgfatal(loc,"diffie-hellman","you must provide a generator\n");
     }
 
-    /* Test that the modulus is really prime */
-    if (mpz_probab_prime_p(&st->p,5)==0) {
-       cfgfatal(loc,"diffie-hellman","modulus must be a prime\n");
+    i=list_elem(args,2);
+    if (i && i->type==t_bool && i->data.bool==False) {
+       Message(M_INFO,"diffie-hellman (%s:%d): skipping modulus "
+               "primality check\n",loc.file,loc.line);
+    } else {
+       /* Test that the modulus is really prime */
+       if (mpz_probab_prime_p(&st->p,5)==0) {
+           cfgfatal(loc,"diffie-hellman","modulus must be a prime\n");
+       }
     }
     st->ops.len=mpz_sizeinbase(&st->p,2)/8;
 
index 0cbb27d10a09b025e7341cd2c65709b0b1477321..dea05f2e912f0294189244603897b25037d1abee 100644 (file)
--- a/netlink.c
+++ b/netlink.c
@@ -48,10 +48,15 @@ struct netlink_client {
     netlink_deliver_fn *deliver;
     void *dst;
     string_t name;
-    bool_t can_deliver;
+    uint32_t link_quality;
     struct netlink_client *next;
 };
 
+struct netlink_route {
+    struct subnet net;
+    struct netlink_client *c;
+};
+
 /* Netlink provides one function to the device driver, to call to deliver
    a packet from the device. The device driver provides one function to
    netlink, for it to call to deliver a packet to the device. */
@@ -71,6 +76,8 @@ struct netlink {
     struct netlink_client *clients;
     netlink_deliver_fn *deliver_to_host; /* Provided by driver */
     struct buffer_if icmp; /* Buffer for assembly of outgoing ICMP */
+    uint32_t n_routes; /* How many routes do we know about? */
+    struct netlink_route *routes;
 };
 
 /* Generic IP checksum routine */
@@ -174,7 +181,9 @@ struct icmphdr {
     } d;
 };
     
-static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf);
+static void netlink_packet_deliver(struct netlink *st,
+                                  struct netlink_client *client,
+                                  struct buffer_if *buf);
 
 static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
                                         uint32_t dest,uint16_t len)
@@ -264,7 +273,10 @@ static uint16_t netlink_icmp_reply_len(struct buffer_if *buf)
     return (hlen>plen?plen:hlen);
 }
 
+/* client indicates where the packet we're constructing a response to
+   comes from. NULL indicates the host. */
 static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
+                               struct netlink_client *client,
                                uint8_t type, uint8_t code)
 {
     struct iphdr *iph=(struct iphdr *)buf->start;
@@ -277,7 +289,7 @@ static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
        h->type=type; h->code=code;
        memcpy(buf_append(&st->icmp,len),buf->start,len);
        netlink_icmp_csum(h);
-       netlink_packet_deliver(st,&st->icmp);
+       netlink_packet_deliver(st,NULL,&st->icmp);
        BUF_ASSERT_FREE(&st->icmp);
     }
 }
@@ -321,11 +333,19 @@ static bool_t netlink_check(struct netlink *st, struct buffer_if *buf)
     return True;
 }
 
-static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf)
+/* Deliver a packet. "client" points to the _origin_ of the packet, not
+   its destination. (May be used when sending ICMP response - avoid
+   asymmetric routing.) */
+static void netlink_packet_deliver(struct netlink *st,
+                                  struct netlink_client *client,
+                                  struct buffer_if *buf)
 {
     struct iphdr *iph=(struct iphdr *)buf->start;
     uint32_t dest=ntohl(iph->daddr);
-    struct netlink_client *c;
+    uint32_t source=ntohl(iph->saddr);
+    uint32_t best_quality;
+    int best_match;
+    int i;
 
     BUF_ASSERT_USED(buf);
 
@@ -335,30 +355,69 @@ static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf)
        return;
     }
     
-    for (c=st->clients; c; c=c->next) {
-       if (subnet_match(c->networks,dest)) {
-           if (c->can_deliver) {
-               c->deliver(c->dst,c,buf);
+    if (!client) {
+       /* Origin of packet is host or secnet. Might be for a tunnel. */
+       best_quality=0;
+       best_match=-1;
+       for (i=0; i<st->n_routes; i++) {
+           if (subnet_match(&st->routes[i].net,dest)) {
+               if (st->routes[i].c->link_quality>best_quality
+                   || best_quality==0) {
+                   best_quality=st->routes[i].c->link_quality;
+                   best_match=i;
+                   /* If quality isn't perfect we may wish to
+                      consider kicking the tunnel with a 0-length
+                      packet to prompt it to perform a key setup.
+                      Then it'll eventually decide it's up or
+                      down. */
+                   /* If quality is perfect we don't need to search
+                       any more. */
+                   if (best_quality>=MAXIMUM_LINK_QUALITY) break;
+               }
+           }
+       }
+       if (best_match==-1) {
+           /* Not going down a tunnel. Might be for the host. 
+              XXX think about this - only situation should be if we're
+              sending ICMP. */
+           if (source!=st->secnet_address) {
+               Message(M_ERROR,"netlink_packet_deliver: outgoing packet "
+                       "from host that won't fit down any of our tunnels!\n");
+               BUF_FREE(buf);
+           } else {
+               st->deliver_to_host(st->dst,NULL,buf);
+               BUF_ASSERT_FREE(buf);
+           }
+       } else {
+           if (best_quality>0) {
+               st->routes[best_match].c->deliver(
+                   st->routes[best_match].c->dst,
+                   st->routes[best_match].c, buf);
                BUF_ASSERT_FREE(buf);
            } else {
                /* Generate ICMP destination unreachable */
-               netlink_icmp_simple(st,buf,3,0);
+               netlink_icmp_simple(st,buf,client,3,0); /* client==NULL */
                BUF_FREE(buf);
            }
-           return;
+       }
+    } else { /* client is set */
+       /* We know the origin is a tunnel - packet must be for the host */
+       if (subnet_matches_list(&st->networks,dest)) {
+           st->deliver_to_host(st->dst,NULL,buf);
+           BUF_ASSERT_FREE(buf);
+       } else {
+           Message(M_ERROR,"%s: packet from tunnel %s can't be delivered "
+                   "to the host\n",st->name,client->name);
+           netlink_icmp_simple(st,buf,client,3,0);
+           BUF_FREE(buf);
        }
     }
-    if (subnet_match(&st->networks,dest)) {
-       st->deliver_to_host(st->dst,NULL,buf);
-       BUF_ASSERT_FREE(buf);
-       return;
-    }
-    Message(M_ERROR,"%s: failed to deliver a packet (bad destination address)"
-           "\nXXX make this message clearer\n");
-    BUF_FREE(buf);
+    BUF_ASSERT_FREE(buf);
 }
 
-static void netlink_packet_forward(struct netlink *st, struct buffer_if *buf)
+static void netlink_packet_forward(struct netlink *st, 
+                                  struct netlink_client *client,
+                                  struct buffer_if *buf)
 {
     struct iphdr *iph=(struct iphdr *)buf->start;
     
@@ -367,7 +426,7 @@ static void netlink_packet_forward(struct netlink *st, struct buffer_if *buf)
     /* Packet has already been checked */
     if (iph->ttl<=1) {
        /* Generate ICMP time exceeded */
-       netlink_icmp_simple(st,buf,11,0);
+       netlink_icmp_simple(st,buf,client,11,0);
        BUF_FREE(buf);
        return;
     }
@@ -375,13 +434,15 @@ static void netlink_packet_forward(struct netlink *st, struct buffer_if *buf)
     iph->check=0;
     iph->check=ip_fast_csum((uint8_t *)iph,iph->ihl);
 
-    netlink_packet_deliver(st,buf);
+    netlink_packet_deliver(st,client,buf);
     BUF_ASSERT_FREE(buf);
 }
 
 /* Someone has been foolish enough to address a packet to us. I
    suppose we should reply to it, just to be polite. */
-static void netlink_packet_local(struct netlink *st, struct buffer_if *buf)
+static void netlink_packet_local(struct netlink *st,
+                                struct netlink_client *client,
+                                struct buffer_if *buf)
 {
     struct icmphdr *h;
 
@@ -405,13 +466,13 @@ static void netlink_packet_local(struct netlink *st, struct buffer_if *buf)
            h->iph.check=0;
            h->iph.check=ip_fast_csum((uint8_t *)h,h->iph.ihl);
            netlink_icmp_csum(h);
-           netlink_packet_deliver(st,buf);
+           netlink_packet_deliver(st,NULL,buf);
            return;
        }
        Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
     } else {
        /* Send ICMP protocol unreachable */
-       netlink_icmp_simple(st,buf,3,2);
+       netlink_icmp_simple(st,buf,client,3,2);
        BUF_FREE(buf);
        return;
     }
@@ -441,8 +502,8 @@ static void netlink_from_tunnel(void *sst, void *cst, struct buffer_if *buf)
     dest=ntohl(iph->daddr);
 
     /* Check that the packet source is in 'nets' and its destination is
-       in client->networks */
-    if (!subnet_match(client->networks,source)) {
+       in st->networks */
+    if (!subnet_matches_list(client->networks,source)) {
        string_t s,d;
        s=ipaddr_to_string(source);
        d=ipaddr_to_string(dest);
@@ -456,11 +517,11 @@ static void netlink_from_tunnel(void *sst, void *cst, struct buffer_if *buf)
        st->networks because secnet's IP address may not be in the
        range the host is willing to deal with) */
     if (dest==st->secnet_address) {
-        netlink_packet_local(st,buf);
+        netlink_packet_local(st,client,buf);
        BUF_ASSERT_FREE(buf);
        return;
     }
-    if (!subnet_match(&st->networks,dest)) {
+    if (!subnet_matches_list(&st->networks,dest)) {
        string_t s,d;
        s=ipaddr_to_string(source);
        d=ipaddr_to_string(dest);
@@ -472,7 +533,7 @@ static void netlink_from_tunnel(void *sst, void *cst, struct buffer_if *buf)
        return;
     }
 
-    netlink_packet_forward(st,buf);
+    netlink_packet_forward(st,client,buf);
 
     BUF_ASSERT_FREE(buf);
 }
@@ -498,7 +559,7 @@ static void netlink_from_host(void *sst, void *cid, struct buffer_if *buf)
     source=ntohl(iph->saddr);
     dest=ntohl(iph->daddr);
 
-    if (!subnet_match(&st->networks,source)) {
+    if (!subnet_matches_list(&st->networks,source)) {
        string_t s,d;
        s=ipaddr_to_string(source);
        d=ipaddr_to_string(dest);
@@ -509,19 +570,19 @@ static void netlink_from_host(void *sst, void *cid, struct buffer_if *buf)
        return;
     }
     if (dest==st->secnet_address) {
-       netlink_packet_local(st,buf);
+       netlink_packet_local(st,NULL,buf);
        BUF_ASSERT_FREE(buf);
        return;
     }
-    netlink_packet_forward(st,buf);
+    netlink_packet_forward(st,NULL,buf);
     BUF_ASSERT_FREE(buf);
 }
 
-static void netlink_set_delivery(void *sst, void *cid, bool_t can_deliver)
+static void netlink_set_quality(void *sst, void *cid, uint32_t quality)
 {
     struct netlink_client *c=cid;
 
-    c->can_deliver=can_deliver;
+    c->link_quality=quality;
 }
 
 static void *netlink_regnets(void *sst, struct subnet_list *nets,
@@ -555,15 +616,71 @@ static void *netlink_regnets(void *sst, struct subnet_list *nets,
     c->deliver=deliver;
     c->dst=dst;
     c->name=client_name; /* XXX copy it? */
-    c->can_deliver=False;
+    c->link_quality=LINK_QUALITY_DOWN;
     c->next=st->clients;
     st->clients=c;
     if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
     if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
+    st->n_routes+=nets->entries;
 
     return c;
 }
 
+static int netlink_compare_route_specificity(const void *ap, const void *bp)
+{
+    const struct netlink_route *a=ap;
+    const struct netlink_route *b=bp;
+
+    if (a->net.len==b->net.len) return 0;
+    if (a->net.len<b->net.len) return 1;
+    return -1;
+}
+
+static void netlink_phase_hook(void *sst, uint32_t new_phase)
+{
+    struct netlink *st=sst;
+    struct netlink_client *c;
+    uint32_t i,j;
+
+    /* All the networks serviced by the various tunnels should now
+     * have been registered.  We build a routing table by sorting the
+     * routes into most-specific-first order.  */
+    st->routes=safe_malloc(st->n_routes*sizeof(*st->routes),
+                          "netlink_phase_hook");
+    /* Fill the table */
+    i=0;
+    for (c=st->clients; c; c=c->next) {
+       for (j=0; j<c->networks->entries; j++) {
+           st->routes[i].net=c->networks->list[j];
+           st->routes[i].c=c;
+           i++;
+       }
+    }
+    /* ASSERT i==st->n_routes */
+    if (i!=st->n_routes) {
+       fatal("netlink: route count error: expected %d got %d\n",
+             st->n_routes,i);
+    }
+    /* Sort the table in descending order of specificity */
+    qsort(st->routes,st->n_routes,sizeof(*st->routes),
+         netlink_compare_route_specificity);
+    Message(M_INFO,"%s: routing table:\n",st->name);
+    for (i=0; i<st->n_routes; i++) {
+       string_t net;
+       net=subnet_to_string(&st->routes[i].net);
+       Message(M_INFO,"%s -> tunnel %s\n",net,st->routes[i].c->name);
+       free(net);
+    }
+    Message(M_INFO,"%s/32 -> netlink \"%s\"\n",
+           ipaddr_to_string(st->secnet_address),st->name);
+    for (i=0; i<st->networks.entries; i++) {
+       string_t net;
+       net=subnet_to_string(&st->networks.list[i]);
+       Message(M_INFO,"%s -> host\n",net);
+       free(net);
+    }
+}
+
 static netlink_deliver_fn *netlink_init(struct netlink *st,
                                        void *dst, struct cloc loc,
                                        dict_t *dict, string_t description,
@@ -577,7 +694,7 @@ static netlink_deliver_fn *netlink_init(struct netlink *st,
     st->ops.st=st;
     st->ops.regnets=netlink_regnets;
     st->ops.deliver=netlink_from_tunnel;
-    st->ops.set_delivery=netlink_set_delivery;
+    st->ops.set_quality=netlink_set_quality;
     st->max_start_pad=0;
     st->max_end_pad=0;
     st->clients=NULL;
@@ -598,6 +715,10 @@ static netlink_deliver_fn *netlink_init(struct netlink *st,
        dict_find_item(dict,"secnet-address", True, "netlink", loc),"netlink");
     st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
     buffer_new(&st->icmp,ICMP_BUFSIZE);
+    st->n_routes=0;
+    st->routes=NULL;
+
+    add_hook(PHASE_SETUP,netlink_phase_hook,st);
 
     return netlink_from_host;
 }
@@ -972,6 +1093,7 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
                                                no extra headers */
        if (st->interface_name)
            strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
+       Message(M_INFO,"%s: about to ioctl(TUNSETIFF)...\n",st->nl.name);
        if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
            fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
        }
diff --git a/rsa.c b/rsa.c
index 0b6f1478837d556fa377ec2d83226f95f9669da9..03318ba16ba75849207a3be6311729fdceb56d43 100644 (file)
--- a/rsa.c
+++ b/rsa.c
@@ -317,19 +317,25 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
 
     /* Now do trial signature/check to make sure it's a real keypair:
        sign the comment string! */
-    mpz_init(&sig);
-    mpz_init(&plain);
-    mpz_init(&check);
-    read_mpbin(&plain,c,strlen(c));
-    mpz_powm(&sig, &plain, &st->d, &st->n);
-    mpz_powm(&check, &sig, &e, &st->n);
-    if (mpz_cmp(&plain,&check)!=0) {
-       cfgfatal(loc,"rsa-private","file \"%s\" does not contain a "
-                "valid RSA key!\n",filename);
+    i=list_elem(args,1);
+    if (i && i->type==t_bool && i->data.bool==False) {
+       Message(M_INFO,"rsa-private (%s:%d): skipping RSA key validity "
+               "check\n",loc.file,loc.line);
+    } else {
+       mpz_init(&sig);
+       mpz_init(&plain);
+       mpz_init(&check);
+       read_mpbin(&plain,c,strlen(c));
+       mpz_powm(&sig, &plain, &st->d, &st->n);
+       mpz_powm(&check, &sig, &e, &st->n);
+       if (mpz_cmp(&plain,&check)!=0) {
+           cfgfatal(loc,"rsa-private","file \"%s\" does not contain a "
+                    "valid RSA key!\n",filename);
+       }
+       mpz_clear(&sig);
+       mpz_clear(&plain);
+       mpz_clear(&check);
     }
-    mpz_clear(&sig);
-    mpz_clear(&plain);
-    mpz_clear(&check);
 
     free(c);
     mpz_clear(&e);
index f0f3a3efa4730e34aec5747230f390a1a1d5b85f..f5b96b6915a53eff81069802a28ad500ebfc9348 100644 (file)
--- a/secnet.h
+++ b/secnet.h
@@ -24,6 +24,7 @@ typedef enum {False,True} bool_t;
 struct subnet {
     uint32_t prefix;
     uint32_t mask;
+    uint32_t len;
 };
 
 struct subnet_list {
@@ -33,7 +34,8 @@ struct subnet_list {
 
 /* Match an address (in HOST byte order) with a subnet list.
    Returns True if matched. */
-extern bool_t subnet_match(struct subnet_list *list, uint32_t address);
+extern bool_t subnet_match(struct subnet *s, uint32_t address);
+extern bool_t subnet_matches_list(struct subnet_list *list, uint32_t address);
 extern bool_t subnets_intersect(struct subnet a, struct subnet b);
 extern bool_t subnet_intersects_with_list(struct subnet a,
                                          struct subnet_list *b);
@@ -353,12 +355,20 @@ struct transform_if {
 
 /* NETLINK interface */
 
-/* Used by netlink to deliver to site, and by site to deliver to netlink.
-   cid is the client identifier returned by netlink_regnets_fn */
+/* Used by netlink to deliver to site, and by site to deliver to
+   netlink.  cid is the client identifier returned by
+   netlink_regnets_fn.  If buf has size 0 then the function is just
+   being called for its site-effects (eg. making the site code attempt
+   to bring up a network link) */
 typedef void netlink_deliver_fn(void *st, void *cid, struct buffer_if *buf);
 /* site code can tell netlink when outgoing packets will be dropped,
-   so netlink can generate appropriate ICMP */
-typedef void netlink_can_deliver_fn(void *st, void *cid, bool_t can_deliver);
+   so netlink can generate appropriate ICMP and make routing decisions */
+#define LINK_QUALITY_DOWN 0   /* No chance of a packet being delivered */
+#define LINK_QUALITY_DOWN_STALE_ADDRESS 1 /* Link down, old address information */
+#define LINK_QUALITY_DOWN_CURRENT_ADDRESS 2 /* Link down, current address information */
+#define LINK_QUALITY_UP 3     /* Link active */
+#define MAXIMUM_LINK_QUALITY 3
+typedef void netlink_link_quality_fn(void *st, void *cid, uint32_t quality);
 /* Register for packets from specified networks. Return value is client
    identifier. */
 typedef void *netlink_regnets_fn(void *st, struct subnet_list *networks,
@@ -370,7 +380,7 @@ struct netlink_if {
     void *st;
     netlink_regnets_fn *regnets;
     netlink_deliver_fn *deliver;
-    netlink_can_deliver_fn *set_delivery;
+    netlink_link_quality_fn *set_quality;
 };
 
 /* DH interface */
diff --git a/site.c b/site.c
index efa1ebb79e43ebb31d3da4e28ec4a8c13c6be5a1..9bfbf9d50f99fff73ff2e0116bb79c568386a4d3 100644 (file)
--- a/site.c
+++ b/site.c
@@ -704,7 +704,7 @@ static void enter_state_run(struct site *st)
     slog(st,LOG_STATE,"entering state RUN");
     st->state=SITE_RUN;
     st->timeout=0;
-    st->netlink->set_delivery(st->netlink->st,st->netlink_cid,True);
+    st->netlink->set_quality(st->netlink->st,st->netlink_cid,LINK_QUALITY_UP);
     /* XXX get rid of key setup data */
 }
 
@@ -821,7 +821,8 @@ static void enter_state_wait(struct site *st)
     st->timeout=st->now+st->wait_timeout;
     st->state=SITE_WAIT;
     st->peer_valid=False;
-    st->netlink->set_delivery(st->netlink->st,st->netlink_cid,False);
+    st->netlink->set_quality(st->netlink->st,st->netlink_cid,
+                            LINK_QUALITY_DOWN);
     BUF_FREE(&st->buffer); /* will have had an outgoing packet in it */
     /* XXX Erase keys etc. */
 }
@@ -892,13 +893,15 @@ 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 */
-       buf_prepend_uint32(buf,LABEL_MSG9);
-       st->current_transform->forwards(st->current_transform->st,
-                                       buf, &transform_err);
-       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);
+       if (buf->size>0) {
+           buf_prepend_uint32(buf,LABEL_MSG9);
+           st->current_transform->forwards(st->current_transform->st,
+                                           buf, &transform_err);
+           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;
     }
@@ -912,7 +915,7 @@ static void site_outgoing(void *sst, void *cid, struct buffer_if *buf)
 
     /* Otherwise we're in the middle of key setup or a wait - just
        throw the outgoing packet away */
-    slog(st,LOG_DROP,"discarding outgoing packet");
+    slog(st,LOG_DROP,"discarding outgoing packet of size %d",buf->size);
     BUF_FREE(buf);
     return;
 }
@@ -1169,6 +1172,11 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
                                         st->transform->max_start_pad+(4*4),
                                         st->transform->max_end_pad,
                                         st->tunname);
+    if (!st->netlink_cid) {
+       fatal("%s: netlink device did not let us register our remote "
+             "networks. Check that they are not local or excluded.\n",
+             st->tunname);
+    }
 
     st->comm->request_notify(st->comm->st, st, site_incoming);
 
diff --git a/util.c b/util.c
index 0ffdcdd8db381504707270c3efcfde083a0b1252..503dfe27b3aa0f3fd740b5aef0a258fe6d1d083c 100644 (file)
--- a/util.c
+++ b/util.c
@@ -239,7 +239,12 @@ uint32_t write_mpbin(MP_INT *a, uint8_t *buffer, uint32_t buflen)
     return i;
 }
 
-bool_t subnet_match(struct subnet_list *list, uint32_t address)
+bool_t subnet_match(struct subnet *s, uint32_t address)
+{
+    return (s->prefix==(address&s->mask));
+}
+
+bool_t subnet_matches_list(struct subnet_list *list, uint32_t address)
 {
     uint32_t i;
     for (i=0; i<list->entries; i++) {
@@ -303,7 +308,10 @@ string_t subnet_to_string(struct subnet *sn)
     for (i=0; mask; i++) {
        mask=(mask<<1);
     }
-    snprintf(s, 19, "%d.%d.%d.%d/%d", a, b, c, d, i);
+    if (i!=sn->len) {
+       fatal("subnet_to_string: invalid subnet structure!\n");
+    }
+    snprintf(s, 19, "%d.%d.%d.%d/%d", a, b, c, d, sn->len);
     return s;
 }
 
@@ -607,7 +615,7 @@ static list_t *buffer_apply(closure_t *self, struct cloc loc, dict_t *context,
 
     buffer_new(&st->ops,len);
     if (lockdown) {
-       Message(M_WARNING,"buffer: XXX lockdown\n");
+       /* XXX mlock the buffer if possible */
     }
     
     return new_closure(&st->cl);