FD.io VPP  v19.04.1-1-ge4a0f9f
Vector Packet Processing
ah_decrypt.c
Go to the documentation of this file.
1 /*
2  * ah_decrypt.c : IPSec AH decrypt node
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 
22 #include <vnet/ipsec/ipsec.h>
23 #include <vnet/ipsec/esp.h>
24 #include <vnet/ipsec/ah.h>
25 #include <vnet/ipsec/ipsec_io.h>
26 
27 #define foreach_ah_decrypt_next \
28  _ (DROP, "error-drop") \
29  _ (IP4_INPUT, "ip4-input") \
30  _ (IP6_INPUT, "ip6-input") \
31  _ (IPSEC_GRE_INPUT, "ipsec-gre-input")
32 
33 #define _(v, s) AH_DECRYPT_NEXT_##v,
34 typedef enum
35 {
37 #undef _
40 
41 #define foreach_ah_decrypt_error \
42  _ (RX_PKTS, "AH pkts received") \
43  _ (DECRYPTION_FAILED, "AH decryption failed") \
44  _ (INTEG_ERROR, "Integrity check failed") \
45  _ (REPLAY, "SA replayed packet")
46 
47 typedef enum
48 {
49 #define _(sym,str) AH_DECRYPT_ERROR_##sym,
51 #undef _
54 
55 static char *ah_decrypt_error_strings[] = {
56 #define _(sym,string) string,
58 #undef _
59 };
60 
61 typedef struct
62 {
66 
67 /* packet trace format function */
68 static u8 *
69 format_ah_decrypt_trace (u8 * s, va_list * args)
70 {
71  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
72  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
73  ah_decrypt_trace_t *t = va_arg (*args, ah_decrypt_trace_t *);
74 
75  s = format (s, "ah: integrity %U seq-num %d",
77  return s;
78 }
79 
82  vlib_node_runtime_t * node, vlib_frame_t * from_frame,
83  int is_ip6)
84 {
85  u32 n_left_from, *from, next_index, *to_next, thread_index;
86  ipsec_main_t *im = &ipsec_main;
87  from = vlib_frame_vector_args (from_frame);
88  n_left_from = from_frame->n_vectors;
89  int icv_size;
90 
91  next_index = node->cached_next_index;
92  thread_index = vm->thread_index;
93 
94  while (n_left_from > 0)
95  {
96  u32 n_left_to_next;
97 
98  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
99 
100  while (n_left_from > 0 && n_left_to_next > 0)
101  {
102  u32 i_bi0;
103  u32 next0;
104  vlib_buffer_t *i_b0;
105  ah_header_t *ah0;
106  ipsec_sa_t *sa0;
107  u32 sa_index0 = ~0;
108  u32 seq;
109  ip4_header_t *ih4 = 0, *oh4 = 0;
110  ip6_header_t *ih6 = 0, *oh6 = 0;
111  u8 ip_hdr_size = 0;
112  u8 tos = 0;
113  u8 ttl = 0;
114  u32 ip_version_traffic_class_and_flow_label = 0;
115  u8 hop_limit = 0;
116  u8 nexthdr = 0;
117  u8 icv_padding_len = 0;
118 
119 
120  i_bi0 = from[0];
121  from += 1;
122  n_left_from -= 1;
123  n_left_to_next -= 1;
124 
125  next0 = AH_DECRYPT_NEXT_DROP;
126 
127  i_b0 = vlib_get_buffer (vm, i_bi0);
128  to_next[0] = i_bi0;
129  to_next += 1;
130  ih4 = vlib_buffer_get_current (i_b0);
131  ih6 = vlib_buffer_get_current (i_b0);
132  sa_index0 = vnet_buffer (i_b0)->ipsec.sad_index;
133  sa0 = pool_elt_at_index (im->sad, sa_index0);
134 
136  thread_index, sa_index0);
137 
138  if (is_ip6)
139  {
140  ip6_ext_header_t *prev = NULL;
141  ip6_ext_header_find_t (ih6, prev, ah0, IP_PROTOCOL_IPSEC_AH);
142  ip_hdr_size = sizeof (ip6_header_t);
143  ASSERT ((u8 *) ah0 - (u8 *) ih6 == ip_hdr_size);
144  }
145  else
146  {
147  ip_hdr_size = ip4_header_bytes (ih4);
148  ah0 = (ah_header_t *) ((u8 *) ih4 + ip_hdr_size);
149  }
150 
151  seq = clib_host_to_net_u32 (ah0->seq_no);
152 
153  /* anti-replay check */
154  if (ipsec_sa_anti_replay_check (sa0, &ah0->seq_no))
155  {
156  i_b0->error = node->errors[AH_DECRYPT_ERROR_REPLAY];
157  goto trace;
158  }
159 
161  (&ipsec_sa_counters, thread_index, sa_index0,
162  1, i_b0->current_length);
163 
164  icv_size = sa0->integ_icv_size;
165  if (PREDICT_TRUE (sa0->integ_alg != IPSEC_INTEG_ALG_NONE))
166  {
167  u8 sig[64];
168  u8 digest[icv_size];
169  u8 *icv = ah0->auth_data;
170  memcpy (digest, icv, icv_size);
171  clib_memset (icv, 0, icv_size);
172 
173  if (is_ip6)
174  {
175  ip_version_traffic_class_and_flow_label =
177  hop_limit = ih6->hop_limit;
179  ih6->hop_limit = 0;
180  nexthdr = ah0->nexthdr;
181  icv_padding_len =
182  ah_calc_icv_padding_len (icv_size, 1 /* is_ipv6 */ );
183  }
184  else
185  {
186  tos = ih4->tos;
187  ttl = ih4->ttl;
188  ih4->tos = 0;
189  ih4->ttl = 0;
190  ih4->checksum = 0;
191  ih4->flags_and_fragment_offset = 0;
192  icv_padding_len =
193  ah_calc_icv_padding_len (icv_size, 0 /* is_ipv6 */ );
194  }
195  hmac_calc (vm, sa0, (u8 *) ih4, i_b0->current_length, sig);
196 
197  if (PREDICT_FALSE (memcmp (digest, sig, icv_size)))
198  {
199  i_b0->error = node->errors[AH_DECRYPT_ERROR_INTEG_ERROR];
200  goto trace;
201  }
202 
204  }
205 
206  vlib_buffer_advance (i_b0,
207  ip_hdr_size + sizeof (ah_header_t) + icv_size +
208  icv_padding_len);
209  i_b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
210 
211  if (PREDICT_TRUE (ipsec_sa_is_set_IS_TUNNEL (sa0)))
212  { /* tunnel mode */
213  if (PREDICT_TRUE (ah0->nexthdr == IP_PROTOCOL_IP_IN_IP))
214  next0 = AH_DECRYPT_NEXT_IP4_INPUT;
215  else if (ah0->nexthdr == IP_PROTOCOL_IPV6)
216  next0 = AH_DECRYPT_NEXT_IP6_INPUT;
217  else
218  {
219  i_b0->error =
220  node->errors[AH_DECRYPT_ERROR_DECRYPTION_FAILED];
221  goto trace;
222  }
223  }
224  else
225  { /* transport mode */
226  if (is_ip6)
227  {
228  vlib_buffer_advance (i_b0, -sizeof (ip6_header_t));
229  oh6 = vlib_buffer_get_current (i_b0);
230  memmove (oh6, ih6, sizeof (ip6_header_t));
231 
232  next0 = AH_DECRYPT_NEXT_IP6_INPUT;
233  oh6->protocol = nexthdr;
234  oh6->hop_limit = hop_limit;
235  oh6->ip_version_traffic_class_and_flow_label =
236  ip_version_traffic_class_and_flow_label;
237  oh6->payload_length =
238  clib_host_to_net_u16 (vlib_buffer_length_in_chain
239  (vm, i_b0) - sizeof (ip6_header_t));
240  }
241  else
242  {
243  vlib_buffer_advance (i_b0, -sizeof (ip4_header_t));
244  oh4 = vlib_buffer_get_current (i_b0);
245  memmove (oh4, ih4, sizeof (ip4_header_t));
246 
247  next0 = AH_DECRYPT_NEXT_IP4_INPUT;
248  oh4->ip_version_and_header_length = 0x45;
249  oh4->fragment_id = 0;
250  oh4->flags_and_fragment_offset = 0;
251  oh4->protocol = ah0->nexthdr;
252  oh4->length =
253  clib_host_to_net_u16 (vlib_buffer_length_in_chain
254  (vm, i_b0));
255  oh4->ttl = ttl;
256  oh4->tos = tos;
257  oh4->checksum = ip4_header_checksum (oh4);
258  }
259  }
260 
261  /* for IPSec-GRE tunnel next node is ipsec-gre-input */
262  if (PREDICT_FALSE (ipsec_sa_is_set_IS_GRE (sa0)))
263  next0 = AH_DECRYPT_NEXT_IPSEC_GRE_INPUT;
264 
265  vnet_buffer (i_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
266  trace:
267  if (PREDICT_FALSE (i_b0->flags & VLIB_BUFFER_IS_TRACED))
268  {
269  i_b0->flags |= VLIB_BUFFER_IS_TRACED;
270  ah_decrypt_trace_t *tr =
271  vlib_add_trace (vm, node, i_b0, sizeof (*tr));
272  tr->integ_alg = sa0->integ_alg;
273  tr->seq_num = seq;
274  }
275  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
276  n_left_to_next, i_bi0, next0);
277  }
278  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
279  }
280  vlib_node_increment_counter (vm, node->node_index, AH_DECRYPT_ERROR_RX_PKTS,
281  from_frame->n_vectors);
282 
283  return from_frame->n_vectors;
284 }
285 
287  vlib_node_runtime_t * node,
288  vlib_frame_t * from_frame)
289 {
290  return ah_decrypt_inline (vm, node, from_frame, 0 /* is_ip6 */ );
291 }
292 
293 /* *INDENT-OFF* */
295  .name = "ah4-decrypt",
296  .vector_size = sizeof (u32),
297  .format_trace = format_ah_decrypt_trace,
298  .type = VLIB_NODE_TYPE_INTERNAL,
299 
300  .n_errors = ARRAY_LEN(ah_decrypt_error_strings),
301  .error_strings = ah_decrypt_error_strings,
302 
303  .n_next_nodes = AH_DECRYPT_N_NEXT,
304  .next_nodes = {
305 #define _(s,n) [AH_DECRYPT_NEXT_##s] = n,
307 #undef _
308  },
309 };
310 /* *INDENT-ON* */
311 
313  vlib_node_runtime_t * node,
314  vlib_frame_t * from_frame)
315 {
316  return ah_decrypt_inline (vm, node, from_frame, 1 /* is_ip6 */ );
317 }
318 
319 /* *INDENT-OFF* */
321  .name = "ah6-decrypt",
322  .vector_size = sizeof (u32),
323  .format_trace = format_ah_decrypt_trace,
324  .type = VLIB_NODE_TYPE_INTERNAL,
325 
326  .n_errors = ARRAY_LEN(ah_decrypt_error_strings),
327  .error_strings = ah_decrypt_error_strings,
328 
329  .n_next_nodes = AH_DECRYPT_N_NEXT,
330  .next_nodes = {
331 #define _(s,n) [AH_DECRYPT_NEXT_##s] = n,
333 #undef _
334  },
335 };
336 /* *INDENT-ON* */
337 
338 /*
339  * fd.io coding-style-patch-verification: ON
340  *
341  * Local Variables:
342  * eval: (c-set-style "gnu")
343  * End:
344  */
static char * ah_decrypt_error_strings[]
Definition: ah_decrypt.c:55
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
u8 * format_ipsec_integ_alg(u8 *s, va_list *args)
Definition: ipsec_format.c:109
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:862
static int ipsec_sa_anti_replay_check(ipsec_sa_t *sa, u32 *seqp)
Definition: ipsec_sa.h:230
#define CLIB_UNUSED(x)
Definition: clib.h:82
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:220
#define PREDICT_TRUE(x)
Definition: clib.h:112
ipsec_integ_alg_t
Definition: ipsec_sa.h:60
#define NULL
Definition: clib.h:58
ipsec_integ_alg_t integ_alg
Definition: ipsec_sa.h:153
u32 thread_index
Definition: main.h:197
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
static uword ah_decrypt_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame, int is_ip6)
Definition: ah_decrypt.c:81
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
u16 flags_and_fragment_offset
Definition: ip4_packet.h:151
#define VLIB_NODE_FN(node)
Definition: node.h:201
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:469
static void ipsec_sa_anti_replay_advance(ipsec_sa_t *sa, u32 *seqp)
Definition: ipsec_sa.h:295
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:366
ah_decrypt_error_t
Definition: ah_decrypt.c:47
unsigned char u8
Definition: types.h:56
vlib_node_registration_t ah6_decrypt_node
(constructor) VLIB_REGISTER_NODE (ah6_decrypt_node)
Definition: ah_decrypt.c:320
ipsec_main_t ipsec_main
Definition: ipsec.c:28
unsigned int seq_no
Definition: ah.h:27
#define always_inline
Definition: clib.h:98
unsigned int u32
Definition: types.h:88
static u8 * format_ah_decrypt_trace(u8 *s, va_list *args)
Definition: ah_decrypt.c:69
unsigned char auth_data[0]
Definition: ah.h:28
static u8 ah_calc_icv_padding_len(u8 icv_size, int is_ipv6)
Definition: ah.h:47
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
#define foreach_ah_decrypt_error
Definition: ah_decrypt.c:41
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
static unsigned int hmac_calc(vlib_main_t *vm, ipsec_sa_t *sa, u8 *data, int data_len, u8 *signature)
Definition: esp.h:106
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:111
static void vlib_prefetch_combined_counter(const vlib_combined_counter_main_t *cm, u32 thread_index, u32 index)
Pre-fetch a per-thread combined counter for the given object index.
Definition: counter.h:235
unsigned char nexthdr
Definition: ah.h:23
u32 node_index
Node index.
Definition: node.h:495
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:368
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1180
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:395
vlib_main_t * vm
Definition: buffer.c:312
vlib_node_registration_t ah4_decrypt_node
(constructor) VLIB_REGISTER_NODE (ah4_decrypt_node)
Definition: ah_decrypt.c:294
#define ARRAY_LEN(x)
Definition: clib.h:62
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:465
#define foreach_ah_decrypt_next
Definition: ah_decrypt.c:27
vlib_combined_counter_main_t ipsec_sa_counters
SA packet & bytes counters.
Definition: ipsec_sa.c:25
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:514
#define ASSERT(truth)
ipsec_sa_t * sad
Definition: ipsec.h:95
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:248
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:372
Definition: defs.h:47
ah_decrypt_next_t
Definition: ah_decrypt.c:34
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:274
#define vnet_buffer(b)
Definition: buffer.h:369
Definition: ah.h:21
#define ip6_ext_header_find_t(i, p, m, t)
Definition: ip6_packet.h:561
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:235
ipsec_integ_alg_t integ_alg
Definition: ah_decrypt.c:63
u8 integ_icv_size
Definition: ipsec_sa.h:120
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:247