- if (is_ip6)
- {
- ip_hdr_size = sizeof (ip6_header_t);
- ih6 = (ip6_header_t *) ((u8 *) esp0 - ip_hdr_size);
- oh6 = vlib_buffer_get_current (ob[0]);
- }
- else
- {
- ip_hdr_size = sizeof (ip4_header_t);
- if (sa0->udp_encap)
- ih4 = (ip4_header_t *) ((u8 *) esp0 - ip_hdr_size -
- sizeof (udp_header_t));
- else
- ih4 = (ip4_header_t *) ((u8 *) esp0 - ip_hdr_size);
- oh4 = vlib_buffer_get_current (ob[0]);
- }
- }
+ if (next[0] < ESP_DECRYPT_N_NEXT)
+ goto trace;
+
+ sa0 = vec_elt_at_index (im->sad, pd->sa_index);
+
+ /*
+ * redo the anti-reply check
+ * in this frame say we have sequence numbers, s, s+1, s+1, s+1
+ * and s and s+1 are in the window. When we did the anti-replay
+ * check above we did so against the state of the window (W),
+ * after packet s-1. So each of the packets in the sequence will be
+ * accepted.
+ * This time s will be cheked against Ws-1, s+1 chceked against Ws
+ * (i.e. the window state is updated/advnaced)
+ * so this time the successive s+! packet will be dropped.
+ * This is a consequence of batching the decrypts. If the
+ * check-dcrypt-advance process was done for each packet it would
+ * be fine. But we batch the decrypts because it's much more efficient
+ * to do so in SW and if we offload to HW and the process is async.
+ *
+ * You're probably thinking, but this means an attacker can send the
+ * above sequence and cause VPP to perform decrpyts that will fail,
+ * and that's true. But if the attacker can determine s (a valid
+ * sequence number in the window) which is non-trivial, it can generate
+ * a sequence s, s+1, s+2, s+3, ... s+n and nothing will prevent any
+ * implementation, sequential or batching, from decrypting these.
+ */
+ if (ipsec_sa_anti_replay_check (sa0, pd->seq))
+ {
+ b[0]->error = node->errors[ESP_DECRYPT_ERROR_REPLAY];
+ next[0] = ESP_DECRYPT_NEXT_DROP;
+ goto trace;
+ }