]> granicus.if.org Git - strace/blob - net.c
net: accept arbitrary option length for getsockopt's SO_LINGER
[strace] / net.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-2000 Wichert Akkerman <wichert@cistron.nl>
6  * Copyright (c) 1999-2017 The strace developers.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "defs.h"
33 #include "print_fields.h"
34
35 #include <sys/stat.h>
36 #include <sys/socket.h>
37 #include <sys/uio.h>
38 #include <sys/un.h>
39 #include <netinet/in.h>
40 #ifdef HAVE_NETINET_TCP_H
41 # include <netinet/tcp.h>
42 #endif
43 #ifdef HAVE_NETINET_UDP_H
44 # include <netinet/udp.h>
45 #endif
46 #ifdef HAVE_NETINET_SCTP_H
47 # include <netinet/sctp.h>
48 #endif
49 #include <arpa/inet.h>
50 #include <net/if.h>
51 #include <asm/types.h>
52 #ifdef HAVE_NETIPX_IPX_H
53 # include <netipx/ipx.h>
54 #else
55 # include <linux/ipx.h>
56 #endif
57
58 #if defined(HAVE_LINUX_IP_VS_H)
59 # include <linux/ip_vs.h>
60 #endif
61 #include "netlink.h"
62 #if defined(HAVE_LINUX_NETFILTER_ARP_ARP_TABLES_H)
63 # include <linux/netfilter_arp/arp_tables.h>
64 #endif
65 #if defined(HAVE_LINUX_NETFILTER_BRIDGE_EBTABLES_H)
66 # include <linux/netfilter_bridge/ebtables.h>
67 #endif
68 #if defined(HAVE_LINUX_NETFILTER_IPV4_IP_TABLES_H)
69 # include <linux/netfilter_ipv4/ip_tables.h>
70 #endif
71 #if defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H)
72 # include <linux/netfilter_ipv6/ip6_tables.h>
73 #endif
74 #include <linux/if_packet.h>
75 #include <linux/icmp.h>
76
77 #include "xlat/socktypes.h"
78 #include "xlat/sock_type_flags.h"
79 #ifndef SOCK_TYPE_MASK
80 # define SOCK_TYPE_MASK 0xf
81 #endif
82
83 #include "xlat/socketlayers.h"
84
85 #include "xlat/inet_protocols.h"
86
87 #ifdef HAVE_BLUETOOTH_BLUETOOTH_H
88 # include <bluetooth/bluetooth.h>
89 # include "xlat/bt_protocols.h"
90 #endif
91
92 void
93 print_ifindex(unsigned int ifindex)
94 {
95 #ifdef HAVE_IF_INDEXTONAME
96         char buf[IFNAMSIZ + 1];
97
98         if (if_indextoname(ifindex, buf)) {
99                 tprints("if_nametoindex(");
100                 print_quoted_string(buf, sizeof(buf), QUOTE_0_TERMINATED);
101                 tprints(")");
102                 return;
103         }
104 #endif
105         tprintf("%u", ifindex);
106 }
107
108 static void
109 decode_sockbuf(struct tcb *const tcp, const int fd, const kernel_ulong_t addr,
110                const kernel_ulong_t addrlen)
111 {
112
113         switch (verbose(tcp) ? getfdproto(tcp, fd) : SOCK_PROTO_UNKNOWN) {
114         case SOCK_PROTO_NETLINK:
115                 decode_netlink(tcp, fd, addr, addrlen);
116                 break;
117         default:
118                 printstrn(tcp, addr, addrlen);
119         }
120 }
121
122 /*
123  * low bits of the socket type define real socket type,
124  * other bits are socket type flags.
125  */
126 static void
127 tprint_sock_type(unsigned int flags)
128 {
129         const char *str = xlookup(socktypes, flags & SOCK_TYPE_MASK);
130
131         if (str) {
132                 tprints(str);
133                 flags &= ~SOCK_TYPE_MASK;
134                 if (!flags)
135                         return;
136                 tprints("|");
137         }
138         printflags(sock_type_flags, flags, "SOCK_???");
139 }
140
141 SYS_FUNC(socket)
142 {
143         printxval(addrfams, tcp->u_arg[0], "AF_???");
144         tprints(", ");
145         tprint_sock_type(tcp->u_arg[1]);
146         tprints(", ");
147         switch (tcp->u_arg[0]) {
148         case AF_INET:
149         case AF_INET6:
150                 printxval(inet_protocols, tcp->u_arg[2], "IPPROTO_???");
151                 break;
152
153         case AF_NETLINK:
154                 printxval(netlink_protocols, tcp->u_arg[2], "NETLINK_???");
155                 break;
156
157 #ifdef HAVE_BLUETOOTH_BLUETOOTH_H
158         case AF_BLUETOOTH:
159                 printxval(bt_protocols, tcp->u_arg[2], "BTPROTO_???");
160                 break;
161 #endif
162
163         default:
164                 tprintf("%" PRI_klu, tcp->u_arg[2]);
165                 break;
166         }
167
168         return RVAL_DECODED | RVAL_FD;
169 }
170
171 SYS_FUNC(bind)
172 {
173         printfd(tcp, tcp->u_arg[0]);
174         tprints(", ");
175         const int addrlen = tcp->u_arg[2];
176         decode_sockaddr(tcp, tcp->u_arg[1], addrlen);
177         tprintf(", %d", addrlen);
178
179         return RVAL_DECODED;
180 }
181
182 SYS_FUNC(listen)
183 {
184         printfd(tcp, tcp->u_arg[0]);
185         tprints(", ");
186         tprintf("%" PRI_klu, tcp->u_arg[1]);
187
188         return RVAL_DECODED;
189 }
190
191 static bool
192 fetch_socklen(struct tcb *const tcp, int *const plen,
193               const kernel_ulong_t sockaddr, const kernel_ulong_t socklen)
194 {
195         return verbose(tcp) && sockaddr && socklen
196                && umove(tcp, socklen, plen) == 0;
197 }
198
199 static int
200 decode_sockname(struct tcb *tcp)
201 {
202         int ulen, rlen;
203
204         if (entering(tcp)) {
205                 printfd(tcp, tcp->u_arg[0]);
206                 tprints(", ");
207                 if (fetch_socklen(tcp, &ulen, tcp->u_arg[1], tcp->u_arg[2])) {
208                         set_tcb_priv_ulong(tcp, ulen);
209                         return 0;
210                 } else {
211                         printaddr(tcp->u_arg[1]);
212                         tprints(", ");
213                         printaddr(tcp->u_arg[2]);
214                         return RVAL_DECODED;
215                 }
216         }
217
218         ulen = get_tcb_priv_ulong(tcp);
219
220         if (syserror(tcp) || umove(tcp, tcp->u_arg[2], &rlen) < 0) {
221                 printaddr(tcp->u_arg[1]);
222                 tprintf(", [%d]", ulen);
223         } else {
224                 decode_sockaddr(tcp, tcp->u_arg[1], ulen > rlen ? rlen : ulen);
225                 if (ulen != rlen)
226                         tprintf(", [%d->%d]", ulen, rlen);
227                 else
228                         tprintf(", [%d]", rlen);
229         }
230
231         return RVAL_DECODED;
232 }
233
234 SYS_FUNC(accept)
235 {
236         return decode_sockname(tcp) | RVAL_FD;
237 }
238
239 SYS_FUNC(accept4)
240 {
241         int rc = decode_sockname(tcp);
242
243         if (rc & RVAL_DECODED) {
244                 tprints(", ");
245                 printflags(sock_type_flags, tcp->u_arg[3], "SOCK_???");
246         }
247
248         return rc | RVAL_FD;
249 }
250
251 SYS_FUNC(send)
252 {
253         printfd(tcp, tcp->u_arg[0]);
254         tprints(", ");
255         decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], tcp->u_arg[2]);
256         tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
257         /* flags */
258         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
259
260         return RVAL_DECODED;
261 }
262
263 SYS_FUNC(sendto)
264 {
265         printfd(tcp, tcp->u_arg[0]);
266         tprints(", ");
267         decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], tcp->u_arg[2]);
268         tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
269         /* flags */
270         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
271         /* to address */
272         const int addrlen = tcp->u_arg[5];
273         tprints(", ");
274         decode_sockaddr(tcp, tcp->u_arg[4], addrlen);
275         /* to length */
276         tprintf(", %d", addrlen);
277
278         return RVAL_DECODED;
279 }
280
281 SYS_FUNC(recv)
282 {
283         if (entering(tcp)) {
284                 printfd(tcp, tcp->u_arg[0]);
285                 tprints(", ");
286         } else {
287                 if (syserror(tcp)) {
288                         printaddr(tcp->u_arg[1]);
289                 } else {
290                         decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1],
291                                      tcp->u_rval);
292                 }
293
294                 tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
295                 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
296         }
297         return 0;
298 }
299
300 SYS_FUNC(recvfrom)
301 {
302         int ulen, rlen;
303
304         if (entering(tcp)) {
305                 printfd(tcp, tcp->u_arg[0]);
306                 tprints(", ");
307                 if (fetch_socklen(tcp, &ulen, tcp->u_arg[4], tcp->u_arg[5])) {
308                         set_tcb_priv_ulong(tcp, ulen);
309                 }
310         } else {
311                 /* buf */
312                 if (syserror(tcp)) {
313                         printaddr(tcp->u_arg[1]);
314                 } else {
315                         decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1],
316                                      tcp->u_rval);
317                 }
318                 /* size */
319                 tprintf(", %" PRI_klu ", ", tcp->u_arg[2]);
320                 /* flags */
321                 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
322                 tprints(", ");
323
324                 ulen = get_tcb_priv_ulong(tcp);
325
326                 if (!fetch_socklen(tcp, &rlen, tcp->u_arg[4], tcp->u_arg[5])) {
327                         /* from address */
328                         printaddr(tcp->u_arg[4]);
329                         tprints(", ");
330                         /* from length */
331                         printaddr(tcp->u_arg[5]);
332                         return 0;
333                 }
334                 if (syserror(tcp)) {
335                         /* from address */
336                         printaddr(tcp->u_arg[4]);
337                         /* from length */
338                         tprintf(", [%d]", ulen);
339                         return 0;
340                 }
341                 /* from address */
342                 decode_sockaddr(tcp, tcp->u_arg[4], ulen > rlen ? rlen : ulen);
343                 /* from length */
344                 if (ulen != rlen)
345                         tprintf(", [%d->%d]", ulen, rlen);
346                 else
347                         tprintf(", [%d]", rlen);
348         }
349         return 0;
350 }
351
352 #include "xlat/shutdown_modes.h"
353
354 SYS_FUNC(shutdown)
355 {
356         printfd(tcp, tcp->u_arg[0]);
357         tprints(", ");
358         printxval(shutdown_modes, tcp->u_arg[1], "SHUT_???");
359
360         return RVAL_DECODED;
361 }
362
363 SYS_FUNC(getsockname)
364 {
365         return decode_sockname(tcp);
366 }
367
368 static void
369 printpair_fd(struct tcb *tcp, const int i0, const int i1)
370 {
371         tprints("[");
372         printfd(tcp, i0);
373         tprints(", ");
374         printfd(tcp, i1);
375         tprints("]");
376 }
377
378 static void
379 decode_pair_fd(struct tcb *const tcp, const kernel_ulong_t addr)
380 {
381         int pair[2];
382
383         if (umove_or_printaddr(tcp, addr, &pair))
384                 return;
385
386         printpair_fd(tcp, pair[0], pair[1]);
387 }
388
389 static int
390 do_pipe(struct tcb *tcp, int flags_arg)
391 {
392         if (exiting(tcp)) {
393                 decode_pair_fd(tcp, tcp->u_arg[0]);
394                 if (flags_arg >= 0) {
395                         tprints(", ");
396                         printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
397                 }
398         }
399         return 0;
400 }
401
402 SYS_FUNC(pipe)
403 {
404 #ifdef HAVE_GETRVAL2
405         if (exiting(tcp) && !syserror(tcp))
406                 printpair_fd(tcp, tcp->u_rval, getrval2(tcp));
407         return 0;
408 #else
409         return do_pipe(tcp, -1);
410 #endif
411 }
412
413 SYS_FUNC(pipe2)
414 {
415         return do_pipe(tcp, 1);
416 }
417
418 SYS_FUNC(socketpair)
419 {
420         if (entering(tcp)) {
421                 printxval(addrfams, tcp->u_arg[0], "AF_???");
422                 tprints(", ");
423                 tprint_sock_type(tcp->u_arg[1]);
424                 tprintf(", %" PRI_klu, tcp->u_arg[2]);
425         } else {
426                 tprints(", ");
427                 decode_pair_fd(tcp, tcp->u_arg[3]);
428         }
429         return 0;
430 }
431
432 #include "xlat/sockoptions.h"
433 #include "xlat/sockipoptions.h"
434 #include "xlat/getsockipoptions.h"
435 #include "xlat/setsockipoptions.h"
436 #include "xlat/sockipv6options.h"
437 #include "xlat/getsockipv6options.h"
438 #include "xlat/setsockipv6options.h"
439 #include "xlat/sockipxoptions.h"
440 #include "xlat/sockrawoptions.h"
441 #include "xlat/sockpacketoptions.h"
442 #include "xlat/socksctpoptions.h"
443 #include "xlat/socktcpoptions.h"
444
445 static void
446 print_sockopt_fd_level_name(struct tcb *tcp, int fd, unsigned int level,
447                             unsigned int name, bool is_getsockopt)
448 {
449         printfd(tcp, fd);
450         tprints(", ");
451         printxval(socketlayers, level, "SOL_??");
452         tprints(", ");
453
454         switch (level) {
455         case SOL_SOCKET:
456                 printxval(sockoptions, name, "SO_???");
457                 break;
458         case SOL_IP:
459                 printxvals(name, "IP_???", sockipoptions,
460                         is_getsockopt ? getsockipoptions : setsockipoptions, NULL);
461                 break;
462         case SOL_IPV6:
463                 printxvals(name, "IPV6_???", sockipv6options,
464                         is_getsockopt ? getsockipv6options : setsockipv6options, NULL);
465                 break;
466         case SOL_IPX:
467                 printxval(sockipxoptions, name, "IPX_???");
468                 break;
469         case SOL_PACKET:
470                 printxval(sockpacketoptions, name, "PACKET_???");
471                 break;
472         case SOL_TCP:
473                 printxval(socktcpoptions, name, "TCP_???");
474                 break;
475         case SOL_SCTP:
476                 printxval(socksctpoptions, name, "SCTP_???");
477                 break;
478         case SOL_RAW:
479                 printxval(sockrawoptions, name, "RAW_???");
480                 break;
481
482                 /* Other SOL_* protocol levels still need work. */
483
484         default:
485                 tprintf("%u", name);
486         }
487
488         tprints(", ");
489 }
490
491 static void
492 print_set_linger(struct tcb *const tcp, const kernel_ulong_t addr,
493                  const unsigned int len)
494 {
495         struct linger linger;
496
497         if (len < sizeof(linger) ||
498             umove(tcp, addr, &linger) < 0) {
499                 printaddr(addr);
500                 return;
501         }
502
503         PRINT_FIELD_D("{", linger, l_onoff);
504         PRINT_FIELD_D(", ", linger, l_linger);
505         tprints("}");
506 }
507
508 static void
509 print_get_linger(struct tcb *const tcp, const kernel_ulong_t addr,
510                  unsigned int len)
511 {
512         struct linger linger;
513
514         if (len < sizeof(linger)) {
515                 if (len != sizeof(linger.l_onoff)) {
516                         printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
517                         return;
518                 }
519         } else {
520                 len = sizeof(linger);
521         }
522
523         if (umoven(tcp, addr, len, &linger) < 0) {
524                 printaddr(addr);
525                 return;
526         }
527
528         PRINT_FIELD_D("{", linger, l_onoff);
529         if (len == sizeof(linger))
530                 PRINT_FIELD_D(", ", linger, l_linger);
531         tprints("}");
532 }
533
534 #ifdef SO_PEERCRED
535 static void
536 print_ucred(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
537 {
538         struct ucred uc;
539
540         if (len != sizeof(uc) ||
541             umove(tcp, addr, &uc) < 0) {
542                 printaddr(addr);
543         } else {
544                 tprintf("{pid=%u, uid=%u, gid=%u}",
545                         (unsigned) uc.pid,
546                         (unsigned) uc.uid,
547                         (unsigned) uc.gid);
548         }
549 }
550 #endif /* SO_PEERCRED */
551
552 #ifdef PACKET_STATISTICS
553 static void
554 print_tpacket_stats(struct tcb *const tcp, const kernel_ulong_t addr,
555                     const int len)
556 {
557         struct tpacket_stats stats;
558
559         if (len != sizeof(stats) ||
560             umove(tcp, addr, &stats) < 0) {
561                 printaddr(addr);
562         } else {
563                 tprintf("{packets=%u, drops=%u}",
564                         stats.tp_packets,
565                         stats.tp_drops);
566         }
567 }
568 #endif /* PACKET_STATISTICS */
569
570 #include "xlat/icmpfilterflags.h"
571
572 static void
573 print_icmp_filter(struct tcb *const tcp, const kernel_ulong_t addr, int len)
574 {
575         struct icmp_filter filter = {};
576
577         if (len > (int) sizeof(filter))
578                 len = sizeof(filter);
579         else if (len <= 0) {
580                 printaddr(addr);
581                 return;
582         }
583
584         if (umoven_or_printaddr(tcp, addr, len, &filter))
585                 return;
586
587         tprints("~(");
588         printflags(icmpfilterflags, ~filter.data, "ICMP_???");
589         tprints(")");
590 }
591
592 static void
593 print_getsockopt(struct tcb *const tcp, const unsigned int level,
594                  const unsigned int name, const kernel_ulong_t addr,
595                  const int len)
596 {
597         if (addr && verbose(tcp))
598         switch (level) {
599         case SOL_SOCKET:
600                 switch (name) {
601                 case SO_LINGER:
602                         print_get_linger(tcp, addr, len);
603                         return;
604 #ifdef SO_PEERCRED
605                 case SO_PEERCRED:
606                         print_ucred(tcp, addr, len);
607                         return;
608 #endif
609                 }
610                 break;
611
612         case SOL_PACKET:
613                 switch (name) {
614 #ifdef PACKET_STATISTICS
615                 case PACKET_STATISTICS:
616                         print_tpacket_stats(tcp, addr, len);
617                         return;
618 #endif
619                 }
620                 break;
621
622         case SOL_RAW:
623                 switch (name) {
624                 case ICMP_FILTER:
625                         print_icmp_filter(tcp, addr, len);
626                         return;
627                 }
628                 break;
629         }
630
631         /* default arg printing */
632
633         if (verbose(tcp)) {
634                 if (len == sizeof(int)) {
635                         printnum_int(tcp, addr, "%d");
636                 } else {
637                         printstrn(tcp, addr, len);
638                 }
639         } else {
640                 printaddr(addr);
641         }
642 }
643
644 SYS_FUNC(getsockopt)
645 {
646         int ulen, rlen;
647
648         if (entering(tcp)) {
649                 print_sockopt_fd_level_name(tcp, tcp->u_arg[0],
650                                             tcp->u_arg[1], tcp->u_arg[2], true);
651
652                 if (verbose(tcp) && tcp->u_arg[4]
653                     && umove(tcp, tcp->u_arg[4], &ulen) == 0) {
654                         set_tcb_priv_ulong(tcp, ulen);
655                         return 0;
656                 } else {
657                         printaddr(tcp->u_arg[3]);
658                         tprints(", ");
659                         printaddr(tcp->u_arg[4]);
660                         return RVAL_DECODED;
661                 }
662         } else {
663                 ulen = get_tcb_priv_ulong(tcp);
664
665                 if (syserror(tcp) || umove(tcp, tcp->u_arg[4], &rlen) < 0) {
666                         printaddr(tcp->u_arg[3]);
667                         tprintf(", [%d]", ulen);
668                 } else {
669                         print_getsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2],
670                                          tcp->u_arg[3], rlen);
671                         if (ulen != rlen)
672                                 tprintf(", [%d->%d]", ulen, rlen);
673                         else
674                                 tprintf(", [%d]", rlen);
675                 }
676         }
677         return 0;
678 }
679
680 #ifdef IP_ADD_MEMBERSHIP
681 static void
682 print_mreq(struct tcb *const tcp, const kernel_ulong_t addr,
683            const unsigned int len)
684 {
685         struct ip_mreq mreq;
686
687         if (len < sizeof(mreq)) {
688                 printstrn(tcp, addr, len);
689                 return;
690         }
691         if (umove_or_printaddr(tcp, addr, &mreq))
692                 return;
693
694         tprintf("{imr_multiaddr=inet_addr(\"%s\")",
695                 inet_ntoa(mreq.imr_multiaddr));
696         tprintf(", imr_interface=inet_addr(\"%s\")}",
697                 inet_ntoa(mreq.imr_interface));
698 }
699 #endif /* IP_ADD_MEMBERSHIP */
700
701 #ifdef IPV6_ADD_MEMBERSHIP
702 static void
703 print_mreq6(struct tcb *const tcp, const kernel_ulong_t addr,
704             const unsigned int len)
705 {
706         struct ipv6_mreq mreq;
707
708         if (len < sizeof(mreq)) {
709                 printstrn(tcp, addr, len);
710                 return;
711         }
712         if (umove_or_printaddr(tcp, addr, &mreq))
713                 return;
714
715         tprints("{");
716         print_inet_addr(AF_INET6, &mreq.ipv6mr_multiaddr,
717                         sizeof(mreq.ipv6mr_multiaddr), "ipv6mr_multiaddr");
718
719         tprints(", ipv6mr_interface=");
720         print_ifindex(mreq.ipv6mr_interface);
721         tprints("}");
722 }
723 #endif /* IPV6_ADD_MEMBERSHIP */
724
725 #ifdef MCAST_JOIN_GROUP
726 static void
727 print_group_req(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
728 {
729         struct group_req greq;
730
731         if (len != sizeof(greq) ||
732             umove(tcp, addr, &greq) < 0) {
733                 printaddr(addr);
734                 return;
735         }
736
737         tprintf("{gr_interface=%u, gr_group=", greq.gr_interface);
738         print_sockaddr(tcp, &greq.gr_group, sizeof(greq.gr_group));
739         tprints("}");
740
741 }
742 #endif /* MCAST_JOIN_GROUP */
743
744 #ifdef PACKET_RX_RING
745 static void
746 print_tpacket_req(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
747 {
748         struct tpacket_req req;
749
750         if (len != sizeof(req) ||
751             umove(tcp, addr, &req) < 0) {
752                 printaddr(addr);
753         } else {
754                 tprintf("{block_size=%u, block_nr=%u, "
755                         "frame_size=%u, frame_nr=%u}",
756                         req.tp_block_size,
757                         req.tp_block_nr,
758                         req.tp_frame_size,
759                         req.tp_frame_nr);
760         }
761 }
762 #endif /* PACKET_RX_RING */
763
764 #ifdef PACKET_ADD_MEMBERSHIP
765 # include "xlat/packet_mreq_type.h"
766
767 static void
768 print_packet_mreq(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
769 {
770         struct packet_mreq mreq;
771
772         if (len != sizeof(mreq) ||
773             umove(tcp, addr, &mreq) < 0) {
774                 printaddr(addr);
775         } else {
776                 unsigned int i;
777
778                 tprintf("{mr_ifindex=%u, mr_type=", mreq.mr_ifindex);
779                 printxval(packet_mreq_type, mreq.mr_type, "PACKET_MR_???");
780                 tprintf(", mr_alen=%u, mr_address=", mreq.mr_alen);
781                 if (mreq.mr_alen > ARRAY_SIZE(mreq.mr_address))
782                         mreq.mr_alen = ARRAY_SIZE(mreq.mr_address);
783                 for (i = 0; i < mreq.mr_alen; ++i)
784                         tprintf("%02x", mreq.mr_address[i]);
785                 tprints("}");
786         }
787 }
788 #endif /* PACKET_ADD_MEMBERSHIP */
789
790 static void
791 print_setsockopt(struct tcb *const tcp, const unsigned int level,
792                  const unsigned int name, const kernel_ulong_t addr,
793                  const int len)
794 {
795         if (addr && verbose(tcp))
796         switch (level) {
797         case SOL_SOCKET:
798                 switch (name) {
799                 case SO_LINGER:
800                         print_set_linger(tcp, addr, len);
801                         return;
802                 }
803                 break;
804
805         case SOL_IP:
806                 switch (name) {
807 #ifdef IP_ADD_MEMBERSHIP
808                 case IP_ADD_MEMBERSHIP:
809                 case IP_DROP_MEMBERSHIP:
810                         print_mreq(tcp, addr, len);
811                         return;
812 #endif /* IP_ADD_MEMBERSHIP */
813 #ifdef MCAST_JOIN_GROUP
814                 case MCAST_JOIN_GROUP:
815                 case MCAST_LEAVE_GROUP:
816                         print_group_req(tcp, addr, len);
817                         return;
818 #endif /* MCAST_JOIN_GROUP */
819                 }
820                 break;
821
822         case SOL_IPV6:
823                 switch (name) {
824 #ifdef IPV6_ADD_MEMBERSHIP
825                 case IPV6_ADD_MEMBERSHIP:
826                 case IPV6_DROP_MEMBERSHIP:
827 # ifdef IPV6_JOIN_ANYCAST
828                 case IPV6_JOIN_ANYCAST:
829 # endif
830 # ifdef IPV6_LEAVE_ANYCAST
831                 case IPV6_LEAVE_ANYCAST:
832 # endif
833                         print_mreq6(tcp, addr, len);
834                         return;
835 #endif /* IPV6_ADD_MEMBERSHIP */
836                 }
837                 break;
838
839         case SOL_PACKET:
840                 switch (name) {
841 #ifdef PACKET_RX_RING
842                 case PACKET_RX_RING:
843 # ifdef PACKET_TX_RING
844                 case PACKET_TX_RING:
845 # endif
846                         print_tpacket_req(tcp, addr, len);
847                         return;
848 #endif /* PACKET_RX_RING */
849 #ifdef PACKET_ADD_MEMBERSHIP
850                 case PACKET_ADD_MEMBERSHIP:
851                 case PACKET_DROP_MEMBERSHIP:
852                         print_packet_mreq(tcp, addr, len);
853                         return;
854 #endif /* PACKET_ADD_MEMBERSHIP */
855                 }
856                 break;
857
858         case SOL_RAW:
859                 switch (name) {
860                 case ICMP_FILTER:
861                         print_icmp_filter(tcp, addr, len);
862                         return;
863                 }
864                 break;
865         }
866
867         /* default arg printing */
868
869         if (verbose(tcp)) {
870                 if (len == sizeof(int)) {
871                         printnum_int(tcp, addr, "%d");
872                 } else {
873                         printstrn(tcp, addr, len);
874                 }
875         } else {
876                 printaddr(addr);
877         }
878 }
879
880 SYS_FUNC(setsockopt)
881 {
882         print_sockopt_fd_level_name(tcp, tcp->u_arg[0],
883                                     tcp->u_arg[1], tcp->u_arg[2], false);
884         print_setsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2],
885                          tcp->u_arg[3], tcp->u_arg[4]);
886         tprintf(", %d", (int) tcp->u_arg[4]);
887
888         return RVAL_DECODED;
889 }