]> granicus.if.org Git - strace/blob - tests/msg_control.c
msghdr.c: limit SCM_RIGHTS output in abbrev mode
[strace] / tests / msg_control.c
1 /*
2  * Check decoding of struct msghdr ancillary data.
3  *
4  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "tests.h"
31 #include <errno.h>
32 #include <stddef.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <sys/socket.h>
37 #include <net/if.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40
41 #ifndef SOL_IP
42 # define SOL_IP 0
43 #endif
44 #ifndef SOL_TCP
45 # define SOL_TCP 6
46 #endif
47
48 #ifndef SCM_SECURITY
49 # define SCM_SECURITY 3
50 #endif
51
52 #define MIN_SIZE_OF(type, member) \
53         (offsetof(type, member) + sizeof(((type *) 0)->member))
54
55 #define VAL_STR(val) val, #val
56
57 static struct cmsghdr *
58 get_cmsghdr(void *const page, const size_t len)
59 {
60         return page - CMSG_ALIGN(len);
61 }
62
63 #define DEFAULT_STRLEN 32
64
65 static void
66 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
67 {
68         size_t nfd = cmsg_len > CMSG_LEN(0)
69                      ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
70         if (!nfd)
71                 return;
72
73         printf(", cmsg_data=[");
74         int *fdp = (int *) CMSG_DATA(cmsg);
75         size_t i;
76         for (i = 0; i < nfd; ++i) {
77                 if (i)
78                         printf(", ");
79 #ifndef VERBOSE_MSGHDR
80                 if (i >= DEFAULT_STRLEN) {
81                         printf("...");
82                         break;
83                 }
84 #endif
85                 printf("%d", fdp[i]);
86         }
87         printf("]");
88 }
89
90 static void
91 test_scm_rights1(struct msghdr *const mh,
92                  const size_t msg_controllen,
93                  void *const page,
94                  const void *const src,
95                  const size_t cmsg_len)
96 {
97         const size_t aligned_cms_len =
98                 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
99         if (cmsg_len >= CMSG_LEN(0)
100             && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
101                 return;
102
103         struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
104
105         if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
106                 cmsg->cmsg_len = cmsg_len;
107         if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
108                 cmsg->cmsg_level = SOL_SOCKET;
109         if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
110                 cmsg->cmsg_type = SCM_RIGHTS;
111
112         size_t src_len =
113                 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
114         if (src_len > CMSG_LEN(0))
115                 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
116
117         mh->msg_control = cmsg;
118         mh->msg_controllen = msg_controllen;
119
120         int rc = sendmsg(-1, mh, 0);
121         int saved_errno = errno;
122
123         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
124                ", msg_iovlen=0");
125         if (msg_controllen < CMSG_LEN(0)) {
126                 if (msg_controllen)
127                         printf(", msg_control=%p", cmsg);
128         } else {
129                 printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET"
130                        ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len);
131                 print_fds(cmsg, src_len);
132                 printf("}");
133                 if (aligned_cms_len < msg_controllen)
134                         printf(", %p", (void *) cmsg + aligned_cms_len);
135                 printf("]");
136         }
137
138         errno = saved_errno;
139         printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
140                (unsigned long) msg_controllen, rc, errno2name());
141 }
142
143 static void
144 test_scm_rights2(struct msghdr *const mh,
145                  const size_t msg_controllen,
146                  void *const page,
147                  const int *const *const src,
148                  const size_t *const cmsg_len)
149 {
150         const size_t aligned_cms_len[2] = {
151                 cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0),
152                 cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0)
153         };
154         if (cmsg_len[0] < CMSG_LEN(0)
155             || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen
156             || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen)
157                 return;
158
159         struct cmsghdr *const cmsg[2] = {
160                 get_cmsghdr(page, msg_controllen),
161                 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
162         };
163         cmsg[0]->cmsg_len = cmsg_len[0];
164         cmsg[0]->cmsg_level = SOL_SOCKET;
165         cmsg[0]->cmsg_type = SCM_RIGHTS;
166         if (cmsg_len[0] > CMSG_LEN(0))
167                 memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0));
168
169         const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0];
170         if (msg_controllen1 >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
171                 cmsg[1]->cmsg_len = cmsg_len[1];
172         if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
173                 cmsg[1]->cmsg_level = SOL_SOCKET;
174         if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
175                 cmsg[1]->cmsg_type = SCM_RIGHTS;
176         size_t src1_len =
177                 cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1;
178         if (src1_len > CMSG_LEN(0))
179                 memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0));
180
181         mh->msg_control = cmsg[0];
182         mh->msg_controllen = msg_controllen;
183
184         int rc = sendmsg(-1, mh, 0);
185         int saved_errno = errno;
186
187         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
188                ", msg_iovlen=0, msg_control=[{cmsg_len=%lu"
189                ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
190                (unsigned long) cmsg_len[0]);
191         print_fds(cmsg[0], cmsg_len[0]);
192         printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
193                (unsigned long) cmsg_len[1]);
194         print_fds(cmsg[1], src1_len);
195         printf("}");
196         if (aligned_cms_len[1] < msg_controllen1)
197                 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]);
198         printf("]");
199
200         errno = saved_errno;
201         printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
202                (unsigned long) msg_controllen, rc, errno2name());
203 }
204
205 static void
206 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
207 {
208         const size_t len = CMSG_SPACE(sizeof(int) * nfds);
209         struct cmsghdr *cmsg = get_cmsghdr(page, len);
210
211         cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds);
212         cmsg->cmsg_level = SOL_SOCKET;
213         cmsg->cmsg_type = SCM_RIGHTS;
214         int *fdp = (int *) CMSG_DATA(cmsg);
215         size_t i;
216         for (i = 0; i < nfds; ++i)
217                 fdp[i] = i;
218
219         mh->msg_control = cmsg;
220         mh->msg_controllen = len;
221
222         int rc = sendmsg(-1, mh, 0);
223         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
224                ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
225                ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
226                (unsigned) cmsg->cmsg_len);
227         print_fds(cmsg, cmsg->cmsg_len);
228         printf("}], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
229                (unsigned long) len, rc, errno2name());
230 }
231
232 static void
233 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
234 {
235         int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
236         if (!n)
237                 return;
238
239         printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
240 }
241
242 static void
243 test_scm_security(struct msghdr *const mh,
244                   const size_t msg_controllen,
245                   void *const page,
246                   const void *const src,
247                   const size_t cmsg_len,
248                   const int cmsg_level,
249                   const char *const cmsg_level_str)
250 {
251         const size_t aligned_cms_len =
252                 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
253         if (cmsg_len >= CMSG_LEN(0)
254             && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
255                 return;
256
257         struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
258
259         cmsg->cmsg_len = cmsg_len;
260         cmsg->cmsg_level = cmsg_level;
261         cmsg->cmsg_type = SCM_SECURITY;
262
263         size_t src_len =
264                 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
265         if (src_len > CMSG_LEN(0))
266                 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
267
268         mh->msg_control = cmsg;
269         mh->msg_controllen = msg_controllen;
270
271         int rc = sendmsg(-1, mh, 0);
272         int saved_errno = errno;
273
274         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
275                ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s"
276                ", cmsg_type=SCM_SECURITY",
277                (unsigned long) cmsg_len, cmsg_level_str);
278         print_security(cmsg, src_len);
279         printf("}");
280         if (aligned_cms_len < msg_controllen)
281                 printf(", %p", (void *) cmsg + aligned_cms_len);
282         printf("]");
283
284         errno = saved_errno;
285         printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
286                (unsigned long) msg_controllen, rc, errno2name());
287 }
288
289 static void
290 test_unknown_type(struct msghdr *const mh,
291                   void *const page,
292                   const int cmsg_level,
293                   const char *const cmsg_level_str,
294                   const char *const cmsg_type_str)
295 {
296         struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
297
298         cmsg->cmsg_len = CMSG_LEN(0);
299         cmsg->cmsg_level = cmsg_level;
300         cmsg->cmsg_type = 0xfacefeed;
301
302         mh->msg_control = cmsg;
303         mh->msg_controllen = cmsg->cmsg_len;
304
305         int rc = sendmsg(-1, mh, 0);
306         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
307                ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
308                ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}"
309                ", 0) = %d %s (%m)\n",
310                (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type,
311                cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name());
312 }
313
314 static void
315 test_sol_socket(struct msghdr *const mh, void *const page)
316 {
317         static const int fds0[] = { -10, -11, -12, -13 };
318         static const int fds1[] = { -15, -16, -17, -18 };
319         size_t msg_controllen, max_msg_controllen;
320
321         max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
322         for (msg_controllen = 0;
323              msg_controllen <= max_msg_controllen;
324              msg_controllen++) {
325                 size_t cmsg_len;
326
327                 for (cmsg_len = 0;
328                      cmsg_len <= msg_controllen + CMSG_LEN(0);
329                      cmsg_len++) {
330                         test_scm_rights1(mh, msg_controllen,
331                                          page, fds0, cmsg_len);
332                 }
333         }
334
335         max_msg_controllen =
336                 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
337                 sizeof(*fds0) - 1;
338         for (msg_controllen = CMSG_LEN(0) * 2;
339              msg_controllen <= max_msg_controllen;
340              msg_controllen++) {
341                 static const int *const fdps[] = { fds0, fds1 };
342                 size_t cmsg_len[2];
343
344                 for (cmsg_len[0] = CMSG_LEN(0);
345                      CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen
346                      && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0));
347                      cmsg_len[0]++) {
348                         const size_t msg_controllen1 =
349                                 msg_controllen - CMSG_ALIGN(cmsg_len[0]);
350
351                         for (cmsg_len[1] = 0;
352                              cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
353                              cmsg_len[1]++) {
354                                 test_scm_rights2(mh, msg_controllen,
355                                                  page, fdps, cmsg_len);
356                         }
357                 }
358         }
359
360         static const char text[16] = "0123456789abcdef";
361         max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1;
362         for (msg_controllen = CMSG_LEN(0);
363              msg_controllen <= max_msg_controllen;
364              msg_controllen++) {
365                 size_t cmsg_len;
366
367                 for (cmsg_len = 0;
368                      cmsg_len <= msg_controllen + CMSG_LEN(0)
369                      && cmsg_len <= CMSG_LEN(sizeof(text));
370                      cmsg_len++) {
371                         test_scm_security(mh, msg_controllen,
372                                           page, text, cmsg_len,
373                                           VAL_STR(SOL_SOCKET));
374                 }
375         }
376
377         test_scm_rights3(mh, page, DEFAULT_STRLEN - 1);
378         test_scm_rights3(mh, page, DEFAULT_STRLEN);
379         test_scm_rights3(mh, page, DEFAULT_STRLEN + 1);
380
381         test_unknown_type(mh, page, VAL_STR(SOL_SOCKET), "SCM_???");
382 }
383
384 static void
385 test_ip_pktinfo(struct msghdr *const mh, void *const page,
386                 const int cmsg_type, const char *const cmsg_type_str)
387 {
388         const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
389         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
390
391         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
392         cmsg->cmsg_level = SOL_IP;
393         cmsg->cmsg_type = cmsg_type;
394
395         struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
396 #ifdef HAVE_IF_INDEXTONAME
397         info->ipi_ifindex = if_nametoindex("lo");
398 #else
399         info->ipi_ifindex = 1;
400 #endif
401         info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4");
402         info->ipi_addr.s_addr = inet_addr("5.6.7.8");
403
404         mh->msg_control = cmsg;
405         mh->msg_controllen = len;
406
407         int rc = sendmsg(-1, mh, 0);
408         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
409                ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
410                ", cmsg_type=%s, cmsg_data={ipi_ifindex=%s"
411                ", ipi_spec_dst=inet_addr(\"%s\")"
412                ", ipi_addr=inet_addr(\"%s\")}}]"
413                ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
414                (unsigned) cmsg->cmsg_len, cmsg_type_str,
415 #ifdef HAVE_IF_INDEXTONAME
416                "if_nametoindex(\"lo\")",
417 #else
418                "1",
419 #endif
420                "1.2.3.4", "5.6.7.8", len, rc, errno2name());
421 }
422
423 static void
424 test_ip_uint(struct msghdr *const mh, void *const page,
425              const int cmsg_type, const char *const cmsg_type_str)
426 {
427         const unsigned int len = CMSG_SPACE(sizeof(int));
428         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
429
430         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
431         cmsg->cmsg_level = SOL_IP;
432         cmsg->cmsg_type = cmsg_type;
433
434         unsigned int *u = (void *) CMSG_DATA(cmsg);
435         *u = 0xfacefeed;
436
437         mh->msg_control = cmsg;
438         mh->msg_controllen = len;
439
440         int rc = sendmsg(-1, mh, 0);
441         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
442                ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
443                ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]"
444                ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
445                (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len,
446                rc, errno2name());
447 }
448
449 static void
450 test_ip_uint8_t(struct msghdr *const mh, void *const page,
451                 const int cmsg_type, const char *const cmsg_type_str)
452 {
453         const unsigned int len = CMSG_SPACE(1);
454         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
455
456         cmsg->cmsg_len = CMSG_LEN(1);
457         cmsg->cmsg_level = SOL_IP;
458         cmsg->cmsg_type = cmsg_type;
459         *CMSG_DATA(cmsg) = 'A';
460
461         mh->msg_control = cmsg;
462         mh->msg_controllen = len;
463
464         int rc = sendmsg(-1, mh, 0);
465         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
466                ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
467                ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]"
468                ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
469                (unsigned) cmsg->cmsg_len, cmsg_type_str,
470                (unsigned) (uint8_t) 'A', len, rc, errno2name());
471 }
472
473 static void
474 print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
475 {
476         const unsigned char *const opts = cmsg_data;
477         unsigned int i;
478         for (i = 0; i < data_len; ++i) {
479                 if (i)
480                         printf(", ");
481                 printf("0x%02x", opts[i]);
482         }
483 }
484
485 static void
486 test_ip_opts(struct msghdr *const mh, void *const page,
487              const int cmsg_type, const char *const cmsg_type_str,
488              const unsigned int opts_len)
489 {
490         unsigned int len = CMSG_SPACE(opts_len);
491         struct cmsghdr *cmsg = get_cmsghdr(page, len);
492
493         cmsg->cmsg_len = CMSG_LEN(opts_len);
494         cmsg->cmsg_level = SOL_IP;
495         cmsg->cmsg_type = cmsg_type;
496         unsigned int i;
497         for (i = 0; i < opts_len; ++i)
498                 CMSG_DATA(cmsg)[i] = 'A' + i;
499
500         mh->msg_control = cmsg;
501         mh->msg_controllen = len;
502
503         int rc = sendmsg(-1, mh, 0);
504         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
505                ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
506                ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[",
507                (unsigned) cmsg->cmsg_len, cmsg_type_str);
508         print_ip_opts(CMSG_DATA(cmsg), opts_len);
509         printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
510                len, rc, errno2name());
511 }
512
513 #ifdef IP_CHECKSUM
514 struct sock_ee {
515         uint32_t ee_errno;
516         uint8_t  ee_origin;
517         uint8_t  ee_type;
518         uint8_t  ee_code;
519         uint8_t  ee_pad;
520         uint32_t ee_info;
521         uint32_t ee_data;
522         struct sockaddr_in offender;
523 };
524
525 static void
526 test_ip_recverr(struct msghdr *const mh, void *const page,
527                 const int cmsg_type, const char *const cmsg_type_str)
528 {
529         const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
530         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
531
532         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
533         cmsg->cmsg_level = SOL_IP;
534         cmsg->cmsg_type = cmsg_type;
535
536         struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
537         e->ee_errno = 0xdeadbeef;
538         e->ee_origin = 2;
539         e->ee_type = 3;
540         e->ee_code = 4;
541         e->ee_info = 0xfacefeed;
542         e->ee_data = 0xbadc0ded;
543         e->offender.sin_family = AF_INET,
544         e->offender.sin_port = htons(12345),
545         e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
546
547         mh->msg_control = cmsg;
548         mh->msg_controllen = len;
549
550         int rc = sendmsg(-1, mh, 0);
551         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
552                ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
553                ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u"
554                ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u"
555                ", offender={sa_family=AF_INET, sin_port=htons(%hu)"
556                ", sin_addr=inet_addr(\"127.0.0.1\")}}}]"
557                ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
558                (unsigned) cmsg->cmsg_len, cmsg_type_str,
559                e->ee_errno, e->ee_origin, e->ee_type,
560                e->ee_code, e->ee_info, e->ee_data,
561                ntohs(e->offender.sin_port),
562                len, rc, errno2name());
563 }
564 #endif
565
566 #ifdef IP_ORIGDSTADDR
567 static void
568 test_ip_origdstaddr(struct msghdr *const mh, void *const page,
569                     const int cmsg_type, const char *const cmsg_type_str)
570 {
571         const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
572         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
573
574         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
575         cmsg->cmsg_level = SOL_IP;
576         cmsg->cmsg_type = cmsg_type;
577
578         struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg);
579         sin->sin_family = AF_INET,
580         sin->sin_port = htons(12345),
581         sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
582
583         mh->msg_control = cmsg;
584         mh->msg_controllen = len;
585
586         int rc = sendmsg(-1, mh, 0);
587         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
588                ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
589                ", cmsg_type=%s, cmsg_data={sa_family=AF_INET"
590                ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]"
591                ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
592                (unsigned) cmsg->cmsg_len, cmsg_type_str,
593                ntohs(sin->sin_port), len, rc, errno2name());
594 }
595 #endif
596
597 static void
598 test_sol_ip(struct msghdr *const mh, void *const page)
599 {
600         test_ip_pktinfo(mh, page, VAL_STR(IP_PKTINFO));
601         test_ip_uint(mh, page, VAL_STR(IP_TTL));
602         test_ip_uint8_t(mh, page, VAL_STR(IP_TOS));
603         test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 1);
604         test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 2);
605         test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 3);
606         test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 4);
607         test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 5);
608         test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 6);
609         test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 7);
610         test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 8);
611 #ifdef IP_CHECKSUM
612         test_ip_recverr(mh, page, VAL_STR(IP_RECVERR));
613 #endif
614 #ifdef IP_ORIGDSTADDR
615         test_ip_origdstaddr(mh, page, VAL_STR(IP_ORIGDSTADDR));
616 #endif
617 #ifdef IP_CHECKSUM
618         test_ip_uint(mh, page, VAL_STR(IP_CHECKSUM));
619 #endif
620         test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
621                           VAL_STR(SOL_IP));
622         test_unknown_type(mh, page, VAL_STR(SOL_IP), "IP_???");
623 }
624
625 static void
626 test_unknown_level(struct msghdr *const mh, void *const page)
627 {
628         struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
629
630         cmsg->cmsg_len = CMSG_LEN(0);
631         cmsg->cmsg_level = SOL_TCP;
632         cmsg->cmsg_type = 0xdeadbeef;
633
634         mh->msg_control = cmsg;
635         mh->msg_controllen = cmsg->cmsg_len;
636
637         int rc = sendmsg(-1, mh, 0);
638         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
639                ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
640                ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}"
641                ", 0) = %d %s (%m)\n",
642                (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type,
643                (unsigned) mh->msg_controllen, rc, errno2name());
644 }
645
646 int main(int ac, const char **av)
647 {
648         int rc = sendmsg(-1, 0, 0);
649         printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
650
651         struct msghdr *mh = tail_alloc(sizeof(*mh));
652         memset(mh, 0, sizeof(*mh));
653
654         rc = sendmsg(-1, mh + 1, 0);
655         printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
656                mh + 1, rc, errno2name());
657
658         void *page = tail_alloc(1) + 1;
659         mh->msg_control = page;
660         mh->msg_controllen = CMSG_LEN(0);
661         rc = sendmsg(-1, mh, 0);
662         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
663                ", msg_iovlen=0, msg_control=%p, msg_controllen=%u"
664                ", msg_flags=0}, 0) = %d %s (%m)\n",
665                page, (unsigned) CMSG_LEN(0), rc, errno2name());
666
667         test_sol_socket(mh, page);
668         test_sol_ip(mh, page);
669         test_unknown_level(mh, page);
670
671         puts("+++ exited with 0 +++");
672         return 0;
673 }