Raspberry Pi の USB-OTG ethernet の MAC address を model B の ethernet と同じ規則で設定する

Raspberry Pi model A/A+/Zero/ZeroW/ZeroHW/Compute Module/Compute module 3ではUSB-OTGが利用できます.(ZeroHW/Compute Module/Compute module 3は自分は未確認)

USB-OTGでUSBをEthernetにしてHostPCからアクセスするようにするとUSBケーブル1本で電源と併用できて便利です.

このときMACアドレスはモジュール読み込み毎に自動生成されます.
以下の例では,接続先(PC等)から見えるMACが HOST MAC 6a:b3:b1:5e:22:89 で,Raspberry Pi の中でのMACが MAC ae:3a:c7:8e:50:38 になっています.

$ sudo modprobe g_ether
$ dmesg | tail -15
[   88.517568] using random self ethernet address
[   88.517590] using random host ethernet address
[   88.519210] usb0: HOST MAC 6a:b3:b1:5e:22:89
[   88.520195] usb0: MAC ae:3a:c7:8e:50:38
[   88.520396] using random self ethernet address
[   88.520412] using random host ethernet address
[   88.520534] g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
[   88.520546] g_ether gadget: g_ether ready
[   88.520580] dwc2 20980000.usb: bound driver g_ether
[   88.866651] IPv6: ADDRCONF(NETDEV_UP): usb0: link is not ready
[   94.048758] dwc2 20980000.usb: new device is high-speed
[   94.128837] dwc2 20980000.usb: new device is high-speed
[   94.197523] dwc2 20980000.usb: new address 9
[   96.057234] g_ether gadget: high-speed config #1: CDC Ethernet (ECM)
[   96.095719] IPv6: ADDRCONF(NETDEV_CHANGE): usb0: link becomes ready
$ /sbin/ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.42.0.212  netmask 255.255.255.0  broadcast 10.42.0.255
        inet6 fe80::5855:ab0c:6628:557c  prefixlen 64  scopeid 0x20<link>
        ether ae:3a:c7:8e:50:38  txqueuelen 1000  (Ethernet)
        RX packets 208  bytes 17243 (16.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 67  bytes 7696 (7.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

これは毎回変わるのでふと気づくとホストPCのネットワークの設定が沢山になっていたり…….

$ nmcli connection show | grep ethernet | wc -l
25

MAC addressを固定するにはモジュール読み込み時に指定してあげればOKです.

$ sudo rmmod g_ether
$ sudo modprobe g_ether host_addr=de:ad:fe:ef:00:01 dev_addr=de:ad:fe:ef:00:00
$ dmesg | egrep usb0:.*MAC | tail -2
[ 1067.248443] usb0: HOST MAC de:ad:fe:ef:00:01
[ 1067.248958] usb0: MAC de:ad:fe:ef:00:00

永続化するには,g_etherモジュールを読んでいるところで指定してあげます.

/boot/cmdline.txt の場合 rootwait の前に以下を追加
modules-load=dwc2,g_cdc g_ether.host_addr=de:ad:fe:ef:00:01 g_ether.dev_addr=de:ad:fe:ef:00:00
/etc/modules の場合
g_ether g_ether.host_addr=de:ad:fe:ef:00:01 g_ether.dev_addr=de:ad:fe:ef:00:00
Note

※g_cdcの場合はこんな感じで

g_cdc g_cdc.host_addr=de:ad:fe:ef:00:01 g_cdc.dev_addr=de:ad:fe:ef:00:00

/etc/rc.local の場合 exit より前の行に以下を追加(※model Aの場合 cmdline.txt, modules 共に module は読み込まれるけど動作はうまく行かないことが多いので rc.local が良さそう)
modprobe g_ether host_addr=de:ad:fe:ef:00:01 dev_addr=de:ad:fe:ef:00:00

このときのMAC addressは g_ether が自動生成したものを使うのが無難だとおもうのですが,ランダムとかでいんだろうか?という不安があります.

ベンダーIDに使われていない領域だったら多分問題ないですが,これから埋まることもありそうです.(IPアドレスのプライベートIPアドレスのような領域があるのかもしれ無いけど未確認)

Raspberry Pi model B シリーズのNICには Raspberry Pi Foundation のベンダーコードが使われています.

nmap のMAC addressベンダー情報のファイルから確認
$ grep -i raspberry /usr/share/nmap/nmap-mac-prefixes
B827EB Raspberry Pi Foundation

Raspberry Pi の smsc95xx の MAC address の生成は,上6桁はベンダーIDの b8:27:eb を,下6桁はボードのserialの下6桁を割り当てているようです.

MAC address generation
To have a predetermined MAC address, a given SMSC LAN9512 must be attached to an EEPROM that contains the MAC address. But on the Raspberry Pi Model B, this EEPROM is not present; therefore, this driver must assign a MAC address itself. We do this by generating a MAC address from the board’s serial number. This guarantees that a given Raspberry Pi will always have the same MAC address and that two Raspberry Pis are extremely unlikely to be assigned the same MAC address.

手元の Raspberry Pi 2 Model B を確認すると確かにそうなっているようです.

$ ifconfig | grep ether
		ether b8:27:eb:ff:56:0a  txqueuelen 1000  (Ethernet)
$ grep Serial /proc/cpuinfo
Serial          : 0000000094ff560a
$ sed -n "s/^Serial.*:.*\(..\)\(..\)\(..\)$/b8:27:eb:\1:\2:\3/p" /proc/cpuinfo
b8:27:eb:ff:56:0a
$ cat /proc/device-tree/model ;echo
Raspberry Pi 2 Model B Rev 1.1
Note

16進数6桁は 0xFFFFFF → 16777215です,Raspberry Pi は2018年3月時点で190万台出荷しているようなので2周目に入っています.低い確率でしょうが同じMAC addressが割り当てられる可能性が…….

we’ve sold 19 million Raspberry Pis in total

内蔵ネットワークに自分でMAC addressを指定したい場合はこんな感じでいけます.

/boot/cmdline.txt に以下を設定
smsc95xx.macaddr=b8:27:eb:00:00:00
/etc/network/interfaces でも設定できるはずだがRaspbianでは未確認
hwaddress ether b8:27:eb:00:00:00

CPU Serialを詐称する手も?

ということで,Raspberry Pi model A / Zero でもこの MAC address が利用できそうな感じです.外向けの HOST MAC をこのアドレスにしてみます.

$ sed -n "s/^Serial.*:.*\(..\)\(..\)\(..\)$/b8:27:eb:\1:\2:\3/p" /proc/cpuinfo | tee ~/macaddress
b8:27:eb:d8:63:18
$ sudo vi /boot/cmdline.txt
$ sudo reboot
  :
  :
$ dmesg | grep usb0
[    4.937660] usb0: HOST MAC b8:27:eb:d8:63:18
[    4.937845] usb0: MAC 86:d7:fe:57:f2:d5

ホストPCでもちゃんと指定したものになっています.

$ /sbin/ifconfig enxb827ebd86318 | grep ether
			 ether b8:27:eb:d8:63:18  txqueuelen 1000  (Ethernet)

とりあえずこれで使ってみようと思います.

環境
$ lsb_release -d
Description:    Raspbian GNU/Linux 9.4 (stretch)
$ uname -m
armv6l
$ cat /proc/device-tree/model ;echo
Raspberry Pi Model A Rev 2

不正なUSBデバイスからPCを守るUSBGuardを試す

BadUSBなどの不正なUSBデバイスからPCが守れないかなちょっと設定すればできそう?そもそも作っている人がいるんじゃ?ということで探したらUSBGuardというソフトウェアを見つけました.

このソフトウェアを導入しておくと,設定したルールに合致しないUSBデバイスはblockされます. デスクトップ利用の場合はGUIのアプレットを利用してUSB接続時にウィンドウがポップアップして接続するか選べたりもします. 便利.
#USB KILLERは……USB配線を外したりUSBコネクタを塞ぐしかないですよね多分.

導入

Debian/Ubuntuにはパッケージがあるのでそちらから導入します.

$ sudo apt install usbguard usbguard-applet-qt

設定

一般ユーザから利用する場合は設定ファイルを編集してユーザかグループを追加してデーモンの再起動を行います. 設定ファイルは/etc/usbguard/usbguard-daemon.confです.

diff --git a/usbguard/usbguard-daemon.conf b/usbguard/usbguard-daemon.conf
index 4a54ca0..7b3a165 100644
--- a/usbguard/usbguard-daemon.conf
+++ b/usbguard/usbguard-daemon.conf
@@ -65,7 +65,7 @@ PresentControllerPolicy=keep
#
# IPCAllowedUsers=username1 username2 ...
#
-IPCAllowedUsers=root
+IPCAllowedUsers=root user1 user2

#
# Groups allowed to use the IPC interface.
@@ -75,7 +75,7 @@ IPCAllowedUsers=root
#
# IPCAllowedGroups=groupname1 groupname2 ...
#
-IPCAllowedGroups=root
+IPCAllowedGroups=root users

#
# Generate device specific rules including the "via-port"

ユーザの場合はIPCAllowedUsers,グループの場合はIPCAllowedGroupsにスペース区切りで書いていきます.

デーモンの再起動

設定を反映するためにデーモンを再起動します.

$ sudo service usbguard restart

CUIでの利用例

usbguardが起動した後に接続されたデバイスはblockされています.

$ usbguard list-devices| tail -2
9: allow id 8087:0024 serial "" name "" hash "Zx7v0FMQEjScKSAFENAiobEs1OGPPB0YWR+yXDCVE04=" parent-hash "WwvSEwd+7257rAqUGLMQjffF7zyqygmmLeQTYnR9QzQ=" via-port "4-1" with-interface 09:00:00
11: block id 1004:631c serial "03a809c94b4befd4" name "LGE Android Phone" hash "P5dSK5xxK4R5QTRzd7KlD8Agf/+28pztL077j1oWqPI=" parent-hash "Zx7v0FMQEjScKSAFENAiobEs1OGPPB0YWR+yXDCVE04=" via-port "4-1.1" with-interface ff:ff:00

blockされている11番目のデバイスを許可してみます.(これは一時的です)

$ usbguard allow-device 11
$ usbguard list-devices| tail -1
11: allow id 1004:631c serial "03a809c94b4befd4" name "LGE Android Phone" hash "P5dSK5xxK4R5QTRzd7KlD8Agf/+28pztL077j1oWqPI=" parent-hash "Zx7v0FMQEjScKSAFENAiobEs1OGPPB0YWR+yXDCVE04=" via-port "4-1.1" with-interface ff:ff:00

状況の確認

USBデバイスの認識状況を監視します.

$ usbguard watch
[IPC] Connected
[device] Inserted: id=12 hash=vi38heJ4vKEdayxiqrQFylpwa3xkVYYUkZi2zbu3sWs= name=Mass Storage Device product_id=1336 serial=00000000000006 vendor_id=048d interface={ 08:06:50} rule_match=0 rule_id=4294967295
[device] Blocked: id=12 name=Mass Storage Device product_id=1336 vendor_id=048d rule_match=0 rule_id=4294967295
[device] Allowed: id=12 name=Mass Storage Device product_id=1336 vendor_id=048d rule_match=0 rule_id=4294967295

GUI(usbguard-applet-qt)の利用例

CUIだとちょっと面倒ですが,デスクトップ利用の場合はusbguard-applet-qtが便利です.

usbguard-applet-qtが起動した状態でUSBデバイスを接続すると以下のようなダイヤログが表示されます.Allowボタンを押すことで利用できるようになります. このとき,Make the decision permanentにチェックを入れておくと,設定が永続化されます.この設定は/etc/usbguard/rules.confに記録されます.

20161007_02:10:22-9078

ダイヤログはタイムアウトすると消えてしまいますが,アプレットのウィンドウから設定画面を呼び出すことができます.ここから設定変更ができます.

20161007_16:10:49-4107

とりあえずはこれくらいで良さそうですが,ルールを書くといろいろ応用が効きそうです.

とりあえずはどうもデーモン起動までに接続されていたデバイスは許可されるようなので内臓デバイスを明示的に許可してその他をblockしようと思います.