There is quite a lot of plumbing of max_start_pad values from one
place to another. Sadly this plumbing is not complete, which can lead
to crashes as the start padding is exhausted. And completing it is a
lot of work which would be difficult to get correct, even if that's
possible in principle.
Instead, we take a different approach. We calculate a single global
max_pad_start value that can be used everywhere. It is the sum of:
* Headers that "site" instances might need add to the start of
packets (source and destination site indices, message type both
inside and outside the encryption;
* Anything that "transform" instances might need to add to the start
of packets. This depends on the transforms, but since it isn't a
priori predictable which path any particular incoming packet might
take, we have to take the worst case.
These transform instances are applied only by "site" and each
packet goes through at most on "forward" transform instance.
* Anything that "comm" instances might need to add. This is
currently only needed for the proxy feature.
This is based on the assumption that a packet may follow one of these
paths:
comm -->- site_incoming --. ,-- site_outgoing -->- comm
\ /
netlink
/ \
tun/slip ----->-----------' `------>---------- tun/slip
On the inbound side, tun and slip have to set up the buffer with the
necessary start padding.
site_incoming only removes stuff from the beginning (since it uses
transform->reverse). netlink doesn't add or remove anything.
It is site_outgoing and comm which may need to prepend things. site
additionally calls transform->forwards.
If in the future a module appears which can take packets out of the
RHS of this diagram and feed them back into the left, it may have to
do something about the buffer.
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
struct icmphdr *h;
BUF_ALLOC(&st->icmp,"netlink_icmp_tmpl");
struct icmphdr *h;
BUF_ALLOC(&st->icmp,"netlink_icmp_tmpl");
- buffer_init(&st->icmp,st->max_start_pad);
+ buffer_init(&st->icmp,calculate_max_start_pad());
h=buf_append(&st->icmp,sizeof(*h));
h->iph.version=4;
h=buf_append(&st->icmp,sizeof(*h));
h->iph.version=4;
}
static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver,
}
static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver,
- void *dst, int32_t max_start_pad)
{
struct netlink_client *c=sst;
{
struct netlink_client *c=sst;
- struct netlink *st=c->nst;
- if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
c->deliver=deliver;
c->dst=dst;
}
c->deliver=deliver;
c->dst=dst;
}
st->cl.type=CL_PURE;
st->cl.apply=netlink_inst_apply;
st->cl.interface=st;
st->cl.type=CL_PURE;
st->cl.apply=netlink_inst_apply;
st->cl.interface=st;
st->clients=NULL;
st->routes=NULL;
st->n_clients=0;
st->clients=NULL;
st->routes=NULL;
st->n_clients=0;
closure_t cl;
void *dst; /* Pointer to host interface state */
cstring_t name;
closure_t cl;
void *dst; /* Pointer to host interface state */
cstring_t name;
struct ipset *networks; /* Local networks */
struct subnet_list *subnets; /* Same as networks, for display */
struct ipset *remote_networks; /* Allowable remote networks */
struct ipset *networks; /* Local networks */
struct subnet_list *subnets; /* Same as networks, for display */
struct ipset *remote_networks; /* Allowable remote networks */
/***** END of utility functions *****/
/***** END of utility functions *****/
+/***** START of max_start_pad handling *****/
+
+extern int32_t site_max_start_pad, transform_max_start_pad,
+ comm_max_start_pad;
+
+void update_max_start_pad(int32_t *our_module_global, int32_t our_instance);
+int32_t calculate_max_start_pad(void);
+
+/***** END of max_start_pad handling *****/
+
/***** SCHEDULING support */
/* If nfds_io is insufficient for your needs, set it to the required
/***** SCHEDULING support */
/* If nfds_io is insufficient for your needs, set it to the required
/* Returned string is in a static buffer. */
struct comm_if {
void *st;
/* Returned string is in a static buffer. */
struct comm_if {
void *st;
comm_request_notify_fn *request_notify;
comm_release_notify_fn *release_notify;
comm_sendmsg_fn *sendmsg;
comm_request_notify_fn *request_notify;
comm_release_notify_fn *release_notify;
comm_sendmsg_fn *sendmsg;
/* TRANSFORM interface */
/* A reversable transformation. Transforms buffer in-place; may add
/* TRANSFORM interface */
/* A reversable transformation. Transforms buffer in-place; may add
- data to start or end. Maximum amount of data to be added before
- the packet specified in max_start_pad. (Reverse transformations decrease
+ data to start or end. (Reverse transformations decrease
length, of course.) Transformations may be key-dependent, in which
case key material is passed in at initialisation time. They may
also depend on internal factors (eg. time) and keep internal
length, of course.) Transformations may be key-dependent, in which
case key material is passed in at initialisation time. They may
also depend on internal factors (eg. time) and keep internal
transform_apply_fn *forwards;
transform_apply_fn *reverse;
transform_destroyinstance_fn *destroy;
transform_apply_fn *forwards;
transform_apply_fn *reverse;
transform_destroyinstance_fn *destroy;
- int32_t max_start_pad; /* same as from transform_if */
};
struct transform_if {
void *st;
};
struct transform_if {
void *st;
- int32_t max_start_pad; /* these two are both <<< INT_MAX */
- int32_t keylen; /* 0 means give the transform exactly as much as there is */
+ int32_t keylen; /* <<< INT_MAX */
transform_createinstance_fn *create;
};
transform_createinstance_fn *create;
};
#define MAXIMUM_LINK_QUALITY 3
typedef void netlink_link_quality_fn(void *st, uint32_t quality);
typedef void netlink_register_fn(void *st, netlink_deliver_fn *deliver,
#define MAXIMUM_LINK_QUALITY 3
typedef void netlink_link_quality_fn(void *st, uint32_t quality);
typedef void netlink_register_fn(void *st, netlink_deliver_fn *deliver,
- void *dst, int32_t max_start_pad);
typedef void netlink_output_config_fn(void *st, struct buffer_if *buf);
typedef bool_t netlink_check_config_fn(void *st, struct buffer_if *buf);
typedef void netlink_set_mtu_fn(void *st, int32_t new_mtu);
typedef void netlink_output_config_fn(void *st, struct buffer_if *buf);
typedef bool_t netlink_check_config_fn(void *st, struct buffer_if *buf);
typedef void netlink_set_mtu_fn(void *st, int32_t new_mtu);
#define SITE_SENTMSG5 7
#define SITE_WAIT 8
#define SITE_SENTMSG5 7
#define SITE_WAIT 8
+int32_t site_max_start_pad = 4*4;
+
static cstring_t state_name(uint32_t state)
{
switch (state) {
static cstring_t state_name(uint32_t state)
{
switch (state) {
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 */
- buffer_init(&st->buffer,st->new_transform->max_start_pad+(4*4));
+ buffer_init(&st->buffer,calculate_max_start_pad());
/* Give the netlink code an opportunity to put its own stuff in the
message (configuration information, etc.) */
buf_prepend_uint32(&st->buffer,LABEL_MSG5);
/* Give the netlink code an opportunity to put its own stuff in the
message (configuration information, etc.) */
buf_prepend_uint32(&st->buffer,LABEL_MSG5);
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 */
- buffer_init(&st->buffer,transform->max_start_pad+(4*4));
+ buffer_init(&st->buffer,calculate_max_start_pad());
/* Give the netlink code an opportunity to put its own stuff in the
message (configuration information, etc.) */
buf_prepend_uint32(&st->buffer,LABEL_MSG6);
/* Give the netlink code an opportunity to put its own stuff in the
message (configuration information, etc.) */
buf_prepend_uint32(&st->buffer,LABEL_MSG6);
if (current_valid(st) && st->buffer.free
&& transport_peers_valid(&st->peers)) {
BUF_ALLOC(&st->buffer,"site:MSG7");
if (current_valid(st) && st->buffer.free
&& transport_peers_valid(&st->peers)) {
BUF_ALLOC(&st->buffer,"site:MSG7");
- buffer_init(&st->buffer,st->current.transform->max_start_pad+(4*3));
+ buffer_init(&st->buffer,calculate_max_start_pad());
buf_append_uint32(&st->buffer,LABEL_MSG7);
buf_append_string(&st->buffer,reason);
if (call_transform_forwards(st, st->current.transform,
buf_append_uint32(&st->buffer,LABEL_MSG7);
buf_append_string(&st->buffer,reason);
if (call_transform_forwards(st, st->current.transform,
st->sharedsecretlen=st->sharedsecretallocd=0;
st->sharedsecret=0;
st->sharedsecretlen=st->sharedsecretallocd=0;
st->sharedsecret=0;
- /* We need to compute some properties of our comms and transports */
-#define COMPUTE_WORST(things,pad) \
- int things##_worst_##pad=0; \
- for (i=0; i<st->n##things; i++) { \
- int thispad=st->things[i]->pad; \
- if (thispad > things##_worst_##pad) \
- things##_worst_##pad=thispad; \
- }
- COMPUTE_WORST(comms,min_start_pad)
- COMPUTE_WORST(transforms,max_start_pad)
-
for (i=0; i<st->ntransforms; i++) {
struct transform_if *ti=st->transforms[i];
uint32_t capbit = 1UL << ti->capab_transformnum;
for (i=0; i<st->ntransforms; i++) {
struct transform_if *ti=st->transforms[i];
uint32_t capbit = 1UL << ti->capab_transformnum;
}
/* We need to register the remote networks with the netlink device */
}
/* We need to register the remote networks with the netlink device */
- st->netlink->reg(st->netlink->st, site_outgoing, st,
- transforms_worst_max_start_pad+(4*4)+
- comms_worst_min_start_pad);
+ st->netlink->reg(st->netlink->st, site_outgoing, st);
for (i=0; i<st->ncomms; i++)
st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming);
for (i=0; i<st->ncomms; i++)
st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming);
if (st->ignoring_packet) {
if (outputchr == OUTPUT_END) {
st->ignoring_packet=False;
if (st->ignoring_packet) {
if (outputchr == OUTPUT_END) {
st->ignoring_packet=False;
- buffer_init(st->buff,st->nl.max_start_pad);
+ buffer_init(st->buff,calculate_max_start_pad());
}
} else {
if (outputchr == OUTPUT_END) {
}
} else {
if (outputchr == OUTPUT_END) {
st->netlink_to_tunnel(&st->nl,st->buff);
BUF_ALLOC(st->buff,"userv_afterpoll");
}
st->netlink_to_tunnel(&st->nl,st->buff);
BUF_ALLOC(st->buff,"userv_afterpoll");
}
- buffer_init(st->buff,st->nl.max_start_pad);
+ buffer_init(st->buff,calculate_max_start_pad());
} else if (outputchr != OUTPUT_NOTHING) {
if (st->buff->size < st->buff->len) {
buf_append_uint8(st->buff,outputchr);
} else if (outputchr != OUTPUT_NOTHING) {
if (st->buff->size < st->buff->len) {
buf_append_uint8(st->buff,outputchr);
st->cl.apply=NULL;
st->cl.interface=&st->ops;
st->ops.st=st;
st->cl.apply=NULL;
st->cl.interface=&st->ops;
st->ops.st=st;
- st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV,
- 4byte IV */
+ update_max_start_pad(&transform_max_start_pad, 28);
+ /* 4byte seqnum, 16byte pad, 4byte MACIV, 4byte IV */
/* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits
for CBCMAC-IV, and 32 bits for init sequence number */
/* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits
for CBCMAC-IV, and 32 bits for init sequence number */
ti->ops.forwards=transform_forward; \
ti->ops.reverse=transform_reverse; \
ti->ops.destroy=transform_destroy; \
ti->ops.forwards=transform_forward; \
ti->ops.reverse=transform_reverse; \
ti->ops.destroy=transform_destroy; \
- ti->ops.max_start_pad=st->ops.max_start_pad; \
ti->keyed=False;
#endif /*TRANSFORM_COMMON_H*/
ti->keyed=False;
#endif /*TRANSFORM_COMMON_H*/
padding_round = 1;
st->p.padding_mask = padding_round-1;
padding_round = 1;
st->p.padding_mask = padding_round-1;
- st->ops.max_start_pad=0;
+ update_max_start_pad(&transform_max_start_pad, 0);
st->ops.keylen=0;
st->ops.create=transform_create;
st->ops.keylen=0;
st->ops.create=transform_create;
}
if (fds[0].revents&POLLIN) {
BUF_ALLOC(st->buff,"tun_afterpoll");
}
if (fds[0].revents&POLLIN) {
BUF_ALLOC(st->buff,"tun_afterpoll");
- buffer_init(st->buff,st->nl.max_start_pad);
- l=read(st->fd,st->buff->start,st->buff->len-st->nl.max_start_pad);
+ buffer_init(st->buff,calculate_max_start_pad());
+ l=read(st->fd,st->buff->start,st->buff->len-calculate_max_start_pad());
if (l<0) {
fatal_perror("tun_afterpoll: read()");
}
if (l<0) {
fatal_perror("tun_afterpoll: read()");
}
uint8_t *sa;
if (st->use_proxy) {
uint8_t *sa;
if (st->use_proxy) {
memcpy(sa,&dest->sin.sin_addr,4);
memset(sa+4,0,4);
memcpy(sa+6,&dest->sin.sin_port,2);
sendto(st->fd,sa,buf->size+8,0,(struct sockaddr *)&st->proxy,
sizeof(st->proxy));
memcpy(sa,&dest->sin.sin_addr,4);
memset(sa+4,0,4);
memcpy(sa+6,&dest->sin.sin_port,2);
sendto(st->fd,sa,buf->size+8,0,(struct sockaddr *)&st->proxy,
sizeof(st->proxy));
} else {
sendto(st->fd, buf->start, buf->size, 0,
(struct sockaddr *)&dest->sin, sizeof(dest->sin));
} else {
sendto(st->fd, buf->start, buf->size, 0,
(struct sockaddr *)&dest->sin, sizeof(dest->sin));
st->cl.apply=NULL;
st->cl.interface=&st->ops;
st->ops.st=st;
st->cl.apply=NULL;
st->cl.interface=&st->ops;
st->ops.st=st;
- st->ops.min_start_pad=0;
st->ops.request_notify=request_notify;
st->ops.release_notify=release_notify;
st->ops.sendmsg=udp_sendmsg;
st->ops.request_notify=request_notify;
st->ops.release_notify=release_notify;
st->ops.sendmsg=udp_sendmsg;
cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n");
}
st->proxy.sin_port=htons(i->data.number);
cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n");
}
st->proxy.sin_port=htons(i->data.number);
- st->ops.min_start_pad=8;
+ update_max_start_pad(&comm_max_start_pad, st->use_proxy ? 8 : 0);
+
add_hook(PHASE_GETRESOURCES,udp_phase_hook,st);
return new_closure(&st->cl);
add_hook(PHASE_GETRESOURCES,udp_phase_hook,st);
return new_closure(&st->cl);
uint32_t their_index, uint32_t msgtype,
struct buffer_if *buf, const char *logwhy)
{
uint32_t their_index, uint32_t msgtype,
struct buffer_if *buf, const char *logwhy)
{
- buffer_init(buf,dest->comm->min_start_pad);
+ buffer_init(buf,calculate_max_start_pad());
buf_append_uint32(buf,their_index);
buf_append_uint32(buf,our_index);
buf_append_uint32(buf,LABEL_NAK);
buf_append_uint32(buf,their_index);
buf_append_uint32(buf,our_index);
buf_append_uint32(buf,LABEL_NAK);
{
add_closure(dict,"sysbuffer",buffer_apply);
}
{
add_closure(dict,"sysbuffer",buffer_apply);
}
+
+void update_max_start_pad(int32_t *our_module_global, int32_t our_instance)
+{
+ if (*our_module_global < our_instance)
+ *our_module_global=our_instance;
+}
+
+int32_t transform_max_start_pad, comm_max_start_pad;
+
+int32_t calculate_max_start_pad(void)
+{
+ return
+ site_max_start_pad +
+ transform_max_start_pad +
+ comm_max_start_pad;
+}