From 2ec28933b6cdeaf98ad8d3d6e9471b50bac91223 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 4 Dec 2014 17:41:07 +0100 Subject: [PATCH 01/12] ipaddress: enable -details option This option was used only for 'ip link', but it can be useful to have it for 'ip address'. Thus it is possible to display link details and addresses with one command. Example: $ ip -d a ls dev gre1 9: gre1@NONE: mtu 1468 qdisc noqueue state UNKNOWN group default link/gre 10.16.0.249 peer 10.16.0.121 promiscuity 0 gre remote 10.16.0.121 local 10.16.0.249 ttl inherit ikey 0.0.0.10 okey 0.0.0.10 icsum ocsum inet 192.168.0.249 peer 192.168.0.121/32 scope global gre1 valid_lft forever preferred_lft forever inet6 fe80::5efe:a10:f9/64 scope link valid_lft forever preferred_lft forever Suggested-by: Christophe Gouault Signed-off-by: Nicolas Dichtel --- ip/ipaddress.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 4d993243..221ae1fc 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -604,7 +604,7 @@ int print_linkinfo(const struct sockaddr_nl *who, if (filter.showqueue) print_queuelen(fp, tb); - if (!filter.family || filter.family == AF_PACKET) { + if (!filter.family || filter.family == AF_PACKET || show_details) { SPRINT_BUF(b1); fprintf(fp, "%s", _SL_); fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); @@ -627,14 +627,14 @@ int print_linkinfo(const struct sockaddr_nl *who, } } - if (do_link && tb[IFLA_PROMISCUITY] && show_details) + if (tb[IFLA_PROMISCUITY] && show_details) fprintf(fp, " promiscuity %u ", *(int*)RTA_DATA(tb[IFLA_PROMISCUITY])); - if (do_link && tb[IFLA_LINKINFO] && show_details) + if (tb[IFLA_LINKINFO] && show_details) print_linktype(fp, tb[IFLA_LINKINFO]); - if (do_link && tb[IFLA_IFALIAS]) { + if ((do_link || show_details) && tb[IFLA_IFALIAS]) { fprintf(fp, "%s alias %s", _SL_, rta_getattr_str(tb[IFLA_IFALIAS])); } @@ -644,7 +644,7 @@ int print_linkinfo(const struct sockaddr_nl *who, __print_link_stats(fp, tb); } - if (do_link && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) { + if ((do_link || show_details) && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) { struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST]; int rem = RTA_PAYLOAD(vflist); for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) From 6fcabac5e0f80cb7dac5ff805809fb1efcb12a10 Mon Sep 17 00:00:00 2001 From: vadimk Date: Fri, 5 Dec 2014 02:18:59 +0200 Subject: [PATCH 02/12] ip monitor: Fix issue when timestamp is printed w/o msg The issue was observed when IPv6 router broadcasted NDUSEROPT messages which are not handled by monitor and caused printing 'Timestamps' w/o message because such kind of rtnl messages is not handled by monitor. As 'ip monitor' by default subscribes to the all mcast rtnl groups except RTGRP_TC then all messages of these rtnl groups which are not handled by monitor may cause such issues. Fixed by subscribing by default to rtnl mcast groups which are supported by 'ip monitor'. Signed-off-by: Vadim Kochan --- ip/ipmonitor.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c index 4cc75f4c..4708e54d 100644 --- a/ip/ipmonitor.c +++ b/ip/ipmonitor.c @@ -134,14 +134,6 @@ static int accept_msg(const struct sockaddr_nl *who, fprintf(fp, "Timestamp: %s %lu us\n", tstr, usecs); return 0; } - if (n->nlmsg_type == RTM_NEWQDISC || - n->nlmsg_type == RTM_DELQDISC || - n->nlmsg_type == RTM_NEWTCLASS || - n->nlmsg_type == RTM_DELTCLASS || - n->nlmsg_type == RTM_NEWTFILTER || - n->nlmsg_type == RTM_DELTFILTER || - n->nlmsg_type == RTM_NEWNDUSEROPT) - return 0; if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP && n->nlmsg_type != NLMSG_DONE) { fprintf(fp, "Unknown message: type=0x%08x(%d) flags=0x%08x(%d)" @@ -155,7 +147,7 @@ static int accept_msg(const struct sockaddr_nl *who, int do_ipmonitor(int argc, char **argv) { char *file = NULL; - unsigned groups = ~RTMGRP_TC; + unsigned groups = 0; int llink=0; int laddr=0; int lroute=0; @@ -165,6 +157,18 @@ int do_ipmonitor(int argc, char **argv) int lnetconf=0; int ifindex=0; + groups |= nl_mgrp(RTNLGRP_LINK); + groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR); + groups |= nl_mgrp(RTNLGRP_IPV6_IFADDR); + groups |= nl_mgrp(RTNLGRP_IPV4_ROUTE); + groups |= nl_mgrp(RTNLGRP_IPV6_ROUTE); + groups |= nl_mgrp(RTNLGRP_IPV4_MROUTE); + groups |= nl_mgrp(RTNLGRP_IPV6_MROUTE); + groups |= nl_mgrp(RTNLGRP_IPV6_PREFIX); + groups |= nl_mgrp(RTNLGRP_NEIGH); + groups |= nl_mgrp(RTNLGRP_IPV4_NETCONF); + groups |= nl_mgrp(RTNLGRP_IPV6_NETCONF); + rtnl_close(&rth); while (argc > 0) { @@ -195,7 +199,6 @@ int do_ipmonitor(int argc, char **argv) lnetconf = 1; groups = 0; } else if (strcmp(*argv, "all") == 0) { - groups = ~RTMGRP_TC; prefix_banner=1; } else if (matches(*argv, "help") == 0) { usage(); From 9d2c16438cdec360d8a2ec214bc455f4a392b718 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Dec 2014 20:19:26 -0800 Subject: [PATCH 03/12] if_bridge: remove in6.h Adding in6.h breaks build with redefined values. --- include/linux/if_bridge.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index ed6868ec..d2de4e67 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -15,7 +15,6 @@ #include #include -#include #define SYSFS_BRIDGE_ATTR "bridge" #define SYSFS_BRIDGE_FDB "brforward" From d68e00f704c19aee1419c56eced3a8e8e7157e35 Mon Sep 17 00:00:00 2001 From: vadimk Date: Fri, 5 Dec 2014 19:19:11 +0200 Subject: [PATCH 04/12] ss: Fix layout/output issues introduced by regression This patch fixes the following issues which was introduced by me in commits: #1 (2dc854854b7f1b) ss: Fixed broken output for Netlink 'Peer Address:Port' column ISSUE: Broken layout when all sockets are printed out #2 (eef43b5052afb7) ss: Identify more netlink protocol names ISSUE: Protocol id is not printed if 'numbers only' output was specified (-n) Also aligned the width of the local/peer ports to be more wider. I tested with a lot of option combinations (I may miss some test cases), but layout seems to me better than the previous released version of iproute2/ss. Signed-off-by: Vadim Kochan --- misc/ss.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index a99294dc..c9733a77 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -101,8 +101,6 @@ int state_width; int addrp_width; int addr_width; int serv_width; -int paddr_width; -int pserv_width; int screen_width; static const char *TCP_PROTO = "tcp"; @@ -2912,10 +2910,11 @@ static void netlink_show_one(struct filter *f, printf("%-*s ", state_width, "UNCONN"); printf("%-6d %-6d ", rq, wq); - if (resolve_services) - { + if (resolve_services) { printf("%*s:", addr_width, nl_proto_n2a(prot, prot_name, sizeof(prot_name))); + } else { + printf("%*d:", addr_width, prot); } if (pid == -1) { @@ -2947,10 +2946,10 @@ static void netlink_show_one(struct filter *f, if (state == NETLINK_CONNECTED) { printf("%*d:%-*d", - paddr_width, dst_group, pserv_width, dst_pid); + addr_width, dst_group, serv_width, dst_pid); } else { printf("%*s*%-*s", - paddr_width, "", pserv_width, ""); + addr_width, "", serv_width, ""); } char *pid_context = NULL; @@ -3684,22 +3683,13 @@ int main(int argc, char *argv[]) printf("%-*s ", state_width, "State"); printf("%-6s %-6s ", "Recv-Q", "Send-Q"); - paddr_width = addr_width; - pserv_width = serv_width; - - /* Netlink service column can be resolved as process name/pid thus it - * can be much wider than address column which is just a - * protocol name/id. - */ - if (current_filter.dbs & (1< Date: Fri, 5 Dec 2014 18:10:08 -0800 Subject: [PATCH 05/12] iproute2/nstat: Bug in displaying icmp stats On Fri, 2014-12-05 at 17:13 -0800, Eric Dumazet wrote: > I guess we could count number of spaces/fields in both lines, > and disable the iproute2 trick if counts match. Something like that maybe ? misc/nstat.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) Tested-by: Vijay Subramanian --- misc/nstat.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/misc/nstat.c b/misc/nstat.c index e54b3ae7..c2cb0564 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -156,6 +156,15 @@ static void load_good_table(FILE *fp) } } +static int count_spaces(const char *line) +{ + int count = 0; + char c; + + while ((c = *line++) != 0) + count += c == ' ' || c == '\n'; + return count; +} static void load_ugly_table(FILE *fp) { @@ -167,10 +176,12 @@ static void load_ugly_table(FILE *fp) char idbuf[sizeof(buf)]; int off; char *p; + int count1, count2, skip = 0; p = strchr(buf, ':'); if (!p) abort(); + count1 = count_spaces(buf); *p = 0; idbuf[0] = 0; strncat(idbuf, buf, sizeof(idbuf) - 1); @@ -199,6 +210,9 @@ static void load_ugly_table(FILE *fp) n = db; if (fgets(buf, sizeof(buf), fp) == NULL) abort(); + count2 = count_spaces(buf); + if (count2 > count1) + skip = count2 - count1; do { p = strrchr(buf, ' '); if (!p) @@ -207,8 +221,8 @@ static void load_ugly_table(FILE *fp) if (sscanf(p+1, "%llu", &n->val) != 1) abort(); /* Trick to skip "dummy" trailing ICMP MIB in 2.4 */ - if (strcmp(idbuf, "IcmpOutAddrMaskReps") == 0) - idbuf[5] = 0; + if (skip) + skip--; else n = n->next; } while (p > buf + off + 2); From d26caee7e9a1ccd83ac1cf047b2337163ae1c12c Mon Sep 17 00:00:00 2001 From: Nikita Edward Baruzdin Date: Fri, 5 Dec 2014 11:41:42 +0300 Subject: [PATCH 06/12] iproute2: Add support for CAN presume-ack feature This patch makes CAN_CTRLMODE_PRESUME_ACK netlink feature configurable. When enabled, the feature sets CAN controller in mode in which acknowledgement absence is ignored. Signed-off-by: Nikita Edward Baruzdin Acked-by: Oliver Hartkopp --- ip/iplink_can.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ip/iplink_can.c b/ip/iplink_can.c index 5b924265..fb503321 100644 --- a/ip/iplink_can.c +++ b/ip/iplink_can.c @@ -37,6 +37,7 @@ static void print_usage(FILE *f) "\t[ one-shot { on | off } ]\n" "\t[ berr-reporting { on | off } ]\n" "\t[ fd { on | off } ]\n" + "\t[ presume-ack { on | off } ]\n" "\n" "\t[ restart-ms TIME-MS ]\n" "\t[ restart ]\n" @@ -99,6 +100,7 @@ static void print_ctrlmode(FILE *f, __u32 cm) _PF(CAN_CTRLMODE_ONE_SHOT, "ONE-SHOT"); _PF(CAN_CTRLMODE_BERR_REPORTING, "BERR-REPORTING"); _PF(CAN_CTRLMODE_FD, "FD"); + _PF(CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK"); #undef _PF if (cm) fprintf(f, "%x", cm); @@ -201,6 +203,10 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); set_ctrlmode("fd", *argv, &cm, CAN_CTRLMODE_FD); + } else if (matches(*argv, "presume-ack") == 0) { + NEXT_ARG(); + set_ctrlmode("presume-ack", *argv, &cm, + CAN_CTRLMODE_PRESUME_ACK); } else if (matches(*argv, "restart") == 0) { __u32 val = 1; From 4e5615b34ce7f952f0302d851884c1cf21352bb8 Mon Sep 17 00:00:00 2001 From: vadimk Date: Sat, 6 Dec 2014 04:05:11 +0200 Subject: [PATCH 07/12] lib names: Use CONFDIR for specify 'group' file path Signed-off-by: Vadim Kochan --- lib/rt_names.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rt_names.c b/lib/rt_names.c index 369e0f4e..e6a1e013 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -469,7 +469,7 @@ static int rtnl_group_init; static void rtnl_group_initialize(void) { rtnl_group_init = 1; - rtnl_hash_initialize("/etc/iproute2/group", + rtnl_hash_initialize(CONFDIR "/group", rtnl_group_hash, 256); } From f00073e8b99385184d2dd2c6b4989b2ade49de96 Mon Sep 17 00:00:00 2001 From: vadimk Date: Sat, 6 Dec 2014 04:05:12 +0200 Subject: [PATCH 08/12] lib names: Add helper func for parse id and name from file Signed-off-by: Vadim Kochan --- lib/rt_names.c | 72 ++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/lib/rt_names.c b/lib/rt_names.c index e6a1e013..1698036b 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -27,43 +27,63 @@ #define CONFDIR "/etc/iproute2" #endif +#define NAME_MAX_LEN 512 + struct rtnl_hash_entry { struct rtnl_hash_entry *next; const char * name; unsigned int id; }; +static int fread_id_name(FILE *fp, int *id, char *namebuf) +{ + char buf[NAME_MAX_LEN]; + + while (fgets(buf, sizeof(buf), fp)) { + char *p = buf; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p == '#' || *p == '\n' || *p == 0) + continue; + + if (sscanf(p, "0x%x %s\n", id, namebuf) != 2 && + sscanf(p, "0x%x %s #", id, namebuf) != 2 && + sscanf(p, "%d %s\n", id, namebuf) != 2 && + sscanf(p, "%d %s #", id, namebuf) != 2) { + strcpy(namebuf, p); + return -1; + } + return 1; + } + return 0; +} + static void rtnl_hash_initialize(const char *file, struct rtnl_hash_entry **hash, int size) { struct rtnl_hash_entry *entry; - char buf[512]; FILE *fp; + int id; + char namebuf[NAME_MAX_LEN] = {0}; + int ret; fp = fopen(file, "r"); if (!fp) return; - while (fgets(buf, sizeof(buf), fp)) { - char *p = buf; - int id; - char namebuf[512]; - while (*p == ' ' || *p == '\t') - p++; - if (*p == '#' || *p == '\n' || *p == 0) - continue; - if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 && - sscanf(p, "0x%x %s #", &id, namebuf) != 2 && - sscanf(p, "%d %s\n", &id, namebuf) != 2 && - sscanf(p, "%d %s #", &id, namebuf) != 2) { + while ((ret = fread_id_name(fp, &id, &namebuf[0]))) { + if (ret == -1) { fprintf(stderr, "Database %s is corrupted at %s\n", - file, p); + file, namebuf); fclose(fp); return; } if (id<0) continue; + entry = malloc(sizeof(*entry)); entry->id = id; entry->name = strdup(namebuf); @@ -75,31 +95,22 @@ rtnl_hash_initialize(const char *file, struct rtnl_hash_entry **hash, int size) static void rtnl_tab_initialize(const char *file, char **tab, int size) { - char buf[512]; FILE *fp; + int id; + char namebuf[NAME_MAX_LEN] = {0}; + int ret; fp = fopen(file, "r"); if (!fp) return; - while (fgets(buf, sizeof(buf), fp)) { - char *p = buf; - int id; - char namebuf[512]; - while (*p == ' ' || *p == '\t') - p++; - if (*p == '#' || *p == '\n' || *p == 0) - continue; - if (sscanf(p, "0x%x %s\n", &id, namebuf) != 2 && - sscanf(p, "0x%x %s #", &id, namebuf) != 2 && - sscanf(p, "%d %s\n", &id, namebuf) != 2 && - sscanf(p, "%d %s #", &id, namebuf) != 2) { + while ((ret = fread_id_name(fp, &id, &namebuf[0]))) { + if (ret == -1) { fprintf(stderr, "Database %s is corrupted at %s\n", - file, p); + file, namebuf); fclose(fp); return; } - if (id<0 || id>size) continue; @@ -185,8 +196,7 @@ int rtnl_rtprot_a2n(__u32 *id, const char *arg) return 0; } - -static char * rtnl_rtscope_tab[256] = { +static const char * rtnl_rtscope_tab[256] = { "global", }; From b00daf6a839cb761e9df6bdb8dd4927a8c5b06f6 Mon Sep 17 00:00:00 2001 From: vadimk Date: Sat, 6 Dec 2014 02:52:19 +0200 Subject: [PATCH 09/12] ss: Use nl_proto_a2n for filtering by netlink proto Now it is posible to filter by existing Netlink protos: ss -A netlink src uevent ss -A netlink src nft ss -A netlink src genl Signed-off-by: Vadim Kochan --- misc/ss.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index c9733a77..e9927a50 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1229,16 +1229,8 @@ void *parse_hostcond(char *addr) } if (addr[0] && strcmp(addr, "*")) { a.addr.bitlen = 32; - if (get_u32(a.addr.data, addr, 0)) { - if (strcmp(addr, "rtnl") == 0) - a.addr.data[0] = 0; - else if (strcmp(addr, "fw") == 0) - a.addr.data[0] = 3; - else if (strcmp(addr, "tcpdiag") == 0) - a.addr.data[0] = 4; - else - return NULL; - } + if (nl_proto_a2n(&a.addr.data[0], addr) == -1) + return NULL; } goto out; } From b0d30f7f3f17cbd54c0806cfda921b416e6a6749 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 20 Dec 2014 11:36:54 -0800 Subject: [PATCH 10/12] rt_names can't be const Needs to be built at runtime. --- lib/rt_names.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rt_names.c b/lib/rt_names.c index 1698036b..e87c65da 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -196,7 +196,7 @@ int rtnl_rtprot_a2n(__u32 *id, const char *arg) return 0; } -static const char * rtnl_rtscope_tab[256] = { +static char * rtnl_rtscope_tab[256] = { "global", }; From 8a504fc35660aa46003b2b68dd3a8777bf77179a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 20 Dec 2014 12:12:34 -0800 Subject: [PATCH 11/12] resolve header file conflict betwen linux/in6.h and netinet/in.h Go back to kernel version of if_bridge.h and use patched version of linux/in6.h and libc-compat.h --- include/linux/if_bridge.h | 1 + include/linux/in6.h | 3 ++- include/linux/libc-compat.h | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index d2de4e67..ed6868ec 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -15,6 +15,7 @@ #include #include +#include #define SYSFS_BRIDGE_ATTR "bridge" #define SYSFS_BRIDGE_FDB "brforward" diff --git a/include/linux/in6.h b/include/linux/in6.h index cc99dc5c..994f4c22 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -149,7 +149,7 @@ struct in6_flowlabel_req { /* * IPV6 socket options */ - +#if __UAPI_DEF_IPV6_OPTIONS #define IPV6_ADDRFORM 1 #define IPV6_2292PKTINFO 2 #define IPV6_2292HOPOPTS 3 @@ -196,6 +196,7 @@ struct in6_flowlabel_req { #define IPV6_IPSEC_POLICY 34 #define IPV6_XFRM_POLICY 35 +#endif /* * Multicast: diff --git a/include/linux/libc-compat.h b/include/linux/libc-compat.h index 629e1046..9e860a0c 100644 --- a/include/linux/libc-compat.h +++ b/include/linux/libc-compat.h @@ -69,6 +69,7 @@ #define __UAPI_DEF_SOCKADDR_IN6 0 #define __UAPI_DEF_IPV6_MREQ 0 #define __UAPI_DEF_IPPROTO_V6 0 +#define __UAPI_DEF_IPV6_OPTIONS 0 #else @@ -82,6 +83,7 @@ #define __UAPI_DEF_SOCKADDR_IN6 1 #define __UAPI_DEF_IPV6_MREQ 1 #define __UAPI_DEF_IPPROTO_V6 1 +#define __UAPI_DEF_IPV6_OPTIONS 1 #endif /* _NETINET_IN_H */ @@ -103,6 +105,7 @@ #define __UAPI_DEF_SOCKADDR_IN6 1 #define __UAPI_DEF_IPV6_MREQ 1 #define __UAPI_DEF_IPPROTO_V6 1 +#define __UAPI_DEF_IPV6_OPTIONS 1 /* Definitions for xattr.h */ #define __UAPI_DEF_XATTR 1 From 8a4025f6a4e182f0f33763238314ff1d96c580db Mon Sep 17 00:00:00 2001 From: vadimk Date: Thu, 4 Dec 2014 12:32:58 +0200 Subject: [PATCH 12/12] ss: Use rtnl_dump_filter in handle_netlink_request Replaced handling netlink messages by rtnl_dump_filter from lib/libnetlink.c, also: - removed unused dump_fp arg; - added MAGIC_SEQ #define for 123456 seq id; - silently exit if ENOENT errno is caused for NETLINK_SOCK_DIAG proto in lib/libnetlink.c: rtnl_duml_filter_l(...) function. This fix was added in a3fd8e58c1787af186f5c4b234ff974544f840b6 by Eric for misc/ss.c Signed-off-by: Vadim Kochan --- include/libnetlink.h | 1 + lib/libnetlink.c | 5 ++ misc/ss.c | 128 ++++++++++++------------------------------- 3 files changed, 42 insertions(+), 92 deletions(-) diff --git a/include/libnetlink.h b/include/libnetlink.h index fe7d5d38..3794ef1b 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -18,6 +18,7 @@ struct rtnl_handle struct sockaddr_nl peer; __u32 seq; __u32 dump; + int proto; }; extern int rcvbuf; diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 8d504a9e..e3b7862c 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -43,6 +43,7 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, memset(rth, 0, sizeof(*rth)); + rth->proto = protocol; rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); if (rth->fd < 0) { perror("Cannot open netlink socket"); @@ -245,6 +246,10 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, "ERROR truncated\n"); } else { errno = -err->error; + if (rth->proto == NETLINK_SOCK_DIAG && + errno == ENOENT) + return -1; + perror("RTNETLINK answers"); } return -1; diff --git a/misc/ss.c b/misc/ss.c index e9927a50..15fa2bc5 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -41,6 +41,8 @@ #include #include +#define MAGIC_SEQ 123456 + #define DIAG_REQUEST(_req, _r) \ struct { \ struct nlmsghdr nlh; \ @@ -49,7 +51,7 @@ .nlh = { \ .nlmsg_type = SOCK_DIAG_BY_FAMILY, \ .nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST,\ - .nlmsg_seq = 123456, \ + .nlmsg_seq = MAGIC_SEQ, \ .nlmsg_len = sizeof(_req), \ }, \ } @@ -1767,7 +1769,7 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) req.nlh.nlmsg_type = DCCPDIAG_GETSOCK; req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = 123456; + req.nlh.nlmsg_seq = MAGIC_SEQ; memset(&req.r, 0, sizeof(req.r)); req.r.idiag_family = AF_INET; req.r.idiag_states = f->states; @@ -1927,7 +1929,7 @@ again: struct inet_diag_msg *r = NLMSG_DATA(h); if (/*h->nlmsg_pid != rth->local.nl_pid ||*/ - h->nlmsg_seq != 123456) + h->nlmsg_seq != MAGIC_SEQ) goto skip_it; if (h->nlmsg_type == NLMSG_DONE) @@ -2412,8 +2414,10 @@ static void unix_list_print(struct unixstat *list, struct filter *f) } } -static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f) +static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, + void *arg) { + struct filter *f = (struct filter *)arg; struct unix_diag_msg *r = NLMSG_DATA(nlh); struct rtattr *tb[UNIX_DIAG_MAX+1]; char name[128]; @@ -2502,90 +2506,30 @@ static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f) return 0; } -static int handle_netlink_request(struct filter *f, FILE *dump_fp, - struct nlmsghdr *req, size_t size, - int (* show_one_sock)(struct nlmsghdr *nlh, struct filter *f)) +static int handle_netlink_request(struct filter *f, struct nlmsghdr *req, + size_t size, rtnl_filter_t show_one_sock) { - int fd; - char buf[16384]; + int ret = -1; + struct rtnl_handle rth; - if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0) + if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG)) return -1; - if (send(fd, req, size, 0) < 0) { - close(fd); - return -1; - } + rth.dump = MAGIC_SEQ; - while (1) { - ssize_t status; - struct nlmsghdr *h; - struct sockaddr_nl nladdr; - socklen_t slen = sizeof(nladdr); + if (rtnl_send(&rth, req, size) < 0) + goto Exit; - status = recvfrom(fd, buf, sizeof(buf), 0, - (struct sockaddr *) &nladdr, &slen); - if (status < 0) { - if (errno == EINTR) - continue; - perror("OVERRUN"); - continue; - } - if (status == 0) { - fprintf(stderr, "EOF on netlink\n"); - goto close_it; - } + if (rtnl_dump_filter(&rth, show_one_sock, f)) + goto Exit; - if (dump_fp) - fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp); - - h = (struct nlmsghdr*)buf; - while (NLMSG_OK(h, status)) { - int err; - - if (/*h->nlmsg_pid != rth->local.nl_pid ||*/ - h->nlmsg_seq != 123456) - goto skip_it; - - if (h->nlmsg_type == NLMSG_DONE) - goto close_it; - - if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); - if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { - fprintf(stderr, "ERROR truncated\n"); - } else { - errno = -err->error; - if (errno != ENOENT) - fprintf(stderr, "DIAG answers %d\n", errno); - } - close(fd); - return -1; - } - if (!dump_fp) { - err = show_one_sock(h, f); - if (err < 0) { - close(fd); - return err; - } - } - -skip_it: - h = NLMSG_NEXT(h, status); - } - - if (status) { - fprintf(stderr, "!!!Remnant of size %zd\n", status); - exit(1); - } - } - -close_it: - close(fd); - return 0; + ret = 0; +Exit: + rtnl_close(&rth); + return ret; } -static int unix_show_netlink(struct filter *f, FILE *dump_fp) +static int unix_show_netlink(struct filter *f) { DIAG_REQUEST(req, struct unix_diag_req r); @@ -2595,8 +2539,7 @@ static int unix_show_netlink(struct filter *f, FILE *dump_fp) if (show_mem) req.r.udiag_show |= UDIAG_SHOW_MEMINFO; - return handle_netlink_request(f, dump_fp, &req.nlh, - sizeof(req), unix_show_sock); + return handle_netlink_request(f, &req.nlh, sizeof(req), unix_show_sock); } static int unix_show(struct filter *f) @@ -2609,7 +2552,7 @@ static int unix_show(struct filter *f) struct unixstat *list = NULL; if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT") - && unix_show_netlink(f, NULL) == 0) + && unix_show_netlink(f) == 0) return 0; if ((fp = net_unix_open()) == NULL) @@ -2683,7 +2626,8 @@ static int unix_show(struct filter *f) return 0; } -static int packet_show_sock(struct nlmsghdr *nlh, struct filter *f) +static int packet_show_sock(const struct sockaddr_nl *addr, + struct nlmsghdr *nlh, void *arg) { struct packet_diag_msg *r = NLMSG_DATA(nlh); struct rtattr *tb[PACKET_DIAG_MAX+1]; @@ -2776,15 +2720,14 @@ static int packet_show_sock(struct nlmsghdr *nlh, struct filter *f) return 0; } -static int packet_show_netlink(struct filter *f, FILE *dump_fp) +static int packet_show_netlink(struct filter *f) { DIAG_REQUEST(req, struct packet_diag_req r); req.r.sdiag_family = AF_PACKET; req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO | PACKET_SHOW_FILTER; - return handle_netlink_request(f, dump_fp, &req.nlh, sizeof(req), - packet_show_sock); + return handle_netlink_request(f, &req.nlh, sizeof(req), packet_show_sock); } @@ -2801,7 +2744,7 @@ static int packet_show(struct filter *f) int ino; unsigned long long sk; - if (packet_show_netlink(f, NULL) == 0) + if (packet_show_netlink(f) == 0) return 0; if ((fp = net_packet_open()) == NULL) @@ -2973,8 +2916,10 @@ static void netlink_show_one(struct filter *f, return; } -static int netlink_show_sock(struct nlmsghdr *nlh, struct filter *f) +static int netlink_show_sock(const struct sockaddr_nl *addr, + struct nlmsghdr *nlh, void *arg) { + struct filter *f = (struct filter *)arg; struct netlink_diag_msg *r = NLMSG_DATA(nlh); struct rtattr *tb[NETLINK_DIAG_MAX+1]; int rq = 0, wq = 0; @@ -3007,7 +2952,7 @@ static int netlink_show_sock(struct nlmsghdr *nlh, struct filter *f) return 0; } -static int netlink_show_netlink(struct filter *f, FILE *dump_fp) +static int netlink_show_netlink(struct filter *f) { DIAG_REQUEST(req, struct netlink_diag_req r); @@ -3015,8 +2960,7 @@ static int netlink_show_netlink(struct filter *f, FILE *dump_fp) req.r.sdiag_protocol = NDIAG_PROTO_ALL; req.r.ndiag_show = NDIAG_SHOW_GROUPS | NDIAG_SHOW_MEMINFO; - return handle_netlink_request(f, dump_fp, &req.nlh, - sizeof(req), netlink_show_sock); + return handle_netlink_request(f, &req.nlh, sizeof(req), netlink_show_sock); } static int netlink_show(struct filter *f) @@ -3029,7 +2973,7 @@ static int netlink_show(struct filter *f) unsigned long long sk, cb; if (!getenv("PROC_NET_NETLINK") && !getenv("PROC_ROOT") && - netlink_show_netlink(f, NULL) == 0) + netlink_show_netlink(f) == 0) return 0; if ((fp = net_netlink_open()) == NULL)