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