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_rx;
20 vlib_node_registration_t ip4_source_port_and_range_check_tx;
22 #define foreach_ip4_source_and_port_range_check_error \
23 _(CHECK_FAIL, "ip4 source and port range check bad packets") \
24 _(CHECK_OK, "ip4 source and port range check good packets")
28 #define _(sym,str) IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_##sym,
29 foreach_ip4_source_and_port_range_check_error
31 IP4_SOURCE_AND_PORT_RANGE_CHECK_N_ERROR,
32 } ip4_source_and_port_range_check_error_t;
34 static char *ip4_source_and_port_range_check_error_strings[] = {
35 #define _(sym,string) string,
36 foreach_ip4_source_and_port_range_check_error
45 ip4_address_t src_addr;
48 } ip4_source_and_port_range_check_trace_t;
51 format_ip4_source_and_port_range_check_trace (u8 * s, va_list * va)
53 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
54 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
55 ip4_source_and_port_range_check_trace_t *t =
56 va_arg (*va, ip4_source_and_port_range_check_trace_t *);
59 s = format (s, "PASS (bypass case)");
61 s = format (s, "fib %d src ip %U %s dst port %d: %s",
62 t->fib_index, format_ip4_address, &t->src_addr,
63 t->is_tcp ? "TCP" : "UDP", (u32) t->port,
64 (t->pass == 1) ? "PASS" : "FAIL");
70 IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP,
71 IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
72 } ip4_source_and_port_range_check_next_t;
76 check_adj_port_range_x1 (ip_adjacency_t * adj, u16 dst_port, u32 next)
78 protocol_port_range_t *range;
82 u16x8vec_t sum, sum_equal_diff2;
83 u16 sum_nonzero, sum_equal, winner_mask;
87 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR || dst_port == 0)
88 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
90 rwh = (u8 *) (&adj->rewrite_header);
91 range = (protocol_port_range_t *) rwh;
93 /* Make the obvious screw-case work. A variant also works w/ no MMX */
94 if (PREDICT_FALSE (dst_port == 65535))
99 i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof (protocol_port_range_t);
102 for (j = 0; j < 8; j++)
103 if (range->low.as_u16[j] == 65535)
107 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
110 key.as_u16x8 = u16x8_splat (dst_port);
112 for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof (protocol_port_range_t);
115 diff1.as_u16x8 = u16x8_sub_saturate (range->low.as_u16x8, key.as_u16x8);
116 diff2.as_u16x8 = u16x8_sub_saturate (range->hi.as_u16x8, key.as_u16x8);
117 sum.as_u16x8 = u16x8_add (diff1.as_u16x8, diff2.as_u16x8);
118 sum_equal_diff2.as_u16x8 =
119 u16x8_is_equal (sum.as_u16x8, diff2.as_u16x8);
120 sum_nonzero = ~u16x8_zero_byte_mask (sum.as_u16x8);
121 sum_equal = ~u16x8_zero_byte_mask (sum_equal_diff2.as_u16x8);
122 winner_mask = sum_nonzero & sum_equal;
127 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
131 ip4_source_and_port_range_check_inline (vlib_main_t * vm,
132 vlib_node_runtime_t * node,
133 vlib_frame_t * frame, int is_tx)
135 ip4_main_t *im = &ip4_main;
136 ip_lookup_main_t *lm = &im->lookup_main;
137 ip_config_main_t *rx_cm =
138 &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
139 ip_config_main_t *tx_cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
140 u32 n_left_from, *from, *to_next;
142 vlib_node_runtime_t *error_node = node;
143 u32 good_packets = 0;
146 from = vlib_frame_vector_args (frame);
147 n_left_from = frame->n_vectors;
148 next_index = node->cached_next_index;
150 while (n_left_from > 0)
154 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
157 while (n_left_from >= 4 && n_left_to_next >= 2)
159 vlib_buffer_t *b0, *b1;
160 ip4_header_t *ip0, *ip1;
161 ip4_fib_mtrie_t *mtrie0, *mtrie1;
162 ip4_fib_mtrie_leaf_t leaf0, leaf1;
163 ip_source_and_port_range_check_config_t *c0, *c1;
164 ip_adjacency_t *adj0 = 0, *adj1 = 0;
165 u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
166 u32 bi1, next1, adj_index1, pass1, save_next1, fib_index1;
167 udp_header_t *udp0, *udp1;
169 /* Prefetch next iteration. */
171 vlib_buffer_t *p2, *p3;
173 p2 = vlib_get_buffer (vm, from[2]);
174 p3 = vlib_get_buffer (vm, from[3]);
176 vlib_prefetch_buffer_header (p2, LOAD);
177 vlib_prefetch_buffer_header (p3, LOAD);
179 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
180 CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
183 bi0 = to_next[0] = from[0];
184 bi1 = to_next[1] = from[1];
190 b0 = vlib_get_buffer (vm, bi0);
191 b1 = vlib_get_buffer (vm, bi1);
194 vec_elt (im->fib_index_by_sw_if_index,
195 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
197 vec_elt (im->fib_index_by_sw_if_index,
198 vnet_buffer (b1)->sw_if_index[VLIB_RX]);
200 ip0 = vlib_buffer_get_current (b0);
201 ip1 = vlib_buffer_get_current (b1);
205 c0 = vnet_get_config_data (&tx_cm->config_main,
206 &b0->current_config_index,
207 &next0, sizeof (c0[0]));
208 c1 = vnet_get_config_data (&tx_cm->config_main,
209 &b1->current_config_index,
210 &next1, sizeof (c1[0]));
214 c0 = vnet_get_config_data (&rx_cm->config_main,
215 &b0->current_config_index,
216 &next0, sizeof (c0[0]));
217 c1 = vnet_get_config_data (&rx_cm->config_main,
218 &b1->current_config_index,
219 &next1, sizeof (c1[0]));
222 /* we can't use the default VRF here... */
223 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
225 ASSERT (c0->fib_index[i] && c1->fib_index[i]);
231 if (ip0->protocol == IP_PROTOCOL_UDP)
234 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
235 if (ip0->protocol == IP_PROTOCOL_TCP)
238 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
242 if (ip0->protocol == IP_PROTOCOL_UDP)
245 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
246 if (ip0->protocol == IP_PROTOCOL_TCP)
249 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
252 if (PREDICT_TRUE (fib_index0 != ~0))
255 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
257 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
259 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
260 &ip0->src_address, 0);
262 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
263 &ip0->src_address, 1);
265 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
266 &ip0->src_address, 2);
268 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
269 &ip0->src_address, 3);
271 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
273 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
278 adj0 = ip_get_adjacency (lm, adj_index0);
283 if (ip1->protocol == IP_PROTOCOL_UDP)
286 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
287 if (ip1->protocol == IP_PROTOCOL_TCP)
290 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
294 if (ip1->protocol == IP_PROTOCOL_UDP)
297 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
298 if (ip1->protocol == IP_PROTOCOL_TCP)
301 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
304 if (PREDICT_TRUE (fib_index1 != ~0))
307 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
309 leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
311 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
312 &ip1->src_address, 0);
314 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
315 &ip1->src_address, 1);
317 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
318 &ip1->src_address, 2);
320 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
321 &ip1->src_address, 3);
323 adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
325 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
328 adj1 = ip_get_adjacency (lm, adj_index1);
333 pass0 |= ip4_address_is_multicast (&ip0->src_address);
335 ip0->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
336 pass0 |= (ip0->protocol != IP_PROTOCOL_UDP)
337 && (ip0->protocol != IP_PROTOCOL_TCP);
341 pass1 |= ip4_address_is_multicast (&ip1->src_address);
343 ip1->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
344 pass1 |= (ip1->protocol != IP_PROTOCOL_UDP)
345 && (ip1->protocol != IP_PROTOCOL_TCP);
348 udp0 = ip4_next_header (ip0);
350 udp1 = ip4_next_header (ip1);
352 if (PREDICT_TRUE (pass0 == 0))
355 next0 = check_adj_port_range_x1
356 (adj0, clib_net_to_host_u16 (udp0->dst_port), next0);
357 good_packets -= (save_next0 != next0);
358 b0->error = error_node->errors
359 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
362 if (PREDICT_TRUE (pass1 == 0))
365 next1 = check_adj_port_range_x1
366 (adj1, clib_net_to_host_u16 (udp1->dst_port), next1);
367 good_packets -= (save_next1 != next1);
368 b1->error = error_node->errors
369 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
372 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
373 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
375 ip4_source_and_port_range_check_trace_t *t =
376 vlib_add_trace (vm, node, b0, sizeof (*t));
377 t->pass = next0 == save_next0;
379 t->fib_index = fib_index0;
380 t->src_addr.as_u32 = ip0->src_address.as_u32;
381 t->port = (pass0 == 0) ?
382 clib_net_to_host_u16 (udp0->dst_port) : 0;
383 t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
386 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
387 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
389 ip4_source_and_port_range_check_trace_t *t =
390 vlib_add_trace (vm, node, b1, sizeof (*t));
391 t->pass = next1 == save_next1;
393 t->fib_index = fib_index1;
394 t->src_addr.as_u32 = ip1->src_address.as_u32;
395 t->port = (pass1 == 0) ?
396 clib_net_to_host_u16 (udp1->dst_port) : 0;
397 t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
400 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
401 to_next, n_left_to_next,
402 bi0, bi1, next0, next1);
405 while (n_left_from > 0 && n_left_to_next > 0)
409 ip4_fib_mtrie_t *mtrie0;
410 ip4_fib_mtrie_leaf_t leaf0;
411 ip_source_and_port_range_check_config_t *c0;
412 ip_adjacency_t *adj0 = 0;
413 u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
423 b0 = vlib_get_buffer (vm, bi0);
426 vec_elt (im->fib_index_by_sw_if_index,
427 vnet_buffer (b0)->sw_if_index[VLIB_RX]);
430 vlib_buffer_advance (b0, sizeof (ethernet_header_t));
432 ip0 = vlib_buffer_get_current (b0);
436 c0 = vnet_get_config_data
437 (&tx_cm->config_main, &b0->current_config_index,
438 &next0, sizeof (c0[0]));
442 c0 = vnet_get_config_data
443 (&rx_cm->config_main, &b0->current_config_index,
444 &next0, sizeof (c0[0]));
447 /* we can't use the default VRF here... */
448 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
450 ASSERT (c0->fib_index[i]);
456 if (ip0->protocol == IP_PROTOCOL_UDP)
459 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN];
460 if (ip0->protocol == IP_PROTOCOL_TCP)
463 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN];
467 if (ip0->protocol == IP_PROTOCOL_UDP)
470 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
471 if (ip0->protocol == IP_PROTOCOL_TCP)
474 [IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
477 if (fib_index0 != ~0)
480 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
482 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
484 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
485 &ip0->src_address, 0);
487 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
488 &ip0->src_address, 1);
490 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
491 &ip0->src_address, 2);
493 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
494 &ip0->src_address, 3);
496 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
498 ASSERT (adj_index0 == ip4_fib_lookup_with_table
500 &ip0->src_address, 0 /* use default route */ ));
501 adj0 = ip_get_adjacency (lm, adj_index0);
504 * $$$ which (src,dst) categories should we always pass?
508 pass0 |= ip4_address_is_multicast (&ip0->src_address);
510 ip0->src_address.as_u32 == clib_host_to_net_u32 (0xFFFFFFFF);
511 pass0 |= (ip0->protocol != IP_PROTOCOL_UDP)
512 && (ip0->protocol != IP_PROTOCOL_TCP);
515 udp0 = ip4_next_header (ip0);
517 if (PREDICT_TRUE (pass0 == 0))
520 next0 = check_adj_port_range_x1
521 (adj0, clib_net_to_host_u16 (udp0->dst_port), next0);
522 good_packets -= (save_next0 != next0);
523 b0->error = error_node->errors
524 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
527 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
528 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
530 ip4_source_and_port_range_check_trace_t *t =
531 vlib_add_trace (vm, node, b0, sizeof (*t));
532 t->pass = next0 == save_next0;
534 t->fib_index = fib_index0;
535 t->src_addr.as_u32 = ip0->src_address.as_u32;
536 t->port = (pass0 == 0) ?
537 clib_net_to_host_u16 (udp0->dst_port) : 0;
538 t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
542 vlib_buffer_advance (b0, -sizeof (ethernet_header_t));
544 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
545 to_next, n_left_to_next,
549 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
553 vlib_node_increment_counter (vm, ip4_source_port_and_range_check_tx.index,
554 IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
557 vlib_node_increment_counter (vm, ip4_source_port_and_range_check_rx.index,
558 IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
560 return frame->n_vectors;
564 ip4_source_and_port_range_check_rx (vlib_main_t * vm,
565 vlib_node_runtime_t * node,
566 vlib_frame_t * frame)
568 return ip4_source_and_port_range_check_inline (vm, node, frame,
573 ip4_source_and_port_range_check_tx (vlib_main_t * vm,
574 vlib_node_runtime_t * node,
575 vlib_frame_t * frame)
577 return ip4_source_and_port_range_check_inline (vm, node, frame,
581 /* Note: Calling same function for both RX and TX nodes
582 as always checking dst_port, although
583 if this changes can easily make new function
587 VLIB_REGISTER_NODE (ip4_source_port_and_range_check_rx) = {
588 .function = ip4_source_and_port_range_check_rx,
589 .name = "ip4-source-and-port-range-check-rx",
590 .vector_size = sizeof (u32),
592 .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
593 .error_strings = ip4_source_and_port_range_check_error_strings,
595 .n_next_nodes = IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
597 [IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP] = "error-drop",
600 .format_buffer = format_ip4_header,
601 .format_trace = format_ip4_source_and_port_range_check_trace,
606 VLIB_REGISTER_NODE (ip4_source_port_and_range_check_tx) = {
607 .function = ip4_source_and_port_range_check_tx,
608 .name = "ip4-source-and-port-range-check-tx",
609 .vector_size = sizeof (u32),
611 .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
612 .error_strings = ip4_source_and_port_range_check_error_strings,
614 .n_next_nodes = IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
616 [IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP] = "error-drop",
619 .format_buffer = format_ip4_header,
620 .format_trace = format_ip4_source_and_port_range_check_trace,
625 set_ip_source_and_port_range_check (vlib_main_t * vm,
627 u32 sw_if_index, u32 is_add)
629 ip4_main_t *im = &ip4_main;
630 ip_lookup_main_t *lm = &im->lookup_main;
631 ip_config_main_t *rx_cm =
632 &lm->feature_config_mains[VNET_IP_RX_UNICAST_FEAT];
633 ip_config_main_t *tx_cm = &lm->feature_config_mains[VNET_IP_TX_FEAT];
635 ip_source_and_port_range_check_config_t config;
640 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
642 config.fib_index[i] = fib_index[i];
645 /* For OUT we are in the RX path */
646 if ((fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT] != ~0) ||
647 (fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT] != ~0))
649 feature_index = im->ip4_unicast_rx_feature_source_and_port_range_check;
651 vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
653 ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
655 ? vnet_config_add_feature
656 : vnet_config_del_feature)
657 (vm, &rx_cm->config_main, ci, feature_index, &config,
659 rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
662 /* For IN we are in the TX path */
663 if ((fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN] != ~0) ||
664 (fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN] != ~0))
666 feature_index = im->ip4_unicast_tx_feature_source_and_port_range_check;
668 vec_validate (tx_cm->config_index_by_sw_if_index, sw_if_index);
670 ci = tx_cm->config_index_by_sw_if_index[sw_if_index];
672 ? vnet_config_add_feature
673 : vnet_config_del_feature)
674 (vm, &tx_cm->config_main, ci, feature_index, &config,
676 tx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
678 vnet_config_update_tx_feature_count (lm, tx_cm, sw_if_index, is_add);
683 static clib_error_t *
684 set_ip_source_and_port_range_check_fn (vlib_main_t * vm,
685 unformat_input_t * input,
686 vlib_cli_command_t * cmd)
688 vnet_main_t *vnm = vnet_get_main ();
689 ip4_main_t *im = &ip4_main;
690 clib_error_t *error = 0;
692 u32 sw_if_index = ~0;
693 u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
694 u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
701 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
707 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
709 if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
714 (input, "tcp-out-vrf %d",
715 &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT]))
719 (input, "udp-out-vrf %d",
720 &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT]))
724 (input, "tcp-in-vrf %d",
725 &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN]))
729 (input, "udp-in-vrf %d",
730 &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN]))
732 else if (unformat (input, "del"))
738 if (sw_if_index == ~0)
739 return clib_error_return (0, "Interface required but not specified");
742 return clib_error_return (0,
743 "TCP or UDP VRF ID required but not specified");
745 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
749 return clib_error_return (0,
750 "TCP, UDP VRF ID should not be 0 (default). Should be distinct VRF for this purpose. ");
754 p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
757 return clib_error_return (0, "Invalid VRF ID %d", vrf_id[i]);
763 set_ip_source_and_port_range_check (vm, fib_index, sw_if_index, is_add);
771 return clib_error_return
773 "set source and port-range on interface returned an unexpected value: %d",
780 VLIB_CLI_COMMAND (set_interface_ip_source_and_port_range_check_command,
782 .path = "set interface ip source-and-port-range-check",
783 .function = set_ip_source_and_port_range_check_fn,
784 .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]",
789 format_source_and_port_rc_adjacency (u8 * s, va_list * args)
791 CLIB_UNUSED (vnet_main_t * vnm) = va_arg (*args, vnet_main_t *);
792 ip_lookup_main_t *lm = va_arg (*args, ip_lookup_main_t *);
793 u32 adj_index = va_arg (*args, u32);
794 ip_adjacency_t *adj = ip_get_adjacency (lm, adj_index);
795 source_range_check_main_t *srm = &source_range_check_main;
796 u8 *rwh = (u8 *) (&adj->rewrite_header);
797 protocol_port_range_t *range;
801 range = (protocol_port_range_t *) rwh;
803 s = format (s, "allow ");
805 for (i = 0; i < srm->ranges_per_adjacency; i++)
807 for (j = 0; j < 8; j++)
809 if (range->low.as_u16[j])
812 s = format (s, ", ");
813 if (range->hi.as_u16[j] > (range->low.as_u16[j] + 1))
814 s = format (s, "%d-%d", (u32) range->low.as_u16[j],
815 (u32) range->hi.as_u16[j] - 1);
817 s = format (s, "%d", range->low.as_u16[j]);
827 ip4_source_and_port_range_check_init (vlib_main_t * vm)
829 source_range_check_main_t *srm = &source_range_check_main;
830 ip4_main_t *im = &ip4_main;
831 ip_lookup_main_t *lm = &im->lookup_main;
834 srm->vnet_main = vnet_get_main ();
836 srm->ranges_per_adjacency =
837 VLIB_BUFFER_PRE_DATA_SIZE / (2 * sizeof (u16x8));
838 srm->special_adjacency_format_function_index =
839 vnet_register_special_adjacency_format_function (lm,
840 format_source_and_port_rc_adjacency);
841 ASSERT (srm->special_adjacency_format_function_index);
846 VLIB_INIT_FUNCTION (ip4_source_and_port_range_check_init);
849 add_port_range_adjacency (ip4_address_t * address,
852 u16 * low_ports, u16 * high_ports, u32 fib_index)
856 source_range_check_main_t *srm = &source_range_check_main;
857 ip4_main_t *im = &ip4_main;
858 ip_lookup_main_t *lm = &im->lookup_main;
859 protocol_port_range_t *range;
862 adj = ip_get_adjacency (lm, adj_index);
863 /* $$$$ fixme: add ports if address + mask match */
864 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ICMP_ERROR)
865 return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
867 ip_adjacency_t template_adj;
868 ip4_add_del_route_args_t a;
870 memset (&template_adj, 0, sizeof (template_adj));
872 template_adj.lookup_next_index = IP_LOOKUP_NEXT_ICMP_ERROR;
873 template_adj.if_address_index = ~0;
874 template_adj.special_adjacency_format_function_index =
875 srm->special_adjacency_format_function_index;
877 rwh = (u8 *) (&template_adj.rewrite_header);
879 range = (protocol_port_range_t *) rwh;
881 if (vec_len (low_ports) > 8 * srm->ranges_per_adjacency)
882 return VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
886 for (i = 0; i < vec_len (low_ports); i++)
888 for (; j < srm->ranges_per_adjacency; j++)
892 if (range->low.as_u16[k] == 0)
894 range->low.as_u16[k] = low_ports[i];
895 range->hi.as_u16[k] = high_ports[i];
909 /* Too many ports specified... */
910 return VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY;
915 memset (&a, 0, sizeof (a));
916 a.flags = IP4_ROUTE_FLAG_FIB_INDEX;
917 a.table_index_or_table_id = fib_index;
918 a.dst_address = address[0];
919 a.dst_address_length = length;
920 a.add_adj = &template_adj;
923 ip4_add_del_route (im, &a);
928 remove_port_range_adjacency (ip4_address_t * address,
931 u16 * low_ports, u16 * high_ports, u32 fib_index)
935 source_range_check_main_t *srm = &source_range_check_main;
936 ip4_main_t *im = &ip4_main;
937 ip_lookup_main_t *lm = &im->lookup_main;
938 protocol_port_range_t *range;
941 adj = ip_get_adjacency (lm, adj_index);
942 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR) /* _ICMP_ERROR is a dummy placeholder */
943 return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
945 rwh = (u8 *) (&adj->rewrite_header);
947 for (i = 0; i < vec_len (low_ports); i++)
949 range = (protocol_port_range_t *) rwh;
950 for (j = 0; j < srm->ranges_per_adjacency; j++)
952 for (k = 0; k < 8; k++)
954 if (low_ports[i] == range->low.as_u16[k] &&
955 high_ports[i] == range->hi.as_u16[k])
957 range->low.as_u16[k] = range->hi.as_u16[k] = 0;
966 range = (protocol_port_range_t *) rwh;
967 /* Have we deleted all ranges yet? */
968 for (i = 0; i < srm->ranges_per_adjacency; i++)
970 for (j = 0; j < 8; j++)
972 if (range->low.as_u16[i] != 0)
977 /* Yes, lose the adjacency... */
979 ip4_add_del_route_args_t a;
981 memset (&a, 0, sizeof (a));
982 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
983 a.table_index_or_table_id = fib_index;
984 a.dst_address = address[0];
985 a.dst_address_length = length;
986 a.adj_index = adj_index;
987 ip4_add_del_route (im, &a);
995 // This will be moved to another file and implemented post API freeze.
997 ip6_source_and_port_range_check_add_del (ip6_address_t * address,
1001 u16 * high_ports, int is_add)
1007 ip4_source_and_port_range_check_add_del (ip4_address_t * address,
1011 u16 * high_ports, int is_add)
1014 ip4_main_t *im = &ip4_main;
1015 // ip_lookup_main_t * lm = &im->lookup_main;
1020 p = hash_get (im->fib_index_by_table_id, vrf_id);
1024 f = find_ip4_fib_by_table_index_or_id (im, vrf_id, 0 /* flags */ );
1025 fib_index = f->index;
1030 adj_index = ip4_fib_lookup_with_table
1031 (im, fib_index, address, 0 /* disable_default_route */ );
1035 remove_port_range_adjacency (address, length, adj_index, low_ports,
1036 high_ports, fib_index);
1040 add_port_range_adjacency (address, length, adj_index, low_ports,
1041 high_ports, fib_index);
1047 static clib_error_t *
1048 ip_source_and_port_range_check_command_fn (vlib_main_t * vm,
1049 unformat_input_t * input,
1050 vlib_cli_command_t * cmd)
1053 u16 *high_ports = 0;
1056 ip4_address_t ip4_addr;
1057 ip6_address_t ip6_addr; //This function will be moved to generic impl when v6 done.
1061 int is_add = 1, ip_ver = ~0;
1065 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1067 if (unformat (input, "%U/%d", unformat_ip4_address, &ip4_addr, &length))
1071 (input, "%U/%d", unformat_ip6_address, &ip6_addr, &length))
1073 else if (unformat (input, "vrf %d", &vrf_id))
1075 else if (unformat (input, "del"))
1077 else if (unformat (input, "port %d", &tmp))
1079 if (tmp == 0 || tmp > 65535)
1080 return clib_error_return (0, "port %d out of range", tmp);
1082 this_hi = this_low + 1;
1083 vec_add1 (low_ports, this_low);
1084 vec_add1 (high_ports, this_hi);
1086 else if (unformat (input, "range %d - %d", &tmp, &tmp2))
1089 return clib_error_return (0, "ports %d and %d out of order",
1091 if (tmp == 0 || tmp > 65535)
1092 return clib_error_return (0, "low port %d out of range", tmp);
1093 if (tmp2 == 0 || tmp2 > 65535)
1094 return clib_error_return (0, "high port %d out of range", tmp2);
1097 vec_add1 (low_ports, this_low);
1098 vec_add1 (high_ports, this_hi);
1105 return clib_error_return (0, " <address>/<mask> not specified");
1108 return clib_error_return (0, " VRF ID required, not specified");
1110 if (vec_len (low_ports) == 0)
1111 return clib_error_return (0,
1112 " Both VRF ID and range/port must be set for a protocol.");
1115 return clib_error_return (0, " VRF ID can not be 0 (default).");
1119 rv = ip4_source_and_port_range_check_add_del
1120 (&ip4_addr, length, vrf_id, low_ports, high_ports, is_add);
1122 return clib_error_return (0, " IPv6 in subsequent patch");
1129 case VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE:
1130 return clib_error_return
1131 (0, " Incorrect adjacency for add/del operation");
1133 case VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY:
1134 return clib_error_return (0, " Too many ports in add/del operation");
1136 case VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY:
1137 return clib_error_return
1138 (0, " Too many ranges requested for add operation");
1141 return clib_error_return (0, " returned an unexpected value: %d", rv);
1148 VLIB_CLI_COMMAND (ip_source_and_port_range_check_command, static) = {
1149 .path = "set ip source-and-port-range-check",
1150 .function = ip_source_and_port_range_check_command_fn,
1152 "set ip source-and-port-range-check <ip-addr>/<mask> [range <nn> - <nn>] [vrf <id>] [del]",
1157 static clib_error_t *
1158 show_source_and_port_range_check_fn (vlib_main_t * vm,
1159 unformat_input_t * input,
1160 vlib_cli_command_t * cmd)
1162 source_range_check_main_t *srm = &source_range_check_main;
1163 ip4_main_t *im = &ip4_main;
1164 ip_lookup_main_t *lm = &im->lookup_main;
1165 protocol_port_range_t *range;
1172 ip_adjacency_t *adj;
1177 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1179 if (unformat (input, "%U", unformat_ip4_address, &addr))
1181 else if (unformat (input, "vrf %d", &vrf_id))
1183 else if (unformat (input, "port %d", &port))
1190 return clib_error_return (0, "<address> not specified");
1193 return clib_error_return (0, "VRF ID required, not specified");
1195 p = hash_get (im->fib_index_by_table_id, vrf_id);
1197 return clib_error_return (0, "VRF %d not found", vrf_id);
1200 adj_index = ip4_fib_lookup_with_table
1201 (im, fib_index, &addr, 0 /* disable_default_route */ );
1203 adj = ip_get_adjacency (lm, adj_index);
1205 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR)
1207 vlib_cli_output (vm, "%U: src address drop", format_ip4_address, &addr);
1213 rv = check_adj_port_range_x1 (adj, (u16) port, 1234);
1215 vlib_cli_output (vm, "%U port %d PASS", format_ip4_address,
1218 vlib_cli_output (vm, "%U port %d FAIL", format_ip4_address,
1225 rwh = (u8 *) (&adj->rewrite_header);
1227 s = format (0, "%U: ", format_ip4_address, &addr);
1229 range = (protocol_port_range_t *) rwh;
1231 for (i = 0; i < srm->ranges_per_adjacency; i++)
1233 for (j = 0; j < 8; j++)
1235 if (range->low.as_u16[j])
1236 s = format (s, "%d - %d ", (u32) range->low.as_u16[j],
1237 (u32) range->hi.as_u16[j]);
1241 vlib_cli_output (vm, "%s", s);
1249 VLIB_CLI_COMMAND (show_source_and_port_range_check, static) = {
1250 .path = "show ip source-and-port-range-check",
1251 .function = show_source_and_port_range_check_fn,
1253 "show ip source-and-port-range-check vrf <nn> <ip-addr> <port>",
1258 * fd.io coding-style-patch-verification: ON
1261 * eval: (c-set-style "gnu")