2016-06-25 13:47:54 +00:00
/*
* Copyright ( c ) 1991 , 1992 Paul Kranenburg < pk @ cs . few . eur . nl >
* Copyright ( c ) 1993 Branko Lankester < branko @ hacktic . nl >
* Copyright ( c ) 1993 , 1994 , 1995 , 1996 Rick Sladkey < jrs @ world . std . com >
* Copyright ( c ) 1996 - 2000 Wichert Akkerman < wichert @ cistron . nl >
* Copyright ( c ) 2005 - 2016 Dmitry V . Levin < ldv @ altlinux . org >
2018-04-05 01:40:00 +00:00
* Copyright ( c ) 2016 - 2018 The strace developers .
2016-06-25 13:47:54 +00:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "defs.h"
2017-07-09 13:54:01 +00:00
# include "print_fields.h"
2016-06-25 13:47:54 +00:00
# include <sys/socket.h>
# include <sys/un.h>
# include <netinet/in.h>
# include <arpa/inet.h>
2017-06-25 00:40:29 +00:00
# include "netlink.h"
2016-06-25 13:47:54 +00:00
# include <linux/if_packet.h>
# include <linux/if_arp.h>
# include <linux/if_ether.h>
# ifdef HAVE_NETIPX_IPX_H
# include <netipx / ipx.h>
# else
# include <linux / ipx.h>
# endif
# include "xlat/addrfams.h"
# include "xlat/arp_hardware_types.h"
# include "xlat/ethernet_protocols.h"
# include "xlat/af_packet_types.h"
2018-05-06 20:28:09 +02:00
# include "xlat/bdaddr_types.h"
2018-05-06 21:24:32 +02:00
# include "xlat/bluetooth_l2_cid.h"
2018-05-06 21:07:31 +02:00
# include "xlat/bluetooth_l2_psm.h"
2018-05-06 19:53:56 +02:00
# include "xlat/hci_channels.h"
2016-06-25 13:47:54 +00:00
# define SIZEOF_SA_FAMILY sizeof(((struct sockaddr *) 0)->sa_family)
2018-05-07 08:52:30 +02:00
const size_t arp_hardware_types_size = ARRAY_SIZE ( arp_hardware_types ) - 1 ;
2018-02-16 19:01:24 +01:00
const size_t ethernet_protocols_size = ARRAY_SIZE ( ethernet_protocols ) - 1 ;
2016-06-25 13:47:54 +00:00
static void
print_sockaddr_data_un ( const void * const buf , const int addrlen )
{
const struct sockaddr_un * const sa_un = buf ;
const int un_len = addrlen > ( int ) sizeof ( * sa_un )
? ( int ) sizeof ( * sa_un ) : addrlen ;
const int path_len = un_len - SIZEOF_SA_FAMILY ;
tprints ( " sun_path= " ) ;
if ( sa_un - > sun_path [ 0 ] ) {
print_quoted_string ( sa_un - > sun_path , path_len + 1 ,
QUOTE_0_TERMINATED ) ;
} else {
tprints ( " @ " ) ;
print_quoted_string ( sa_un - > sun_path + 1 , path_len - 1 , 0 ) ;
}
}
2017-06-15 21:02:14 +00:00
bool
print_inet_addr ( const int af ,
const void * const addr ,
const unsigned int len ,
const char * const var_name )
{
char buf [ INET6_ADDRSTRLEN ] ;
switch ( af ) {
case AF_INET :
2017-07-10 01:45:18 +00:00
if ( inet_ntop ( af , addr , buf , sizeof ( buf ) ) ) {
2017-08-20 11:10:03 +00:00
if ( var_name )
tprintf ( " %s=inet_addr( \" %s \" ) " , var_name , buf ) ;
else
tprints ( buf ) ;
2017-07-10 01:45:18 +00:00
return true ;
}
2017-06-15 21:02:14 +00:00
break ;
case AF_INET6 :
2017-07-10 01:45:18 +00:00
if ( inet_ntop ( af , addr , buf , sizeof ( buf ) ) ) {
2017-08-20 11:10:03 +00:00
if ( var_name )
tprintf ( " inet_pton(%s, \" %s \" , &%s) " ,
" AF_INET6 " , buf , var_name ) ;
else
tprints ( buf ) ;
2017-07-10 01:45:18 +00:00
return true ;
}
2017-06-15 21:02:14 +00:00
break ;
}
2017-08-20 11:10:03 +00:00
if ( var_name )
tprintf ( " %s= " , var_name ) ;
2017-08-19 11:04:00 +00:00
print_quoted_string ( addr , len , QUOTE_FORCE_HEX ) ;
2017-07-10 01:45:18 +00:00
return false ;
2017-06-15 21:02:14 +00:00
}
2017-08-22 11:35:20 +00:00
bool
decode_inet_addr ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const int family ,
const char * const var_name )
{
union {
struct in_addr a4 ;
struct in6_addr a6 ;
} addrbuf ;
size_t size = 0 ;
switch ( family ) {
case AF_INET :
size = sizeof ( addrbuf . a4 ) ;
break ;
case AF_INET6 :
size = sizeof ( addrbuf . a6 ) ;
break ;
}
if ( ! size | | len < size ) {
if ( var_name )
tprintf ( " %s= " , var_name ) ;
printstr_ex ( tcp , addr , len , QUOTE_FORCE_HEX ) ;
return false ;
}
if ( umoven ( tcp , addr , size , & addrbuf ) < 0 ) {
if ( var_name )
tprintf ( " %s= " , var_name ) ;
printaddr ( addr ) ;
return false ;
}
return print_inet_addr ( family , & addrbuf , size , var_name ) ;
}
2016-06-25 13:47:54 +00:00
static void
print_sockaddr_data_in ( const void * const buf , const int addrlen )
{
const struct sockaddr_in * const sa_in = buf ;
2017-07-09 13:54:01 +00:00
PRINT_FIELD_NET_PORT ( " " , * sa_in , sin_port ) ;
2017-07-09 13:54:01 +00:00
PRINT_FIELD_INET4_ADDR ( " , " , * sa_in , sin_addr ) ;
2016-06-25 13:47:54 +00:00
}
# define SIN6_MIN_LEN offsetof(struct sockaddr_in6, sin6_scope_id)
static void
print_sockaddr_data_in6 ( const void * const buf , const int addrlen )
{
const struct sockaddr_in6 * const sa_in6 = buf ;
2017-07-09 13:54:01 +00:00
PRINT_FIELD_NET_PORT ( " " , * sa_in6 , sin6_port ) ;
2017-07-09 13:54:01 +00:00
PRINT_FIELD_INET_ADDR ( " , " , * sa_in6 , sin6_addr , AF_INET6 ) ;
2017-06-15 21:02:14 +00:00
tprintf ( " , sin6_flowinfo=htonl(%u) " , ntohl ( sa_in6 - > sin6_flowinfo ) ) ;
2016-06-25 13:47:54 +00:00
if ( addrlen < = ( int ) SIN6_MIN_LEN )
return ;
# if defined IN6_IS_ADDR_LINKLOCAL && defined IN6_IS_ADDR_MC_LINKLOCAL
if ( IN6_IS_ADDR_LINKLOCAL ( & sa_in6 - > sin6_addr )
| | IN6_IS_ADDR_MC_LINKLOCAL ( & sa_in6 - > sin6_addr ) )
2017-07-09 13:54:01 +00:00
PRINT_FIELD_IFINDEX ( " , " , * sa_in6 , sin6_scope_id ) ;
2016-06-25 13:47:54 +00:00
else
# endif
2017-07-09 13:54:01 +00:00
PRINT_FIELD_U ( " , " , * sa_in6 , sin6_scope_id ) ;
2016-06-25 13:47:54 +00:00
}
static void
print_sockaddr_data_ipx ( const void * const buf , const int addrlen )
{
const struct sockaddr_ipx * const sa_ipx = buf ;
unsigned int i ;
2017-07-09 13:54:01 +00:00
PRINT_FIELD_NET_PORT ( " " , * sa_ipx , sipx_port ) ;
tprintf ( " , sipx_network=htonl(%#08x) "
2016-06-25 13:47:54 +00:00
" , sipx_node=[ " ,
ntohl ( sa_ipx - > sipx_network ) ) ;
for ( i = 0 ; i < IPX_NODE_LEN ; + + i ) {
tprintf ( " %s%#02x " , i ? " , " : " " ,
sa_ipx - > sipx_node [ i ] ) ;
}
2017-07-10 02:23:00 +00:00
PRINT_FIELD_0X ( " ], " , * sa_ipx , sipx_type ) ;
2016-06-25 13:47:54 +00:00
}
static void
print_sockaddr_data_nl ( const void * const buf , const int addrlen )
{
const struct sockaddr_nl * const sa_nl = buf ;
2017-07-10 02:23:00 +00:00
PRINT_FIELD_D ( " " , * sa_nl , nl_pid ) ;
PRINT_FIELD_0X ( " , " , * sa_nl , nl_groups ) ;
2016-06-25 13:47:54 +00:00
}
static void
print_sockaddr_data_ll ( const void * const buf , const int addrlen )
{
const struct sockaddr_ll * const sa_ll = buf ;
tprints ( " sll_protocol=htons( " ) ;
2018-02-16 19:01:24 +01:00
printxval_search ( ethernet_protocols , ntohs ( sa_ll - > sll_protocol ) ,
" ETH_P_??? " ) ;
2017-07-09 13:54:01 +00:00
PRINT_FIELD_IFINDEX ( " ), " , * sa_ll , sll_ifindex ) ;
2016-06-25 13:47:54 +00:00
tprints ( " , sll_hatype= " ) ;
2018-05-07 08:32:45 +02:00
printxval_search ( arp_hardware_types , sa_ll - > sll_hatype , " ARPHRD_??? " ) ;
2016-06-25 13:47:54 +00:00
tprints ( " , sll_pkttype= " ) ;
2018-05-15 21:41:47 +00:00
printxval_index ( af_packet_types , sa_ll - > sll_pkttype , " PACKET_??? " ) ;
2016-06-25 13:47:54 +00:00
tprintf ( " , sll_halen=%u " , sa_ll - > sll_halen ) ;
if ( sa_ll - > sll_halen ) {
const unsigned int oob_halen =
addrlen - offsetof ( struct sockaddr_ll , sll_addr ) ;
unsigned int i ;
tprints ( " , sll_addr=[ " ) ;
for ( i = 0 ; i < sa_ll - > sll_halen ; + + i ) {
if ( i )
tprints ( " , " ) ;
if ( i > = oob_halen ) {
tprints ( " ... " ) ;
break ;
}
tprintf ( " %#02x " , sa_ll - > sll_addr [ i ] ) ;
}
tprints ( " ] " ) ;
}
}
static void
print_sockaddr_data_raw ( const void * const buf , const int addrlen )
{
const char * const data = buf + SIZEOF_SA_FAMILY ;
const int datalen = addrlen - SIZEOF_SA_FAMILY ;
tprints ( " sa_data= " ) ;
print_quoted_string ( data , datalen , 0 ) ;
}
2018-05-06 19:53:56 +02:00
static uint16_t
btohs ( uint16_t val )
{
# ifdef WORDS_BIGENDIAN
return ( val < < 8 ) | ( val > > 8 ) ;
# else
return val ;
# endif
}
2018-05-06 21:07:31 +02:00
static void
print_bluetooth_l2_psm ( const char * prefix , uint16_t psm )
{
const uint16_t psm_he = btohs ( psm ) ;
const char * psm_name = xlookup ( bluetooth_l2_psm , psm_he ) ;
const bool psm_str = psm_name | | ( psm_he > = L2CAP_PSM_LE_DYN_START
& & psm_he < = L2CAP_PSM_LE_DYN_END )
| | ( psm_he > = L2CAP_PSM_DYN_START ) ;
tprintf ( " %shtobs( " , prefix ) ;
if ( xlat_verbose ( xlat_verbosity ) ! = XLAT_STYLE_ABBREV | | ! psm_str )
tprintf ( " %#x " , psm_he ) ;
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_RAW )
goto print_bluetooth_l2_psm_end ;
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_VERBOSE | | ! psm_str )
tprints ( " /* " ) ;
if ( psm_name ) {
tprints ( psm_name ) ;
} else if ( psm_he > = L2CAP_PSM_LE_DYN_START
& & psm_he < = L2CAP_PSM_LE_DYN_END ) {
print_xlat ( L2CAP_PSM_LE_DYN_START ) ;
tprintf ( " + %u " , psm_he - L2CAP_PSM_LE_DYN_START ) ;
} else if ( psm_he > = L2CAP_PSM_DYN_START ) {
print_xlat ( L2CAP_PSM_DYN_START ) ;
tprintf ( " + %u " , psm_he - L2CAP_PSM_DYN_START ) ;
} else {
tprints ( " L2CAP_PSM_??? " ) ;
}
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_VERBOSE | | ! psm_str )
tprints ( " */ " ) ;
print_bluetooth_l2_psm_end :
tprints ( " ) " ) ;
}
2018-05-06 21:24:32 +02:00
static void
print_bluetooth_l2_cid ( const char * prefix , uint16_t cid )
{
const uint16_t cid_he = btohs ( cid ) ;
const char * cid_name = xlookup ( bluetooth_l2_cid , cid_he ) ;
const bool cid_str = cid_name | | ( cid_he > = L2CAP_CID_DYN_START ) ;
tprintf ( " %shtobs( " , prefix ) ;
if ( xlat_verbose ( xlat_verbosity ) ! = XLAT_STYLE_ABBREV | | ! cid_str )
tprintf ( " %#x " , cid_he ) ;
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_RAW )
goto print_bluetooth_l2_cid_end ;
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_VERBOSE | | ! cid_str )
tprints ( " /* " ) ;
if ( cid_name ) {
tprints ( cid_name ) ;
} else if ( cid_he > = L2CAP_CID_DYN_START ) {
print_xlat ( L2CAP_CID_DYN_START ) ;
tprintf ( " + %u " , cid_he - L2CAP_CID_DYN_START ) ;
} else {
tprints ( " L2CAP_CID_??? " ) ;
}
if ( xlat_verbose ( xlat_verbosity ) = = XLAT_STYLE_VERBOSE | | ! cid_str )
tprints ( " */ " ) ;
print_bluetooth_l2_cid_end :
tprints ( " ) " ) ;
}
2016-06-25 13:47:54 +00:00
static void
print_sockaddr_data_bt ( const void * const buf , const int addrlen )
{
2018-05-06 19:53:56 +02:00
struct sockaddr_hci {
/* sa_family_t */ uint16_t hci_family ;
uint16_t hci_dev ;
uint16_t hci_channel ;
} ;
struct bdaddr {
uint8_t b [ 6 ] ;
} ATTRIBUTE_PACKED ;
struct sockaddr_sco {
/* sa_family_t */ uint16_t sco_family ;
struct bdaddr sco_bdaddr ;
} ;
struct sockaddr_rc {
/* sa_family_t */ uint16_t rc_family ;
struct bdaddr rc_bdaddr ;
uint8_t rc_channel ;
} ;
struct sockaddr_l2 {
/* sa_family_t */ uint16_t l2_family ;
/* little endiang */ uint16_t l2_psm ;
struct bdaddr l2_bdaddr ;
/* little endian */ uint16_t l2_cid ;
uint8_t l2_bdaddr_type ;
} ;
2016-06-25 13:47:54 +00:00
switch ( addrlen ) {
case sizeof ( struct sockaddr_hci ) : {
const struct sockaddr_hci * const hci = buf ;
tprintf ( " hci_dev=htobs(%hu), hci_channel= " ,
btohs ( hci - > hci_dev ) ) ;
2018-05-15 21:41:47 +00:00
printxval_index ( hci_channels , hci - > hci_channel ,
" HCI_CHANNEL_??? " ) ;
2016-06-25 13:47:54 +00:00
break ;
}
case sizeof ( struct sockaddr_sco ) : {
const struct sockaddr_sco * const sco = buf ;
2018-05-07 00:04:18 +02:00
print_mac_addr ( " sco_bdaddr= " , sco - > sco_bdaddr . b ,
sizeof ( sco - > sco_bdaddr . b ) ) ;
2016-06-25 13:47:54 +00:00
break ;
}
case sizeof ( struct sockaddr_rc ) : {
const struct sockaddr_rc * const rc = buf ;
2018-05-07 00:04:18 +02:00
print_mac_addr ( " rc_bdaddr= " , rc - > rc_bdaddr . b ,
sizeof ( rc - > rc_bdaddr . b ) ) ;
tprintf ( " , rc_channel=%u " , rc - > rc_channel ) ;
2016-06-25 13:47:54 +00:00
break ;
}
2018-05-08 17:46:33 +02:00
case offsetof ( struct sockaddr_l2 , l2_bdaddr_type ) :
2016-06-25 13:47:54 +00:00
case sizeof ( struct sockaddr_l2 ) : {
const struct sockaddr_l2 * const l2 = buf ;
2018-05-06 21:07:31 +02:00
print_bluetooth_l2_psm ( " l2_psm= " , l2 - > l2_psm ) ;
2018-05-07 00:04:18 +02:00
print_mac_addr ( " , l2_bdaddr= " , l2 - > l2_bdaddr . b ,
sizeof ( l2 - > l2_bdaddr . b ) ) ;
2018-05-06 21:24:32 +02:00
print_bluetooth_l2_cid ( " , l2_cid= " , l2 - > l2_cid ) ;
2018-05-08 17:46:33 +02:00
if ( addrlen = = sizeof ( struct sockaddr_l2 ) ) {
tprints ( " , l2_bdaddr_type= " ) ;
printxval_index ( bdaddr_types ,
l2 - > l2_bdaddr_type ,
" BDADDR_??? " ) ;
}
2016-06-25 13:47:54 +00:00
break ;
}
default :
print_sockaddr_data_raw ( buf , addrlen ) ;
break ;
}
}
typedef void ( * const sockaddr_printer ) ( const void * const , const int ) ;
static const struct {
const sockaddr_printer printer ;
const int min_len ;
} sa_printers [ ] = {
[ AF_UNIX ] = { print_sockaddr_data_un , SIZEOF_SA_FAMILY + 1 } ,
[ AF_INET ] = { print_sockaddr_data_in , sizeof ( struct sockaddr_in ) } ,
[ AF_IPX ] = { print_sockaddr_data_ipx , sizeof ( struct sockaddr_ipx ) } ,
[ AF_INET6 ] = { print_sockaddr_data_in6 , SIN6_MIN_LEN } ,
[ AF_NETLINK ] = { print_sockaddr_data_nl , SIZEOF_SA_FAMILY + 1 } ,
[ AF_PACKET ] = { print_sockaddr_data_ll , sizeof ( struct sockaddr_ll ) } ,
[ AF_BLUETOOTH ] = { print_sockaddr_data_bt , SIZEOF_SA_FAMILY + 1 } ,
} ;
void
2017-07-09 16:04:24 +00:00
print_sockaddr ( const void * const buf , const int addrlen )
2016-06-25 13:47:54 +00:00
{
const struct sockaddr * const sa = buf ;
tprints ( " {sa_family= " ) ;
2018-05-15 21:41:47 +00:00
printxval_index ( addrfams , sa - > sa_family , " AF_??? " ) ;
2016-06-25 13:47:54 +00:00
if ( addrlen > ( int ) SIZEOF_SA_FAMILY ) {
tprints ( " , " ) ;
if ( sa - > sa_family < ARRAY_SIZE ( sa_printers )
& & sa_printers [ sa - > sa_family ] . printer
& & addrlen > = sa_printers [ sa - > sa_family ] . min_len ) {
sa_printers [ sa - > sa_family ] . printer ( buf , addrlen ) ;
} else {
print_sockaddr_data_raw ( buf , addrlen ) ;
}
}
tprints ( " } " ) ;
}
int
2016-12-26 10:26:03 +00:00
decode_sockaddr ( struct tcb * const tcp , const kernel_ulong_t addr , int addrlen )
2016-06-25 13:47:54 +00:00
{
if ( addrlen < 2 ) {
printaddr ( addr ) ;
return - 1 ;
}
union {
struct sockaddr sa ;
struct sockaddr_storage storage ;
char pad [ sizeof ( struct sockaddr_storage ) + 1 ] ;
} addrbuf ;
if ( ( unsigned ) addrlen > sizeof ( addrbuf . storage ) )
addrlen = sizeof ( addrbuf . storage ) ;
if ( umoven_or_printaddr ( tcp , addr , addrlen , addrbuf . pad ) )
return - 1 ;
memset ( & addrbuf . pad [ addrlen ] , 0 , sizeof ( addrbuf . pad ) - addrlen ) ;
2017-07-09 16:04:24 +00:00
print_sockaddr ( & addrbuf , addrlen ) ;
2016-06-25 13:47:54 +00:00
return addrbuf . sa . sa_family ;
}