2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
15 #include <vnet/ip/ip.h>
16 #include <vnet/ip/ip_source_and_port_range_check.h>
19 vlib_node_registration_t ip4_source_port_and_range_check;
21 #define foreach_ip4_source_and_port_range_check_error \
22 _(CHECK_FAIL, "ip4 source and port range check bad packets") \
23 _(CHECK_OK, "ip4 source and port range check good packets")
27 #define _(sym,str) IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_##sym,
28 foreach_ip4_source_and_port_range_check_error
30 IP4_SOURCE_AND_PORT_RANGE_CHECK_N_ERROR,
31 } ip4_source_and_port_range_check_error_t;
33 static char *ip4_source_and_port_range_check_error_strings[] = {
34 #define _(sym,string) string,
35 foreach_ip4_source_and_port_range_check_error
44 ip4_address_t src_addr;
47 } ip4_source_and_port_range_check_trace_t;
50 format_ip4_source_and_port_range_check_trace (u8 * s, va_list * va)
52 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
53 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
54 ip4_source_and_port_range_check_trace_t *t =
55 va_arg (*va, ip4_source_and_port_range_check_trace_t *);
58 s = format (s, "PASS (bypass case)");
60 s = format (s, "fib %d src ip %U %s dst port %d: %s",
61 t->fib_index, format_ip4_address, &t->src_addr,
62 t->is_tcp ? "TCP" : "UDP", (u32) t->dst_port,
63 (t->pass == 1) ? "PASS" : "FAIL");
69 IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP,
70 IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
71 } ip4_source_and_port_range_check_next_t;
75 check_adj_port_range_x1 (ip_adjacency_t * adj, u16 dst_port, u32 next)
77 protocol_port_range_t *range;
81 u16x8vec_t sum, sum_equal_diff2;
82 u16 sum_nonzero, sum_equal, winner_mask;
86 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR || dst_port == 0)
87 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
89 rwh = (u8 *) (&adj->rewrite_header);
90 range = (protocol_port_range_t *) rwh;
92 /* Make the obvious screw-case work. A variant also works w/ no MMX */
93 if (PREDICT_FALSE (dst_port == 65535))
98 i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof (protocol_port_range_t);
101 for (j = 0; j < 8; j++)
102 if (range->low.as_u16[j] == 65535)
106 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
109 key.as_u16x8 = u16x8_splat (dst_port);
111 for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof (protocol_port_range_t);
114 diff1.as_u16x8 = u16x8_sub_saturate (range->low.as_u16x8, key.as_u16x8);
115 diff2.as_u16x8 = u16x8_sub_saturate (range->hi.as_u16x8, key.as_u16x8);
116 sum.as_u16x8 = u16x8_add (diff1.as_u16x8, diff2.as_u16x8);
117 sum_equal_diff2.as_u16x8 =
118 u16x8_is_equal (sum.as_u16x8, diff2.as_u16x8);
119 sum_nonzero = ~u16x8_zero_byte_mask (sum.as_u16x8);
120 sum_equal = ~u16x8_zero_byte_mask (sum_equal_diff2.as_u16x8);
121 winner_mask = sum_nonzero & sum_equal;
126 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
130 ip4_source_and_port_range_check_inline
131 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
133 ip4_main_t *im = &ip4_main;
134 ip_lookup_main_t *lm = &im->lookup_main;
135 ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
136 u32 n_left_from, *from, *to_next;
138 vlib_node_runtime_t *error_node = node;
139 u32 good_packets = 0;
142 from = vlib_frame_vector_args (frame);
143 n_left_from = frame->n_vectors;
144 next_index = node->cached_next_index;
146 while (n_left_from > 0)
150 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
153 while (n_left_from >= 4 && n_left_to_next >= 2)
155 vlib_buffer_t *b0, *b1;
156 ip4_header_t *ip0, *ip1;
157 ip4_fib_mtrie_t *mtrie0, *mtrie1;
158 ip4_fib_mtrie_leaf_t leaf0, leaf1;
159 ip_source_and_port_range_check_config_t *c0, *c1;
160 ip_adjacency_t *adj0 = 0, *adj1 = 0;
161 u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
162 u32 bi1, next1, adj_index1, pass1, save_next1, fib_index1;
163 udp_header_t *udp0, *udp1;
165 /* Prefetch next iteration. */
167 vlib_buffer_t *p2, *p3;
169 p2 = vlib_get_buffer (vm, from[2]);
170 p3 = vlib_get_buffer (vm, from[3]);
172 vlib_prefetch_buffer_header (p2, LOAD);
173 vlib_prefetch_buffer_header (p3, LOAD);
175 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
176 CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
179 bi0 = to_next[0] = from[0];
180 bi1 = to_next[1] = from[1];
186 b0 = vlib_get_buffer (vm, bi0);
187 b1 = vlib_get_buffer (vm, bi1);
190 vec_elt (im->fib_index_by_sw_if_index,
191 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
193 vec_elt (im->fib_index_by_sw_if_index,
194 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
196 ip0 = vlib_buffer_get_current (b0);
197 ip1 = vlib_buffer_get_current (b1);
199 c0 = vnet_get_config_data (&cm->config_main,
200 &b0->current_config_index,
201 &next0, sizeof (c0[0]));
202 c1 = vnet_get_config_data (&cm->config_main,
203 &b1->current_config_index,
204 &next1, sizeof (c1[0]));
206 /* we can't use the default VRF here... */
207 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
209 ASSERT (c0->fib_index[i] && c1->fib_index[i]);
213 if (ip0->protocol == IP_PROTOCOL_UDP)
215 c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
216 if (ip0->protocol == IP_PROTOCOL_TCP)
218 c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
220 if (PREDICT_TRUE (fib_index0 != ~0))
223 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
225 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
227 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
228 &ip0->src_address, 0);
230 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
231 &ip0->src_address, 1);
233 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
234 &ip0->src_address, 2);
236 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
237 &ip0->src_address, 3);
239 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
241 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
246 adj0 = ip_get_adjacency (lm, adj_index0);
249 if (ip1->protocol == IP_PROTOCOL_UDP)
251 c1->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
252 if (ip1->protocol == IP_PROTOCOL_TCP)
254 c1->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
256 if (PREDICT_TRUE (fib_index1 != ~0))
259 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
261 leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
263 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
264 &ip1->src_address, 0);
266 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
267 &ip1->src_address, 1);
269 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
270 &ip1->src_address, 2);
272 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
273 &ip1->src_address, 3);
275 adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
277 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
281 adj1 = ip_get_adjacency (lm, adj_index1);
286 pass0 |= ip4_address_is_multicast (&ip0->src_address);
288 ip0->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
289 pass0 |= (ip0->protocol != IP_PROTOCOL_UDP)
290 && (ip0->protocol != IP_PROTOCOL_TCP);
294 pass1 |= ip4_address_is_multicast (&ip1->src_address);
296 ip1->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
297 pass1 |= (ip1->protocol != IP_PROTOCOL_UDP)
298 && (ip1->protocol != IP_PROTOCOL_TCP);
301 udp0 = ip4_next_header (ip0);
303 udp1 = ip4_next_header (ip1);
305 if (PREDICT_TRUE (pass0 == 0))
308 next0 = check_adj_port_range_x1
309 (adj0, clib_net_to_host_u16 (udp0->dst_port), next0);
310 good_packets -= (save_next0 != next0);
311 b0->error = error_node->errors
312 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
315 if (PREDICT_TRUE (pass1 == 0))
318 next1 = check_adj_port_range_x1
319 (adj1, clib_net_to_host_u16 (udp1->dst_port), next1);
320 good_packets -= (save_next1 != next1);
321 b1->error = error_node->errors
322 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
325 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
326 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
328 ip4_source_and_port_range_check_trace_t *t =
329 vlib_add_trace (vm, node, b0, sizeof (*t));
330 t->pass = next0 == save_next0;
332 t->fib_index = fib_index0;
333 t->src_addr.as_u32 = ip0->src_address.as_u32;
334 t->dst_port = (pass0 == 0) ?
335 clib_net_to_host_u16 (udp0->dst_port) : 0;
336 t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
339 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
340 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
342 ip4_source_and_port_range_check_trace_t *t =
343 vlib_add_trace (vm, node, b1, sizeof (*t));
344 t->pass = next1 == save_next1;
346 t->fib_index = fib_index1;
347 t->src_addr.as_u32 = ip1->src_address.as_u32;
348 t->dst_port = (pass1 == 0) ?
349 clib_net_to_host_u16 (udp1->dst_port) : 0;
350 t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
353 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
354 to_next, n_left_to_next,
355 bi0, bi1, next0, next1);
358 while (n_left_from > 0 && n_left_to_next > 0)
362 ip4_fib_mtrie_t *mtrie0;
363 ip4_fib_mtrie_leaf_t leaf0;
364 ip_source_and_port_range_check_config_t *c0;
365 ip_adjacency_t *adj0 = 0;
366 u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
376 b0 = vlib_get_buffer (vm, bi0);
379 vec_elt (im->fib_index_by_sw_if_index,
380 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
382 ip0 = vlib_buffer_get_current (b0);
384 c0 = vnet_get_config_data
385 (&cm->config_main, &b0->current_config_index,
386 &next0, sizeof (c0[0]));
388 /* we can't use the default VRF here... */
389 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
391 ASSERT (c0->fib_index[i]);
395 if (ip0->protocol == IP_PROTOCOL_UDP)
397 c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
398 if (ip0->protocol == IP_PROTOCOL_TCP)
400 c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
402 if (fib_index0 != ~0)
405 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
407 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
409 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
410 &ip0->src_address, 0);
412 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
413 &ip0->src_address, 1);
415 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
416 &ip0->src_address, 2);
418 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
419 &ip0->src_address, 3);
421 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
423 ASSERT (adj_index0 == ip4_fib_lookup_with_table
425 &ip0->src_address, 0 /* use default route */ ));
426 adj0 = ip_get_adjacency (lm, adj_index0);
429 * $$$ which (src,dst) categories should we always pass?
433 pass0 |= ip4_address_is_multicast (&ip0->src_address);
435 ip0->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
436 pass0 |= (ip0->protocol != IP_PROTOCOL_UDP)
437 && (ip0->protocol != IP_PROTOCOL_TCP);
440 udp0 = ip4_next_header (ip0);
442 if (PREDICT_TRUE (pass0 == 0))
445 next0 = check_adj_port_range_x1
446 (adj0, clib_net_to_host_u16 (udp0->dst_port), next0);
447 good_packets -= (save_next0 != next0);
448 b0->error = error_node->errors
449 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
452 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
453 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
455 ip4_source_and_port_range_check_trace_t *t =
456 vlib_add_trace (vm, node, b0, sizeof (*t));
457 t->pass = next0 == save_next0;
459 t->fib_index = fib_index0;
460 t->src_addr.as_u32 = ip0->src_address.as_u32;
461 t->dst_port = (pass0 == 0) ?
462 clib_net_to_host_u16 (udp0->dst_port) : 0;
463 t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
466 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
467 to_next, n_left_to_next,
471 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
474 vlib_node_increment_counter (vm, ip4_source_port_and_range_check.index,
475 IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
477 return frame->n_vectors;
481 ip4_source_and_port_range_check (vlib_main_t * vm,
482 vlib_node_runtime_t * node,
483 vlib_frame_t * frame)
485 return ip4_source_and_port_range_check_inline (vm, node, frame);
489 VLIB_REGISTER_NODE (ip4_source_port_and_range_check) = {
490 .function = ip4_source_and_port_range_check,
491 .name = "ip4-source-and-port-range-check",
492 .vector_size = sizeof (u32),
494 .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
495 .error_strings = ip4_source_and_port_range_check_error_strings,
497 .n_next_nodes = IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
499 [IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP] = "error-drop",
502 .format_buffer = format_ip4_header,
503 .format_trace = format_ip4_source_and_port_range_check_trace,
508 set_ip_source_and_port_range_check (vlib_main_t * vm,
510 u32 sw_if_index, u32 is_add)
512 ip4_main_t *im = &ip4_main;
513 ip_lookup_main_t *lm = &im->lookup_main;
514 ip_config_main_t *rx_cm = &lm->rx_config_mains[VNET_UNICAST];
516 ip_source_and_port_range_check_config_t config;
521 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
523 config.fib_index[i] = fib_index[i];
526 feature_index = im->ip4_unicast_rx_feature_source_and_port_range_check;
528 vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
530 ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
532 ? vnet_config_add_feature
533 : vnet_config_del_feature)
534 (vm, &rx_cm->config_main, ci, feature_index, &config, sizeof (config));
535 rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
540 static clib_error_t *
541 set_ip_source_and_port_range_check_fn (vlib_main_t * vm,
542 unformat_input_t * input,
543 vlib_cli_command_t * cmd)
545 vnet_main_t *vnm = vnet_get_main ();
546 ip4_main_t *im = &ip4_main;
547 clib_error_t *error = 0;
549 u32 sw_if_index = ~0;
550 u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
551 u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
558 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
564 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
566 if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
571 (input, "tcp-out-vrf %d",
572 &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT]))
576 (input, "udp-out-vrf %d",
577 &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT]))
581 (input, "tcp-in-vrf %d",
582 &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN]))
586 (input, "udp-in-vrf %d",
587 &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN]))
589 else if (unformat (input, "del"))
595 if (sw_if_index == ~0)
596 return clib_error_return (0, "Interface required but not specified");
599 return clib_error_return (0,
600 "TCP or UDP VRF ID required but not specified");
602 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
606 return clib_error_return (0,
607 "TCP, UDP VRF ID should not be 0 (default). Should be distinct VRF for this purpose. ");
611 p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
614 return clib_error_return (0, "Invalid VRF ID %d", vrf_id[i]);
620 set_ip_source_and_port_range_check (vm, fib_index, sw_if_index, is_add);
628 return clib_error_return
630 "set source and port-range on interface returned an unexpected value: %d",
637 VLIB_CLI_COMMAND (set_interface_ip_source_and_port_range_check_command,
639 .path = "set interface ip source-and-port-range-check",
640 .function = set_ip_source_and_port_range_check_fn,
641 .short_help = "set int ip source-and-port-range-check <intfc> [tcp-out-vrf <n>] [udp-out-vrf <n>] [tcp-in-vrf <n>] [udp-in-vrf <n>] [del]",
646 format_source_and_port_rc_adjacency (u8 * s, va_list * args)
648 CLIB_UNUSED (vnet_main_t * vnm) = va_arg (*args, vnet_main_t *);
649 ip_lookup_main_t *lm = va_arg (*args, ip_lookup_main_t *);
650 u32 adj_index = va_arg (*args, u32);
651 ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index);
652 source_range_check_main_t *srm = &source_range_check_main;
653 u8 *rwh = (u8 *) (&adj->rewrite_header);
654 protocol_port_range_t *range;
658 range = (protocol_port_range_t *) rwh;
660 s = format (s, "allow ");
662 for (i = 0; i < srm->ranges_per_adjacency; i++)
664 for (j = 0; j < 8; j++)
666 if (range->low.as_u16[j])
669 s = format (s, ", ");
670 if (range->hi.as_u16[j] > (range->low.as_u16[j] + 1))
671 s = format (s, "%d-%d", (u32) range->low.as_u16[j],
672 (u32) range->hi.as_u16[j] - 1);
674 s = format (s, "%d", range->low.as_u16[j]);
684 ip4_source_and_port_range_check_init (vlib_main_t * vm)
686 source_range_check_main_t *srm = &source_range_check_main;
687 ip4_main_t *im = &ip4_main;
688 ip_lookup_main_t *lm = &im->lookup_main;
691 srm->vnet_main = vnet_get_main ();
693 srm->ranges_per_adjacency =
694 VLIB_BUFFER_PRE_DATA_SIZE / (2 * sizeof (u16x8));
695 srm->special_adjacency_format_function_index =
696 vnet_register_special_adjacency_format_function (lm,
697 format_source_and_port_rc_adjacency);
698 ASSERT (srm->special_adjacency_format_function_index);
703 VLIB_INIT_FUNCTION (ip4_source_and_port_range_check_init);
706 add_port_range_adjacency (ip4_address_t * address,
709 u16 * low_ports, u16 * high_ports, u32 fib_index)
713 source_range_check_main_t *srm = &source_range_check_main;
714 ip4_main_t *im = &ip4_main;
715 ip_lookup_main_t *lm = &im->lookup_main;
716 protocol_port_range_t *range;
719 adj = ip_get_adjacency (lm, adj_index);
720 /* $$$$ fixme: add ports if address + mask match */
721 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ICMP_ERROR)
722 return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
724 ip_adjacency_t template_adj;
725 ip4_add_del_route_args_t a;
727 memset (&template_adj, 0, sizeof (template_adj));
729 template_adj.lookup_next_index = IP_LOOKUP_NEXT_ICMP_ERROR;
730 template_adj.if_address_index = ~0;
731 template_adj.special_adjacency_format_function_index =
732 srm->special_adjacency_format_function_index;
734 rwh = (u8 *) (&template_adj.rewrite_header);
736 range = (protocol_port_range_t *) rwh;
738 if (vec_len (low_ports) > 8 * srm->ranges_per_adjacency)
739 return VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
743 for (i = 0; i < vec_len (low_ports); i++)
745 for (; j < srm->ranges_per_adjacency; j++)
749 if (range->low.as_u16[k] == 0)
751 range->low.as_u16[k] = low_ports[i];
752 range->hi.as_u16[k] = high_ports[i];
766 /* Too many ports specified... */
767 return VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY;
772 memset (&a, 0, sizeof (a));
773 a.flags = IP4_ROUTE_FLAG_FIB_INDEX;
774 a.table_index_or_table_id = fib_index;
775 a.dst_address = address[0];
776 a.dst_address_length = length;
777 a.add_adj = &template_adj;
780 ip4_add_del_route (im, &a);
785 remove_port_range_adjacency (ip4_address_t * address,
788 u16 * low_ports, u16 * high_ports, u32 fib_index)
792 source_range_check_main_t *srm = &source_range_check_main;
793 ip4_main_t *im = &ip4_main;
794 ip_lookup_main_t *lm = &im->lookup_main;
795 protocol_port_range_t *range;
798 adj = ip_get_adjacency (lm, adj_index);
799 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR) /* _ICMP_ERROR is a dummy placeholder */
800 return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
802 rwh = (u8 *) (&adj->rewrite_header);
804 for (i = 0; i < vec_len (low_ports); i++)
806 range = (protocol_port_range_t *) rwh;
807 for (j = 0; j < srm->ranges_per_adjacency; j++)
809 for (k = 0; k < 8; k++)
811 if (low_ports[i] == range->low.as_u16[k] &&
812 high_ports[i] == range->hi.as_u16[k])
814 range->low.as_u16[k] = range->hi.as_u16[k] = 0;
823 range = (protocol_port_range_t *) rwh;
824 /* Have we deleted all ranges yet? */
825 for (i = 0; i < srm->ranges_per_adjacency; i++)
827 for (j = 0; j < 8; j++)
829 if (range->low.as_u16[i] != 0)
834 /* Yes, lose the adjacency... */
836 ip4_add_del_route_args_t a;
838 memset (&a, 0, sizeof (a));
839 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
840 a.table_index_or_table_id = fib_index;
841 a.dst_address = address[0];
842 a.dst_address_length = length;
843 a.adj_index = adj_index;
844 ip4_add_del_route (im, &a);
852 // This will be moved to another file and implemented post API freeze.
854 ip6_source_and_port_range_check_add_del (ip6_address_t * address,
858 u16 * high_ports, int is_add)
864 ip4_source_and_port_range_check_add_del (ip4_address_t * address,
868 u16 * high_ports, int is_add)
871 ip4_main_t *im = &ip4_main;
872 // ip_lookup_main_t * lm = &im->lookup_main;
877 p = hash_get (im->fib_index_by_table_id, vrf_id);
881 f = find_ip4_fib_by_table_index_or_id (im, vrf_id, 0 /* flags */ );
882 fib_index = f->index;
887 adj_index = ip4_fib_lookup_with_table
888 (im, fib_index, address, 0 /* disable_default_route */ );
892 remove_port_range_adjacency (address, length, adj_index, low_ports,
893 high_ports, fib_index);
897 add_port_range_adjacency (address, length, adj_index, low_ports,
898 high_ports, fib_index);
904 static clib_error_t *
905 ip_source_and_port_range_check_command_fn (vlib_main_t * vm,
906 unformat_input_t * input,
907 vlib_cli_command_t * cmd)
913 ip4_address_t ip4_addr;
914 ip6_address_t ip6_addr; //This function will be moved to generic impl when v6 done.
918 int is_add = 1, ip_ver = ~0;
922 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
924 if (unformat (input, "%U/%d", unformat_ip4_address, &ip4_addr, &length))
928 (input, "%U/%d", unformat_ip6_address, &ip6_addr, &length))
930 else if (unformat (input, "vrf %d", &vrf_id))
932 else if (unformat (input, "del"))
934 else if (unformat (input, "port %d", &tmp))
936 if (tmp == 0 || tmp > 65535)
937 return clib_error_return (0, "port %d out of range", tmp);
939 this_hi = this_low + 1;
940 vec_add1 (low_ports, this_low);
941 vec_add1 (high_ports, this_hi);
943 else if (unformat (input, "range %d - %d", &tmp, &tmp2))
946 return clib_error_return (0, "ports %d and %d out of order",
948 if (tmp == 0 || tmp > 65535)
949 return clib_error_return (0, "low port %d out of range", tmp);
950 if (tmp2 == 0 || tmp2 > 65535)
951 return clib_error_return (0, "high port %d out of range", tmp2);
954 vec_add1 (low_ports, this_low);
955 vec_add1 (high_ports, this_hi);
962 return clib_error_return (0, " <address>/<mask> not specified");
965 return clib_error_return (0, " VRF ID required, not specified");
967 if (vec_len (low_ports) == 0)
968 return clib_error_return (0,
969 " Both VRF ID and range/port must be set for a protocol.");
972 return clib_error_return (0, " VRF ID can not be 0 (default).");
976 rv = ip4_source_and_port_range_check_add_del
977 (&ip4_addr, length, vrf_id, low_ports, high_ports, is_add);
979 return clib_error_return (0, " IPv6 in subsequent patch");
986 case VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE:
987 return clib_error_return
988 (0, " Incorrect adjacency for add/del operation");
990 case VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY:
991 return clib_error_return (0, " Too many ports in add/del operation");
993 case VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY:
994 return clib_error_return
995 (0, " Too many ranges requested for add operation");
998 return clib_error_return (0, " returned an unexpected value: %d", rv);
1005 VLIB_CLI_COMMAND (ip_source_and_port_range_check_command, static) = {
1006 .path = "set ip source-and-port-range-check",
1007 .function = ip_source_and_port_range_check_command_fn,
1009 "set ip source-and-port-range-check <ip-addr>/<mask> [range <nn>-<nn> tcp-vrf <id>] [vrf <id>] [del]",
1014 static clib_error_t *
1015 show_source_and_port_range_check_fn (vlib_main_t * vm,
1016 unformat_input_t * input,
1017 vlib_cli_command_t * cmd)
1019 source_range_check_main_t *srm = &source_range_check_main;
1020 ip4_main_t *im = &ip4_main;
1021 ip_lookup_main_t *lm = &im->lookup_main;
1022 protocol_port_range_t *range;
1029 ip_adjacency_t *adj;
1034 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1036 if (unformat (input, "%U", unformat_ip4_address, &addr))
1038 else if (unformat (input, "vrf %d", &vrf_id))
1040 else if (unformat (input, "port %d", &port))
1047 return clib_error_return (0, "<address> not specified");
1050 return clib_error_return (0, "VRF ID required, not specified");
1052 p = hash_get (im->fib_index_by_table_id, vrf_id);
1054 return clib_error_return (0, "VRF %d not found", vrf_id);
1057 adj_index = ip4_fib_lookup_with_table
1058 (im, fib_index, &addr, 0 /* disable_default_route */ );
1060 adj = ip_get_adjacency (lm, adj_index);
1062 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR)
1064 vlib_cli_output (vm, "%U: src address drop", format_ip4_address, &addr);
1070 rv = check_adj_port_range_x1 (adj, (u16) port, 1234);
1072 vlib_cli_output (vm, "%U port %d PASS", format_ip4_address,
1075 vlib_cli_output (vm, "%U port %d FAIL", format_ip4_address,
1082 rwh = (u8 *) (&adj->rewrite_header);
1084 s = format (0, "%U: ", format_ip4_address, &addr);
1086 range = (protocol_port_range_t *) rwh;
1088 for (i = 0; i < srm->ranges_per_adjacency; i++)
1090 for (j = 0; j < 8; j++)
1092 if (range->low.as_u16[j])
1093 s = format (s, "%d - %d ", (u32) range->low.as_u16[j],
1094 (u32) range->hi.as_u16[j]);
1098 vlib_cli_output (vm, "%s", s);
1106 VLIB_CLI_COMMAND (show_source_and_port_range_check, static) = {
1107 .path = "show ip source-and-port-range-check",
1108 .function = show_source_and_port_range_check_fn,
1110 "show ip source-and-port-range-check vrf <nn> <ip-addr> <port>",
1115 * fd.io coding-style-patch-verification: ON
1118 * eval: (c-set-style "gnu")