Commit 46fc7da3 authored by Antonin Décimo's avatar Antonin Décimo Committed by Juliusz Chroboczek

Follow the spec closely for the preparse phase.

The exact narration is implemented, with all the specified
optimisations.

- neighbour creation is delayed;
- if multiple PCs are found, only the first one is processed, the
  remaining ones are be silently ignored;
- a node ignores all challenge requests contained in a packet except
  the last one;
- and it ignores a challenge request in the case where it is contained
  in a packet with an Index that matches the one in the Neighbour Table
  and a PC that is smaller or equal to the one contained in the
  Neighbour Table.
parent 87f39d05
...@@ -447,21 +447,20 @@ network_address(int ae, const unsigned char *a, unsigned int len, ...@@ -447,21 +447,20 @@ network_address(int ae, const unsigned char *a, unsigned int len,
return network_prefix(ae, -1, 0, a, NULL, len, a_r); return network_prefix(ae, -1, 0, a, NULL, len, a_r);
} }
static int static struct neighbour *
preparse_packet(const unsigned char *packet, int bodylen, preparse_packet(const unsigned char *body, int bodylen,
struct neighbour *neigh, struct interface *ifp) const unsigned char *address, struct interface *ifp)
{ {
int i; int rc, i;
const unsigned char *message; struct neighbour *neigh = NULL;
unsigned char type, len; int challenge_success = 0, accept_packet = 0;
int challenge_success = 0; const unsigned char *pc = NULL, *index = NULL, *nonce = NULL;
int have_index = 0, index_len; int index_len, nonce_len;
unsigned char pc[4], index[256];
i = 0; i = 0;
while(i < bodylen) { while(i < bodylen) {
message = packet + 4 + i; const unsigned char *message = body + 4 + i;
type = message[0]; unsigned char len, type = message[0];
if(type == MESSAGE_PAD1) { if(type == MESSAGE_PAD1) {
i++; i++;
continue; continue;
...@@ -484,15 +483,25 @@ preparse_packet(const unsigned char *packet, int bodylen, ...@@ -484,15 +483,25 @@ preparse_packet(const unsigned char *packet, int bodylen,
fprintf(stderr, "Overlong PC TLV.\n"); fprintf(stderr, "Overlong PC TLV.\n");
break; break;
} }
debugf("Received PC from %s.\n", if(index != NULL)
format_address(neigh->address)); goto done;
memcpy(pc, message + 2, 4); debugf("Received PC from %s.\n", format_address(address));
pc = message + 2;
index = message + 6;
index_len = len - 4; index_len = len - 4;
memcpy(index, message + 6, len - 4); } else if(type == MESSAGE_CHALLENGE_REQUEST) {
have_index = 1; debugf("Received challenge request from %s.\n",
format_address(address));
nonce = message + 2;
nonce_len = len;
} else if(type == MESSAGE_CHALLENGE_REPLY) { } else if(type == MESSAGE_CHALLENGE_REPLY) {
debugf("Received challenge reply from %s.\n", debugf("Received challenge reply from %s.\n",
format_address(neigh->address)); format_address(address));
neigh = neigh != NULL ? neigh : find_neighbour(address, ifp);
if(neigh == NULL)
goto done;
gettime(&now); gettime(&now);
if(len == sizeof(neigh->nonce) && if(len == sizeof(neigh->nonce) &&
memcmp(neigh->nonce, message + 2, len) == 0 && memcmp(neigh->nonce, message + 2, len) == 0 &&
...@@ -501,38 +510,52 @@ preparse_packet(const unsigned char *packet, int bodylen, ...@@ -501,38 +510,52 @@ preparse_packet(const unsigned char *packet, int bodylen,
} else { } else {
debugf("Challenge failed.\n"); debugf("Challenge failed.\n");
} }
} else if(type == MESSAGE_CHALLENGE_REQUEST) {
debugf("Received challenge request from %s.\n",
format_address(neigh->address));
send_challenge_reply(neigh, message + 2, len);
} }
done:
i += len + 2; i += len + 2;
} }
if(!have_index) { if(index == NULL) {
debugf("No PC in packet.\n"); debugf("No PC in packet.\n");
return 0; goto maybe_send_challenge_reply;
} }
if(neigh->have_index && neigh->index_len == index_len && if(challenge_success) {
memcmp(index, neigh->index, index_len) == 0) {
if(memcmp(neigh->pc, pc, 4) < 0) {
memcpy(neigh->pc, pc, 4);
return 1;
} else {
debugf("Out of order PC.\n");
return 0;
}
} else if(challenge_success) {
neigh->index_len = index_len; neigh->index_len = index_len;
memcpy(neigh->index, index, index_len); memcpy(neigh->index, index, index_len);
memcpy(neigh->pc, pc, 4); memcpy(neigh->pc, pc, 4);
neigh->have_index = 1; neigh->have_index = 1;
return 1; accept_packet = 1;
} else { goto maybe_send_challenge_reply;
send_challenge_request(neigh); }
return 0;
if(neigh == NULL || !neigh->have_index || neigh->index_len != index_len ||
memcmp(index, neigh->index, index_len) != 0) {
neigh = neigh != NULL ? neigh : find_neighbour(address, ifp);
if(neigh == NULL)
return NULL;
rc = send_challenge_request(neigh);
if(rc)
fputs("Could not send challenge request.\n", stderr);
goto maybe_send_challenge_reply;
}
if(memcmp(pc, neigh->pc, 4) <= 0) {
debugf("Out of order PC.\n");
return NULL;
}
memcpy(neigh->pc, pc, 4);
return neigh;
maybe_send_challenge_reply:
if(nonce != NULL) { /* a challenge request was received */
neigh = neigh != NULL ? neigh : find_neighbour(address, ifp);
if(neigh == NULL)
return NULL;
send_challenge_reply(neigh, nonce, nonce_len);
} }
return accept_packet ? neigh : NULL;
} }
void void
...@@ -591,24 +614,17 @@ parse_packet(const unsigned char *from, struct interface *ifp, ...@@ -591,24 +614,17 @@ parse_packet(const unsigned char *from, struct interface *ifp,
return; return;
} }
neigh = find_neighbour(from, ifp); neigh = preparse_packet(packet, bodylen, from, ifp);
if(neigh == NULL) { if(neigh == NULL) {
fprintf(stderr, "Couldn't allocate neighbour.\n"); fputs("Received wrong PC or failed the challenge.\n", stderr);
return;
}
if(preparse_packet(packet, bodylen, neigh, ifp) == 0) {
fprintf(stderr, "Received wrong PC or failed the challenge.\n");
return; return;
} }
} }
neigh = neigh != NULL ? neigh : find_neighbour(from, ifp);
if(neigh == NULL) { if(neigh == NULL) {
neigh = find_neighbour(from, ifp); fputs("Couldn't allocate neighbour.\n", stderr);
if(neigh == NULL ) { return;
fprintf(stderr, "Couldn't allocate neighbour.\n");
return;
}
} }
i = 0; i = 0;
...@@ -1216,15 +1232,17 @@ send_challenge_request(struct neighbour *neigh) ...@@ -1216,15 +1232,17 @@ send_challenge_request(struct neighbour *neigh)
debugf("Sending challenge request to %s on %s.\n", debugf("Sending challenge request to %s on %s.\n",
format_address(neigh->address), neigh->ifp->name); format_address(neigh->address), neigh->ifp->name);
rc = read_random_bytes(neigh->nonce, NONCE_LEN); rc = read_random_bytes(neigh->nonce, NONCE_LEN);
if(rc < NONCE_LEN) if(rc < NONCE_LEN) {
perror("read_random_bytes");
return -1; return -1;
}
start_message(&neigh->buf, neigh->ifp, MESSAGE_CHALLENGE_REQUEST, NONCE_LEN); start_message(&neigh->buf, neigh->ifp, MESSAGE_CHALLENGE_REQUEST, NONCE_LEN);
accumulate_bytes(&neigh->buf, neigh->nonce, NONCE_LEN); accumulate_bytes(&neigh->buf, neigh->nonce, NONCE_LEN);
end_message(&neigh->buf, MESSAGE_CHALLENGE_REQUEST, NONCE_LEN); end_message(&neigh->buf, MESSAGE_CHALLENGE_REQUEST, NONCE_LEN);
gettime(&now); gettime(&now);
timeval_add_msec(&neigh->challenge_deadline, &now, 300); timeval_add_msec(&neigh->challenge_deadline, &now, 300);
schedule_flush_now(&neigh->buf); schedule_flush_now(&neigh->buf);
return 1; return 0;
} }
void void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment