promisc

mac mini

Windows 11が発表された。リーク通りのネタにお墨付きを与えた格好。 Windows 11 のシステム要件、機能、デバイスの要件について 今回は、こんなおまけも付くらしい。やっぱり世間で流行っているものは、取り入れておかんとなって事だ。 Windows 11ではAndroidアプリが動作

こんなのやだってんで、ラズパイを調べてみたんだけど、それをもっと頑丈にした、弁当箱がアプルから発売されてる。Mac miniですって。ミニと言う割には、巨人用の箱だな。

Mac miniと言えば、BSD系のOS。そんなのやだって言うリナ族も居る訳で。そんな人達が喜びそうなエミュレータが紹介されてた。 UTMを使ってM1 Mac上でUbuntuを動かす

オイラーは軽く動くやつが欲しいぞ。Debian 11 のメジャーデビューは何時だ?

T型コネクタ

T型コネクタ なんてのを思い出しちゃぞ。モノタロウでも買えるのね。ああ、エレキ知らない人に説明すると、teeね。尚更分からないか。

信号線の途中から、信号を取り出す為のタッピングコネクタね。スパイ御用達。昔よくお世話になった。懐かしいな。 wiresharkでUSBのパケットを盗聴出来るなんて書いたものだから、連想記憶が発動したのさ。

とあるBUSラインを盗聴出来るように、タッピング装置を自作した事が有るぞ。 流れる信号をデコードしないと、扱い辛い。そこで、出入りのソフト屋さんに頼んで、コードを書いて貰った。

ハード一式はこちらにしかないので、debugは弊社内で。Linuxは何使ってますって聴いたら、Plamo Linux ですって言われたんで、用意した覚えがある。 シンプルでよかったな。

WiresharkでUSBメモリのパケットキャプチャしてみた!

kill -9 at OpenBSD

前回の続き、tcpdumpを動かしておいて、それをkill -9で即死させた時、ちゃんとpromiscモードはクリアされてた。tcpdumpの特殊性ゆえに、考慮されているのかな? そんなのコード嫁。でもいいんだけど、基本は簡単な物を調べる、です。

こんな事もあろうかと、mypc.cを作っておいた。こいつを動かしておいて、有無を言わさず即死させたらどうなる? 考えていてもしょうがないので、カーネルを追跡。

(gdb) bt
#0  ifpromisc (ifp=0xd184b030, pswitch=0) at /usr/src/sys/net/if.c:2928
#1  0xd0d7b09b in bpf_detachd (d=0xd1875d00) at /usr/src/sys/net/bpf.c:323
#2  0xd0d7b42f in bpfclose (dev=136960, flag=3, mode=8192, p=0xd168518c) at /usr/src/sys/net/bpf.c:390
#3  0xd07aea58 in spec_close_clone (ap=0xf1d49948) at /usr/src/sys/kern/spec_vnops.c:769
#4  0xd07acbe9 in spec_close (v=0xf1d49948) at /usr/src/sys/kern/spec_vnops.c:503
#5  0xd057a98c in VOP_CLOSE (vp=0xf1d11900, fflag=3, cred=0xd17f4c60, p=0xd168518c) at /usr/src/sys/ker\
n/vfs_vops.c:174
#6  0xd03689e0 in vn_close (vp=0xf1d11900, flags=3, cred=0xd17f4c60, p=0xd168518c) at /usr/src/sys/kern\
/vfs_vnops.c:301
#7  0xd0367e9f in vn_closefile (fp=0xd1683620, p=0xd168518c) at /usr/src/sys/kern/vfs_vnops.c:613
#8  0xd03887e1 in fdrop (fp=0xd1683620, p=0xd168518c) at /usr/src/sys/kern/kern_descrip.c:1273
#9  0xd038ad35 in closef (fp=0xd1683620, p=0xd168518c) at /usr/src/sys/kern/kern_descrip.c:1257
#10 0xd038bd22 in fdfree (p=0xd168518c) at /usr/src/sys/kern/kern_descrip.c:1196
#11 0xd070b001 in exit1 (p=0xd168518c, rv=9, flags=1) at /usr/src/sys/kern/kern_exit.c:194
#12 0xd0a0e197 in sigexit (p=0xd168518c, signum=9) at /usr/src/sys/kern/kern_sig.c:1499
#13 0xd0a0ed6c in postsig (p=0xd168518c, signum=9) at /usr/src/sys/kern/kern_sig.c:1431
#14 0xd0a0fe35 in userret (p=0xd168518c) at /usr/src/sys/kern/kern_sig.c:1890
#15 0xd06baedd in mi_syscall_return (p=0xd168518c, code=3, error=-1, retval=0xf1d49d0c) at /usr/src/sys\
/sys/syscall_mi.h:112
#16 0xd06babc7 in syscall (frame=0xf1d49d50) at /usr/src/sys/arch/i386/i386/trap.c:619
#17 0xd09afd1d in Xsyscall_untramp ()
#18 0xf1d49d50 in ?? ()
#19 0x03682175 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

Ctl-c でも、ほぼ同様なコースを辿り、promiscはクリアされてた。出来の悪いSIGに反応しないプログラムを書いても、ちゃんと後始末をしてくれている。素晴らしい!

FreeBSDでも、同じ挙動になったよ。さすがBSD族だ。

about Linux

NICがpromiscモードになってる指標としてifconfigのstatusに出て来るそれを目印にしてた。リナでは、それが表われないんだ。

プロミスキャスモード(Promiscuous Mode)

なんてやると、確かに現れるけどね。tcpdumpしてる状態では出てこない。そこで自作のmypc.cですよ。構造が簡単だからgdbで追い易い。これ、オイラーの昔からの流儀ね。

オシロスコープで波形を調べる時、まれにしか表われない波形を観測する為、輝度を上げ、回りの光を遮光する為、昔の写真屋さんのように、作業服をオシロに被せて観測してる人を散見した。オイラーこういうの苦手。 波形を観測し易いように、プログラムを組み替えて、悠悠とオシロを眺めたものだ。こうでなくっちゃね。

自前でコンパイルしたlibpcapを組み込んで、 LD_LIBRARY_PATH を設定して、いざ出陣。

(gdb) bt
#0  pcap_activate_linux (handle=0x405590) at ./pcap-linux.c:961
#1  0xb7f911f7 in pcap_activate (p=0x405590) at ./pcap.c:2721
#2  0xb7f91766 in pcap_open_live (device=0xbffff59d "wlp5s0", snaplen=4096, promisc=1, to_ms=1000, errbuf=0xbffff5a4 "R\t") at ./pcap.c:2847
#3  0x00401430 in main () at mypc.c:50

ちまちまとソースを見て行ったら、 /sys/class/net/IFname あたりを見ておくと良いかも。check at debian(64)

root@pen:/sys/class/net/ens33# ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
         :
root@pen:/sys/class/net/ens33# ifconfig ens33 promisc
root@pen:/sys/class/net/ens33# ifconfig ens33
ens33: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST>  mtu 1500
         :

これに対応して、目星を付けたデータは、下記のように変化した。

sakae@pen:/sys/class/net/ens33$ cat flags
0x1003
sakae@pen:/sys/class/net/ens33$ cat flags
0x1103

/usr/include/net/if.h

IFF_UP = 0x1,               /* Interface is up.  */
IFF_BROADCAST = 0x2,        /* Broadcast address valid.  */
IFF_RUNNING = 0x40,         /* Resources allocated.  */
IFF_PROMISC = 0x100,        /* Receive all packets.  */
IFF_MULTICAST = 0x1000,     /* Supports multicast.  */

動かぬ証拠だな。

もう一つ、バグっぽいの。tcpdumpでずっとpromiscにしておき、flagとかを確認

sakae@pen:/sys/class/net/ens33$ cat flags
0x1103
sakae@pen:/sys/class/net/ens33$ /sbin/ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
  :

ちゃんとフラグは立っているのに、ifconfigではそれが見えず。これって、悪い人の盗聴を助長するしかけだな。でも、良心は残っているようで、kill -9 で、突然死させると、該当のflagは落ちたよ。rootさんは、怪しげな盗聴を発見したら、迷わずプロセスを殺しましょう。

これでお終いにしてもいいんだけど、いまいちすっきりしない。NICの石のflagにpromiscが反映されない点。詳細は以前にやったuftraceとかを走らせれば判明するだろうと軽く考えた。

まて、もっとお手軽な誰でも出来る方法があるぞ。

root@pen:/tmp# strace -o LOG tcpdump port 8080
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel

systemcallのログを取得。そして

sakae@pen:/tmp$ grep ioctl LOG | grep ens33
ioctl(3, SIOCGIFHWADDR, {ifr_name="ens33", ifr_hwaddr={sa_family=ARPHRD_ETHER, sa_data=00:0c:29:4d:18:2d}}) = 0
ioctl(3, SIOCGIFINDEX, {ifr_name="ens33", }) = 0
ioctl(4, SIOCGIFFLAGS, {ifr_name="ens33", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
ioctl(3, SIOCGIFHWADDR, {ifr_name="ens33", ifr_hwaddr={sa_family=ARPHRD_ETHER, sa_data=00:0c:29:4d:18:2d}}) = 0
ioctl(3, SIOCGIFINDEX, {ifr_name="ens33", }) = 0

NICの設定をノーマルに戻しているのは引っかかってきた。けど、セットの現場は発見できず。LOGを精査する。

setsockopt(3, SOL_PACKET, PACKET_ADD_MEMBERSHIP, {mr_ifindex=if_nametoindex("ens33"), mr_type=PACKET_MR_PROMISC, mr_alen=0, mr_address=}, 16) = 0

どうやら、これっぽい。setsockoptってのは、systemcallの一員なのね。

pcap-linux.c/activate_pf_packet

/*
 * Hmm, how can we set promiscuous mode on all interfaces?
 * I am not sure if that is possible at all.  For now, we
 * silently ignore attempts to turn promiscuous mode on
 * for the "any" device (so you don't have to explicitly
 * disable it in programs such as tcpdump).
 */

if (!is_any_device && handle->opt.promisc) {
        memset(&mr, 0, sizeof(mr));
        mr.mr_ifindex = handlep->ifindex;
        mr.mr_type    = PACKET_MR_PROMISC;
        if (setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
            &mr, sizeof(mr)) == -1) {
                pcap_fmt_errmsg_for_errno(handle->errbuf,
                    PCAP_ERRBUF_SIZE, errno, "setsockopt (PACKET_ADD_MEMBERSHIP)");
                close(sock_fd);
                return PCAP_ERROR;
        }
}

どうやら、これっぽい。それにして、何でリナにpfなんて語句が出て来るの? なんか裏道っぽい事をやってる雰囲気。だから、正統なifconfigでは、表に出てこないのか。

/usr/include/linux/if_packet.h に、こんな定義が有った。これってリナ専用のNICの裏仕様書だな。得意の速く動けば良い。それには、パケットをあちこち引き回すんじゃなくて、nmapで処理しちゃえ。それで、新たな枠組みが必要ですって事か。

#define PACKET_MR_MULTICAST     0
#define PACKET_MR_PROMISC       1
#define PACKET_MR_ALLMULTI      2
#define PACKET_MR_UNICAST       3

ifconfig.c

リナでpromiscをどうやってセットしてるか? 昔堅気のオイラーは、net-tools/ifconfig.cなんてのを参照してみた。

        if (!strcmp(*spp, "promisc")) {
            goterr |= set_flag(ifr.ifr_name, IFF_PROMISC);
            spp++;
            continue;
        }
        if (!strcmp(*spp, "-promisc")) {
            goterr |= clr_flag(ifr.ifr_name, IFF_PROMISC);
            if (test_flag(ifr.ifr_name, IFF_PROMISC) > 0)
                fprintf(stderr, _("Warning: Interface %s still in promisc mode.\
.. maybe other application is running?\n"), ifr.ifr_name);
            spp++;
            continue;
        }

こんなのが書いてあった。そして、呼び出しているのは、

/* Set a certain interface flag. */
static int set_flag(char *ifname, short flag)
{
    struct ifreq ifr;

    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) {
        fprintf(stderr, _("%s: ERROR while getting interface flags: %s\n"),
                ifname, strerror(errno));
        return (-1);
    }
    safe_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    ifr.ifr_flags |= flag;
    if (ioctl(skfd, SIOCSIFFLAGS, &ifr) < 0) {
        perror("SIOCSIFFLAGS");
        return -1;
    }
    return (0);
}

現状のステータスと言うか、コントロールワードを石から読み込み、それに新たなBITをORして、書き戻している。極めて真っ当なやり方だ。これなら、ちゃんと石の現状を表現してる。

それに対して、libpcapで使われている手法は、石の特性を無視して、隠れて操作しているな。 何だか、2枚舌みたいで、気持ち悪い。まあ、リナは動けばOKってのがデフォだからなあ。

slattach.c

net-toolsの面白いものを発見。前回ちょいと言及したslipだ。

SLATTACH(8)           Linux System Administrator's Manual          SLATTACH(8)

NAME
       slattach - attach a network interface to a serial line

SYNOPSIS
       slattach [-dehlLmnqv] [-c command] [-p proto] [-s speed] [tty]

DESCRIPTION
       Slattach is a tiny little program that can be used to put a normal ter‐
       minal ("serial") line into one of several "network" modes, thus  allow‐
       ing you to use it for point-to-point links to other computers.

こんなものが残っていたとは。ifconfigは最近では推奨されないって事だけど、古い物を捨て去る風潮だな。こういう歴史を抹殺してく訳だ。まあ、今のパソコンにRS232CのI/Fなんて付いていないから、このコマンドが残っていても使い道は、ないだろうけど。

有効に使えたのは、モデムを付けて、パソコン通信してた時代までです(それって、昭和の時代だからね)。

pcap-filter

いい加減リナに秋田んで、OpenBSDのtcpdumpのツリーを見てる。そしたら、面白いやつを発見。tcpdumpでパケットをフィルターするのはpcapに丸投げしてるんだ。そして、そのフィルターの書式が

PCAP-FILTER(5)                File Formats Manual               PCAP-FILTER(5)

NAME
     pcap-filter – packet filter syntax

DESCRIPTION
     pcap_compile(3) compiles pcap filters for software such as tcpdump(8).
     The resulting filter program can then be applied to some stream of
     packets to determine which packets will be supplied to pcap_loop(3),
     pcap_dispatch(3), pcap_next(3), or pcap_next_ex(3).
      :

pcapを使った極小のやつにも、pcap-compileが出て来た。コンパイルしてるのか。そしてコンパイル結果は、tcpdumpで確認出来るとな。

ob# tcpdump -d ip
(000) ldh      [12]
(001) jeq      #0x800           jt 2    jf 3
(002) ret      #116
(003) ret      #0
ob# tcpdump -d tcp
(000) ldh      [12]
(001) jeq      #0x86dd          jt 2    jf 4
(002) ldb      [20]
(003) jeq      #0x6             jt 7    jf 8
(004) jeq      #0x800           jt 5    jf 8
(005) ldb      [23]
(006) jeq      #0x6             jt 7    jf 8
(007) ret      #116
(008) ret      #0

最初のフィルターは、ipだけ通してね。次のフィルターはtcpなパケットだけを通してねって指示だ。何となく分かるような気がする。

最初のやつだと、パケットの12番目のデータが0x800なら、それはIPパケットですって読める。 それはいいんだけど、この翻訳された超ミニ言語を実行する機構が必要だな。

ひょっとして bpf(4)

Filter machine
  A filter program is an array of instructions with all branches forwardly
  directed, terminated by a “return” instruction.  Each instruction
  performs some action on the pseudo-machine state, which consists of an
  accumulator, index register, scratch memory store, and implicit program
  counter.

  The following structure defines the instruction format:

        struct bpf_insn {
                u_int16_t       code;
                u_char          jt;
                u_char          jf;
                u_int32_t       k;
        };

この後に例が沢山出て来てる。一方tcpdumpのオプションをちょいとC語風に表示するように指示してみた。なんか、bpfの説明と符合してるね。

ob# tcpdump -dd ip
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 1, 0x00000800 },
{ 0x6, 0, 0, 0x00000074 },
{ 0x6, 0, 0, 0x00000000 },

そして動かぬ証拠を掴んだ。 libpcap/bpf_image.c

case BPF_LD|BPF_W|BPF_ABS:
        op = "ld";
        fmt = "[%d]";
        break;

case BPF_LD|BPF_H|BPF_ABS:
        op = "ldh";
        fmt = "[%d]";
        break;

case BPF_LD|BPF_B|BPF_ABS:
        op = "ldb";
        fmt = "[%d]";
        break;

case BPF_JMP|BPF_JEQ|BPF_K:
        op = "jeq";
        fmt = "#0x%x";
        break;
 :

BPFのコマンドをlibpcap流の表記で印字する、逆アセンブラーなんだな。

BPF