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");