From patchwork Fri Jan 8 08:32:37 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Colitti X-Patchwork-Id: 564646 X-Patchwork-Delegate: shemminger@vyatta.com Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id EC4341402A0 for ; Fri, 8 Jan 2016 19:32:57 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b=oWnx4V52; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754300AbcAHIcx (ORCPT ); Fri, 8 Jan 2016 03:32:53 -0500 Received: from mail-pa0-f46.google.com ([209.85.220.46]:35047 "EHLO mail-pa0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754287AbcAHIcw (ORCPT ); Fri, 8 Jan 2016 03:32:52 -0500 Received: by mail-pa0-f46.google.com with SMTP id ho8so17949571pac.2 for ; Fri, 08 Jan 2016 00:32:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=2zgDBPxGNFTDBTHtYG/IyHo+n44TwxIymiIY2x9jXP8=; b=oWnx4V52mVjbCB3UlwMrYHOVnthFKsXPVJBcfO4ttoT+0iUMtfdeomj6V5GqSYSits CsxIFwcfjps1+G3uqgFOcFGpM/v4DpTFONlJTEuF6xxCnkqgRzn8QqwJlh2+tRlFjwFE pHJ3zF8jyy0Rqdao7BzbaEjQ88nEcyE71qx14aC8gNfF9HnrTL47Eqm0gGo5b2l2pr25 8+lVkPpKB9Nc3oF6qec5xhz5JKU9e2gmBLMF485zmJRogeIH/Ag7cBLxNetTVfifYxtG CsIDB/q4t4qjtkIyGJ8FlLIsOqkEqSjh3kUcKmKHLC+lBSloAYp0SIhr8DOnZnsiCfCN owPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=2zgDBPxGNFTDBTHtYG/IyHo+n44TwxIymiIY2x9jXP8=; b=gPkOH6L8TqOmwJZZsvmM0LBfKbcv6oHl095M2v7olamXFA7NrN6a/xulhzOiy3ye6Q CyF+1gI6rT3OvyS12BUR9GNhRx0FvLA2KkBNGp2//ZNzs8eFqc/6p6+pq3GFtpVIPh+X 5ok4zXsh1oE1J5j9DS/VatyWfzymy+e5lts5GAMwVtIlu659ZPzvBugifi1E2h3XeK58 rSCdVsGNsjJRzfkPQ+t0O+C4ncmXtvqkU0jMwnBv4mn3kyGpQ8MwOLq5lG26YpcVXtqZ qQzCxXkzLleF138ye5CecvvO25GCTp/V+mErS3CyyLd12kKcbARFR0JrqLUGzvYcfZtF AuQQ== X-Gm-Message-State: ALoCoQnynU27sz6wXCdNq+Oiz1ecuemLITM2OMbzQ4EOgfCbjiRrta4Q7Yc80ugjxI+2kYixbgNdCC9AskWtEdQUDkfudpl8lA== X-Received: by 10.66.156.134 with SMTP id we6mr86387438pab.92.1452241971644; Fri, 08 Jan 2016 00:32:51 -0800 (PST) Received: from flyingsaucer.corp.google.com ([100.102.148.18]) by smtp.gmail.com with ESMTPSA id 68sm2836688pfa.78.2016.01.08.00.32.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 08 Jan 2016 00:32:50 -0800 (PST) From: Lorenzo Colitti To: netdev@vger.kernel.org Cc: stephen@networkplumber.org, eric.dumazet@gmail.com, zenczykowski@gmail.com, Lorenzo Colitti Subject: [iproute PATCH v4 2/2] ss: support closing inet sockets via SOCK_DESTROY. Date: Fri, 8 Jan 2016 17:32:37 +0900 Message-Id: <1452241957-18854-3-git-send-email-lorenzo@google.com> X-Mailer: git-send-email 2.6.0.rc2.230.g3dd15c0 In-Reply-To: <1452241957-18854-1-git-send-email-lorenzo@google.com> References: <1452241957-18854-1-git-send-email-lorenzo@google.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch adds a -K / --kill option to ss that attempts to forcibly close matching sockets using SOCK_DESTROY. Because ss typically prints sockets instead of acting on them, and because the kernel only supports forcibly closing some types of sockets, the output of -K is as follows: - If closing the socket succeeds, the socket is printed. - If the kernel does not support forcibly closing this type of socket (e.g., if it's a UDP socket, or a TIME_WAIT socket), the socket is silently skipped. - If an error occurs (e.g., permission denied), the error is reported and ss exits. Signed-off-by: Lorenzo Colitti --- include/linux/sock_diag.h | 1 + man/man8/ss.8 | 5 +++++ misc/ss.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index 024e1f4..dafcb89 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h @@ -4,6 +4,7 @@ #include #define SOCK_DIAG_BY_FAMILY 20 +#define SOCK_DESTROY 21 struct sock_diag_req { __u8 sdiag_family; diff --git a/man/man8/ss.8 b/man/man8/ss.8 index f4d5264..758460c 100644 --- a/man/man8/ss.8 +++ b/man/man8/ss.8 @@ -48,6 +48,11 @@ Show process using socket. .B \-i, \-\-info Show internal TCP information. .TP +.B \-K, \-\-kill +Attempts to forcibly close sockets. This option displays sockets that are +successfully closed and silently skips sockets that the kernel does not support +closing. It supports IPv4 and IPv6 sockets only. +.TP .B \-s, \-\-summary Print summary statistics. This option does not parse socket lists obtaining summary from various sources. It is useful when amount of sockets is so huge diff --git a/misc/ss.c b/misc/ss.c index 0dab32c..13fcc8f 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -160,6 +160,7 @@ struct filter int states; int families; struct ssfilter *f; + bool kill; }; static const struct filter default_dbs[MAX_DB] = { @@ -2194,8 +2195,27 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) struct inet_diag_arg { struct filter *f; int protocol; + struct rtnl_handle *rth; }; +static int kill_inet_sock(const struct sockaddr_nl *addr, + struct nlmsghdr *h, void *arg) +{ + struct inet_diag_msg *d = NLMSG_DATA(h); + struct inet_diag_arg *diag_arg = arg; + struct rtnl_handle *rth = diag_arg->rth; + DIAG_REQUEST(req, struct inet_diag_req_v2 r); + + req.nlh.nlmsg_type = SOCK_DESTROY; + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.nlh.nlmsg_seq = ++rth->seq; + req.r.sdiag_family = d->idiag_family; + req.r.sdiag_protocol = diag_arg->protocol; + req.r.id = d->id; + + return rtnl_talk(rth, &req.nlh, NULL, 0); +} + static int show_one_inet_sock(const struct sockaddr_nl *addr, struct nlmsghdr *h, void *arg) { @@ -2205,6 +2225,15 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, if (!(diag_arg->f->families & (1 << r->idiag_family))) return 0; + if (diag_arg->f->kill && kill_inet_sock(addr, h, arg) != 0) { + if (errno == EOPNOTSUPP || errno == ENOENT) { + /* Socket can't be closed, or is already closed. */ + return 0; + } else { + perror("SOCK_DESTROY answers"); + return -1; + } + } if ((err = inet_show_sock(h, diag_arg->f, diag_arg->protocol)) < 0) return err; @@ -2214,12 +2243,21 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol) { int err = 0; - struct rtnl_handle rth; + struct rtnl_handle rth, rth2; int family = PF_INET; struct inet_diag_arg arg = { .f = f, .protocol = protocol }; if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG)) return -1; + + if (f->kill) { + if (rtnl_open_byproto(&rth2, 0, NETLINK_SOCK_DIAG)) { + rtnl_close(&rth); + return -1; + } + arg.rth = &rth2; + } + rth.dump = MAGIC_SEQ; rth.dump_fp = dump_fp; if (preferred_family == PF_INET6) @@ -2243,6 +2281,8 @@ again: Exit: rtnl_close(&rth); + if (arg.rth) + rtnl_close(arg.rth); return err; } @@ -3489,6 +3529,8 @@ static void _usage(FILE *dest) " -x, --unix display only Unix domain sockets\n" " -f, --family=FAMILY display sockets of type FAMILY\n" "\n" +" -K, --kill forcibly close sockets, display what was closed\n" +"\n" " -A, --query=QUERY, --socket=QUERY\n" " QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]\n" "\n" @@ -3579,6 +3621,7 @@ static const struct option long_opts[] = { { "context", 0, 0, 'Z' }, { "contexts", 0, 0, 'z' }, { "net", 1, 0, 'N' }, + { "kill", 0, 0, 'K' }, { 0 } }; @@ -3593,7 +3636,7 @@ int main(int argc, char *argv[]) int ch; int state_filter = 0; - while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:", + while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:K", long_opts, NULL)) != EOF) { switch(ch) { case 'n': @@ -3774,6 +3817,9 @@ int main(int argc, char *argv[]) if (netns_switch(optarg)) exit(1); break; + case 'K': + current_filter.kill = 1; + break; case 'h': help(); case '?':