github.com/cilium/cilium@v1.16.2/bpf/tests/bpf_nat_tests.c (about) 1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright Authors of Cilium */ 3 4 #include "common.h" 5 6 #include <bpf/ctx/skb.h> 7 #include <bpf/api.h> 8 9 #define ENABLE_SCTP 10 #define ENABLE_IPV4 11 #define ENABLE_NODEPORT 12 #include <node_config.h> 13 14 #undef EVENTS_MAP 15 #define EVENTS_MAP test_events_map 16 #define DEBUG 17 18 #include <lib/dbg.h> 19 #include <lib/eps.h> 20 #include <lib/nat.h> 21 #include <lib/time.h> 22 23 #define IP_ENDPOINT 1 24 #define IP_HOST 2 25 #define IP_ROUTER 3 26 #define IP_WORLD 4 27 28 static char pkt[100]; 29 30 __always_inline int mk_icmp4_error_pkt(void *dst, __u8 error_hdr, bool egress) 31 { 32 void *orig = dst; 33 34 struct ethhdr l2 = { 35 .h_source = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, 36 .h_dest = {0x12, 0x23, 0x34, 0x45, 0x56, 0x67}, 37 .h_proto = bpf_htons(ETH_P_IP) 38 }; 39 memcpy(dst, &l2, sizeof(struct ethhdr)); 40 dst += sizeof(struct ethhdr); 41 42 /* Building an IP/ICMP Error Unreach need to fragment sent by 43 * a networking equipment IP_ROUTER in response to a packet 44 * that is exceeding the MTU. 45 */ 46 unsigned int saddr = egress ? IP_ENDPOINT : IP_ROUTER; 47 unsigned int daddr = egress ? IP_WORLD : IP_HOST; 48 struct iphdr l3 = { 49 .version = 4, 50 .ihl = 5, 51 .protocol = IPPROTO_ICMP, 52 .saddr = bpf_htonl(saddr), 53 .daddr = bpf_htonl(daddr), 54 }; 55 memcpy(dst, &l3, sizeof(struct iphdr)); 56 dst += sizeof(struct iphdr); 57 58 struct icmphdr icmphdr __align_stack_8 = { 59 .type = ICMP_DEST_UNREACH, 60 .code = ICMP_FRAG_NEEDED, 61 .un = { 62 .frag = { 63 .mtu = bpf_htons(THIS_MTU), 64 }, 65 }, 66 }; 67 memcpy(dst, &icmphdr, sizeof(struct icmphdr)); 68 dst += sizeof(struct icmphdr); 69 70 /* Embedded packet is referring the original packet that triggers the 71 * ICMP. 72 */ 73 struct iphdr inner_l3 = { 74 .version = 4, 75 .ihl = 5, 76 .protocol = error_hdr, 77 .saddr = bpf_htonl(IP_HOST), 78 .daddr = bpf_htonl(IP_WORLD), 79 }; 80 if (egress) { 81 inner_l3.saddr = bpf_htonl(IP_WORLD); 82 inner_l3.daddr = bpf_htonl(IP_ENDPOINT); 83 } 84 85 memcpy(dst, &inner_l3, sizeof(struct iphdr)); 86 dst += sizeof(struct iphdr); 87 88 __u16 sport = 32768, dport = 80; 89 90 if (egress) { 91 sport = 79; 92 dport = error_hdr == IPPROTO_SCTP ? 32767 : 3030; 93 } 94 95 switch (error_hdr) { 96 case IPPROTO_TCP: { 97 struct tcphdr inner_l4 = { 98 .source = bpf_htons(sport), 99 .dest = bpf_htons(dport), 100 }; 101 memcpy(dst, &inner_l4, sizeof(struct tcphdr)); 102 dst += sizeof(struct tcphdr); 103 } 104 break; 105 case IPPROTO_UDP: { 106 struct udphdr inner_l4 = { 107 .source = bpf_htons(sport), 108 .dest = bpf_htons(dport), 109 }; 110 memcpy(dst, &inner_l4, sizeof(struct udphdr)); 111 dst += sizeof(struct udphdr); 112 } 113 break; 114 case IPPROTO_SCTP: { 115 struct { 116 __be16 sport; 117 __be16 dport; 118 } inner_l4; 119 120 inner_l4.sport = bpf_htons(sport), 121 inner_l4.dport = bpf_htons(dport), 122 123 memcpy(dst, &inner_l4, sizeof(inner_l4)); 124 dst += sizeof(inner_l4); 125 } 126 break; 127 case IPPROTO_ICMP: { 128 struct icmphdr inner_l4 __align_stack_8 = { 129 .type = egress ? ICMP_ECHOREPLY : ICMP_ECHO, 130 .un = { 131 .echo = { 132 .id = bpf_htons(egress ? dport : sport) 133 }, 134 }, 135 }; 136 memcpy(dst, &inner_l4, sizeof(struct icmphdr)); 137 dst += sizeof(struct icmphdr); 138 } 139 break; 140 } 141 return dst - orig; 142 } 143 144 CHECK("tc", "nat4_icmp_error_tcp") 145 int test_nat4_icmp_error_tcp(__maybe_unused struct __ctx_buff *ctx) 146 { 147 int pkt_size = mk_icmp4_error_pkt(pkt, IPPROTO_TCP, false); 148 { 149 void *data = (void *)(long)ctx->data; 150 void *data_end = (void *)(long)ctx->data_end; 151 152 if (data + pkt_size > data_end) 153 return TEST_ERROR; 154 155 memcpy(data, pkt, pkt_size); 156 } 157 158 test_init(); 159 /* The test is validating that the function snat_v4_rev_nat() 160 * will rev-nat the ICMP Unreach error need to fragment to the 161 * correct endpoint. Also, to be valid, the embedded packet 162 * should be NATed as-well, meaning that the source addr of 163 * the original packet will be switched from IP_HOST to 164 * IP_ENDPOINT, Also for TCP/UDP the dest port and ICMP the 165 * identifier. 166 * 167 * This test is validating the TCP case. 168 */ 169 170 int ret; 171 172 /* As a pre-requist we intruct the NAT table 173 * to simulate an ingress packet sent by 174 * endpoint to the world. 175 */ 176 struct ipv4_ct_tuple tuple = { 177 .nexthdr = IPPROTO_TCP, 178 .saddr = bpf_htonl(IP_ENDPOINT), 179 .daddr = bpf_htonl(IP_WORLD), 180 .sport = bpf_htons(3030), 181 .dport = bpf_htons(80), 182 .flags = 0, 183 }; 184 struct ipv4_nat_target target = { 185 .addr = bpf_htonl(IP_HOST), 186 .min_port = NODEPORT_PORT_MIN_NAT, 187 .max_port = NODEPORT_PORT_MIN_NAT + 1, 188 }; 189 struct ipv4_nat_entry state; 190 struct trace_ctx trace; 191 void *map; 192 193 map = get_cluster_snat_map_v4(target.cluster_id); 194 assert(map); 195 196 ret = snat_v4_new_mapping(ctx, map, &tuple, &state, &target, 197 false, NULL); 198 assert(ret == 0); 199 200 /* This is the entry-point of the test, calling 201 * snat_v4_rev_nat(). 202 */ 203 ret = snat_v4_rev_nat(ctx, &target, &trace, NULL); 204 assert(ret == 0); 205 206 __u16 proto; 207 void *data; 208 void *data_end; 209 210 int l3_off; 211 int l4_off; 212 struct iphdr *ip4; 213 struct icmphdr icmphdr __align_stack_8; 214 215 assert(validate_ethertype(ctx, &proto)); 216 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 217 if (data + pkt_size > data_end) 218 test_fatal("packet shrank"); 219 220 /* Validating outer headers */ 221 assert(ip4->protocol == IPPROTO_ICMP); 222 assert(ip4->saddr == bpf_htonl(IP_ROUTER)); 223 assert(ip4->daddr == bpf_htonl(IP_ENDPOINT)); 224 225 l3_off = ETH_HLEN; 226 l4_off = l3_off + ipv4_hdrlen(ip4); 227 if (ctx_load_bytes(ctx, l4_off, &icmphdr, sizeof(icmphdr)) < 0) 228 test_fatal("can't load icmp headers"); 229 assert(icmphdr.type == ICMP_DEST_UNREACH); 230 assert(icmphdr.code == ICMP_FRAG_NEEDED); 231 232 /* Validating inner headers */ 233 int in_l3_off; 234 int in_l4_off; 235 struct iphdr in_ip4; 236 struct { 237 __be16 sport; 238 __be16 dport; 239 } in_l4hdr; 240 241 in_l3_off = l4_off + sizeof(icmphdr); 242 if (ctx_load_bytes(ctx, in_l3_off, &in_ip4, 243 sizeof(in_ip4)) < 0) 244 test_fatal("can't load embedded ip headers"); 245 assert(in_ip4.protocol == IPPROTO_TCP); 246 assert(in_ip4.saddr == bpf_htonl(IP_ENDPOINT)); 247 assert(in_ip4.daddr == bpf_htonl(IP_WORLD)); 248 249 in_l4_off = in_l3_off + ipv4_hdrlen(&in_ip4); 250 if (ctx_load_bytes(ctx, in_l4_off, &in_l4hdr, sizeof(in_l4hdr)) < 0) 251 test_fatal("can't load embedded l4 headers"); 252 assert(in_l4hdr.sport == bpf_htons(3030)); 253 assert(in_l4hdr.dport == bpf_htons(80)); 254 255 test_finish(); 256 } 257 258 CHECK("tc", "nat4_icmp_error_udp") 259 int test_nat4_icmp_error_udp(__maybe_unused struct __ctx_buff *ctx) 260 { 261 int pkt_size = mk_icmp4_error_pkt(pkt, IPPROTO_UDP, false); 262 { 263 void *data = (void *)(long)ctx->data; 264 void *data_end = (void *)(long)ctx->data_end; 265 266 if (data + pkt_size > data_end) 267 return TEST_ERROR; 268 269 memcpy(data, pkt, pkt_size); 270 } 271 272 test_init(); 273 /* The test is validating that the function snat_v4_rev_nat() 274 * will rev-nat the ICMP Unreach error need to fragment to the 275 * correct endpoint. Also, to be valid, the embedded packet 276 * should be NATed as-well, meaning that the source addr of 277 * the original packet will be switched from IP_HOST to 278 * IP_ENDPOINT, Also for TCP/UDP the dest port and ICMP the 279 * identifier. 280 * 281 * This test is validating the UDP case. 282 */ 283 284 int ret; 285 286 /* As a pre-requist we intruct the NAT table 287 * to simulate an ingress packet sent by 288 * endpoint to the world. 289 */ 290 struct ipv4_ct_tuple tuple = { 291 .nexthdr = IPPROTO_UDP, 292 .saddr = bpf_htonl(IP_ENDPOINT), 293 .daddr = bpf_htonl(IP_WORLD), 294 .sport = bpf_htons(9999), 295 .dport = bpf_htons(80), 296 .flags = 0, 297 }; 298 struct ipv4_nat_target target = { 299 .addr = bpf_htonl(IP_HOST), 300 .min_port = NODEPORT_PORT_MIN_NAT, 301 .max_port = NODEPORT_PORT_MIN_NAT + 1, 302 }; 303 struct ipv4_nat_entry state; 304 struct trace_ctx trace; 305 void *map; 306 307 map = get_cluster_snat_map_v4(target.cluster_id); 308 assert(map); 309 310 ret = snat_v4_new_mapping(ctx, map, &tuple, &state, &target, 311 false, NULL); 312 assert(ret == 0); 313 314 /* This is the entry-point of the test, calling 315 * snat_v4_rev_nat(). 316 */ 317 ret = snat_v4_rev_nat(ctx, &target, &trace, NULL); 318 assert(ret == 0); 319 320 __u16 proto; 321 void *data; 322 void *data_end; 323 324 int l3_off; 325 int l4_off; 326 struct iphdr *ip4; 327 struct icmphdr icmphdr __align_stack_8; 328 329 assert(validate_ethertype(ctx, &proto)); 330 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 331 if (data + pkt_size > data_end) 332 test_fatal("packet shrank"); 333 334 /* Validating outer headers */ 335 assert(ip4->protocol == IPPROTO_ICMP); 336 assert(ip4->saddr == bpf_htonl(IP_ROUTER)); 337 assert(ip4->daddr == bpf_htonl(IP_ENDPOINT)); 338 339 l3_off = ETH_HLEN; 340 l4_off = l3_off + ipv4_hdrlen(ip4); 341 if (ctx_load_bytes(ctx, l4_off, &icmphdr, sizeof(icmphdr)) < 0) 342 test_fatal("can't load icmp headers"); 343 assert(icmphdr.type == ICMP_DEST_UNREACH); 344 assert(icmphdr.code == ICMP_FRAG_NEEDED); 345 346 /* Validating inner headers */ 347 int in_l3_off; 348 int in_l4_off; 349 struct iphdr in_ip4; 350 struct { 351 __be16 sport; 352 __be16 dport; 353 } in_l4hdr; 354 355 in_l3_off = l4_off + sizeof(icmphdr); 356 if (ctx_load_bytes(ctx, in_l3_off, &in_ip4, 357 sizeof(in_ip4)) < 0) 358 test_fatal("can't load embedded ip headers"); 359 assert(in_ip4.protocol == IPPROTO_UDP); 360 assert(in_ip4.saddr == bpf_htonl(IP_ENDPOINT)); 361 assert(in_ip4.daddr == bpf_htonl(IP_WORLD)); 362 363 in_l4_off = in_l3_off + ipv4_hdrlen(&in_ip4); 364 if (ctx_load_bytes(ctx, in_l4_off, &in_l4hdr, sizeof(in_l4hdr)) < 0) 365 test_fatal("can't load embedded l4 headers"); 366 assert(in_l4hdr.sport == bpf_htons(9999)); 367 assert(in_l4hdr.dport == bpf_htons(80)); 368 369 test_finish(); 370 } 371 372 CHECK("tc", "nat4_icmp_error_icmp") 373 int test_nat4_icmp_error_icmp(__maybe_unused struct __ctx_buff *ctx) 374 { 375 int pkt_size = mk_icmp4_error_pkt(pkt, IPPROTO_ICMP, false); 376 { 377 void *data = (void *)(long)ctx->data; 378 void *data_end = (void *)(long)ctx->data_end; 379 380 if (data + pkt_size > data_end) 381 return TEST_ERROR; 382 383 memcpy(data, pkt, pkt_size); 384 } 385 386 test_init(); 387 /* The test is validating that the function snat_v4_rev_nat() 388 * will rev-nat the ICMP Unreach error need to fragment to the 389 * correct endpoint. Also, to be valid, the embedded packet 390 * should be NATed as-well, meaning that the source addr of 391 * the original packet will be switched from IP_HOST to 392 * IP_ENDPOINT, Also for TCP/UDP the dest port and ICMP the 393 * identifier. 394 * 395 * This test is validating the ICMP case. 396 */ 397 398 int ret; 399 400 /* As a pre-requist we intruct the NAT table 401 * to simulate an ingress packet sent by 402 * endpoint to the world. 403 */ 404 struct ipv4_ct_tuple tuple = { 405 .nexthdr = IPPROTO_ICMP, 406 .saddr = bpf_htonl(IP_ENDPOINT), 407 .daddr = bpf_htonl(IP_WORLD), 408 .sport = bpf_htons(123), 409 .flags = 0, 410 }; 411 struct ipv4_nat_target target = { 412 .addr = bpf_htonl(IP_HOST), 413 .min_port = NODEPORT_PORT_MIN_NAT, 414 .max_port = NODEPORT_PORT_MIN_NAT + 1, 415 }; 416 struct ipv4_nat_entry state; 417 struct trace_ctx trace; 418 void *map; 419 420 map = get_cluster_snat_map_v4(target.cluster_id); 421 assert(map); 422 423 ret = snat_v4_new_mapping(ctx, map, &tuple, &state, &target, 424 false, NULL); 425 assert(ret == 0); 426 427 /* This is the entry-point of the test, calling 428 * snat_v4_rev_nat(). 429 */ 430 ret = snat_v4_rev_nat(ctx, &target, &trace, NULL); 431 assert(ret == 0); 432 433 __u16 proto; 434 void *data; 435 void *data_end; 436 437 int l3_off; 438 int l4_off; 439 struct iphdr *ip4; 440 struct icmphdr icmphdr __align_stack_8; 441 442 assert(validate_ethertype(ctx, &proto)); 443 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 444 if (data + pkt_size > data_end) 445 test_fatal("packet shrank"); 446 447 /* Validating outer headers */ 448 assert(ip4->protocol == IPPROTO_ICMP); 449 assert(ip4->saddr == bpf_htonl(IP_ROUTER)); 450 assert(ip4->daddr == bpf_htonl(IP_ENDPOINT)); 451 452 l3_off = ETH_HLEN; 453 l4_off = l3_off + ipv4_hdrlen(ip4); 454 if (ctx_load_bytes(ctx, l4_off, &icmphdr, sizeof(icmphdr)) < 0) 455 test_fatal("can't load icmp headers"); 456 assert(icmphdr.type == ICMP_DEST_UNREACH); 457 assert(icmphdr.code == ICMP_FRAG_NEEDED); 458 459 /* Validating inner headers */ 460 int in_l3_off; 461 int in_l4_off; 462 struct iphdr in_ip4; 463 struct icmphdr in_l4hdr __align_stack_8; 464 465 in_l3_off = l4_off + sizeof(icmphdr); 466 if (ctx_load_bytes(ctx, in_l3_off, &in_ip4, 467 sizeof(in_ip4)) < 0) 468 test_fatal("can't load embedded ip headers"); 469 assert(in_ip4.protocol == IPPROTO_ICMP); 470 assert(in_ip4.saddr == bpf_htonl(IP_ENDPOINT)); 471 assert(in_ip4.daddr == bpf_htonl(IP_WORLD)); 472 473 in_l4_off = in_l3_off + ipv4_hdrlen(&in_ip4); 474 if (ctx_load_bytes(ctx, in_l4_off, &in_l4hdr, sizeof(in_l4hdr)) < 0) 475 test_fatal("can't load embedded l4 headers"); 476 assert(in_l4hdr.un.echo.id == bpf_htons(123)); 477 478 test_finish(); 479 } 480 481 CHECK("tc", "nat4_icmp_error_sctp") 482 int test_nat4_icmp_error_sctp(__maybe_unused struct __ctx_buff *ctx) 483 { 484 int pkt_size = mk_icmp4_error_pkt(pkt, IPPROTO_SCTP, false); 485 { 486 void *data = (void *)(long)ctx->data; 487 void *data_end = (void *)(long)ctx->data_end; 488 489 if (data + pkt_size > data_end) 490 return TEST_ERROR; 491 492 memcpy(data, pkt, pkt_size); 493 } 494 495 test_init(); 496 /* This test is validating the SCTP case. 497 */ 498 499 int ret; 500 501 /* As a pre-requist we intruct the NAT table 502 * to simulate an ingress packet sent by 503 * endpoint to the world. 504 */ 505 struct ipv4_ct_tuple tuple = { 506 .nexthdr = IPPROTO_SCTP, 507 .saddr = bpf_htonl(IP_ENDPOINT), 508 .daddr = bpf_htonl(IP_WORLD), 509 .sport = bpf_htons(9999), 510 .dport = bpf_htons(80), 511 .flags = 0, 512 }; 513 struct ipv4_nat_target target = { 514 .addr = bpf_htonl(IP_HOST), 515 .min_port = NODEPORT_PORT_MIN_NAT, 516 .max_port = NODEPORT_PORT_MIN_NAT + 1, 517 }; 518 struct ipv4_nat_entry state; 519 struct trace_ctx trace; 520 void *map; 521 522 map = get_cluster_snat_map_v4(target.cluster_id); 523 assert(map); 524 525 ret = snat_v4_new_mapping(ctx, map, &tuple, &state, &target, 526 false, NULL); 527 assert(ret == 0); 528 529 /* This is the entry-point of the test, calling 530 * snat_v4_rev_nat(). 531 */ 532 ret = snat_v4_rev_nat(ctx, &target, &trace, NULL); 533 assert(ret == DROP_CSUM_L4); 534 535 /* nothing really change with udp/tcp */ 536 test_finish(); 537 } 538 539 CHECK("tc", "nat4_icmp_error_tcp_egress") 540 int test_nat4_icmp_error_tcp_egress(__maybe_unused struct __ctx_buff *ctx) 541 { 542 int pkt_size = mk_icmp4_error_pkt(pkt, IPPROTO_TCP, true); 543 { 544 void *data = (void *)(long)ctx->data; 545 void *data_end = (void *)(long)ctx->data_end; 546 547 if (data + pkt_size > data_end) 548 return TEST_ERROR; 549 550 memcpy(data, pkt, pkt_size); 551 } 552 553 test_init(); 554 /* The test is validating that the function snat_v4_nat() 555 * will nat the ICMP Unreach error need to fragment to the 556 * correct source. Also, to be valid, the embedded packet 557 * should be NATed as-well, meaning that the dest addr of 558 * the original packet will be switched from IP_ENDPOINT to 559 * IP_HOST, Also for TCP/UDP the dest port and ICMP the 560 * identifier. 561 * 562 * This test is validating the TCP case. 563 */ 564 565 int ret; 566 567 /* As a pre-requist we intruct the NAT table 568 * to simulate an egress packet sent by 569 * endpoint to the world. 570 */ 571 struct ipv4_ct_tuple tuple = { 572 .nexthdr = IPPROTO_TCP, 573 .saddr = bpf_htonl(IP_ENDPOINT), 574 .daddr = bpf_htonl(IP_WORLD), 575 .sport = bpf_htons(3030), 576 .dport = bpf_htons(79), 577 .flags = 0, 578 }; 579 struct ipv4_nat_target target = { 580 .addr = bpf_htonl(IP_HOST), 581 .min_port = NODEPORT_PORT_MIN_NAT - 1, 582 .max_port = NODEPORT_PORT_MIN_NAT, 583 }; 584 struct ipv4_nat_entry state; 585 void *map; 586 587 map = get_cluster_snat_map_v4(target.cluster_id); 588 assert(map); 589 590 ret = snat_v4_new_mapping(ctx, map, &tuple, &state, &target, 591 false, NULL); 592 assert(ret == 0); 593 594 struct ipv4_ct_tuple icmp_tuple = {}; 595 struct trace_ctx trace; 596 void *data, *data_end; 597 struct iphdr *ip4; 598 int l4_off; 599 600 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 601 snat_v4_init_tuple(ip4, NAT_DIR_EGRESS, &icmp_tuple); 602 l4_off = ETH_HLEN + ipv4_hdrlen(ip4); 603 604 /* This is the entry-point of the test, calling 605 * snat_v4_nat(). 606 */ 607 ret = snat_v4_nat(ctx, &icmp_tuple, ip4, l4_off, ipv4_has_l4_header(ip4), 608 &target, &trace, NULL); 609 assert(ret == 0); 610 611 __u16 proto; 612 int l3_off; 613 struct icmphdr icmphdr __align_stack_8; 614 615 assert(validate_ethertype(ctx, &proto)); 616 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 617 if (data + pkt_size > data_end) 618 test_fatal("packet shrank"); 619 620 /* Validating outer headers */ 621 assert(ip4->protocol == IPPROTO_ICMP); 622 assert(ip4->saddr == bpf_htonl(IP_HOST)); 623 assert(ip4->daddr == bpf_htonl(IP_WORLD)); 624 625 l3_off = ETH_HLEN; 626 l4_off = l3_off + ipv4_hdrlen(ip4); 627 if (ctx_load_bytes(ctx, l4_off, &icmphdr, sizeof(icmphdr)) < 0) 628 test_fatal("can't load icmp headers"); 629 assert(icmphdr.type == ICMP_DEST_UNREACH); 630 assert(icmphdr.code == ICMP_FRAG_NEEDED); 631 632 /* Validating inner headers */ 633 int in_l3_off; 634 int in_l4_off; 635 struct iphdr in_ip4; 636 struct { 637 __be16 sport; 638 __be16 dport; 639 } in_l4hdr; 640 641 in_l3_off = l4_off + sizeof(icmphdr); 642 if (ctx_load_bytes(ctx, in_l3_off, &in_ip4, 643 sizeof(in_ip4)) < 0) 644 test_fatal("can't load embedded ip headers"); 645 assert(in_ip4.protocol == IPPROTO_TCP); 646 assert(in_ip4.saddr == bpf_htonl(IP_WORLD)); 647 assert(in_ip4.daddr == bpf_htonl(IP_HOST)); 648 649 in_l4_off = in_l3_off + ipv4_hdrlen(&in_ip4); 650 if (ctx_load_bytes(ctx, in_l4_off, &in_l4hdr, sizeof(in_l4hdr)) < 0) 651 test_fatal("can't load embedded l4 headers"); 652 assert(in_l4hdr.sport == bpf_htons(79)); 653 assert(in_l4hdr.dport == bpf_htons(32767)); 654 655 test_finish(); 656 } 657 658 CHECK("tc", "nat4_icmp_error_udp_egress") 659 int test_nat4_icmp_error_udp_egress(__maybe_unused struct __ctx_buff *ctx) 660 { 661 int pkt_size = mk_icmp4_error_pkt(pkt, IPPROTO_UDP, true); 662 { 663 void *data = (void *)(long)ctx->data; 664 void *data_end = (void *)(long)ctx->data_end; 665 666 if (data + pkt_size > data_end) 667 return TEST_ERROR; 668 669 memcpy(data, pkt, pkt_size); 670 } 671 672 test_init(); 673 /* The test is validating that the function snat_v4_nat() 674 * will nat the ICMP Unreach error need to fragment to the 675 * correct source. Also, to be valid, the embedded packet 676 * should be NATed as-well, meaning that the dest addr of 677 * the original packet will be switched from IP_ENDPOINT to 678 * IP_HOST, Also for TCP/UDP the dest port and ICMP the 679 * identifier. 680 * 681 * This test is validating the UDP case. 682 */ 683 684 int ret; 685 686 /* As a pre-requist we intruct the NAT table 687 * to simulate an egress packet sent by 688 * endpoint to the world. 689 */ 690 struct ipv4_ct_tuple tuple = { 691 .nexthdr = IPPROTO_UDP, 692 .saddr = bpf_htonl(IP_ENDPOINT), 693 .daddr = bpf_htonl(IP_WORLD), 694 .sport = bpf_htons(3030), 695 .dport = bpf_htons(79), 696 .flags = 0, 697 }; 698 struct ipv4_nat_target target = { 699 .addr = bpf_htonl(IP_HOST), 700 .min_port = NODEPORT_PORT_MIN_NAT - 1, 701 .max_port = NODEPORT_PORT_MIN_NAT, 702 }; 703 struct ipv4_nat_entry state; 704 void *map; 705 706 map = get_cluster_snat_map_v4(target.cluster_id); 707 assert(map); 708 709 ret = snat_v4_new_mapping(ctx, map, &tuple, &state, &target, 710 false, NULL); 711 assert(ret == 0); 712 713 struct ipv4_ct_tuple icmp_tuple = {}; 714 struct trace_ctx trace; 715 void *data, *data_end; 716 struct iphdr *ip4; 717 int l4_off; 718 719 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 720 l4_off = ETH_HLEN + ipv4_hdrlen(ip4); 721 snat_v4_init_tuple(ip4, NAT_DIR_EGRESS, &icmp_tuple); 722 723 /* This is the entry-point of the test, calling 724 * snat_v4_nat(). 725 */ 726 ret = snat_v4_nat(ctx, &icmp_tuple, ip4, l4_off, ipv4_has_l4_header(ip4), 727 &target, &trace, NULL); 728 assert(ret == 0); 729 730 __u16 proto; 731 int l3_off; 732 struct icmphdr icmphdr __align_stack_8; 733 734 assert(validate_ethertype(ctx, &proto)); 735 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 736 if (data + pkt_size > data_end) 737 test_fatal("packet shrank"); 738 739 /* Validating outer headers */ 740 assert(ip4->protocol == IPPROTO_ICMP); 741 assert(ip4->saddr == bpf_htonl(IP_HOST)); 742 assert(ip4->daddr == bpf_htonl(IP_WORLD)); 743 744 l3_off = ETH_HLEN; 745 l4_off = l3_off + ipv4_hdrlen(ip4); 746 if (ctx_load_bytes(ctx, l4_off, &icmphdr, sizeof(icmphdr)) < 0) 747 test_fatal("can't load icmp headers"); 748 assert(icmphdr.type == ICMP_DEST_UNREACH); 749 assert(icmphdr.code == ICMP_FRAG_NEEDED); 750 751 /* Validating inner headers */ 752 int in_l3_off; 753 int in_l4_off; 754 struct iphdr in_ip4; 755 struct { 756 __be16 sport; 757 __be16 dport; 758 } in_l4hdr; 759 760 in_l3_off = l4_off + sizeof(icmphdr); 761 if (ctx_load_bytes(ctx, in_l3_off, &in_ip4, 762 sizeof(in_ip4)) < 0) 763 test_fatal("can't load embedded ip headers"); 764 assert(in_ip4.protocol == IPPROTO_UDP); 765 assert(in_ip4.saddr == bpf_htonl(IP_WORLD)); 766 assert(in_ip4.daddr == bpf_htonl(IP_HOST)); 767 768 in_l4_off = in_l3_off + ipv4_hdrlen(&in_ip4); 769 if (ctx_load_bytes(ctx, in_l4_off, &in_l4hdr, sizeof(in_l4hdr)) < 0) 770 test_fatal("can't load embedded l4 headers"); 771 assert(in_l4hdr.sport == bpf_htons(79)); 772 assert(in_l4hdr.dport == bpf_htons(32767)); 773 774 test_finish(); 775 } 776 777 CHECK("tc", "nat4_icmp_error_icmp_egress") 778 int test_nat4_icmp_error_icmp_egress(__maybe_unused struct __ctx_buff *ctx) 779 { 780 int pkt_size = mk_icmp4_error_pkt(pkt, IPPROTO_ICMP, true); 781 { 782 void *data = (void *)(long)ctx->data; 783 void *data_end = (void *)(long)ctx->data_end; 784 785 if (data + pkt_size > data_end) 786 return TEST_ERROR; 787 788 memcpy(data, pkt, pkt_size); 789 } 790 791 test_init(); 792 /* The test is validating that the function snat_v4_nat() 793 * will nat the ICMP Unreach error need to fragment to the 794 * correct source. Also, to be valid, the embedded packet 795 * should be NATed as-well, meaning that the dest addr of 796 * the original packet will be switched from IP_ENDPOINT to 797 * IP_HOST, Also for TCP/UDP the dest port and ICMP the 798 * identifier. 799 * 800 * This test is validating the ICMP case. 801 */ 802 803 int ret; 804 805 /* As a pre-requist we intruct the NAT table 806 * to simulate an egress packet sent by 807 * endpoint to the world. 808 */ 809 struct ipv4_ct_tuple tuple = { 810 .nexthdr = IPPROTO_ICMP, 811 .saddr = bpf_htonl(IP_ENDPOINT), 812 .daddr = bpf_htonl(IP_WORLD), 813 .sport = bpf_htons(3030), 814 .flags = 0, 815 }; 816 struct ipv4_nat_target target = { 817 .addr = bpf_htonl(IP_HOST), 818 .min_port = NODEPORT_PORT_MIN_NAT - 1, 819 .max_port = NODEPORT_PORT_MIN_NAT, 820 }; 821 struct ipv4_nat_entry state; 822 void *map; 823 824 map = get_cluster_snat_map_v4(target.cluster_id); 825 assert(map); 826 827 ret = snat_v4_new_mapping(ctx, map, &tuple, &state, &target, 828 false, NULL); 829 assert(ret == 0); 830 831 struct ipv4_ct_tuple icmp_tuple = {}; 832 struct trace_ctx trace; 833 void *data, *data_end; 834 struct iphdr *ip4; 835 int l4_off; 836 837 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 838 l4_off = ETH_HLEN + ipv4_hdrlen(ip4); 839 snat_v4_init_tuple(ip4, NAT_DIR_EGRESS, &icmp_tuple); 840 841 /* This is the entry-point of the test, calling 842 * snat_v4_nat(). 843 */ 844 ret = snat_v4_nat(ctx, &icmp_tuple, ip4, l4_off, ipv4_has_l4_header(ip4), 845 &target, &trace, NULL); 846 assert(ret == 0); 847 848 __u16 proto; 849 int l3_off; 850 struct icmphdr icmphdr __align_stack_8; 851 852 assert(validate_ethertype(ctx, &proto)); 853 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 854 if (data + pkt_size > data_end) 855 test_fatal("packet shrank"); 856 857 /* Validating outer headers */ 858 assert(ip4->protocol == IPPROTO_ICMP); 859 assert(ip4->saddr == bpf_htonl(IP_HOST)); 860 assert(ip4->daddr == bpf_htonl(IP_WORLD)); 861 862 l3_off = ETH_HLEN; 863 l4_off = l3_off + ipv4_hdrlen(ip4); 864 if (ctx_load_bytes(ctx, l4_off, &icmphdr, sizeof(icmphdr)) < 0) 865 test_fatal("can't load icmp headers"); 866 assert(icmphdr.type == ICMP_DEST_UNREACH); 867 assert(icmphdr.code == ICMP_FRAG_NEEDED); 868 869 /* Validating inner headers */ 870 int in_l3_off; 871 int in_l4_off; 872 struct iphdr in_ip4; 873 struct icmphdr in_l4hdr __align_stack_8; 874 875 in_l3_off = l4_off + sizeof(icmphdr); 876 if (ctx_load_bytes(ctx, in_l3_off, &in_ip4, 877 sizeof(in_ip4)) < 0) 878 test_fatal("can't load embedded ip headers"); 879 assert(in_ip4.protocol == IPPROTO_ICMP); 880 assert(in_ip4.saddr == bpf_htonl(IP_WORLD)); 881 assert(in_ip4.daddr == bpf_htonl(IP_HOST)); 882 883 in_l4_off = in_l3_off + ipv4_hdrlen(&in_ip4); 884 if (ctx_load_bytes(ctx, in_l4_off, &in_l4hdr, sizeof(in_l4hdr)) < 0) 885 test_fatal("can't load embedded l4 headers"); 886 assert(in_l4hdr.un.echo.id == bpf_htons(32767)); 887 888 test_finish(); 889 } 890 891 CHECK("tc", "nat4_icmp_error_sctp_egress") 892 int test_nat4_icmp_error_sctp_egress(__maybe_unused struct __ctx_buff *ctx) 893 { 894 int pkt_size = mk_icmp4_error_pkt(pkt, IPPROTO_SCTP, true); 895 { 896 void *data = (void *)(long)ctx->data; 897 void *data_end = (void *)(long)ctx->data_end; 898 899 if (data + pkt_size > data_end) 900 return TEST_ERROR; 901 902 memcpy(data, pkt, pkt_size); 903 } 904 905 test_init(); 906 /* This test is validating the SCTP case. 907 */ 908 909 int ret; 910 911 /* As a pre-requist we intruct the NAT table 912 * to simulate an egress packet sent by 913 * endpoint to the world. 914 */ 915 struct ipv4_ct_tuple tuple = { 916 .nexthdr = IPPROTO_SCTP, 917 .saddr = bpf_htonl(IP_ENDPOINT), 918 .daddr = bpf_htonl(IP_WORLD), 919 .sport = bpf_htons(32767), /* STCP requires ports are the same after NAT */ 920 .dport = bpf_htons(79), 921 .flags = 0, 922 }; 923 struct ipv4_nat_target target = { 924 .addr = bpf_htonl(IP_HOST), 925 .min_port = NODEPORT_PORT_MIN_NAT - 1, 926 .max_port = NODEPORT_PORT_MIN_NAT, 927 }; 928 struct ipv4_nat_entry state; 929 void *map; 930 931 map = get_cluster_snat_map_v4(target.cluster_id); 932 assert(map); 933 934 ret = snat_v4_new_mapping(ctx, map, &tuple, &state, &target, 935 false, NULL); 936 assert(ret == 0); 937 938 struct ipv4_ct_tuple icmp_tuple = {}; 939 struct trace_ctx trace; 940 void *data, *data_end; 941 struct iphdr *ip4; 942 int l4_off; 943 944 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 945 l4_off = ETH_HLEN + ipv4_hdrlen(ip4); 946 snat_v4_init_tuple(ip4, NAT_DIR_EGRESS, &icmp_tuple); 947 948 /* This is the entry-point of the test, calling 949 * snat_v4_nat(). 950 */ 951 ret = snat_v4_nat(ctx, &icmp_tuple, ip4, l4_off, ipv4_has_l4_header(ip4), 952 &target, &trace, NULL); 953 assert(ret == 0); 954 955 __u16 proto; 956 int l3_off; 957 struct icmphdr icmphdr __align_stack_8; 958 959 assert(validate_ethertype(ctx, &proto)); 960 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 961 if (data + pkt_size > data_end) 962 test_fatal("packet shrank"); 963 964 /* Validating outer headers */ 965 assert(ip4->protocol == IPPROTO_ICMP); 966 assert(ip4->saddr == bpf_htonl(IP_HOST)); 967 assert(ip4->daddr == bpf_htonl(IP_WORLD)); 968 969 l3_off = ETH_HLEN; 970 l4_off = l3_off + ipv4_hdrlen(ip4); 971 if (ctx_load_bytes(ctx, l4_off, &icmphdr, sizeof(icmphdr)) < 0) 972 test_fatal("can't load icmp headers"); 973 assert(icmphdr.type == ICMP_DEST_UNREACH); 974 assert(icmphdr.code == ICMP_FRAG_NEEDED); 975 976 /* Validating inner headers */ 977 int in_l3_off; 978 int in_l4_off; 979 struct iphdr in_ip4; 980 struct { 981 __be16 sport; 982 __be16 dport; 983 } in_l4hdr; 984 985 in_l3_off = l4_off + sizeof(icmphdr); 986 if (ctx_load_bytes(ctx, in_l3_off, &in_ip4, 987 sizeof(in_ip4)) < 0) 988 test_fatal("can't load embedded ip headers"); 989 assert(in_ip4.protocol == IPPROTO_SCTP); 990 assert(in_ip4.saddr == bpf_htonl(IP_WORLD)); 991 assert(in_ip4.daddr == bpf_htonl(IP_HOST)); 992 993 in_l4_off = in_l3_off + ipv4_hdrlen(&in_ip4); 994 if (ctx_load_bytes(ctx, in_l4_off, &in_l4hdr, sizeof(in_l4hdr)) < 0) 995 test_fatal("can't load embedded l4 headers"); 996 assert(in_l4hdr.sport == bpf_htons(79)); 997 assert(in_l4hdr.dport == bpf_htons(32767)); 998 999 test_finish(); 1000 } 1001 1002 BPF_LICENSE("Dual BSD/GPL");