aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2016-09-14 01:58:55 +0900
committerMaciej Zenczykowski <maze@google.com>2016-09-23 04:44:56 +0000
commitd4db01bf3fe57ba65af116cfa399f89f90002ba7 (patch)
treef35c1a92fdf0b707b4812a898c83521c3733c082
parentfb80ac03aff71033570e1b13cd52bdfa9e60e6a0 (diff)
downloadiproute2-nougat-mr1.2-release.tar.gz
ss: Support displaying and filtering on socket marks.android-cts_7.1_r1android-cts-7.1_r9android-cts-7.1_r8android-cts-7.1_r7android-cts-7.1_r6android-cts-7.1_r5android-cts-7.1_r4android-cts-7.1_r3android-cts-7.1_r29android-cts-7.1_r28android-cts-7.1_r27android-cts-7.1_r26android-cts-7.1_r25android-cts-7.1_r24android-cts-7.1_r23android-cts-7.1_r22android-cts-7.1_r21android-cts-7.1_r20android-cts-7.1_r2android-cts-7.1_r19android-cts-7.1_r18android-cts-7.1_r17android-cts-7.1_r16android-cts-7.1_r15android-cts-7.1_r14android-cts-7.1_r13android-cts-7.1_r12android-cts-7.1_r11android-cts-7.1_r10android-cts-7.1_r1android-7.1.1_r9android-7.1.1_r8android-7.1.1_r7android-7.1.1_r61android-7.1.1_r60android-7.1.1_r6android-7.1.1_r59android-7.1.1_r58android-7.1.1_r57android-7.1.1_r56android-7.1.1_r55android-7.1.1_r54android-7.1.1_r53android-7.1.1_r52android-7.1.1_r51android-7.1.1_r50android-7.1.1_r49android-7.1.1_r48android-7.1.1_r47android-7.1.1_r46android-7.1.1_r45android-7.1.1_r44android-7.1.1_r43android-7.1.1_r42android-7.1.1_r41android-7.1.1_r40android-7.1.1_r4android-7.1.1_r39android-7.1.1_r38android-7.1.1_r35android-7.1.1_r33android-7.1.1_r32android-7.1.1_r31android-7.1.1_r3android-7.1.1_r28android-7.1.1_r27android-7.1.1_r26android-7.1.1_r25android-7.1.1_r24android-7.1.1_r23android-7.1.1_r22android-7.1.1_r21android-7.1.1_r20android-7.1.1_r2android-7.1.1_r17android-7.1.1_r16android-7.1.1_r15android-7.1.1_r14android-7.1.1_r13android-7.1.1_r12android-7.1.1_r11android-7.1.1_r10android-7.1.1_r1nougat-mr1.8-releasenougat-mr1.7-releasenougat-mr1.6-releasenougat-mr1.5-releasenougat-mr1.4-releasenougat-mr1.3-releasenougat-mr1.2-releasenougat-mr1.1-releasenougat-mr1-volantis-releasenougat-mr1-security-releasenougat-mr1-releasenougat-mr1-flounder-releasenougat-mr1-devnougat-mr1-cts-release
This allows the user to dump sockets with a given mark (via "fwmark = 0x1234/0x1234" or "fwmark = 12345", etc.) , and to display the socket marks of dumped sockets. The relevant kernel commits are: d545caca827b ("net: inet: diag: expose the socket mark to privileged processes.") and - a52e95abf772 ("net: diag: allow socket bytecode filters to match socket marks") Signed-off-by: Lorenzo Colitti <lorenzo@google.com> [Backport of net-next ec75249b141e99b978e6494345d468595f5b829f] Bug: 23113288 Change-Id: If4beb143fdb1f841c6f11e1a70a7f3dc25df1c96
-rw-r--r--include/linux/inet_diag.h14
-rw-r--r--misc/ss.c51
-rw-r--r--misc/ssfilter.h2
-rw-r--r--misc/ssfilter.y23
4 files changed, 87 insertions, 3 deletions
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index 1db41168..016de886 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -72,6 +72,8 @@ enum {
INET_DIAG_BC_AUTO,
INET_DIAG_BC_S_COND,
INET_DIAG_BC_D_COND,
+ INET_DIAG_BC_DEV_COND, /* u32 ifindex */
+ INET_DIAG_BC_MARK_COND,
};
struct inet_diag_hostcond {
@@ -81,6 +83,11 @@ struct inet_diag_hostcond {
__be32 addr[0];
};
+struct inet_diag_markcond {
+ __u32 mark;
+ __u32 mask;
+};
+
/* Base info structure. It contains socket identity (addrs/ports/cookie)
* and, alas, the information shown by netstat. */
struct inet_diag_msg {
@@ -113,9 +120,14 @@ enum {
INET_DIAG_DCTCPINFO,
INET_DIAG_PROTOCOL, /* response attribute only */
INET_DIAG_SKV6ONLY,
+ INET_DIAG_LOCALS,
+ INET_DIAG_PEERS,
+ INET_DIAG_PAD,
+ INET_DIAG_MARK,
+ __INET_DIAG_MAX,
};
-#define INET_DIAG_MAX INET_DIAG_SKV6ONLY
+#define INET_DIAG_MAX (__INET_DIAG_MAX - 1)
/* INET_DIAG_MEM */
diff --git a/misc/ss.c b/misc/ss.c
index 13fcc8f6..12a343c0 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -738,6 +738,7 @@ struct sockstat
unsigned long long sk;
char *name;
char *peer_name;
+ __u32 mark;
};
struct dctcpstat
@@ -806,6 +807,9 @@ static void sock_details_print(struct sockstat *s)
printf(" ino:%u", s->ino);
printf(" sk:%llx", s->sk);
+
+ if (s->mark)
+ printf(" fwmark:0x%x", s->mark);
}
static void sock_addr_print_width(int addr_len, const char *addr, char *delim,
@@ -1043,6 +1047,8 @@ struct aafilter
{
inet_prefix addr;
int port;
+ __u32 mark;
+ __u32 mask;
struct aafilter *next;
};
@@ -1148,7 +1154,12 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
struct aafilter *a = (void*)f->pred;
return s->lport <= a->port;
}
+ case SSF_MARKMASK:
+ {
+ struct aafilter *a = (void *)f->pred;
+ return (s->mark & a->mask) == a->mark;
+ }
/* Yup. It is recursion. Sorry. */
case SSF_AND:
return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s);
@@ -1297,6 +1308,23 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
*bytecode = a;
return l1+4;
}
+ case SSF_MARKMASK:
+ {
+ struct aafilter *a = (void *)f->pred;
+ struct instr {
+ struct inet_diag_bc_op op;
+ struct inet_diag_markcond cond;
+ };
+ int inslen = sizeof(struct instr);
+
+ if (!(*bytecode = malloc(inslen))) abort();
+ ((struct instr *)*bytecode)[0] = (struct instr) {
+ { INET_DIAG_BC_MARK_COND, inslen, inslen + 4 },
+ { a->mark, a->mask},
+ };
+
+ return inslen;
+ }
default:
abort();
}
@@ -1546,6 +1574,25 @@ out:
return res;
}
+void *parse_markmask(const char *markmask)
+{
+ struct aafilter a, *res;
+
+ if (strchr(markmask, '/')) {
+ if (sscanf(markmask, "%i/%i", &a.mark, &a.mask) != 2)
+ return NULL;
+ } else {
+ a.mask = 0xffffffff;
+ if (sscanf(markmask, "%i", &a.mark) != 1)
+ return NULL;
+ }
+
+ res = malloc(sizeof(*res));
+ if (res)
+ memcpy(res, &a, sizeof(a));
+ return res;
+}
+
static char *proto_name(int protocol)
{
switch (protocol) {
@@ -2015,6 +2062,10 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
s.iface = r->id.idiag_if;
s.sk = cookie_sk_get(&r->id.idiag_cookie[0]);
+ s.mark = 0;
+ if (tb[INET_DIAG_MARK])
+ s.mark = *(__u32 *) RTA_DATA(tb[INET_DIAG_MARK]);
+
if (s.local.family == AF_INET) {
s.local.bytelen = s.remote.bytelen = 4;
} else {
diff --git a/misc/ssfilter.h b/misc/ssfilter.h
index 53922a84..c7293cc0 100644
--- a/misc/ssfilter.h
+++ b/misc/ssfilter.h
@@ -8,6 +8,7 @@
#define SSF_S_GE 7
#define SSF_S_LE 8
#define SSF_S_AUTO 9
+#define SSF_MARKMASK 11
#include <stdbool.h>
@@ -20,3 +21,4 @@ struct ssfilter
int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp);
void *parse_hostcond(char *addr, bool is_port);
+void *parse_markmask(const char *markmask);
diff --git a/misc/ssfilter.y b/misc/ssfilter.y
index 9906ad86..ba6b06f3 100644
--- a/misc/ssfilter.y
+++ b/misc/ssfilter.y
@@ -39,7 +39,7 @@ static void yyerror(char *s)
%}
-%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND
+%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND MARKMASK FWMARK
%left '|'
%left '&'
%nonassoc '!'
@@ -111,7 +111,14 @@ expr: DCOND HOSTCOND
{
$$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3));
}
-
+ | FWMARK '=' MARKMASK
+ {
+ $$ = alloc_node(SSF_MARKMASK, $3);
+ }
+ | FWMARK NEQ MARKMASK
+ {
+ $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3));
+ }
| AUTOBOUND
{
$$ = alloc_node(SSF_S_AUTO, NULL);
@@ -240,6 +247,10 @@ int yylex(void)
tok_type = SPORT;
return SPORT;
}
+ if (strcmp(curtok, "fwmark") == 0) {
+ tok_type = FWMARK;
+ return FWMARK;
+ }
if (strcmp(curtok, ">=") == 0 ||
strcmp(curtok, "ge") == 0 ||
strcmp(curtok, "geq") == 0)
@@ -266,6 +277,14 @@ int yylex(void)
tok_type = AUTOBOUND;
return AUTOBOUND;
}
+ if (tok_type == FWMARK) {
+ yylval = (void*)parse_markmask(curtok);
+ if (yylval == NULL) {
+ fprintf(stderr, "Cannot parse mark %s.\n", curtok);
+ exit(1);
+ }
+ return MARKMASK;
+ }
yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT);
if (yylval == NULL) {
fprintf(stderr, "Cannot parse dst/src address.\n");