@@ -34,6 +34,9 @@
#include "libnetlink.h"
#include "namespace.h"
#include "SNAPSHOT.h"
+#include "ss_out_fmt.h"
+#include "ss_json_fmt.h"
+#include "ss_types.h"
#include <linux/tcp.h>
#include <linux/sock_diag.h>
@@ -101,6 +104,7 @@ int show_sock_ctx = 0;
/* If show_users & show_proc_ctx only do user_ent_hash_build() once */
int user_ent_hash_build_init = 0;
int follow_events = 0;
+int json_output = 0;
int netid_width;
int state_width;
@@ -714,7 +718,6 @@ static int is_ephemeral(int port)
return (port >= ip_local_port_min && port<= ip_local_port_max);
}
-
static const char *__resolve_service(int port)
{
struct scache *c;
@@ -3064,6 +3067,9 @@ static int print_summary(void)
printf("\n");
+ if (json_output && has_successor)
+ printf(",\n");
+
return 0;
}
@@ -3090,6 +3096,7 @@ static void _usage(FILE *dest)
" -z, --contexts display process and socket SELinux security contexts\n"
" -N, --net switch to the specified network namespace name\n"
"\n"
+" -j, --json format output in JSON\n"
" -4, --ipv4 display only IP version 4 sockets\n"
" -6, --ipv6 display only IP version 6 sockets\n"
" -0, --packet display PACKET sockets\n"
@@ -3189,6 +3196,7 @@ static const struct option long_opts[] = {
{ "help", 0, 0, 'h' },
{ "context", 0, 0, 'Z' },
{ "contexts", 0, 0, 'z' },
+ { "json", 0, 0, 'j' },
{ "net", 1, 0, 'N' },
{ 0 }
@@ -3204,7 +3212,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:j",
long_opts, NULL)) != EOF) {
switch(ch) {
case 'n':
@@ -3383,6 +3391,10 @@ int main(int argc, char *argv[])
if (netns_switch(optarg))
exit(1);
break;
+ case 'j':
+ fmt_type = FMT_JSON;
+ json_output = 1;
+ break;
case 'h':
case '?':
help();
@@ -3464,11 +3476,33 @@ int main(int argc, char *argv[])
exit(-1);
}
}
+ printf("\"TCP\": [\n");
inet_show_netlink(¤t_filter, dump_fp, IPPROTO_TCP);
+ res_json_fmt_branch(current_filter.dbs & (1<<NETLINK_DB) ||
+ current_filter.dbs & PACKET_DBM ||
+ current_filter.dbs & UNIX_DBM ||
+ current_filter.dbs & (1<<RAW_DB) ||
+ current_filter.dbs & (1<<UDP_DB) ||
+ current_filter.dbs & (1<<TCP_DB) ||
+ current_filter.dbs & (1<<DCCP_DB), ']');
fflush(dump_fp);
exit(0);
}
+ if (do_summary) {
+ print_summary(current_filter.dbs & PACKET_DBM ||
+ current_filter.dbs & UNIX_DBM ||
+ current_filter.dbs & (1<<RAW_DB) ||
+ current_filter.dbs & (1<<UDP_DB) ||
+ current_filter.dbs & (1<<TCP_DB) ||
+ current_filter.dbs & (1<<DCCP_DB));
+ if (do_default && argc == 0) {
+ if (json_output)
+ printf("}\n");
+ exit(0);
+ }
+ }
+
if (ssfilter_parse(¤t_filter.f, argc, argv, filter_fp))
usage();
@@ -3490,62 +3524,140 @@ int main(int argc, char *argv[])
}
}
- addrp_width = screen_width;
- addrp_width -= netid_width+1;
- addrp_width -= state_width+1;
- addrp_width -= 14;
+ if (!json_output) {
+
+ addrp_width = screen_width;
+ addrp_width -= netid_width + 1;
+ addrp_width -= state_width + 1;
+ addrp_width -= 14;
+
+ if (addrp_width & 1) {
+ if (netid_width)
+ netid_width++;
+ else if (state_width)
+ state_width++;
+ }
+
+ addrp_width /= 2;
+ addrp_width--;
+
+ serv_width = resolve_services ? 7 : 5;
+
+ if (addrp_width < 15 + serv_width + 1)
+ addrp_width = 15 + serv_width + 1;
- if (addrp_width&1) {
+ addr_width = addrp_width - serv_width - 1;
if (netid_width)
- netid_width++;
- else if (state_width)
- state_width++;
- }
+ printf("%-*s ", netid_width, "Netid");
+ if (state_width)
+ printf("%-*s ", state_width, "State");
+ printf("%-6s %-6s ", "Recv-Q", "Send-Q");
- addrp_width /= 2;
- addrp_width--;
+ /* Make enough space for the local/remote port field */
+ addr_width -= 13;
+ serv_width += 13;
- serv_width = resolve_services ? 7 : 5;
+ printf("%*s:%-*s %*s:%-*s\n",
+ addr_width, "Local Address", serv_width, "Port",
+ addr_width, "Peer Address", serv_width, "Port");
+ }
- if (addrp_width < 15+serv_width+1)
- addrp_width = 15+serv_width+1;
+ fflush(stdout);
- addr_width = addrp_width - serv_width - 1;
+ if (current_filter.dbs & (1<<NETLINK_DB)) {
+ if (json_output) {
+ printf("\"NETLINK\": [\n");
+ netlink_show(¤t_filter);
+ json_first_elem = 1;
+ res_json_fmt_branch(current_filter.dbs & PACKET_DBM ||
+ current_filter.dbs & UNIX_DBM ||
+ current_filter.dbs & (1<<RAW_DB) ||
+ current_filter.dbs & (1<<UDP_DB) ||
+ current_filter.dbs & (1<<TCP_DB) ||
+ current_filter.dbs & (1<<DCCP_DB), ']');
+ } else
+ netlink_show(¤t_filter);
+ }
+ if (current_filter.dbs & PACKET_DBM) {
+ if (json_output) {
+ printf("\"PACKET\": [\n");
+ packet_show(¤t_filter);
+ json_first_elem = 1;
+ res_json_fmt_branch(
+ current_filter.dbs & UNIX_DBM ||
+ current_filter.dbs & (1<<RAW_DB) ||
+ current_filter.dbs & (1<<UDP_DB) ||
+ current_filter.dbs & (1<<TCP_DB) ||
+ current_filter.dbs & (1<<DCCP_DB), ']');
+ } else
+ packet_show(¤t_filter);
+ }
+ if (current_filter.dbs & UNIX_DBM) {
+ if (json_output) {
+ printf("\"UNIX\": [\n");
+ unix_show(¤t_filter);
+ json_first_elem = 1;
+ res_json_fmt_branch(
+ current_filter.dbs & (1<<RAW_DB) ||
+ current_filter.dbs & (1<<UDP_DB) ||
+ current_filter.dbs & (1<<TCP_DB) ||
+ current_filter.dbs & (1<<DCCP_DB), ']');
- if (netid_width)
- printf("%-*s ", netid_width, "Netid");
- if (state_width)
- printf("%-*s ", state_width, "State");
- printf("%-6s %-6s ", "Recv-Q", "Send-Q");
+ } else
+ unix_show(¤t_filter);
+ }
+ if (current_filter.dbs & (1<<RAW_DB)) {
+ if (json_output) {
+ printf("\"RAW\": [\n");
+ raw_show(¤t_filter);
+ json_first_elem = 1;
+ res_json_fmt_branch(
+ current_filter.dbs & (1<<UDP_DB) ||
+ current_filter.dbs & (1<<TCP_DB) ||
+ current_filter.dbs & (1<<DCCP_DB), ']');
- /* Make enough space for the local/remote port field */
- addr_width -= 13;
- serv_width += 13;
+ } else
+ raw_show(¤t_filter);
+ }
+ if (current_filter.dbs & (1<<UDP_DB)) {
+ if (json_output) {
+ printf("\"UDP\": [\n");
+ udp_show(¤t_filter);
+ json_first_elem = 1;
+ res_json_fmt_branch(
+ current_filter.dbs & (1<<TCP_DB) ||
+ current_filter.dbs & (1<<DCCP_DB), ']');
- printf("%*s:%-*s %*s:%-*s\n",
- addr_width, "Local Address", serv_width, "Port",
- addr_width, "Peer Address", serv_width, "Port");
+ } else
+ udp_show(¤t_filter);
+ }
+ if (current_filter.dbs & (1<<TCP_DB)) {
+ if (json_output) {
+ printf("\"TCP\": [\n");
+ tcp_show(¤t_filter, IPPROTO_TCP);
+ json_first_elem = 1;
+ res_json_fmt_branch(
+ current_filter.dbs & (1<<DCCP_DB), ']');
+ } else
+ tcp_show(¤t_filter, IPPROTO_TCP);
+ }
+ if (current_filter.dbs & (1<<DCCP_DB)) {
+ if (json_output) {
+ printf("\"DCCP\": [\n");
+ tcp_show(¤t_filter, IPPROTO_DCCP);
+ printf("]\n");
+ } else
+ tcp_show(¤t_filter, IPPROTO_DCCP);
+ }
+
+ if (json_output)
+ printf("}\n");
fflush(stdout);
if (follow_events)
exit(handle_follow_request(¤t_filter));
- if (current_filter.dbs & (1<<NETLINK_DB))
- netlink_show(¤t_filter);
- if (current_filter.dbs & PACKET_DBM)
- packet_show(¤t_filter);
- if (current_filter.dbs & UNIX_DBM)
- unix_show(¤t_filter);
- if (current_filter.dbs & (1<<RAW_DB))
- raw_show(¤t_filter);
- if (current_filter.dbs & (1<<UDP_DB))
- udp_show(¤t_filter);
- if (current_filter.dbs & (1<<TCP_DB))
- tcp_show(¤t_filter, IPPROTO_TCP);
- if (current_filter.dbs & (1<<DCCP_DB))
- tcp_show(¤t_filter, IPPROTO_DCCP);
-
if (show_users || show_proc_ctx || show_sock_ctx)
user_ent_destroy();