[linux] abstract socket address

netstatUNIXドメインソケットを見ると、先頭に '@' が付いてるパスとそうでないものがある。

# netstat -ax
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node   Path
unix  2      [ ACC ]     STREAM     LISTENING     5826     @/com/ubuntu/upstart
unix  6      [ ]         DGRAM                    7364     /dev/log

/bin/lsで見えるかどうかくらいは分かるんだけど。

調べた。

抽象ソケットアドレス と呼ぶらしい

Hi all, the attached path adds support for unix socket in abstract namespace.
They are special sockets without filesystem correspondence (so you can use
them without thinking about permissions or in chroot). In netstat they are
reported with a '@' prefix.

netstatで参照すると'@'がprefixとしてつく

ファイルシステムに関係無く扱えるのでパーミッション,chroot気にせず使えるとね

abstract (抽象): 抽象ソケットアドレスは、 sun_path[0] がヌルバイト ('\0') であることから区別できる。 sun_path の残りの全バイトによりソケットの「名前」が定義される (名前中のヌルバイトには特別な意味はない)。 この名前はファイルシステムのパス名とは何の関係もない。 この名前空間におけるソケットのアドレスは、 sun_path の残りのバイトで表される。 getsockname(2), getpeername(2), accept(2) が抽象ソケットのアドレスを返す際には、その長さは sizeof(struct sockaddr_un) であり、 sun_path に抽象名前空間の名前が格納される。 ソケットの抽象名前空間Linux による拡張であり、移植性はない。

@ はどこで付くの?

# cat /proc/net/unix
Num       RefCount Protocol Flags    Type St Inode Path
ffff88001cc2c680: 00000002 00000000 00010000 0001 01  5826 @/com/ubuntu/upstart
ffff88001cc2d380: 00000002 00000000 00010000 0001 01 53603 @/var/lib/lxc/001/command
ffff88001cc2e3c0: 00000002 00000000 00010000 0005 01  6091 @/org/kernel/udev/udevd
ffff88001eb80d00: 00000002 00000000 00010000 0001 01  7343 /var/run/dbus/system_bus_socket
ffff88001eb81a00: 00000006 00000000 00000000 0002 01  7364 /dev/log
static int unix_seq_show(struct seq_file *seq, void *v)
{

/* 略 */

                         if (!UNIX_ABSTRACT(s))
                                len--;
                        else {
                                seq_putc(seq, '@');
                               i++;
                         }

あったあった。謎が解決した。

perlで試す

  • 検証用コード
#!/usr/bin/perl

use strict;
use warnings;
use IO::Socket::UNIX;

# 先頭に \0 入れれば 抽象ソケットを生成する
my $sock = IO::Socket::UNIX->new( Local => "\0/path/not/exists") or die $!;
sleep(100);


これを実行して、別セッションで netstat の出力を見る

$ netstat -x | grep path
unix  2      [ ]         STREAM                   55077    @/path/not/exists

いけました。

蛇足

UNIXドメインソケットは ネットワークの名前空間 (≒ CLONE_NEWNET) に属する

unshare --net で 名前空間を切り離してから netstat すると見えなくなる

# unshare --net -- netstat -x
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags       Type       State         I-Node   Path

IPなソケットだけが対象だと思ってた > CLONE_NEWNET