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 ですって言われたんで、用意した覚えがある。 シンプルでよかったな。
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に出て来るそれを目印にしてた。リナでは、それが表われないんだ。
なんてやると、確かに現れるけどね。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流の表記で印字する、逆アセンブラーなんだな。