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")
26 #define _(sym,str) IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_##sym,
27 foreach_ip4_source_and_port_range_check_error
29 IP4_SOURCE_AND_PORT_RANGE_CHECK_N_ERROR,
30 } ip4_source_and_port_range_check_error_t;
32 static char * ip4_source_and_port_range_check_error_strings[] = {
33 #define _(sym,string) string,
34 foreach_ip4_source_and_port_range_check_error
42 ip4_address_t src_addr;
45 } ip4_source_and_port_range_check_trace_t;
47 static u8 * format_ip4_source_and_port_range_check_trace (u8 * s, va_list * va)
49 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
50 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
51 ip4_source_and_port_range_check_trace_t * t =
52 va_arg (*va, ip4_source_and_port_range_check_trace_t *);
55 s = format (s, "PASS (bypass case)");
57 s = format (s, "fib %d src ip %U %s dst port %d: %s",
58 t->fib_index, format_ip4_address, &t->src_addr, t->is_tcp ? "TCP" : "UDP",
60 (t->pass == 1) ? "PASS" : "FAIL");
65 IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP,
66 IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
67 } ip4_source_and_port_range_check_next_t;
70 static inline u32 check_adj_port_range_x1 (ip_adjacency_t * adj,
74 protocol_port_range_t *range;
78 u16x8vec_t sum, sum_equal_diff2;
79 u16 sum_nonzero, sum_equal, winner_mask;
83 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR || dst_port == 0)
84 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
86 rwh = (u8 *)(&adj->rewrite_header);
87 range = (protocol_port_range_t *)rwh;
89 /* Make the obvious screw-case work. A variant also works w/ no MMX */
90 if (PREDICT_FALSE(dst_port == 65535))
94 for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof(protocol_port_range_t); i++)
96 for (j = 0; j < 8; j++)
97 if (range->low.as_u16x8[j] == 65535)
101 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
104 key.as_u16x8 = u16x8_splat (dst_port);
106 for (i = 0; i < VLIB_BUFFER_PRE_DATA_SIZE / sizeof(protocol_port_range_t); i++)
108 diff1.as_u16x8 = u16x8_sub_saturate (range->low.as_u16x8, key.as_u16x8);
109 diff2.as_u16x8 = u16x8_sub_saturate (range->hi.as_u16x8, key.as_u16x8);
110 sum.as_u16x8 = u16x8_add (diff1.as_u16x8, diff2.as_u16x8);
111 sum_equal_diff2.as_u16x8 = u16x8_is_equal (sum.as_u16x8, diff2.as_u16x8);
112 sum_nonzero = ~u16x8_zero_byte_mask (sum.as_u16x8);
113 sum_equal = ~u16x8_zero_byte_mask (sum_equal_diff2.as_u16x8);
114 winner_mask = sum_nonzero & sum_equal;
119 return IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP;
123 ip4_source_and_port_range_check_inline
124 (vlib_main_t * vm, vlib_node_runtime_t * node,
125 vlib_frame_t * frame)
127 ip4_main_t * im = &ip4_main;
128 ip_lookup_main_t * lm = &im->lookup_main;
129 ip_config_main_t * cm = &lm->rx_config_mains[VNET_UNICAST];
130 u32 n_left_from, * from, * to_next;
132 vlib_node_runtime_t * error_node = node;
133 u32 good_packets = 0;
136 from = vlib_frame_vector_args (frame);
137 n_left_from = frame->n_vectors;
138 next_index = node->cached_next_index;
140 while (n_left_from > 0)
144 vlib_get_next_frame (vm, node, next_index,
145 to_next, n_left_to_next);
148 while (n_left_from >= 4 && n_left_to_next >= 2)
150 vlib_buffer_t * b0, * b1;
151 ip4_header_t * ip0, * ip1;
152 ip4_fib_mtrie_t * mtrie0, * mtrie1;
153 ip4_fib_mtrie_leaf_t leaf0, leaf1;
154 ip_source_and_port_range_check_config_t * c0, * c1;
155 ip_adjacency_t * adj0 = 0, * adj1 = 0;
156 u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
157 u32 bi1, next1, adj_index1, pass1, save_next1, fib_index1;
158 udp_header_t * udp0, * udp1;
160 /* Prefetch next iteration. */
162 vlib_buffer_t * p2, * p3;
164 p2 = vlib_get_buffer (vm, from[2]);
165 p3 = vlib_get_buffer (vm, from[3]);
167 vlib_prefetch_buffer_header (p2, LOAD);
168 vlib_prefetch_buffer_header (p3, LOAD);
170 CLIB_PREFETCH (p2->data, sizeof (ip0[0]), LOAD);
171 CLIB_PREFETCH (p3->data, sizeof (ip1[0]), LOAD);
174 bi0 = to_next[0] = from[0];
175 bi1 = to_next[1] = from[1];
181 b0 = vlib_get_buffer (vm, bi0);
182 b1 = vlib_get_buffer (vm, bi1);
184 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (b0)->sw_if_index[VLIB_RX]);
185 fib_index1 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (b1)->sw_if_index[VLIB_RX]);
187 ip0 = vlib_buffer_get_current (b0);
188 ip1 = vlib_buffer_get_current (b1);
190 c0 = vnet_get_config_data (&cm->config_main,
191 &b0->current_config_index,
194 c1 = vnet_get_config_data (&cm->config_main,
195 &b1->current_config_index,
199 /* we can't use the default VRF here... */
200 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
202 ASSERT(c0->fib_index[i] && c1->fib_index[i]);
206 if (ip0->protocol == IP_PROTOCOL_UDP)
207 fib_index0 = c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
208 if (ip0->protocol == IP_PROTOCOL_TCP)
209 fib_index0 = c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
211 if (PREDICT_TRUE(fib_index0 != ~0))
214 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
216 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
218 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
219 &ip0->src_address, 0);
221 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
222 &ip0->src_address, 1);
224 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
225 &ip0->src_address, 2);
227 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
228 &ip0->src_address, 3);
230 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
232 ASSERT (adj_index0 == ip4_fib_lookup_with_table (im, fib_index0,
234 0 /* use dflt rt */));
235 adj0 = ip_get_adjacency (lm, adj_index0);
238 if (ip1->protocol == IP_PROTOCOL_UDP)
239 fib_index1 = c1->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
240 if (ip1->protocol == IP_PROTOCOL_TCP)
241 fib_index1 = c1->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
243 if (PREDICT_TRUE(fib_index1 != ~0))
246 mtrie1 = &vec_elt_at_index (im->fibs, fib_index1)->mtrie;
248 leaf1 = IP4_FIB_MTRIE_LEAF_ROOT;
250 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
251 &ip1->src_address, 0);
253 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
254 &ip1->src_address, 1);
256 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
257 &ip1->src_address, 2);
259 leaf1 = ip4_fib_mtrie_lookup_step (mtrie1, leaf1,
260 &ip1->src_address, 3);
262 adj_index1 = ip4_fib_mtrie_leaf_get_adj_index (leaf1);
264 ASSERT (adj_index1 == ip4_fib_lookup_with_table (im, fib_index1,
267 adj1 = ip_get_adjacency (lm, adj_index1);
272 pass0 |= ip4_address_is_multicast (&ip0->src_address);
273 pass0 |= ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
274 pass0 |= (ip0->protocol != IP_PROTOCOL_UDP) &&
275 (ip0->protocol != IP_PROTOCOL_TCP);
279 pass1 |= ip4_address_is_multicast (&ip1->src_address);
280 pass1 |= ip1->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
281 pass1 |= (ip1->protocol != IP_PROTOCOL_UDP) &&
282 (ip1->protocol != IP_PROTOCOL_TCP);
285 udp0 = ip4_next_header (ip0);
287 udp1 = ip4_next_header (ip1);
289 if (PREDICT_TRUE(pass0 == 0))
292 next0 = check_adj_port_range_x1
293 (adj0, clib_net_to_host_u16(udp0->dst_port), next0);
294 good_packets -= (save_next0 != next0);
295 b0->error = error_node->errors
296 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
299 if (PREDICT_TRUE(pass1 == 0))
302 next1 = check_adj_port_range_x1
303 (adj1, clib_net_to_host_u16(udp1->dst_port), next1);
304 good_packets -= (save_next1 != next1);
305 b1->error = error_node->errors
306 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
309 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
310 && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
311 ip4_source_and_port_range_check_trace_t * t =
312 vlib_add_trace (vm, node, b0, sizeof (*t));
313 t->pass = next0 == save_next0;
315 t->fib_index = fib_index0;
316 t->src_addr.as_u32 = ip0->src_address.as_u32;
317 t->dst_port = (pass0 == 0) ?
318 clib_net_to_host_u16(udp0->dst_port) : 0;
319 t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
322 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
323 && (b1->flags & VLIB_BUFFER_IS_TRACED))) {
324 ip4_source_and_port_range_check_trace_t * t =
325 vlib_add_trace (vm, node, b1, sizeof (*t));
326 t->pass = next1 == save_next1;
328 t->fib_index = fib_index1;
329 t->src_addr.as_u32 = ip1->src_address.as_u32;
330 t->dst_port = (pass1 == 0) ?
331 clib_net_to_host_u16(udp1->dst_port) : 0;
332 t->is_tcp = ip1->protocol == IP_PROTOCOL_TCP;
335 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
336 to_next, n_left_to_next,
337 bi0, bi1, next0, next1);
340 while (n_left_from > 0 && n_left_to_next > 0)
344 ip4_fib_mtrie_t * mtrie0;
345 ip4_fib_mtrie_leaf_t leaf0;
346 ip_source_and_port_range_check_config_t * c0;
347 ip_adjacency_t * adj0 = 0;
348 u32 bi0, next0, adj_index0, pass0, save_next0, fib_index0;
358 b0 = vlib_get_buffer (vm, bi0);
360 fib_index0 = vec_elt (im->fib_index_by_sw_if_index, vnet_buffer (b0)->sw_if_index[VLIB_RX]);
362 ip0 = vlib_buffer_get_current (b0);
364 c0 = vnet_get_config_data
365 (&cm->config_main, &b0->current_config_index,
369 /* we can't use the default VRF here... */
370 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
372 ASSERT(c0->fib_index[i]);
376 if (ip0->protocol == IP_PROTOCOL_UDP)
377 fib_index0 = c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT];
378 if (ip0->protocol == IP_PROTOCOL_TCP)
379 fib_index0 = c0->fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT];
381 if (fib_index0 != ~0)
384 mtrie0 = &vec_elt_at_index (im->fibs, fib_index0)->mtrie;
386 leaf0 = IP4_FIB_MTRIE_LEAF_ROOT;
388 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
389 &ip0->src_address, 0);
391 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
392 &ip0->src_address, 1);
394 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
395 &ip0->src_address, 2);
397 leaf0 = ip4_fib_mtrie_lookup_step (mtrie0, leaf0,
398 &ip0->src_address, 3);
400 adj_index0 = ip4_fib_mtrie_leaf_get_adj_index (leaf0);
402 ASSERT (adj_index0 == ip4_fib_lookup_with_table
405 0 /* use default route */));
406 adj0 = ip_get_adjacency (lm, adj_index0);
409 * $$$ which (src,dst) categories should we always pass?
413 pass0 |= ip4_address_is_multicast (&ip0->src_address);
414 pass0 |= ip0->src_address.as_u32 == clib_host_to_net_u32(0xFFFFFFFF);
415 pass0 |= (ip0->protocol != IP_PROTOCOL_UDP) &&
416 (ip0->protocol != IP_PROTOCOL_TCP);
419 udp0 = ip4_next_header (ip0);
421 if (PREDICT_TRUE(pass0 == 0))
424 next0 = check_adj_port_range_x1
425 (adj0, clib_net_to_host_u16(udp0->dst_port), next0);
426 good_packets -= (save_next0 != next0);
427 b0->error = error_node->errors
428 [IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_FAIL];
431 if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
432 && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
433 ip4_source_and_port_range_check_trace_t * t =
434 vlib_add_trace (vm, node, b0, sizeof (*t));
435 t->pass = next0 == save_next0;
437 t->fib_index = fib_index0;
438 t->src_addr.as_u32 = ip0->src_address.as_u32;
439 t->dst_port = (pass0 == 0) ?
440 clib_net_to_host_u16(udp0->dst_port) : 0;
441 t->is_tcp = ip0->protocol == IP_PROTOCOL_TCP;
444 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
445 to_next, n_left_to_next,
449 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
452 vlib_node_increment_counter (vm, ip4_source_port_and_range_check.index,
453 IP4_SOURCE_AND_PORT_RANGE_CHECK_ERROR_CHECK_OK,
455 return frame->n_vectors;
459 ip4_source_and_port_range_check (vlib_main_t * vm,
460 vlib_node_runtime_t * node,
461 vlib_frame_t * frame)
463 return ip4_source_and_port_range_check_inline (vm, node, frame);
466 VLIB_REGISTER_NODE (ip4_source_port_and_range_check) = {
467 .function = ip4_source_and_port_range_check,
468 .name = "ip4-source-and-port-range-check",
469 .vector_size = sizeof (u32),
471 .n_errors = ARRAY_LEN(ip4_source_and_port_range_check_error_strings),
472 .error_strings = ip4_source_and_port_range_check_error_strings,
474 .n_next_nodes = IP4_SOURCE_AND_PORT_RANGE_CHECK_N_NEXT,
476 [IP4_SOURCE_AND_PORT_RANGE_CHECK_NEXT_DROP] = "error-drop",
479 .format_buffer = format_ip4_header,
480 .format_trace = format_ip4_source_and_port_range_check_trace,
483 int set_ip_source_and_port_range_check (vlib_main_t * vm,
488 ip4_main_t * im = &ip4_main;
489 ip_lookup_main_t * lm = &im->lookup_main;
490 ip_config_main_t * rx_cm = &lm->rx_config_mains[VNET_UNICAST];
492 ip_source_and_port_range_check_config_t config;
497 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
499 config.fib_index[i] = fib_index[i];
502 feature_index = im->ip4_unicast_rx_feature_source_and_port_range_check;
504 vec_validate (rx_cm->config_index_by_sw_if_index, sw_if_index);
506 ci = rx_cm->config_index_by_sw_if_index[sw_if_index];
508 ? vnet_config_add_feature
509 : vnet_config_del_feature)
510 (vm, &rx_cm->config_main,
515 rx_cm->config_index_by_sw_if_index[sw_if_index] = ci;
520 static clib_error_t *
521 set_ip_source_and_port_range_check_fn (vlib_main_t * vm,
522 unformat_input_t * input,
523 vlib_cli_command_t * cmd)
525 vnet_main_t * vnm = vnet_get_main();
526 ip4_main_t * im = &ip4_main;
527 clib_error_t * error = 0;
529 u32 sw_if_index = ~0;
530 u32 vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
531 u32 fib_index[IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS];
538 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
544 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
546 if (unformat (input, "%U", unformat_vnet_sw_interface, vnm,
549 else if (unformat (input, "tcp-out-vrf %d", &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_OUT]))
551 else if (unformat (input, "udp-out-vrf %d", &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_OUT]))
553 else if (unformat (input, "tcp-in-vrf %d", &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_TCP_IN]))
555 else if (unformat (input, "udp-in-vrf %d", &vrf_id[IP_SOURCE_AND_PORT_RANGE_CHECK_PROTOCOL_UDP_IN]))
557 else if (unformat (input, "del"))
563 if (sw_if_index == ~0)
564 return clib_error_return (0, "Interface required but not specified");
567 return clib_error_return (0, "TCP or UDP VRF ID required but not specified");
569 for (i = 0; i < IP_SOURCE_AND_PORT_RANGE_CHECK_N_PROTOCOLS; i++)
573 return clib_error_return (0, "TCP, UDP VRF ID should not be 0 (default). Should be distinct VRF for this purpose. ");
577 p = hash_get (im->fib_index_by_table_id, vrf_id[i]);
580 return clib_error_return (0, "Invalid VRF ID %d", vrf_id[i]);
585 rv = set_ip_source_and_port_range_check (vm, fib_index, sw_if_index, is_add);
593 return clib_error_return
594 (0, "set source and port-range on interface returned an unexpected value: %d", rv);
599 VLIB_CLI_COMMAND (set_interface_ip_source_and_port_range_check_command,
601 .path = "set interface ip source-and-port-range-check",
602 .function = set_ip_source_and_port_range_check_fn,
603 .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]",
606 static u8 * format_source_and_port_rc_adjacency (u8 * s, va_list * args)
608 CLIB_UNUSED (vnet_main_t * vnm) = va_arg (*args, vnet_main_t *);
609 ip_lookup_main_t * lm = va_arg (*args, ip_lookup_main_t *);
610 u32 adj_index = va_arg (*args, u32);
611 ip_adjacency_t * adj = ip_get_adjacency (lm, adj_index);
612 source_range_check_main_t * srm = &source_range_check_main;
613 u8 * rwh = (u8 *) (&adj->rewrite_header);
614 protocol_port_range_t * range;
618 range = (protocol_port_range_t *) rwh;
620 s = format (s, "allow ");
622 for (i = 0; i < srm->ranges_per_adjacency; i++)
624 for (j = 0; j < 8; j++)
626 if (range->low.as_u16[j])
629 s = format (s, ", ");
630 if (range->hi.as_u16[j] > (range->low.as_u16[j] + 1))
631 s = format (s, "%d-%d", (u32) range->low.as_u16[j],
632 (u32) range->hi.as_u16[j] - 1);
634 s = format (s, "%d", range->low.as_u16[j]);
643 clib_error_t * ip4_source_and_port_range_check_init (vlib_main_t * vm)
645 source_range_check_main_t * srm = &source_range_check_main;
646 ip4_main_t * im = &ip4_main;
647 ip_lookup_main_t * lm = &im->lookup_main;
650 srm->vnet_main = vnet_get_main();
652 srm->ranges_per_adjacency = VLIB_BUFFER_PRE_DATA_SIZE / (2*sizeof(u16x8));
653 srm->special_adjacency_format_function_index =
654 vnet_register_special_adjacency_format_function
655 (lm, format_source_and_port_rc_adjacency);
656 ASSERT (srm->special_adjacency_format_function_index);
661 VLIB_INIT_FUNCTION (ip4_source_and_port_range_check_init);
663 int add_port_range_adjacency(ip4_address_t * address,
670 ip_adjacency_t * adj;
672 source_range_check_main_t * srm = &source_range_check_main;
673 ip4_main_t * im = &ip4_main;
674 ip_lookup_main_t * lm = &im->lookup_main;
675 protocol_port_range_t * range;
678 adj = ip_get_adjacency (lm, adj_index);
679 /* $$$$ fixme: add ports if address + mask match */
680 if (adj->lookup_next_index == IP_LOOKUP_NEXT_ICMP_ERROR)
681 return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
683 ip_adjacency_t template_adj;
684 ip4_add_del_route_args_t a;
686 memset (&template_adj, 0, sizeof (template_adj));
688 template_adj.lookup_next_index = IP_LOOKUP_NEXT_ICMP_ERROR;
689 template_adj.if_address_index = ~0;
690 template_adj.special_adjacency_format_function_index =
691 srm->special_adjacency_format_function_index;
693 rwh = (u8 *) (&template_adj.rewrite_header);
695 range = (protocol_port_range_t *) rwh;
697 if (vec_len (low_ports) > 8 * srm->ranges_per_adjacency)
698 return VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
702 for (i = 0; i < vec_len (low_ports); i++)
704 for (; j < srm->ranges_per_adjacency; j++)
708 if (range->low.as_u16[k] == 0)
710 range->low.as_u16[k] = low_ports[i];
711 range->hi.as_u16[k] = high_ports[i];
725 /* Too many ports specified... */
726 return VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY;
731 memset (&a, 0, sizeof(a));
732 a.flags = IP4_ROUTE_FLAG_FIB_INDEX;
733 a.table_index_or_table_id = fib_index;
734 a.dst_address = address[0];
735 a.dst_address_length = length;
736 a.add_adj = &template_adj;
739 ip4_add_del_route (im, &a);
743 int remove_port_range_adjacency(ip4_address_t * address,
750 ip_adjacency_t * adj;
752 source_range_check_main_t * srm = &source_range_check_main;
753 ip4_main_t * im = &ip4_main;
754 ip_lookup_main_t * lm = &im->lookup_main;
755 protocol_port_range_t * range;
758 adj = ip_get_adjacency (lm, adj_index);
759 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR) /* _ICMP_ERROR is a dummy placeholder */
760 return VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE;
762 rwh = (u8 *)(&adj->rewrite_header);
764 for (i = 0; i < vec_len (low_ports); i++)
766 range = (protocol_port_range_t *) rwh;
767 for (j = 0; j < srm->ranges_per_adjacency; j++)
769 for (k = 0; k < 8; k++)
771 if (low_ports[i] == range->low.as_u16[k] &&
772 high_ports[i] == range->hi.as_u16[k])
774 range->low.as_u16[k] = range->hi.as_u16[k] = 0;
783 range = (protocol_port_range_t *) rwh;
784 /* Have we deleted all ranges yet? */
785 for (i = 0; i < srm->ranges_per_adjacency; i++)
787 for (j = 0; j < 8; j++)
789 if (range->low.as_u16[i] != 0)
794 /* Yes, lose the adjacency... */
796 ip4_add_del_route_args_t a;
798 memset (&a, 0, sizeof(a));
799 a.flags = IP4_ROUTE_FLAG_FIB_INDEX | IP4_ROUTE_FLAG_DEL;
800 a.table_index_or_table_id = fib_index;
801 a.dst_address = address[0];
802 a.dst_address_length = length;
803 a.adj_index = adj_index;
804 ip4_add_del_route (im, &a);
812 // This will be moved to another file and implemented post API freeze.
813 int ip6_source_and_port_range_check_add_del (ip6_address_t * address,
822 int ip4_source_and_port_range_check_add_del (ip4_address_t * address,
830 ip4_main_t * im = &ip4_main;
831 // ip_lookup_main_t * lm = &im->lookup_main;
836 p = hash_get (im->fib_index_by_table_id, vrf_id);
840 f = find_ip4_fib_by_table_index_or_id (im, vrf_id, 0 /* flags */);
841 fib_index = f->index;
846 adj_index = ip4_fib_lookup_with_table
847 (im, fib_index, address, 0 /* disable_default_route */);
851 remove_port_range_adjacency(address, length, adj_index, low_ports, high_ports, fib_index);
855 add_port_range_adjacency(address, length, adj_index, low_ports, high_ports, fib_index);
861 static clib_error_t *
862 ip_source_and_port_range_check_command_fn (vlib_main_t * vm,
863 unformat_input_t * input,
864 vlib_cli_command_t * cmd)
867 u16 * high_ports = 0;
870 ip4_address_t ip4_addr;
871 ip6_address_t ip6_addr; //This function will be moved to generic impl when v6 done.
875 int is_add = 1, ip_ver = ~0;
879 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
881 if (unformat (input, "%U/%d", unformat_ip4_address, &ip4_addr, &length))
883 else if (unformat (input, "%U/%d", unformat_ip6_address, &ip6_addr, &length))
885 else if (unformat (input, "vrf %d", &vrf_id))
887 else if (unformat (input, "del"))
889 else if (unformat (input, "port %d", &tmp))
891 if (tmp == 0 || tmp > 65535)
892 return clib_error_return (0, "port %d out of range", tmp);
894 this_hi = this_low + 1;
895 vec_add1 (low_ports, this_low);
896 vec_add1 (high_ports, this_hi);
898 else if (unformat (input, "range %d - %d", &tmp, &tmp2))
901 return clib_error_return (0, "ports %d and %d out of order",
903 if (tmp == 0 || tmp > 65535)
904 return clib_error_return (0, "low port %d out of range", tmp);
905 if (tmp2 == 0 || tmp2 > 65535)
906 return clib_error_return (0, "high port %d out of range", tmp2);
909 vec_add1 (low_ports, this_low);
910 vec_add1 (high_ports, this_hi);
917 return clib_error_return (0, " <address>/<mask> not specified");
920 return clib_error_return (0, " VRF ID required, not specified");
922 if ( vec_len (low_ports) == 0)
923 return clib_error_return (0, " Both VRF ID and range/port must be set for a protocol.");
926 return clib_error_return (0, " VRF ID can not be 0 (default).");
930 rv = ip4_source_and_port_range_check_add_del
931 (&ip4_addr, length, vrf_id, low_ports, high_ports, is_add);
933 return clib_error_return (0, " IPv6 in subsequent patch");
940 case VNET_API_ERROR_INCORRECT_ADJACENCY_TYPE:
941 return clib_error_return
942 (0, " Incorrect adjacency for add/del operation");
944 case VNET_API_ERROR_EXCEEDED_NUMBER_OF_PORTS_CAPACITY:
945 return clib_error_return
946 (0, " Too many ports in add/del operation");
948 case VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY:
949 return clib_error_return
950 (0, " Too many ranges requested for add operation");
953 return clib_error_return
954 (0, " returned an unexpected value: %d", rv);
960 VLIB_CLI_COMMAND (ip_source_and_port_range_check_command, static) = {
961 .path = "set ip source-and-port-range-check",
962 .function = ip_source_and_port_range_check_command_fn,
964 "set ip source-and-port-range-check <ip-addr>/<mask> [range <nn>-<nn> tcp-vrf <id>] [vrf <id>] [del]",
968 static clib_error_t *
969 show_source_and_port_range_check_fn (vlib_main_t * vm,
970 unformat_input_t * input,
971 vlib_cli_command_t * cmd)
973 source_range_check_main_t * srm = & source_range_check_main;
974 ip4_main_t * im = &ip4_main;
975 ip_lookup_main_t * lm = &im->lookup_main;
976 protocol_port_range_t * range;
988 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
990 if (unformat (input, "%U", unformat_ip4_address, &addr))
992 else if (unformat (input, "vrf %d", &vrf_id))
994 else if (unformat (input, "port %d", &port))
1001 return clib_error_return (0, "<address> not specified");
1004 return clib_error_return (0, "VRF ID required, not specified");
1006 p = hash_get (im->fib_index_by_table_id, vrf_id);
1008 return clib_error_return (0, "VRF %d not found", vrf_id);
1011 adj_index = ip4_fib_lookup_with_table
1012 (im, fib_index, &addr, 0 /* disable_default_route */);
1014 adj = ip_get_adjacency (lm, adj_index);
1016 if (adj->lookup_next_index != IP_LOOKUP_NEXT_ICMP_ERROR)
1018 vlib_cli_output (vm, "%U: src address drop", format_ip4_address, &addr);
1024 rv = check_adj_port_range_x1 (adj, (u16) port, 1234);
1026 vlib_cli_output (vm, "%U port %d PASS", format_ip4_address,
1029 vlib_cli_output (vm, "%U port %d FAIL", format_ip4_address,
1036 rwh = (u8 *) (&adj->rewrite_header);
1038 s = format (0, "%U: ", format_ip4_address, &addr);
1040 range = (protocol_port_range_t *) rwh;
1042 for (i = 0; i < srm->ranges_per_adjacency; i++)
1044 for (j = 0; j < 8; j++)
1046 if (range->low.as_u16[j])
1047 s = format (s, "%d - %d ", (u32) range->low.as_u16[j],
1048 (u32) range->hi.as_u16[j]);
1052 vlib_cli_output (vm, "%s", s);
1059 VLIB_CLI_COMMAND (show_source_and_port_range_check, static) = {
1060 .path = "show ip source-and-port-range-check",
1061 .function = show_source_and_port_range_check_fn,
1063 "show ip source-and-port-range-check vrf <nn> <ip-addr> <port>",