diff options
| author | Eugene Syromyatnikov <evgsyr@gmail.com> | 2018-08-31 05:48:19 +0200 |
|---|---|---|
| committer | Eugene Syromyatnikov <evgsyr@gmail.com> | 2019-10-13 04:10:29 +0200 |
| commit | e2b6d40b6d645df817180b7424867b34865ce469 (patch) | |
| tree | 31e23c3f64f7ad6a377407a151fd5886b3636cfd | |
| parent | a9aa3e03bdd47c6b5f5ee9916551fb4abd7b63d0 (diff) | |
| download | strace-esyr/net.tar.gz | |
netlink: avoid parsing data that has been just retrievedesyr/net
get_fd_nl_family did a weird thing: it parsed netlink socket address in
order to get netlink proto, but the address itself is constructed based
on the netlink proto number in the first place. Avoid doing so by
stashing information about netlink protocol right after nul byte of the
sockaddress and providing it on request.
* socketutils.c (cache_entry): Add has_data field.
(cache_inode_details): Add data argument, store it in has_data field.
(get_sockdata_by_inode_cached): New function.
(inet_parse_response, unix_parse_response, packet_parse_response):
Pass false in data argument of cache_inode_details call.
(netlink_parse_response): Append ndiag_protocol value to details string,
pass true to cache_inode_details call.
(unix_get, inet_get, packet_get): Add data argument, return NULL
if called with data == true.
(netlink_get): Add data argument, call get_sockdata_by_inode_cached
instead of get_sockaddr_by_inode_cached if called with data == true.
(protocols): Add data arguments to the type definition of the get field.
(get_sockaddr_by_inode_uncached): Add data argument, pass
it to protocols->get.
(print_sockaddr_by_inode_uncached): Call get_sockaddr_by_inode_uncached
with data == false.
(get_sockaddr_by_inode): Call get_sockaddr_by_inode_uncached with
data == false;
(get_sockdata_by_inode): New function.
* defs.h (get_sockdata_by_inode): New declaration.
* netlink.c (get_fd_nl_family): Use get_sockdata_by_inode.
| -rw-r--r-- | defs.h | 1 | ||||
| -rw-r--r-- | netlink.c | 23 | ||||
| -rw-r--r-- | socketutils.c | 79 |
3 files changed, 62 insertions, 41 deletions
@@ -982,6 +982,7 @@ extern void print_ax25_addr(const void /* ax25_address */ *addr); extern void print_x25_addr(const void /* struct x25_address */ *addr); extern void print_rose_addr(const void /* rose_address */ *addr); extern const char *get_sockaddr_by_inode(struct tcb *, int fd, unsigned long inode); +extern const char *get_sockdata_by_inode(struct tcb *, int fd, unsigned long inode); extern bool print_sockaddr_by_inode(struct tcb *, int fd, unsigned long inode); extern void print_dirfd(struct tcb *, int); @@ -73,28 +73,11 @@ get_fd_nl_family(struct tcb *const tcp, const int fd) if (!inode) return -1; - const char *const details = get_sockaddr_by_inode(tcp, fd, inode); - if (!details) + const char *const data = get_sockdata_by_inode(tcp, fd, inode); + if (!data) return -1; - const char *const nl_details = STR_STRIP_PREFIX(details, "NETLINK:["); - if (nl_details == details) - return -1; - - const struct xlat_data *xlats = netlink_protocols->data; - for (uint32_t idx = 0; idx < netlink_protocols->size; idx++) { - if (!netlink_protocols->data[idx].str) - continue; - - const char *name = STR_STRIP_PREFIX(xlats[idx].str, "NETLINK_"); - if (!strncmp(nl_details, name, strlen(name))) - return xlats[idx].val; - } - - if (*nl_details >= '0' && *nl_details <= '9') - return atoi(nl_details); - - return -1; + return data[0]; } static void diff --git a/socketutils.c b/socketutils.c index 6013355e3..9294ffc94 100644 --- a/socketutils.c +++ b/socketutils.c @@ -36,6 +36,7 @@ typedef struct { unsigned long inode; char *details; + bool has_data; } cache_entry; #define CACHE_SIZE 1024U @@ -43,12 +44,13 @@ static cache_entry cache[CACHE_SIZE]; #define CACHE_MASK (CACHE_SIZE - 1) static int -cache_inode_details(const unsigned long inode, char *const details) +cache_inode_details(const unsigned long inode, char *const details, bool data) { cache_entry *e = &cache[inode & CACHE_MASK]; free(e->details); e->inode = inode; e->details = details; + e->has_data = data; return 1; } @@ -60,6 +62,14 @@ get_sockaddr_by_inode_cached(const unsigned long inode) return (e && inode == e->inode) ? e->details : NULL; } +static const char * +get_sockdata_by_inode_cached(const unsigned long inode) +{ + const cache_entry *const e = &cache[inode & CACHE_MASK]; + return (e && inode == e->inode && e->has_data) + ? e->details + strlen(e->details) + 1 : NULL; +} + static bool print_sockaddr_by_inode_cached(const unsigned long inode) { @@ -178,7 +188,7 @@ inet_parse_response(const void *const data, const int data_len, return false; } - return cache_inode_details(inode, details); + return cache_inode_details(inode, details, false); } static bool @@ -339,7 +349,7 @@ unix_parse_response(const void *data, const int data_len, peer_str, path_str) < 0) return -1; - return cache_inode_details(inode, details); + return cache_inode_details(inode, details, false); } static bool @@ -404,16 +414,18 @@ netlink_parse_response(const void *data, const int data_len, if (netlink_proto) { netlink_proto = STR_STRIP_PREFIX(netlink_proto, "NETLINK_"); - if (asprintf(&details, "%s:[%s:%u]", proto_name, - netlink_proto, diag_msg->ndiag_portid) < 0) + if (asprintf(&details, "%s:[%s:%u]%c%c", proto_name, + netlink_proto, diag_msg->ndiag_portid, + '\0', diag_msg->ndiag_protocol) < 0) return -1; } else { - if (asprintf(&details, "%s:[%u]", proto_name, - (unsigned) diag_msg->ndiag_protocol) < 0) + if (asprintf(&details, "%s:[%u]%c%c", proto_name, + (unsigned) diag_msg->ndiag_protocol, + '\0', diag_msg->ndiag_protocol) < 0) return -1; } - return cache_inode_details(inode, details); + return cache_inode_details(inode, details, true); } struct packet_cb_data { @@ -527,15 +539,18 @@ packet_parse_response(const void *data, const int data_len, cb_data->ret = details; if (have_ifindex && ifindex) - return cache_inode_details(inode, details); + return cache_inode_details(inode, details, false); return 1; } static const char * unix_get(struct tcb *tcp, const int fd, const int family, const int proto, - const unsigned long inode, const char *name) + const unsigned long inode, const char *name, bool data) { + if (data) + return NULL; + return unix_send_query(tcp, fd, inode) && receive_responses(tcp, fd, inode, SOCK_DIAG_BY_FAMILY, unix_parse_response, (void *) name) @@ -544,8 +559,11 @@ unix_get(struct tcb *tcp, const int fd, const int family, const int proto, static const char * inet_get(struct tcb *tcp, const int fd, const int family, const int protocol, - const unsigned long inode, const char *proto_name) + const unsigned long inode, const char *proto_name, bool data) { + if (data) + return NULL; + return inet_send_query(tcp, fd, family, protocol) && receive_responses(tcp, fd, inode, SOCK_DIAG_BY_FAMILY, inet_parse_response, (void *) proto_name) @@ -554,21 +572,25 @@ inet_get(struct tcb *tcp, const int fd, const int family, const int protocol, static const char * netlink_get(struct tcb *tcp, const int fd, const int family, const int protocol, - const unsigned long inode, const char *proto_name) + const unsigned long inode, const char *proto_name, bool data) { return netlink_send_query(tcp, fd, inode) && receive_responses(tcp, fd, inode, SOCK_DIAG_BY_FAMILY, netlink_parse_response, (void *) proto_name) - ? get_sockaddr_by_inode_cached(inode) : NULL; + ? (data ? get_sockdata_by_inode_cached + : get_sockaddr_by_inode_cached)(inode) : NULL; } static const char * packet_get(struct tcb *tcp, const int fd, const int family, const int protocol, - const unsigned long inode, const char *proto_name) + const unsigned long inode, const char *proto_name, bool data) { struct packet_cb_data cb_data = { proto_name }; + if (data) + return NULL; + return packet_send_query(tcp, fd, inode) && receive_responses(tcp, fd, inode, SOCK_DIAG_BY_FAMILY, packet_parse_response, @@ -580,9 +602,10 @@ static const struct { const char *const name; const char * (*const get)(struct tcb *, int fd, int family, int protocol, unsigned long inode, - const char *proto_name); + const char *proto_name, bool data); int family; int proto; + bool has_data; } protocols[] = { [SOCK_PROTO_UNIX] = { "UNIX", unix_get, AF_UNIX}, /* @@ -622,7 +645,8 @@ static const struct { { "PINGv6", inet_get, AF_INET6, IPPROTO_ICMP }, [SOCK_PROTO_RAWv6] = { "RAWv6", inet_get, AF_INET6, IPPROTO_RAW }, - [SOCK_PROTO_NETLINK] = { "NETLINK", netlink_get, AF_NETLINK }, + [SOCK_PROTO_NETLINK] = + { "NETLINK", netlink_get, AF_NETLINK, 0, true }, [SOCK_PROTO_AX25] = { "AX25", NULL, AF_AX25 }, [SOCK_PROTO_DDP] = { "DDP", NULL, AF_APPLETALK }, [SOCK_PROTO_NETROM] = { "NETROM", NULL, AF_NETROM }, @@ -654,7 +678,7 @@ get_family_by_proto(enum sock_proto proto) static const char * get_sockaddr_by_inode_uncached(struct tcb *tcp, const unsigned long inode, - const enum sock_proto proto) + const enum sock_proto proto, bool data) { if ((unsigned int) proto >= ARRAY_SIZE(protocols) || (proto != SOCK_PROTO_UNKNOWN && !protocols[proto].get)) @@ -668,7 +692,7 @@ get_sockaddr_by_inode_uncached(struct tcb *tcp, const unsigned long inode, if (proto != SOCK_PROTO_UNKNOWN) { details = protocols[proto].get(tcp, fd, protocols[proto].family, protocols[proto].proto, inode, - protocols[proto].name); + protocols[proto].name, data); } else { unsigned int i; for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1; @@ -679,7 +703,7 @@ get_sockaddr_by_inode_uncached(struct tcb *tcp, const unsigned long inode, protocols[proto].family, protocols[proto].proto, inode, - protocols[proto].name); + protocols[proto].name, data); if (details) break; } @@ -693,7 +717,8 @@ static bool print_sockaddr_by_inode_uncached(struct tcb *tcp, const unsigned long inode, const enum sock_proto proto) { - const char *details = get_sockaddr_by_inode_uncached(tcp, inode, proto); + const char *details = get_sockaddr_by_inode_uncached(tcp, inode, proto, + false); if (details) { tprints(details); @@ -716,7 +741,19 @@ get_sockaddr_by_inode(struct tcb *const tcp, const int fd, { const char *details = get_sockaddr_by_inode_cached(inode); return details ? details : - get_sockaddr_by_inode_uncached(tcp, inode, getfdproto(tcp, fd)); + get_sockaddr_by_inode_uncached(tcp, inode, getfdproto(tcp, fd), + false); +} + +const char * +get_sockdata_by_inode(struct tcb *const tcp, const int fd, + const unsigned long inode) +{ + const char *data = get_sockdata_by_inode_cached(inode); + + return data ? data : + get_sockaddr_by_inode_uncached(tcp, inode, getfdproto(tcp, fd), + true); } /* Given an inode number of a socket, print out its protocol details. */ |
