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/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 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; 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(); 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/lib/rt_names.c b/lib/rt_names.c index 369e0f4e..e87c65da 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,7 +196,6 @@ int rtnl_rtprot_a2n(__u32 *id, const char *arg) return 0; } - static char * rtnl_rtscope_tab[256] = { "global", }; @@ -469,7 +479,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); } 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); diff --git a/misc/ss.c b/misc/ss.c index a99294dc..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), \ }, \ } @@ -101,8 +103,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"; @@ -1231,16 +1231,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; } @@ -1777,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; @@ -1937,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) @@ -2422,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]; @@ -2512,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); @@ -2605,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) @@ -2619,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) @@ -2693,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]; @@ -2786,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); } @@ -2811,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) @@ -2912,10 +2845,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 +2881,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; @@ -2982,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; @@ -3016,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); @@ -3024,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) @@ -3038,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) @@ -3684,22 +3619,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<