* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <arpa/inet.h> /* inet_ntop */
+#include <netinet/in.h> /* in6_addr */
#include <fcntl.h> /* open(2) */
#include <inttypes.h> /* SCNu16 */
#include <linux/net.h> /* SS_* */
static void load_xinfo_from_proc_raw(ino_t netns_inode);
static void load_xinfo_from_proc_tcp(ino_t netns_inode);
static void load_xinfo_from_proc_udp(ino_t netns_inode);
+static void load_xinfo_from_proc_tcp6(ino_t netns_inode);
static int self_netns_fd = -1;
static struct stat self_netns_sb;
load_xinfo_from_proc_tcp(netns);
load_xinfo_from_proc_udp(netns);
load_xinfo_from_proc_raw(netns);
+ load_xinfo_from_proc_tcp6(netns);
}
static void load_sock_xinfo_with_fd(int fd, ino_t netns)
return be32_to_cpu(v);
}
+/*
+ * AF_INET6
+ */
+struct inet6_xinfo {
+ struct sock_xinfo sock;
+ struct in6_addr local_addr;
+ struct in6_addr remote_addr;
+};
+
/*
* L4 abstract-layer for protocols stacked on IP and IP6.
*/
}
struct l4_xinfo {
- struct inet_xinfo inet;
+ union {
+ struct inet_xinfo inet;
+ struct inet6_xinfo inet6;
+ };
enum l4_state st;
};
enum l4_side { L4_LOCAL, L4_REMOTE };
+enum l3_decorator { L3_DECO_START, L3_DECO_END };
struct l4_xinfo_class {
struct sock_xinfo_class sock;
void * (*get_addr)(struct l4_xinfo *, enum l4_side);
bool (*is_any_addr)(void *);
int family;
+ const char *l3_decorator[2];
};
#define l3_fill_column_handler(L3, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
void *raddr = class->get_addr(l4, L4_REMOTE);
char local_s[BUFSIZ];
char remote_s[BUFSIZ];
+ const char *start = class->l3_decorator[L3_DECO_START];
+ const char *end = class->l3_decorator[L3_DECO_END];
if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
xasprintf(&str, "state=%s", st_str);
else if (l4->st == TCP_LISTEN
|| !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
- xasprintf(&str, "state=%s laddr=%s:%"SCNu16,
+ xasprintf(&str, "state=%s laddr=%s%s%s:%"SCNu16,
st_str,
- local_s, tcp->local_port);
+ start, local_s, end, tcp->local_port);
else
- xasprintf(&str, "state=%s laddr=%s:%"SCNu16" raddr=%s:%"SCNu16,
+ xasprintf(&str, "state=%s laddr=%s%s%s:%"SCNu16" raddr=%s%s%s:%"SCNu16,
st_str,
- local_s, tcp->local_port,
- remote_s, tcp->remote_port);
+ start, local_s, end, tcp->local_port,
+ start, remote_s, end, tcp->remote_port);
return str;
}
p = tcp->remote_port; \
} \
if (n && inet_ntop(class->family, n, s, sizeof(s))) \
- xasprintf(STR, "%s:%"SCNu16, s, p); \
+ xasprintf(STR, "%s%s%s:%"SCNu16, \
+ class->l3_decorator[L3_DECO_START], \
+ s, \
+ class->l3_decorator[L3_DECO_END], \
+ p); \
break; \
case COL_##L4##_LPORT: \
p = tcp->local_port; \
.get_addr = tcp_xinfo_get_addr,
.is_any_addr = tcp_xinfo_is_any_addr,
.family = AF_INET,
+ .l3_decorator = {"", ""},
};
static bool L4_verify_initial_line(const char *line)
.get_addr = tcp_xinfo_get_addr,
.is_any_addr = tcp_xinfo_is_any_addr,
.family = AF_INET,
+ .l3_decorator = {"", ""},
};
static void load_xinfo_from_proc_udp(ino_t netns_inode)
.get_addr = tcp_xinfo_get_addr,
.is_any_addr = tcp_xinfo_is_any_addr,
.family = AF_INET,
+ .l3_decorator = {"", ""},
};
static void load_xinfo_from_proc_raw(ino_t netns_inode)
"/proc/net/raw",
&raw_xinfo_class);
}
+
+/*
+ * TCP6
+ */
+static struct sock_xinfo *tcp6_xinfo_scan_line(const struct sock_xinfo_class *class,
+ char * line,
+ ino_t netns_inode,
+ enum sysfs_byteorder byteorder)
+{
+ uint32_t local_addr[4];
+ unsigned int local_port;
+ uint32_t remote_addr[4];
+ unsigned int remote_port;
+ unsigned int st;
+ unsigned long inode;
+ struct tcp_xinfo *tcp;
+ struct inet6_xinfo *inet6;
+ struct sock_xinfo *sock;
+
+ if (sscanf(line,
+ "%*d: "
+ "%08x%08x%08x%08x:%04x "
+ "%08x%08x%08x%08x:%04x "
+ "%x %*x:%*x %*x:%*x %*x %*u %*d %lu ",
+ local_addr+0, local_addr+1, local_addr+2, local_addr+3, &local_port,
+ remote_addr+0, remote_addr+1, remote_addr+2, remote_addr+3, &remote_port,
+ &st, &inode) != 12)
+ return NULL;
+
+ if (inode == 0)
+ return NULL;
+
+ tcp = xmalloc(sizeof(struct tcp_xinfo));
+ inet6 = &tcp->l4.inet6;
+ sock = &inet6->sock;
+ sock->class = class;
+ sock->inode = (ino_t)inode;
+ sock->netns_inode = netns_inode;
+ tcp->local_port = local_port;
+ for (int i = 0; i < 4; i++) {
+ inet6->local_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, local_addr[i]);
+ inet6->remote_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, remote_addr[i]);
+ }
+ tcp->remote_port = remote_port;
+ tcp->l4.st = st;
+
+ return sock;
+}
+
+static bool tcp6_fill_column(struct proc *proc __attribute__((__unused__)),
+ struct sock_xinfo *sock_xinfo,
+ struct sock *sock __attribute__((__unused__)),
+ struct libscols_line *ln __attribute__((__unused__)),
+ int column_id,
+ size_t column_index __attribute__((__unused__)),
+ char **str)
+{
+ return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
+ || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
+}
+
+static void *tcp6_xinfo_get_addr(struct l4_xinfo * l4, enum l4_side side)
+{
+ return (side == L4_LOCAL)
+ ? &l4->inet6.local_addr
+ : &l4->inet6.remote_addr;
+}
+
+static bool tcp6_xinfo_is_any_addr(void *addr)
+{
+ return IN6_ARE_ADDR_EQUAL(addr, &(struct in6_addr)IN6ADDR_ANY_INIT);
+}
+
+static const struct l4_xinfo_class tcp6_xinfo_class = {
+ .sock = {
+ .get_name = tcp_get_name,
+ .get_type = tcp_get_type,
+ .get_state = tcp_get_state,
+ .get_listening = tcp_get_listening,
+ .fill_column = tcp6_fill_column,
+ .free = NULL,
+ },
+ .scan_line = tcp6_xinfo_scan_line,
+ .get_addr = tcp6_xinfo_get_addr,
+ .is_any_addr = tcp6_xinfo_is_any_addr,
+ .family = AF_INET6,
+ .l3_decorator = {"[", "]"},
+};
+
+static void load_xinfo_from_proc_tcp6(ino_t netns_inode)
+{
+ load_xinfo_from_proc_inet_L4(netns_inode,
+ "/proc/net/tcp6",
+ &tcp6_xinfo_class);
+}