/proc/net/unix
[root@localhost c]# cat /proc/net/unix Num RefCount Protocol Flags Type St Inode Path dead2b40: 00000002 00000000 00010000 0001 01 13517 @ISCSIADM_ABSTRACT_NAMESPACE ddffc6c0: 00000002 00000000 00010000 0001 01 10821 /var/run/abrt/abrt.socket db47e480: 00000002 00000000 00010000 0001 01 13109 @ISCSID_UIP_ABSTRACT_NAMESPACE : ddffc000: 00000003 00000000 00000000 0001 03 10811 dca4c6c0: 00000003 00000000 00000000 0001 03 10800 /run/systemd/stdout-syslog-bridge dca4c900: 00000003 00000000 00000000 0001 03 10799 db47ed80: 00000003 00000000 00000000 0001 03 10639 /run/systemd/stdout-syslog-bridge db47f440: 00000003 00000000 00000000 0001 03 10088 db47e000: 00000002 00000000 00000000 0002 01 7932
検証サンプル
[root@localhost c]# cat proc_unix.c #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> void main(int argc, char * argv[]) { struct sockaddr_un sock_addr; int status, sock; int file_flag = atoi(argv[1]); int listen_flag = atoi(argv[2]); sock = socket(AF_UNIX, SOCK_STREAM, 0); sock_addr.sun_family = AF_UNIX; strcpy(sock_addr.sun_path, "0123456789"); remove(sock_addr.sun_path); if (!file_flag) { sock_addr.sun_path[0] =0; } bind(sock, (struct sockaddr*) &sock_addr, sizeof(struct sockaddr_un)); if (listen_flag) { listen(sock, 0); } system("cat /proc/net/unix | grep -i --text 1234"); }結果(Pathのバイナリ部表示はgrep故です。)
Num RefCount Protocol Flags Type St Inode Path [root@localhost c]# ./proc_unix.o 0 0 <--- チェックサム no-listen debf9440: 00000002 00000000 00000000 0001 01 16533 @12345678・G %顛'顛窶AG' 玩?AGYG [root@localhost c]# ./proc_unix.o 0 1 <--- チェックサム listen debf8fc0: 00000002 00000000 00010000 0001 01 16537 @12345678・G 肝?苞帥`AG 玩?AGYG [root@localhost c]# ./proc_unix.o 1 0 <--- inode no-listen debf8fc0: 00000002 00000000 00000000 0001 01 16545 0123456789 [root@localhost c]# ./proc_unix.o 1 1 <--- inode listen dca4db00: 00000002 00000000 00010000 0001 01 15641 0123456789・Numはソケットのアドレスで、/dev/kmemによるソケット属性等の更新故の実装かと。
・ソケット作成時、s->sk_refcnt=1で、bind/connect毎にインクリメントされます。
・Flagsはlistenされていると__SO_ACCEPTCON(1 << 16)で、されていないと0です。
・connectされていないとs->sk_socket=0です。
・Pathの@はソケットのunix_socket_table[]登録をinode noでなく、チェックサムとし、チェックサムのサイズは、bindシステムコールのlen引数sizeof(struct sockaddr_un)で、チェックサムは123456789でなく、&sock_addrのsizeof(struct sockaddr_un)で、異なるコマンド間でのソケットconnectするには、path名に掛かるサイズ値でbindする必要があります。
・inodeはs->addr->name->sun_pathのinodeなく、ソケット作成時に取得されるnodevでのpusedo mountされたsockfsファイルシステム下のinodeです。
実装
Num :sRefCount :s->sk_refcnt
Protocol :0
Flags :s->sk_state == TCP_LISTEN ? __SO_ACCEPTCON : 0
Type :s->sk_type
St :s->sk_socket ?
(s->sk_state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED):
(s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING)
Inode :s->sk_socket->vfs_inode->i_ino
Path :s->addr->name->sun_path
typedef enum { SS_FREE = 0, /* not allocated */ SS_UNCONNECTED, /* unconnected to any socket */ SS_CONNECTING, /* in process of connecting */ SS_CONNECTED, /* connected to socket */ SS_DISCONNECTING /* in process of disconnecting */ } socket_state; #define __SO_ACCEPTCON (1 << 16) /* performed a listen */ enum sock_type { SOCK_STREAM = 1, SOCK_DGRAM = 2, SOCK_RAW = 3, SOCK_RDM = 4, SOCK_SEQPACKET = 5, SOCK_DCCP = 6, SOCK_PACKET = 10, }; root/arch/mips/include/asm/socket.hでの実装では、SOCK_DGRAM/SOCK_STREAM値は、逆転しています。 enum sock_type { SOCK_DGRAM = 1, SOCK_STREAM = 2, SOCK_RAW = 3, SOCK_RDM = 4, SOCK_SEQPACKET = 5, SOCK_DCCP = 6, SOCK_PACKET = 10, }; enum { TCP_ESTABLISHED = 1, TCP_SYN_SENT, TCP_SYN_RECV, TCP_FIN_WAIT1, TCP_FIN_WAIT2, TCP_TIME_WAIT, TCP_CLOSE, TCP_CLOSE_WAIT, TCP_LAST_ACK, TCP_LISTEN, TCP_CLOSING, /* Now a valid state */ TCP_MAX_STATES /* Leave at the end! */ } struct sockaddr_un { __kernel_sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ }; static int unix_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) seq_puts(seq, "Num RefCount Protocol Flags Type St " "Inode Path\n"); else { struct sock *s = v; struct unix_sock *u = unix_sk(s); unix_state_lock(s); seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu", s, atomic_read(&s->sk_refcnt), 0, s->sk_state == TCP_LISTEN ? __SO_ACCEPTCON : 0, s->sk_type, s->sk_socket ? (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), sock_i_ino(s)); if (u->addr) { int i, len; seq_putc(seq, ' '); i = 0; len = u->addr->len - sizeof(short); if (!UNIX_ABSTRACT(s)) len--; else { seq_putc(seq, '@'); i++; } for ( ; i < len; i++) seq_putc(seq, u->addr->name->sun_path[i]); } unix_state_unlock(s); seq_putc(seq, '\n'); } return 0; }len = u->addr->len - sizeof(short)は、u->addr->lenはsizeof(struct sockaddr_un)で、 __kernel_sa_family_t sun_familyサイズ分です。
補足
pathのないソケットはbindされてないソケットで、実務上ではsocketpaireによるソケットという事です。socketpareはs->sk_state値によりlistenはエラーで、バックログ更新できませんが、掛かるソケットアドレスから/dev/kmemによりs->sk_stateを変更する事で、listenが動作可能となるはずです。又listenは何回コールする事が可能で、listenをエラーとさせる事でバックログ設定を不可にさせることも可能かと。