最近和各大AI大語言模型一起合作寫了個小項目,讓大家看看AI離取代人類還差多遠。
開發大家都在一個共享環境下,連docker
都不能運行,rootless也沒有。不過好在linux環境,弄個proot
能apt或者yum install自由,但是諸如podman
這樣的程序還是沒法運行。一陣惱火,于是下載了linux kernel直接ARCH=um
編譯出user mode linux,我自己運行自己的內核總可以了吧。
喜滋滋編譯完,好了,這個kernel沒有網絡。挖墳找找自己以前寫的文章看看當時怎么配置user mode linux的,結果是要tun/tap設備,這個需要管理員先開一些權限,在rootless下可以用,但是這個權限沒開啊…
于是開始到處找不用tun/tap的方法。發現了user mode linux的網絡可以支持daemon
和slirp
模式,這不是很好么。于是興沖沖跑去github搜索一下,有些好些年前的項目,編譯出來,怎么都不能運行?daemon
模式有點復雜的,相當于需要從二層網絡開始處理…而slirp
是三層網絡,只處理ip packet。
那我只要有個程序處理這些ip packet連上internet,我的user mode linux不就可以聯網了么。于是喊上LLM,這還不簡單。
首先登場的當然是寫代碼目前最強的Claude4,讓它用c寫一個簡單的slirp程序,結果程序是能一次性編譯通過,但是好像用user mode linux加載沒什么反應。然后嘗試了下gemini2.5pro,gpt4o,qwen3,都不能一次性編譯通過了都…
這下遇到瓶頸了,很煩躁。繼續手動搜索,突然找到了libslirp
,眼前一亮。于是讓claude4用c和libslirp
寫一個簡單的slirp程序,程序有一處錯誤改正下就能正常編譯了,但是運行以后還是什么都沒有。于是手動從libslirp
的gitlab上扒下來一個ping的example,發現編譯不過,原來是libslirp
最新已經4.9了,一般linux源里的都還是4.4,版本號改變不大但是內部api有一些大動靜…加上文檔寫得很差,AI都寫得不太對了。(所以知道了吧,要想不被AI取代,請把項目文檔寫差一點…目前為止我讓AI寫調用公司產品API的代碼復雜的就沒有對過的,發現它被文檔毒害得不淺,或者說產品文檔實在質量太差,連參數都能列錯…而開發k8s operator代碼剛剛的,因為人家文檔不錯,正確案例也多…)
寫了半天,發現這個libslirp
好像只是一個網絡packet封裝啊,看完文檔發現它還是要靠一些手段諸如tun/tap連到外面…我要是能這么做,早就iptables配置好了啊…然后還試用了下slirp4netns
(unshare
-> no permission),同樣的問題…
然后繼續搜索引擎,突然找到了個pySLiRP
,它是需要一個/dev/usbXXX設備作中介,通過PPP協議傳輸packet數據的。于是我又仔細看了下slirp的說明,據說是通過stdin和stdout交換數據。于是拿到這個pySLiRP
以后,看了下它是通過打開usb設備設定baud rate通信的,我讓AI寫點代碼把它替換掉不就好了?于是讓claude4和gemini2.5pro比賽寫代碼,因為pySLiRP
用的是asyncio
,它通過第三方庫打開usb設備得到async的reader
和writer
,這下目標明確,讓倆模型寫一段python代碼將stdin和stdout轉化為async的reader
和writer
。嗶嗶嗶,代碼寫得很快,claude4響應比gemini快不少,質量也好很多,但是有些時候claude4沒處理好的細節可能gemini可以補上一些,所以基本我還是喜歡讓2個模型一起寫代碼,增加成功率(qwen3的代碼能力確實還是有待提高的,大部分時候不能滿足開發要求,所以這里暫時選了claude4+gemini2.5pro)。這次AI的代碼直接放到原有代碼里,把接口換成調用AI的代碼,一次性成功。我還讓AI給加了dump hex數據到stderr的代碼。運行user mode linux,配置網絡,ping一下某個ip,然后終于有數據打印到stderr了。
因為網絡知識奇差無比,這些hex是啥意思?直接問AI好了,解釋下這坨binary是什么意思。哦,很給力,兩個AI都解析出了這坨binary是一個ip packet,并且是一個icmp ping的packet,只是兩頭多了0xc0。這里claude說不知道這是啥意思,但是gemini給出了猜測,根據這個0xc0,很像是slip
的protocol。
然后再去查slip protocol,原來就是一些encode/decode的約定。這時候再讀pySLiRP
的代碼,用了一套PPP protocol,牛頭不對馬嘴啊…但是有了最基礎的輸入輸出數據樣本,我又試了一下libslirp
,完全不知道怎么控制它啊…算了,用raw的形式先把ping搞定,至少要先讓ping有unreachable host輸出。
于是先讓AI寫了倆函數去encode和decode slip,這樣我們從stdin拿到數據,然后decode以后就是一個純ip packet了。然后讓AI寫一個函數,如果我有一個ping的ip packet,解析之后生成一個unreachable host的ping response。對于這種特別明確的任務,claude4可怕的地方就來了,一次性寫對,直接使用。于是我們有了第一個slirp的python版本——slirp.py
。放到user mode linux里,配置好網絡,ping一下,穩定得到unreachable host了!甚至其他curl或者網絡請求都會得到“無響應”的響應。最初版本成功!
寫到這里突然意識到目前這個項目實際上是寫一個程序,這個程序要求是一邊處理ip packet,另一邊處理和外界的聯系,有點像NAT,或者更像proxy,但是不同的地方是兩邊處理的粒度不一樣。比如ping,我們得到ip packet,然后我們要把icmp的payload拿到,然后使用user mode下的socket
發送這些payload,再得到response payload,并且構造ip packet去響應user mode linux的網絡請求。
所以剛才的unreachable host版本寫完以后,我讓AI寫一個程序,可以rootless得發送icmp payload,并且得到icmp response,并生成一個可用得response ip packet…把這次的代碼和最初版本接起來,得到一個可以ping外部ip的slirp版本。當然,如果是ping內部同虛擬網段的機器,我們還可以讓AI寫個程序一直response ok就好了。至此ping的部分就做好了。
這給了我一部分和AI繼續合作的信心。因為考慮到后續python的運行速度可能會比較慢,所以又讓AI把之前的代碼用golang寫了一遍。很不錯,各個部分都是一次性編譯通過并且運行無誤。
之后就進入udp處理的部分了。這個部分主要是先支持ping www.csdn.net,因為上面的最初版本,里面會判斷如果是icmp ping,再判斷是內部網絡還是外部網絡ip,就能走通ping,其他的ip packet還是unreachable host,所以ping www.csdn.net會告訴我domain name暫時不可用,打出的ip packet第一個也是一個dns query的udp packet。relay吧,udp packet發送過來,然后slirp維護一個map
,并和對應net.UDPConn
通信就好了。從udp packet里拿到payload,拿到服務器的ip和port,發送payload,拿到response,拼接一個合適的ip packet發送回去,通路成功!這下ping一個域名也可以了。我出要求,AI寫代碼,我負責integration整合并且debug…還算順利。
之后有一個難題就是udp是無狀態的,那我在map里的connection什么時候釋放呢?之后想了個簡單策略,如果30s沒有通信,直接timeout釋放掉,之后它發送數據再創建連接好了。至于udp server如何處理,暫時不慌,以后再說吧。
接下來就是處理tcp了。這個時候也是gpt5剛出來的時候,讓它寫了點代碼,真的是牛頭不對馬嘴,算了,還是繼續claude4+gemini吧…這個時候代碼已經有個600多行了,在免費的高級模型里,已經不能讀代碼然后改了。沒關系,我們直接讓它寫一個處理tcp的ip packet,然后再寫一個程序處理tcp payload的讀寫,把兩個程序代碼拼一起就完成了最基本的。
這個時候把claude4的代碼貼進去,運行,然后curl http://bing.com,看到log已經顯示連接到bing的ip,并且發送了http request,只是curl一直報錯 http/0.9 not allow之類,傻眼了。把代碼片段貼給倆AI模型,然后告訴我了幾個錯誤的bug…這下抓瞎了…只能看看curl的源代碼哪里報這個錯,但是看代碼還是要花不少時間…
這個時候正好是gpt5出了gpt5-high和gpt5-chat不同版本的時候,那就試試gpt5-high吧,把處理tcp的部分直接貼給它,它直接指出了錯誤,給口碑崩塌的gpt5挽回了一些顏面…原來是處理SYN SYN-ACK ACK的時候SeqNum忘了加一!不錯,AI對有效context內代碼的理解已經很給力了。
寫到這里,slirp.go
已經在沒有第三方庫的情況下1000多行能夠處理簡單curl http://some-index-server
了,比如準備好一個寫了world的hello文件放nginx上,curl一下會返回world。之后接著就要考慮如何給超過MTU的tcp分片傳輸了…先休息下,等完成了放代碼出來…
(未完待續)