前言
最近拿到一台要價不菲的轉檯 (FLIR PTU-E46
以下稱為 PTU),預計要用在無線通道量測的自動化量測系統中,必須能控制其轉向,並且要能夠知道當前角度。
仔細研究一下 PTU 的說明書,發現除了 RS-485/232 外,還可以用網際網路來通訊。之後整個系統中預計會有兩個 PTU,為了能讓電腦少一點連接線甚至少到只需要一條網路線,用網路介面來做通訊媒介當然是首選。
廠商有附一個軟體,可以尋找 PTU 在區網內的 IP,但我發現這個軟體使用上非常碰運氣,怎麼說呢?我執行這找 IP 的程式 10 次,可能只有 1 次找得到 IP,重點是每次 PTU 重機開 IP 就會跑掉,這樣對開發人員或使用者來說都是麻煩。
可能看到這裡,就會有人建議可以指定一個 IP 給儀器,這樣不用每次重新開機都要搜尋。這樣可行是沒有錯的,但是指定 IP 並非人人都會,在未來系統的操作手冊中可能就要大篇幅說明這樣的設定流程。
當要控制一個儀器之前,若要先開一個軟體找到它 IP,然後再記下 IP 輸入進另外一個程式裡,連我自己操作都覺得很麻煩!
因此,我就思考,若能自己寫一個能順利找 IP 的程式,再把此功能鑲嵌在未來控制 PTU 的程式裡,豈不美哉?將找 IP 與控制的程式整合在一起,只需要點點滑鼠就能與 PTU 連線,使用者不需花時間在連線上面,大家都開心。
我的一個原則:自動化系統越少人工輸入的地方越好。
想法
這的確是個問題,通常儀器商不會給原始碼,加上可以想像程式整合後,使用流程上會有多方便,此問題便成立。首先想想這問題該如何切入?
(開始自言自語) 當然是寫一個跟附的軟體一樣的功能阿!但我沒原始程式碼怎麼辦呢?網路上也找不到其他人有說廠商的尋找 IP 程式怎麼寫。啊!這軟體是用來找 IP 的,那肯定跟網路有關,要能使用網路通訊,必定要發封包,對!關鍵應該就是封包!只是不知道封包的內容是甚麼?印象中我好像有學過用 Wireshark 截取封包來看內容,趕緊去載!
一步步破解
觀察原軟體所發送封包
載好就來看看這個軟體到底發甚麼封包才能找到儀器,先開啟 Wireshark 預備好,再執行廠商附的尋找 PTU IP 的程式
登愣~抓到!答案呼之欲出,看起來很神秘的程式,說穿不值一文錢。
原來是直接利用 UDP 廣播 (255.255.255.255) 的方式,來找出儀器的 IP 是多少。第一個廣播封包是由我的電腦 (192.168.0.101) 發出,訊息長度是 10 Bytes,這訊息內容就如同「嗨,我想要找的 PTU 們,你們在哪呀?我的通關密語是 "xxxx"(封包內文)」。
當 PTU 判斷廣播封包的通關密語正確,第二個廣播封包便是由 PTU (192.168.0.100) 這端發出,訊息長度是 17 Bytes,想當然就是回應「你好,我在這!我的通關密語是 "yyyy"(封包內文)」。
這時,當軟體判斷接收到包含通關密語 "yyyy" 的封包之時,該封包的 Source IP 即為儀器的 IP!嘿嘿,短短兩個封包,說明一切!
現在知道這程式是如何運作的,基本上也不需要它的原始碼,只要做出一樣的功能即可。也就是說,若能寫出一個程式,發送廣播封包,讓儀器有反應並且回應一個廣播封包,再去抓此封包的 Source IP 就可以解決這個看似困難的問題。
那現在就來看看他們之間的通關密語是甚麼吧
這下可更清楚了,電腦端先說 DCUD_PING\0
,儀器端再回覆 DCUD_PONG\0KERNEL\0
。雖然個人覺得儀器端的回覆訊息應該有打錯字,PONG 應該為 PING,但是不管這麼多了,說不定儀器商有發現,只是礙於已經賣出產品,目的能溝通正常運行達到就好,沒想到會被別人在這種情況下看到錯字XD。 (但我後來又想想,應該是兵乓球的 PING PONG,賦予這兩個封包有個來回對答的感覺)
實作
到目前為止,分析的步驟已經結束,完全清楚主機和儀器們在聊什麼,可藉此抓封包來源 IP 得知儀器所在位置。
現在就要開始實做,因為之後控制的軟體的開發都是以 MATLAB
為主,因此採用 MATLAB
來傳送與接收封包,目前知道此封包是
- 廣播
- 連接埠是 4930
- 採用 UDP
- 包含通關密語
DCUD_PING\0
MATLAB
是一個很強大的軟體,工程上的需求應該都有內建函式能用。找到他關於封包發送接收的物件有 tcpip
、udp
等等,但在此只會用到 udp
物件。
先看看在 MATLAB
裡面 help udp
的介紹
OBJ = udp('RHOST', RPORT) constructs an udp object associated with remote host, RHOST, and remote port value, RPORT.
非常簡單!只要給目的地端 IP (RHOST = 255.255.255.255) 和目的端的連接埠 (RPORT = 4930),就能建立一個udp物件
1 | >> u = udp('255.255.255.255', 4930); %創建一個 udp 物件叫 u。 |
u.Status
是這個 udp
物件現在的狀態,closed
為還沒連線,open
才為連線成功,物件建立好之後要讓其狀態為 open
才能通訊喔!
1 | >> fopen(u); %用來打開通訊協定物件的連線狀態 |
這樣代表連線是可以的。來吧,接下來就是傳一個包含通關密語的封包出去看看。
傳送是用 fwrite
、fprintf
與 query
fwrite(udp, A)
:將資料A
用連線好的udp
物件發送出去。fprintf(udp, A)
:與fwrite
功能一樣,但不同的是會「自動」在A
最後加上一個換行 (LF
) 碼,再傳送出去。query(udp, A)
:包含fprintf
的功能,除此之外,還會抓一個在緩存區的封包進來,若一定時間內都沒有封包能抓,query
會回覆逾時的結果。
為了跟廠商軟體所發送的封包一樣,因此選擇不會有添加物的 fwrite
來控制封包內容,實現發送封包。
1 | >> A = ['DCUD_PING' char(0)]; %通關密語 'DCUD_PING\0' |
發送封包後,查看 Wireshark 竟然還是空的,難道哪裡做錯或想錯了嗎?目標 IP 為 255.255.255.255 沒錯呀,摁?這個 IP 是廣播 IP,所以每個區網都有,我的電腦好像有兩三張網卡,但我目前沒有設定要廣播在哪個區網,該不會廣播錯網域了吧?來看看其他網域的封包
我猜得果然沒錯,儀器是在 192.168.0.0/24 網域內,而這個廣播封包被送去 169.254.0.0/16,儀器當然不會回應。若我想廣播在 192.168.0.0/24,那我必定要以 192.168.0.100 的身分去做廣播,否則會像上面的情況廣播去別地方。那就看看如何設定 udp
物件吧!在 MATLAB
有一個很好用的函式叫做 get(obj)
,他能列出物件obj的所有屬性
1 | >> get(u) |
又抓到了!在此就可以設定自己的 IP (LocalHost) 與連接埠 (LocalPort)。由於儀器廣播的目標連接埠是 4930,因此 LocalPort 需要設定為 4930,否則就算儀器廣播封包送出,連接埠沒對上也接收不到。
再驗證一遍自己的想法
1 | >> u = udp('255.255.255.255', 4930, 'LocalHost', '192.168.0.101', 'LocalPort', 4930); |
有沒有!看起來跟廠商附的軟體發的封包一模一樣!但其實我的目標就是模仿到一樣啦。
收成
到現在這步,已經可以坐收儀器發出來的封包,在 MATLAB
裡用 fgetl
、fgets
、fscanf
或 fread
來收封包,這些指令都能回傳封包的來源 IP,所以都可以使用,我選擇使用 fscanf
1 | >> [A, count, MSG, DatagramAddress] = fscanf(u); %抓封包 |
喔耶,終於拿到儀器的 IP 了。
結論
遇到工程問題要解決時,必須先弄清其原理,才有創造的可能。這篇是我個人認為將在課堂上所學到的知識與實際問題應用結合的一個典型範例,在此勉勵自己若將來遇到其它問題,也能夠先弄懂原理再舉一反三。