mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2026-01-04 15:17:43 +00:00
ss: Support displaying and filtering on socket marks.
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>
This commit is contained in:
parent
4bfe682536
commit
ec75249b14
52
misc/ss.c
52
misc/ss.c
@ -737,6 +737,7 @@ struct sockstat {
|
||||
unsigned long long sk;
|
||||
char *name;
|
||||
char *peer_name;
|
||||
__u32 mark;
|
||||
};
|
||||
|
||||
struct dctcpstat {
|
||||
@ -808,6 +809,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,
|
||||
@ -1047,6 +1051,8 @@ struct aafilter {
|
||||
inet_prefix addr;
|
||||
int port;
|
||||
unsigned int iface;
|
||||
__u32 mark;
|
||||
__u32 mask;
|
||||
struct aafilter *next;
|
||||
};
|
||||
|
||||
@ -1166,6 +1172,12 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
|
||||
struct aafilter *a = (void *)f->pred;
|
||||
|
||||
return s->iface == a->iface;
|
||||
}
|
||||
case SSF_MARKMASK:
|
||||
{
|
||||
struct aafilter *a = (void *)f->pred;
|
||||
|
||||
return (s->mark & a->mask) == a->mark;
|
||||
}
|
||||
/* Yup. It is recursion. Sorry. */
|
||||
case SSF_AND:
|
||||
@ -1341,6 +1353,23 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
|
||||
{
|
||||
/* bytecompile for SSF_DEVCOND not supported yet */
|
||||
return 0;
|
||||
}
|
||||
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();
|
||||
@ -1621,6 +1650,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) {
|
||||
@ -2138,6 +2186,10 @@ static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s)
|
||||
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
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#define SSF_S_LE 8
|
||||
#define SSF_S_AUTO 9
|
||||
#define SSF_DEVCOND 10
|
||||
#define SSF_MARKMASK 11
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -22,3 +23,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_devcond(char *name);
|
||||
void *parse_markmask(const char *markmask);
|
||||
|
||||
@ -36,7 +36,7 @@ static void yyerror(char *s)
|
||||
|
||||
%}
|
||||
|
||||
%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME
|
||||
%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME MARKMASK FWMARK
|
||||
%left '|'
|
||||
%left '&'
|
||||
%nonassoc '!'
|
||||
@ -116,7 +116,14 @@ expr: DCOND HOSTCOND
|
||||
{
|
||||
$$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $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);
|
||||
@ -249,6 +256,10 @@ int yylex(void)
|
||||
tok_type = DEVNAME;
|
||||
return DEVNAME;
|
||||
}
|
||||
if (strcmp(curtok, "fwmark") == 0) {
|
||||
tok_type = FWMARK;
|
||||
return FWMARK;
|
||||
}
|
||||
if (strcmp(curtok, ">=") == 0 ||
|
||||
strcmp(curtok, "ge") == 0 ||
|
||||
strcmp(curtok, "geq") == 0)
|
||||
@ -283,6 +294,14 @@ int yylex(void)
|
||||
}
|
||||
return DEVCOND;
|
||||
}
|
||||
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");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user