/
esp.c
108 lines (101 loc) · 3.77 KB
/
esp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
* OpenConnect (SSL + DTLS) VPN client
*
* Copyright © 2008-2015 Intel Corporation.
*
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include <config.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "openconnect-internal.h"
/* Eventually we're going to have to have more than one incoming ESP
context at a time, to allow for the overlap period during a rekey.
So pass the 'esp' even though for now it's redundant. */
int verify_packet_seqno(struct openconnect_info *vpninfo,
struct esp *esp, uint32_t seq)
{
/*
* For incoming, esp->seq is the next *expected* packet, being
* the sequence number *after* the latest we have received.
*
* Since it must always be true that packet esp->seq-1 has been
* received, so there's no need to explicitly record that.
*
* So the backlog bitmap covers the 32 packets prior to that,
* with the LSB representing packet (esp->seq - 2), and the MSB
* representing (esp->seq - 33). A received packet is represented
* by a zero bit, and a missing packet is represented by a one.
*
* Thus we can allow out-of-order reception of packets that are
* within a reasonable interval of the latest packet received.
*/
if (seq == esp->seq) {
/* The common case. This is the packet we expected next. */
esp->seq_backlog <<= 1;
esp->seq++;
return 0;
} else if (seq + 33 < esp->seq) {
/* Too old. We can't know if it's a replay. */
vpn_progress(vpninfo, PRG_DEBUG,
_("Discarding ancient ESP packet with seq %u (expected %u)\n"),
seq, esp->seq);
return -EINVAL;
} else if (seq < esp->seq) {
/* Within the backlog window, so we remember whether we've seen it or not. */
uint32_t mask = 1 << (esp->seq - seq - 2);
if (esp->seq_backlog & mask) {
vpn_progress(vpninfo, PRG_TRACE,
_("Accepting out-of-order ESP packet with seq %u (expected %u)\n"),
seq, esp->seq);
esp->seq_backlog &= ~mask;
return 0;
}
vpn_progress(vpninfo, PRG_DEBUG,
_("Discarding replayed ESP packet with seq %u\n"),
seq);
return -EINVAL;
} else {
/* The packet we were expecting has gone missing; this one is newer. */
int delta = seq - esp->seq;
if (delta >= 32) {
/* We jumped a long way into the future. We have not seen
* any of the previous 32 packets so set the backlog bitmap
* to all ones. */
esp->seq_backlog = 0xffffffff;
} else if (delta == 31) {
/* Avoid undefined behaviour that shifting by 32 would incur.
* The (clear) top bit represents the packet which is currently
* esp->seq - 1, which we know was already received. */
esp->seq_backlog = 0x7fffffff;
} else {
/* We have missed (delta) packets. Shift the backlog by that
* amount *plus* the one we would have shifted it anyway if
* we'd received the packet we were expecting. The zero bit
* representing the packet which is currently esp->seq - 1,
* which we know has been received, ends up at bit position
* (1<<delta). Then we set all the bits lower than that, which
* represent the missing packets. */
esp->seq_backlog <<= delta + 1;
esp->seq_backlog |= (1<<delta) - 1;
}
vpn_progress(vpninfo, PRG_TRACE,
_("Accepting later-than-expected ESP packet with seq %u (expected %u)\n"),
seq, esp->seq);
esp->seq = seq + 1;
return 0;
}
}