(root)/
strace-6.5/
tests-mx32/
inet-cmsg.c
       1  /*
       2   * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
       3   * Copyright (c) 2015-2021 The strace developers.
       4   * All rights reserved.
       5   *
       6   * SPDX-License-Identifier: GPL-2.0-or-later
       7   */
       8  
       9  #include "tests.h"
      10  #include <assert.h>
      11  #include <fcntl.h>
      12  #include <stdio.h>
      13  #include <stdint.h>
      14  #include <unistd.h>
      15  #include <sys/socket.h>
      16  #include <netinet/in.h>
      17  #include <arpa/inet.h>
      18  
      19  static void
      20  print_pktinfo(const struct cmsghdr *c)
      21  {
      22  	printf("IP_PKTINFO, cmsg_data={ipi_ifindex=%s"
      23  	       ", ipi_spec_dst=inet_addr(\"%s\")"
      24  	       ", ipi_addr=inet_addr(\"%s\")}",
      25  	       IFINDEX_LO_STR, "127.0.0.1", "127.0.0.1");
      26  }
      27  
      28  static void
      29  print_ttl(const struct cmsghdr *c)
      30  {
      31  	const unsigned int *ttl = (const unsigned int *) CMSG_DATA(c);
      32  
      33  	printf("IP_TTL, cmsg_data=[%u]", *ttl);
      34  }
      35  
      36  static void
      37  print_tos(const struct cmsghdr *c)
      38  {
      39  	const uint8_t *tos = (const uint8_t *) CMSG_DATA(c);
      40  
      41  	printf("IP_TOS, cmsg_data=[%#x]", *tos);
      42  }
      43  
      44  static void
      45  print_opts(const char *name, const struct cmsghdr *c)
      46  {
      47  	const unsigned char *opts = (const unsigned char *) CMSG_DATA(c);
      48  	const size_t len = c->cmsg_len - CMSG_ALIGN(sizeof(*c));
      49  
      50  	printf("%s", name);
      51  	if (len) {
      52  		printf(", cmsg_data=[");
      53  		for (size_t i = 0; i < len; ++i)
      54  			printf("%s%#x", i ? ", " : "", opts[i]);
      55  		printf("]");
      56  	}
      57  }
      58  
      59  #ifdef IP_ORIGDSTADDR
      60  static void
      61  print_origdstaddr(const struct cmsghdr *c)
      62  {
      63  	const struct sockaddr_in *sin =
      64  		(const struct sockaddr_in *) CMSG_DATA(c);
      65  
      66  	printf("IP_ORIGDSTADDR, cmsg_data={sa_family=AF_INET, sin_port=htons(%u)"
      67  	       ", sin_addr=inet_addr(\"127.0.0.1\")}", ntohs(sin->sin_port));
      68  }
      69  #endif
      70  
      71  int
      72  main(void)
      73  {
      74  	int i;
      75  	while ((i = open("/dev/null", O_RDWR)) < 3)
      76  		assert(i >= 0);
      77  	assert(!close(0));
      78  	assert(!close(3));
      79  
      80  	if (socket(AF_INET, SOCK_DGRAM, 0))
      81  		perror_msg_and_skip("socket");
      82  	struct sockaddr_in addr = {
      83  		.sin_family = AF_INET,
      84  		.sin_addr.s_addr = htonl(INADDR_LOOPBACK)
      85  	};
      86  	socklen_t len = sizeof(addr);
      87  	if (bind(0, (struct sockaddr *) &addr, len))
      88  		perror_msg_and_skip("bind");
      89  	assert(!getsockname(0, (struct sockaddr *) &addr, &len));
      90  
      91  	assert(socket(AF_INET, SOCK_DGRAM, 0) == 3);
      92  	assert(!connect(3, (struct sockaddr *) &addr, len));
      93  
      94  	const int opt_1 = htonl(0x01000000);
      95  #define SETSOCKOPT(fd, name) assert(!setsockopt(fd, IPPROTO_IP, (name), &opt_1, sizeof(opt_1)))
      96  	SETSOCKOPT(3, IP_OPTIONS);
      97  	SETSOCKOPT(0, IP_PKTINFO);
      98  	SETSOCKOPT(0, IP_RECVTTL);
      99  	SETSOCKOPT(0, IP_RECVTOS);
     100  	SETSOCKOPT(0, IP_RECVOPTS);
     101  	SETSOCKOPT(0, IP_RETOPTS);
     102  #ifdef IP_RECVORIGDSTADDR
     103  	SETSOCKOPT(0, IP_RECVORIGDSTADDR);
     104  #endif
     105  
     106  	static const char data[] = "data";
     107  	const size_t size = sizeof(data) - 1;
     108  	assert(send(3, data, size, 0) == (int) size);
     109  	assert(!close(3));
     110  
     111  	char buf[size];
     112  	struct iovec iov = {
     113  		.iov_base = buf,
     114  		.iov_len = sizeof(buf)
     115  	};
     116  	struct cmsghdr control[16];
     117  	struct msghdr mh = {
     118  		.msg_name = &addr,
     119  		.msg_namelen = len,
     120  		.msg_iov = &iov,
     121  		.msg_iovlen = 1,
     122  		.msg_control = control,
     123  		.msg_controllen = sizeof(control)
     124  	};
     125  
     126  	assert(recvmsg(0, &mh, 0) == (int) size);
     127  	assert(!close(0));
     128  
     129  	printf("recvmsg(0, {msg_name={sa_family=AF_INET, sin_port=htons(%u)"
     130  	       ", sin_addr=inet_addr(\"127.0.0.1\")}, msg_namelen=%u"
     131  	       ", msg_iov=[{iov_base=\"%s\", iov_len=%u}], msg_iovlen=1"
     132  	       ", msg_control=[",
     133  	       ntohs(addr.sin_port), (unsigned) mh.msg_namelen,
     134  	       data, (unsigned) size);
     135  
     136  	for (struct cmsghdr *c = CMSG_FIRSTHDR(&mh);
     137  	     c; c = CMSG_NXTHDR(&mh, c)) {
     138  		if (IPPROTO_IP != c->cmsg_level)
     139  			continue;
     140  		if (c != control)
     141  			printf(", ");
     142  		printf("{cmsg_len=%lu, cmsg_level=SOL_IP, cmsg_type=",
     143  		       (unsigned long) c->cmsg_len);
     144  		switch (c->cmsg_type) {
     145  			case IP_PKTINFO:
     146  				print_pktinfo(c);
     147  				break;
     148  			case IP_TTL:
     149  				print_ttl(c);
     150  				break;
     151  			case IP_TOS:
     152  				print_tos(c);
     153  				break;
     154  			case IP_RECVOPTS:
     155  				print_opts("IP_RECVOPTS", c);
     156  				break;
     157  			case IP_RETOPTS:
     158  				print_opts("IP_RETOPTS", c);
     159  				break;
     160  #ifdef IP_ORIGDSTADDR
     161  			case IP_ORIGDSTADDR:
     162  				print_origdstaddr(c);
     163  				break;
     164  #endif
     165  			default:
     166  				printf("%d", c->cmsg_type);
     167  				break;
     168  		}
     169  		printf("}");
     170  	}
     171  	printf("], msg_controllen=%lu, msg_flags=0}, 0) = %u\n",
     172  	       (unsigned long) mh.msg_controllen, (unsigned) size);
     173  	puts("+++ exited with 0 +++");
     174  
     175  	return 0;
     176  }