Commit 7af48590 authored by Jeff Johnson's avatar Jeff Johnson Committed by Mike Frysinger

netstat: update SCTP support

The parsing logic doesn't handle IPv6 addresses.
Clean it all up.
parent 3bbfa090
...@@ -19,3 +19,5 @@ char *safe_strncpy(char *dst, const char *src, size_t size); ...@@ -19,3 +19,5 @@ char *safe_strncpy(char *dst, const char *src, size_t size);
#define netmin(a,b) ((a)<(b) ? (a) : (b)) #define netmin(a,b) ((a)<(b) ? (a) : (b))
#define netmax(a,b) ((a)>(b) ? (a) : (b)) #define netmax(a,b) ((a)>(b) ? (a) : (b))
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
...@@ -771,161 +771,262 @@ static int igmp_info(void) ...@@ -771,161 +771,262 @@ static int igmp_info(void)
igmp_do_one, "igmp", "igmp6"); igmp_do_one, "igmp", "igmp6");
} }
static int ip_parse_dots(uint32_t *addr, char const *src) { static const char *sctp_socket_state_str(int state)
unsigned a, b, c, d; {
unsigned ret = 4-sscanf(src, "%u.%u.%u.%u", &a, &b, &c, &d); if (state >= 0 && state < ARRAY_SIZE(tcp_state))
*addr = htonl((a << 24)|(b << 16)|(c << 8)|d); return tcp_state[state];
return ret; else {
static char state_str_buf[64];
sprintf(state_str_buf, "UNKNOWN(%d)", state);
return state_str_buf;
}
} }
static void print_ip_service(struct sockaddr_in *addr, char const *protname, static const struct aftype *process_sctp_addr_str(const char *addr_str, struct sockaddr *sa)
char *buf, unsigned size) { {
const struct aftype *ap; if (strchr(addr_str,':')) {
#if HAVE_AFINET6
if(size == 0) return; extern struct aftype inet6_aftype;
/* Demangle what the kernel gives us */
/* print host */ struct in6_addr in6;
if((ap = get_afntype(addr->sin_family)) == NULL) { char addr6_str[INET6_ADDRSTRLEN];
fprintf(stderr, _("netstat: unsupported address family %d !\n"), unsigned u0, u1, u2, u3, u4, u5, u6, u7;
addr->sin_family); sscanf(addr_str, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
return; &u0, &u1, &u2, &u3, &u4, &u5, &u6, &u7);
} in6.s6_addr16[0] = htons(u0);
safe_strncpy(buf, ap->sprint((struct sockaddr*)addr, flag_not), size); in6.s6_addr16[1] = htons(u1);
in6.s6_addr16[2] = htons(u2);
in6.s6_addr16[3] = htons(u3);
in6.s6_addr16[4] = htons(u4);
in6.s6_addr16[5] = htons(u5);
in6.s6_addr16[6] = htons(u6);
in6.s6_addr16[7] = htons(u7);
inet_ntop(AF_INET6, &in6, addr6_str, sizeof(addr6_str));
inet6_aftype.input(1, addr6_str, sa);
sa->sa_family = AF_INET6;
#endif
} else {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
sin->sin_addr.s_addr = inet_addr(addr_str);
sa->sa_family = AF_INET;
}
return get_afntype(sa->sa_family);
}
/* print service */ static void sctp_eps_do_one(int lnr, char *line, const char *proto)
if(flag_all || (flag_lst && !addr->sin_port) || (!flag_lst && addr->sin_port)) { {
char bfs[32]; char buffer[1024];
int state, port;
int uid;
unsigned long inode;
const struct aftype *ap;
struct sockaddr_storage localsas;
struct sockaddr *localsa = (struct sockaddr *)&localsas;
const char *sst_str;
const char *lport_str;
const char *uid_str;
const char *inode_str;
char *laddrs_str;
snprintf(bfs, sizeof(bfs), "%s", if (lnr == 0) {
get_sname(addr->sin_port, (char*)protname, flag_not & FLAG_NUM_PORT)); /* ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS */
return;
}
strtok(line, " \t\n"); /* skip endpt */
strtok(0, " \t\n"); /* skip sock */
strtok(0, " \t\n"); /* skip sty */
sst_str = strtok(0, " \t\n");
strtok(0, " \t\n"); /* skip hash bucket */
lport_str = strtok(0, " \t\n");
uid_str = strtok(0, " \t\n");
inode_str = strtok(0, " \t\n");
laddrs_str = strtok(0, "\t\n");
if (!sst_str || !lport_str || !uid_str || !inode_str) {
fprintf(stderr, _("warning, got bogus sctp eps line.\n"));
return;
}
state = atoi(sst_str);
port = atoi(lport_str);
uid = atoi(uid_str);
inode = strtoul(inode_str,0,0);
const char *this_local_addr;
int first = 1;
char local_port[16];
snprintf(local_port, sizeof(local_port), "%s",
get_sname(htons(port), proto, flag_not & FLAG_NUM_PORT));
for (this_local_addr = strtok(laddrs_str, " \t\n");
this_local_addr;
this_local_addr = strtok(0, " \t\n")) {
char local_addr[64];
ap = process_sctp_addr_str(this_local_addr, localsa);
if (ap)
safe_strncpy(local_addr, ap->sprint(localsa, flag_not), sizeof(local_addr));
else
sprintf(local_addr, _("unsupported address family %d"), localsa->sa_family);
/* check if we must cut on host and/or service name */ if (first)
{ printf("sctp ");
unsigned const bufl = strlen(buf); else
unsigned const bfsl = strlen(bfs); printf("\n ");
sprintf(buffer, "%s:%s", local_addr, local_port);
if(bufl+bfsl+2 > size) { printf("%-47s", buffer);
unsigned const half = (size-2)>>1; printf(" %-11s", first ? sctp_socket_state_str(state) : "");
if(bufl > half) { first = 0;
if(bfsl > half) {
buf[size-2-half] = '\0';
bfs[half+1] = '\0';
}
else buf[size-2-bfsl] = '\0';
}
else bfs[size-2-bufl] = '\0';
}
} }
strcat(buf, ":"); finish_this_one(uid, inode, "");
strcat(buf, bfs);
}
} }
/* process single SCTP endpoint */ static void sctp_assoc_do_one(int lnr, char *line, const char *proto)
static void sctp_do_ept(int lnr, char const *line, const char *prot)
{ {
struct sockaddr_in laddr, raddr; char buffer[1024];
unsigned uid, inode; int state, lport,rport;
int uid;
char l_addr[23], r_addr[23]; unsigned rxqueue,txqueue;
unsigned long inode;
/* fill sockaddr_in structures */
{
unsigned lport;
unsigned ate;
if(lnr == 0) return;
if(sscanf(line, "%*X %*X %*u %*u %*u %u %u %u %n",
&lport, &uid, &inode, &ate) < 3) goto err;
/* decode IP address */
if(ip_parse_dots(&laddr.sin_addr.s_addr, line+ate)) goto err;
raddr.sin_addr.s_addr = htonl(0);
laddr.sin_family = raddr.sin_family = AF_INET;
laddr.sin_port = htons(lport);
raddr.sin_port = htons(0);
}
/* print IP:service to l_addr and r_addr */ const struct aftype *ap;
print_ip_service(&laddr, prot, l_addr, sizeof(l_addr)); struct sockaddr_storage localsas, remotesas;
print_ip_service(&raddr, prot, r_addr, sizeof(r_addr)); struct sockaddr *localsa = (struct sockaddr *)&localsas;
struct sockaddr *remotesa = (struct sockaddr *)&remotesas;
/* Print line */ const char *sst_str;
printf("%-4s %6d %6d %-*s %-*s %-11s", const char *txqueue_str;
prot, 0, 0, const char *rxqueue_str;
(int)netmax(23,strlen(l_addr)), l_addr, const char *lport_str, *rport_str;
(int)netmax(23,strlen(r_addr)), r_addr, const char *uid_str;
_(tcp_state[TCP_LISTEN])); const char *inode_str;
finish_this_one(uid, inode, ""); char *laddrs_str;
return; char *raddrs_str;
err:
fprintf(stderr, "SCTP error in line: %d\n", lnr);
}
/* process single SCTP association */ if (lnr == 0) {
static void sctp_do_assoc(int lnr, char const *line, const char *prot) /* ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT RPORT LADDRS <-> RADDRS */
{ return;
struct sockaddr_in laddr, raddr; }
unsigned long rxq, txq;
unsigned uid, inode; strtok(line, " \t\n"); /* skip assoc */
strtok(0, " \t\n"); /* skip sock */
char l_addr[23], r_addr[23]; strtok(0, " \t\n"); /* skip sty */
sst_str = strtok(0, " \t\n");
/* fill sockaddr_in structures */ strtok(0, " \t\n");
{ strtok(0, " \t\n"); /* skip hash bucket */
unsigned lport, rport; strtok(0, " \t\n"); /* skip hash assoc-id */
unsigned ate; txqueue_str = strtok(0, " \t\n");
char const *addr; rxqueue_str = strtok(0, " \t\n");
uid_str = strtok(0, " \t\n");
if(lnr == 0) return; inode_str = strtok(0, " \t\n");
if(sscanf(line, "%*X %*X %*u %*u %*u %*u %*u %lu %lu %u %u %u %u %n", lport_str = strtok(0, " \t\n");
&txq, &rxq, &uid, &inode, &lport, &rport, &ate) < 6) goto err; rport_str = strtok(0, " \t\n");
laddrs_str = strtok(0, "<->\t\n");
/* decode IP addresses */ raddrs_str = strtok(0, "<->\t\n");
addr = strchr(line+ate, '*');
if(addr == 0) goto err; if (!sst_str || !txqueue_str || !rxqueue_str || !uid_str ||
if(ip_parse_dots(&laddr.sin_addr.s_addr, ++addr)) goto err; !inode_str || !lport_str || !rport_str) {
addr = strchr(addr, '*'); fprintf(stderr, _("warning, got bogus sctp assoc line.\n"));
if(addr == 0) goto err; return;
if(ip_parse_dots(&raddr.sin_addr.s_addr, ++addr)) goto err; }
/* complete sockaddr_in structures */ state = atoi(sst_str);
laddr.sin_family = raddr.sin_family = AF_INET; txqueue = atoi(txqueue_str);
laddr.sin_port = htons(lport); rxqueue = atoi(rxqueue_str);
raddr.sin_port = htons(rport); uid = atoi(uid_str);
} inode = strtoul(inode_str, 0, 0);
lport = atoi(lport_str);
rport = atoi(rport_str);
/*print all addresses*/
const char *this_local_addr;
const char *this_remote_addr;
char *ss1, *ss2;
int first = 1;
char local_port[16];
char remote_port[16];
snprintf(local_port, sizeof(local_port), "%s",
get_sname(htons(lport), proto,
flag_not & FLAG_NUM_PORT));
snprintf(remote_port, sizeof(remote_port), "%s",
get_sname(htons(rport), proto,
flag_not & FLAG_NUM_PORT));
this_local_addr = strtok_r(laddrs_str, " \t\n", &ss1);
this_remote_addr = strtok_r(raddrs_str, " \t\n", &ss2);
while (this_local_addr || this_remote_addr) {
char local_addr[64];
char remote_addr[64];
if (this_local_addr) {
if (this_local_addr[0] == '*') {
/* skip * */
this_local_addr++;
}
ap = process_sctp_addr_str(this_local_addr, localsa);
if (ap)
safe_strncpy(local_addr,
ap->sprint(localsa, flag_not), sizeof(local_addr));
else
sprintf(local_addr, _("unsupported address family %d"), localsa->sa_family);
}
if (this_remote_addr) {
if (this_remote_addr[0] == '*') {
/* skip * */
this_remote_addr++;
}
ap = process_sctp_addr_str(this_remote_addr, remotesa);
if (ap)
safe_strncpy(remote_addr,
ap->sprint(remotesa, flag_not), sizeof(remote_addr));
else
sprintf(remote_addr, _("unsupported address family %d"), remotesa->sa_family);
}
if (first)
printf("sctp %6u %6u ", rxqueue, txqueue);
else
printf("\n ");
if (this_local_addr) {
if (first)
sprintf(buffer, "%s:%s", local_addr, local_port);
else
sprintf(buffer, "%s", local_addr);
printf("%-23s", buffer);
} else
printf("%-23s", "");
printf(" ");
if (this_remote_addr) {
if (first)
sprintf(buffer, "%s:%s", remote_addr, remote_port);
else
sprintf(buffer, "%s", remote_addr);
printf("%-23s", buffer);
} else
printf("%-23s", "");
/* print IP:service to l_addr and r_addr */ printf(" %-11s", first ? sctp_socket_state_str(state) : "");
print_ip_service(&laddr, prot, l_addr, sizeof(l_addr));
print_ip_service(&raddr, prot, r_addr, sizeof(r_addr)); first = 0;
this_local_addr = strtok_r(0, " \t\n", &ss1);
/* Print line */ this_remote_addr = strtok_r(0, " \t\n", &ss2);
printf("%-4s %6ld %6ld %-*s %-*s %-11s", }
prot, rxq, txq, finish_this_one(uid, inode, "");
(int)netmax(23,strlen(l_addr)), l_addr,
(int)netmax(23,strlen(r_addr)), r_addr,
_(tcp_state[TCP_ESTABLISHED]));
finish_this_one(uid, inode, "");
return;
err:
fprintf(stderr, "SCTP error in line: %d\n", lnr);
} }
static int sctp_info_epts(void) { static int sctp_info_eps(void)
INFO_GUTS6(_PATH_PROCNET_SCTPEPTS, _PATH_PROCNET_SCTP6EPTS, "AF INET (sctp)", {
sctp_do_ept, "sctp", "sctp6"); INFO_GUTS6(_PATH_PROCNET_SCTPEPTS, _PATH_PROCNET_SCTP6EPTS, "AF INET (sctp)",
sctp_eps_do_one, "sctp", "sctp6");
} }
static int sctp_info_assocs(void) { static int sctp_info_assocs(void)
INFO_GUTS6(_PATH_PROCNET_SCTPASSOCS, _PATH_PROCNET_SCTP6ASSOCS, "AF INET (sctp)", {
sctp_do_assoc, "sctp", "sctp6"); INFO_GUTS6(_PATH_PROCNET_SCTPASSOCS, _PATH_PROCNET_SCTP6ASSOCS, "AF INET (sctp)",
sctp_assoc_do_one, "sctp", "sctp6");
} }
static int sctp_info(void) { static int sctp_info(void)
int res; {
res = sctp_info_epts(); int res = sctp_info_eps();
if(res) return res; return res ? res : sctp_info_assocs();
return sctp_info_assocs();
} }
static void addr_do_one(char *buf, size_t buf_len, size_t short_len, const struct aftype *ap, static void addr_do_one(char *buf, size_t buf_len, size_t short_len, const struct aftype *ap,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment