Home | History | Annotate | Download | only in tests-m32
      1 /*
      2  * Copyright (c) 2015-2016 Dmitry V. Levin <ldv (at) altlinux.org>
      3  * Copyright (c) 2015-2017 The strace developers.
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "tests.h"
     30 #include <assert.h>
     31 #include <fcntl.h>
     32 #include <stdio.h>
     33 #include <stdint.h>
     34 #include <unistd.h>
     35 #include <sys/socket.h>
     36 #include <netinet/in.h>
     37 #include <arpa/inet.h>
     38 
     39 static void
     40 print_pktinfo(const struct cmsghdr *c)
     41 {
     42 	printf("IP_PKTINFO, cmsg_data={ipi_ifindex=%s"
     43 	       ", ipi_spec_dst=inet_addr(\"%s\")"
     44 	       ", ipi_addr=inet_addr(\"%s\")}",
     45 	       IFINDEX_LO_STR, "127.0.0.1", "127.0.0.1");
     46 }
     47 
     48 static void
     49 print_ttl(const struct cmsghdr *c)
     50 {
     51 	const unsigned int *ttl = (const unsigned int *) CMSG_DATA(c);
     52 
     53 	printf("IP_TTL, cmsg_data=[%u]", *ttl);
     54 }
     55 
     56 static void
     57 print_tos(const struct cmsghdr *c)
     58 {
     59 	const uint8_t *tos = (const uint8_t *) CMSG_DATA(c);
     60 
     61 	printf("IP_TOS, cmsg_data=[%#x]", *tos);
     62 }
     63 
     64 static void
     65 print_opts(const char *name, const struct cmsghdr *c)
     66 {
     67 	const unsigned char *opts = (const unsigned char *) CMSG_DATA(c);
     68 	const size_t len = c->cmsg_len - CMSG_ALIGN(sizeof(*c));
     69 
     70 	printf("%s", name);
     71 	if (len) {
     72 		printf(", cmsg_data=[");
     73 		size_t i;
     74 		for (i = 0; i < len; ++i)
     75 			printf("%s0x%02x", i ? ", " : "", opts[i]);
     76 		printf("]");
     77 	}
     78 }
     79 
     80 #ifdef IP_ORIGDSTADDR
     81 static void
     82 print_origdstaddr(const struct cmsghdr *c)
     83 {
     84 	const struct sockaddr_in *sin =
     85 		(const struct sockaddr_in *) CMSG_DATA(c);
     86 
     87 	printf("IP_ORIGDSTADDR, cmsg_data={sa_family=AF_INET, sin_port=htons(%u)"
     88 	       ", sin_addr=inet_addr(\"127.0.0.1\")}", ntohs(sin->sin_port));
     89 }
     90 #endif
     91 
     92 int
     93 main(void)
     94 {
     95 	int i;
     96 	while ((i = open("/dev/null", O_RDWR)) < 3)
     97 		assert(i >= 0);
     98 	assert(!close(0));
     99 	assert(!close(3));
    100 
    101 	if (socket(AF_INET, SOCK_DGRAM, 0))
    102 		perror_msg_and_skip("socket");
    103 	struct sockaddr_in addr = {
    104 		.sin_family = AF_INET,
    105 		.sin_addr.s_addr = htonl(INADDR_LOOPBACK)
    106 	};
    107 	socklen_t len = sizeof(addr);
    108 	if (bind(0, (struct sockaddr *) &addr, len))
    109 		perror_msg_and_skip("bind");
    110 	assert(!getsockname(0, (struct sockaddr *) &addr, &len));
    111 
    112 	assert(socket(AF_INET, SOCK_DGRAM, 0) == 3);
    113 	assert(!connect(3, (struct sockaddr *) &addr, len));
    114 
    115 	const int opt_1 = htonl(0x01000000);
    116 #define SETSOCKOPT(fd, name) assert(!setsockopt(fd, IPPROTO_IP, (name), &opt_1, sizeof(opt_1)))
    117 	SETSOCKOPT(3, IP_OPTIONS);
    118 	SETSOCKOPT(0, IP_PKTINFO);
    119 	SETSOCKOPT(0, IP_RECVTTL);
    120 	SETSOCKOPT(0, IP_RECVTOS);
    121 	SETSOCKOPT(0, IP_RECVOPTS);
    122 	SETSOCKOPT(0, IP_RETOPTS);
    123 #ifdef IP_RECVORIGDSTADDR
    124 	SETSOCKOPT(0, IP_RECVORIGDSTADDR);
    125 #endif
    126 
    127 	static const char data[] = "data";
    128 	const size_t size = sizeof(data) - 1;
    129 	assert(send(3, data, size, 0) == (int) size);
    130 	assert(!close(3));
    131 
    132 	char buf[size];
    133 	struct iovec iov = {
    134 		.iov_base = buf,
    135 		.iov_len = sizeof(buf)
    136 	};
    137 	struct cmsghdr control[16];
    138 	struct msghdr mh = {
    139 		.msg_name = &addr,
    140 		.msg_namelen = len,
    141 		.msg_iov = &iov,
    142 		.msg_iovlen = 1,
    143 		.msg_control = control,
    144 		.msg_controllen = sizeof(control)
    145 	};
    146 
    147 	assert(recvmsg(0, &mh, 0) == (int) size);
    148 	assert(!close(0));
    149 
    150 	printf("recvmsg(0, {msg_name={sa_family=AF_INET, sin_port=htons(%u)"
    151 	       ", sin_addr=inet_addr(\"127.0.0.1\")}, msg_namelen=%u"
    152 	       ", msg_iov=[{iov_base=\"%s\", iov_len=%u}], msg_iovlen=1"
    153 	       ", msg_control=[",
    154 	       ntohs(addr.sin_port), (unsigned) mh.msg_namelen,
    155 	       data, (unsigned) size);
    156 
    157 	struct cmsghdr *c;
    158 	for (c = CMSG_FIRSTHDR(&mh); c; c = CMSG_NXTHDR(&mh, c)) {
    159 		if (IPPROTO_IP != c->cmsg_level)
    160 			continue;
    161 		if (c != control)
    162 			printf(", ");
    163 		printf("{cmsg_len=%lu, cmsg_level=SOL_IP, cmsg_type=",
    164 		       (unsigned long) c->cmsg_len);
    165 		switch (c->cmsg_type) {
    166 			case IP_PKTINFO:
    167 				print_pktinfo(c);
    168 				break;
    169 			case IP_TTL:
    170 				print_ttl(c);
    171 				break;
    172 			case IP_TOS:
    173 				print_tos(c);
    174 				break;
    175 			case IP_RECVOPTS:
    176 				print_opts("IP_RECVOPTS", c);
    177 				break;
    178 			case IP_RETOPTS:
    179 				print_opts("IP_RETOPTS", c);
    180 				break;
    181 #ifdef IP_ORIGDSTADDR
    182 			case IP_ORIGDSTADDR:
    183 				print_origdstaddr(c);
    184 				break;
    185 #endif
    186 			default:
    187 				printf("%d", c->cmsg_type);
    188 				break;
    189 		}
    190 		printf("}");
    191 	}
    192 	printf("], msg_controllen=%lu, msg_flags=0}, 0) = %u\n",
    193 	       (unsigned long) mh.msg_controllen, (unsigned) size);
    194 	puts("+++ exited with 0 +++");
    195 
    196 	return 0;
    197 }
    198