星期二, 4月 29, 2014

getaddrinfo()

getaddrinfo() 取得網址或服務所有符合的 socket 位址,可能需要 DNS 查詢。
int getaddrinfo(                 // 回傳 0 成功,其它錯誤
    const char *node,            // 名稱網址或數字網址
    const char *service,         // 服務 "http" 或 "80"
    const struct addrinfo *hints,// 位址規範
    struct addrinfo **res);      // 回傳位址串

網址 (node) 或服務 (service) 其中至少要有一個,加上 hints 的規範,在 res 回傳一串符合的位址。node 如果是名稱網址,需要 DNS 查詢。res 可能回傳多個位址、多個協定 (AF_INET 或 AF_INET6)、多個 socket types (SOCK_STREAM 或 SOCK_DGRAM 等),順序依據 RFC 3484 的定義,會使修改 /etc/gai.conf 調整,上尾愛用 freeaddrinfo() 放掉動態配的記憶體。

service 可以是 service name 或十進位數字字串,決定回傳位址的 port 部份。沒 service 則未定。(疑問:DNS 查詢不會設定回傳的 port?)

hints 和 res 內容攏是 struct addrinfo。

struct addrinfo {
    int              ai_flags;
    int              ai_family;   // AF_UNSPEC, AF_INET, AF_INET6
    int              ai_socktype; // 0, SOCK_STREAM, SOCK_DGRAM
    int              ai_protocol; //
    socklen_t        ai_addrlen;  // ai_addr 長度
    struct sockaddr *ai_addr;     // socket 位址
    char            *ai_canonname;
    struct addrinfo *ai_next;     // linked-list
};

沒 hints 相當於設 ai_socktype 和 ai_protocol 為 0、ai_family 為 AF_UNSPEC、和 ai_flags 為 AI_V4MAPPED | AI_ADDRCONFIG (POSIX 規範是 0)。

ai_flags:
  • AI_NUMERICHOST:node 必須是數字網址,不進行可能愛開時間的 DNS 查詢。
  • AI_PASSIVE:沒 node 時才有作用,回傳的 socket addresses 是 INADDR_ANY 或 IN6ADDR_ANY_INIT,適合 bind() 後 accept() 的 socket,應用在接受任何主機的連線。原本沒設回傳的 socket addresse 適合用在 connect()、sendto()、或 sendmsg(),沒 node 會是 INADDR_LOOPBACK 或 IN6ADDR_LOOPBACK_INIT,應用在打算 communicate with peers running on the same host..
  • AI_NUMERICSERV:已知不需要時用來禁止進行 name resolution service,有 service 時,要是數字字串。
  • AI_CANONNAME:回傳的第一個位址的 ai_canonname 有主機 official name。
  • AI_ADDRCONFIG:自己有設定 IPv4 界面才回傳 IPv4 位址,有設定 IPv6 界面才回傳 IPv6 位址,確保回傳的位址自己是能使用的。loopback 位址不視為設定的界面。
  • AI_V4MAPPED:如果 hints.ai_family 是 AF_INET6 且沒有符合的 IPv6 位址,回傳 IPv4-mapped IPv6 addresses。
  • AI_ALL:同時回傳 IPv6 和 IPv4-mapped IPv6 addresses,AI_V4MAPPED 有設才有意義。
  • AI_IDN:需要的話,node 中非 ASCII 字元依據 locale 先轉成 ASCII Compatible Encoding (ACE) 的 IDN 格式,才進行 name resolution。
  • AI_CANONIDN:如果 AI_CANONNAME 有設,回傳 ai_canonname 包含的 ACE xn-- prefix 部份,會依據 locale 轉換。
  • AI_IDN_ALLOW_UNASSIGNED:IDNA 處理允許 unassigned Unicode code points。
  • AI_IDN_USE_STD3_ASCII_RULES:IDNA 處理檢查 output 是 STD3 conforming hostname。

ai_protocol:
ai_addr:指到 struct sockaddr,內含 sa_family 及 sa_data

回傳值 0 表示成功,其它則有錯誤,可用 gai_strerror() 轉換成錯誤字串。

  • EAI_ADDRFAMILY:沒有符合的 ai_family。
  • EAI_AGAIN:name server 回暫時失敗,稍後 Try again。
  • EAI_BADFLAGS:hints.ai_flags 有錯誤,包括 AI_CANONNAME 但 ai_canonname 是空的。
  • EAI_FAIL:name server 回 permanent failure。
  • EAI_FAMILY:請求的 ai_family 不支援。
  • EAI_MEMORY:Out of memory.
  • EAI_NODATA:指定的網址存在,但沒定義任何 network addresses。
  • EAI_NONAME:node 或 service 未知。hints.ai_flags 是 AI_NUMERICSERV,但 service 不是數字字串。
  • EAI_SERVICE:請求的 service 在指定的 socket type 沒有,可能其它 socket type 有。例如:service 是「shell」需要 stream socket,但 hints.ai_protocol 是 IPPROTO_UDP 或 hints.ai_socktype 是 SOCK_DGRAM。hints.ai_socktype 是 SOCK_RAW 沒有 service 概念,但卻設了 service。
  • EAI_SOCKTYPE:請求的 hints.ai_socktype 不支援,包括和 hints.ai_protocol 所指不一致,例如 SOCK_DGRAM 和IPPROTO_TCP。
  • EAI_SYSTEM:其它系統錯誤,檢查 errno for details.

inet_aton():只適用於轉換 IPv4 數字 IP。雖然 getaddrinfo() 也可以,但使用了許多系統呼叫。
inet_addr():obsoleted by inet_aton()
inet_pton():轉換 IPv4 或 IPv6 數字位址為二進位。

結合舊式 gethostbyname() 及 getservbyname() 的功能,並且是 reentrant 及支援 IPv6,輸出也方便後續 socket 程式直接利用。

getaddrinfo() 本身並不知道所謂的 DNS,或者對位址 cache,strace 呼叫 getaddrinfo() 的程式,可能呼叫超過 100 個系統呼叫,包括:
  • 開啟 PF_NETLINK socket 得知有那些界面,是 IPv4 或 IPv6 或兩者。
  • socket 連接 Name Service Cache Daemon,開啟 socket /var/run/nscd/socket。依據內部狀態,可能會嘗試兩次。nscd socket 界面似乎沒標準。
  • /etc/nsswitch.conf 得到「hosts: files myhostname dns」說要找 host,首先問 library libnss_files.so,如果失敗問 libnss_myhostname.so,最後問 libnss_dns.so。
  • 載入 libnss_files.so 查詢 /etc/hosts。
  • 載入 libnss_dns.so 讀 /etc/resolv.conf 進行 DNS 查詢。
  • 讀取 getaddrinof() 設定檔 /etc/gai.conf
  • 嘗試 socket 連接取得的位址
參考:
  1. man getaddrinfo
  2. Beej's Guide to Network Programming 正體中文版getaddrinfo()-準備開始!
  3. What does getaddrinfo do?
  4. dnsmasq 可提供 DNS cache
  5. 待讀:https://engineering.purdue.edu/kak/compsec/NewLectures
  6. 待讀:https://libwebsockets.org/lws-api-doc-master/html/md_READMEs_README_8async-dns.html/Lecture17.pdf 
  7. Anatomy of a Linux DNS Lookup - Part I:ping 會查看 nsswitch.conf,但 host 不會。兩者都會查看 /etc/resolv.conf。

在 VirtualBox 執行 OpenWrt

準備及啟動
  1. 編譯產生 OpenWrt Image
    git clone git://git.openwrt.org/openwrt.git # trunk,目前是 r40588
    cd openwrt
    make # 可能需要安裝編譯 OpenWrt 所需要的套件,例如 subversion、libncurses5-dev 等,再 make
    # 出現選單,在 Target System 選 x86,在 Target Images 加選 Build VirtualBox image files
    # 經過長久的編譯
    # 產生的 vdi 擋在 bin/x86 目錄下 
  2. 安裝 VirtualBox
  3. 執行 VirtualBox
    • 按「新增」
      • 名稱及作業系統:自訂名稱,類型選 Linux,版本選 Linux 2.6 / 3.x (32 bit)
      • 記憶體大小:至少要約 32MB (試過 16MB 不行)
      • 硬碟:使用現有的虛擬硬碟檔案,選編譯產生的 vdi 檔
      • 建立
    • 按「設定值」
      • 「存放裝置」:可移除「控制器: IDE」
      • 「音效」:可停用
      • 「網路」:我偏好「橋接介面卡」
      • 「序列埠」->「連接埠 1」:勾選「啟用連接埠」
      • 確定
    • 按「啟動」:此時會出現 OpenWrt 的 console 視窗,Enter 後可進行操作。
總共有三個環境:1. 在 openwrt 目錄下的 OpenWrt 編譯環境,2. VirtualBox 管理員,3. VirtualBox 下運行的 OpenWrt 及其 console。

重新編譯

在 OpenWrt 編譯環境下執行「make menuconfig」可選擇所需要的套件,再執行「make」可重新編譯。重新編譯會產生產生新 vdi 檔,在 VirtualBox 下再啟動 OpenWrt 時,會有 UUID 錯誤而無法執行。

解法步驟:
  1. 在 VirtualBox 管理員的「檔案」->「虛擬媒體管理員」->選有使用的 vdi 檔:「釋放」、「移除」
  2. 「設定值」->「存放裝置」->「控制器: SATA」->「加入硬碟」->「選擇現有的磁碟」->選 openwrt 下的 bin/x86 目錄下的 vdi 檔

將 LAN 改為 dhcp

在 OpenWrt console
vi /etc/config/network # 編輯
#修改
ifup lan

編譯為將 LAN 預設 dhcp
到 OpenWrt 編譯環境修改 package/base-files/files/etc/config/network

瘦身

可移除 ppp 等

參考來源:

  1. http://wiki.openwrt.org/doc/howto/virtualbox

星期六, 4月 26, 2014

使用 minicom

minicom 是比 screen 更傳統的序列埠通訊軟體,好處是歷史捲軸可以直接拉。一樣需要使用者加入 dialout 群組,使用時才不需要 root 權限。

安裝

sudo apt-get install minicom

初次使用

minicom # 如果沒加入 dialout 群組,需要 sudo,設定會儲存在 /etc/minicom,而不是使用者目錄
# 出現「minicom: 無法開啟檔案 /dev/tty8: 拒絕不符權限的操作」
minicom -D /dev/ttyS0 # 指定序列設備,如果是 USB 的話,可能是 /dev/ttyUSB0
# 設定:Ctrl-A O 參考這裡作「序列埠設定」(一般需要關閉「硬體 Flow 控制」,其中序列設備須再次設定才會儲存) 並「儲存設定為 dfl」(會存在 ~/.minirc.dfl) 後「離開本畫面」
# 結束:Ctrl-A Q

參數

  • -C <file>:capture file
    • screen 下執行
    • 其它方式
      sudo stty -F /dev/ttyUSB0 115200
      sudo cat /dev/ttyUSB0 > my_log_file.txt &
    • C 程式:https://www.linuxquestions.org/questions/linux-general-1/capuring-data-with-minicom-over-tty-interface-4175558631/#post5448720
  • -D /dev/ttyUSB0:指定序列裝置
  • -w:自動換行

此外

minicom 還有傳檔案、多個設定檔等其他功能,詳情見 man minicom。

星期二, 4月 15, 2014

VirtualBox 安裝及使用

Linux (Lubuntu 13.10) 主端 (host) 安裝
sudo apt-get install virtualbox
會自動加裝 dkms, libgoap3, libvncserver0, virtualbox-dkms (VirtualBox 用的 kernel 模組原始碼, 產生 vbox*.ko), virtualbox-qt (VirtualBox GUI) 等。

新增客端 (guest)
  • 左下角按鍵 → 附屬應用程式 → VirtualBox
    • 新增:
    • 設定:網路使用橋接,關掉不需要的週邊
      • 疑問:網路橋接效能會比 NAT 差嗎?
    • 啟動:掛載安裝光碟或 iso 檔安裝作業系統
  • 客端作業系統安裝完成後,可以再安裝客端額外功能 (Guest Addition, 內容包括一些驅動程式及系統應用程式),讓主客間有更好的整合及效能。
客端:Windows XP
  • 安裝作業系統
    • 疑問:用 FAT 會比 NTFS 好嗎?(似乎 NTFS 較好 [參考])
  • 安裝客端額外功能:(VirtualBox 客端視窗) 裝置 → 安裝 Guest Additions
    • 網路下載
    • 掛載
    • Setup Wizard 安裝
  • 參考:Using Windows XP in VirtualBox on Linux
客端:Ubuntu
  • 安裝 Guest Additions 前要先安裝「sudo apt-get install dkms」,不然那些 kernel modules 無法安裝

檢視 Host=right Ctrl

  • 全螢幕模式 Host+F
  • 無縫模式 Host+L
  • 縮放模式 Host+C

其他

  • 共用資料夾
  • 客端使用 USB 裝置
  • 備份虛擬機器 (Export 和 Import):檔案 → 匯出應用裝置
  • 複製 vdi 檔 (由於 UUID 問題,不能直接複製 [參考])
    • VBoxManage clonehd ubnsrv.vdi ubnsrv_new.vdi (VirtualBox 4.0+)
    • VBoxManage clonevdi ubnsrv.vdi ubnsrv_new.vdi (之前)
    • 原本是動態,複製為靜態,加 --variant fixed
    • 原本不是 vdi 格式,複製為 vdi 格式,加 --format VDI
  • 壓縮 vdi 檔:[參考] 以 Windows guest 為例
    1. 移除 guest 上不需要的檔案
    2. defrag
    3. sdelete -z C:
    4. guest 關機
    5. vboxmanage modifyhd /path/to/thedisk.vdi --compact
    試過,即是是靜態 vdi 檔,實際大小會小於虛擬大小,懷疑其實是變成動態 vdi 檔
待究

備份光碟

Linux 可用「cat /dev/cdrom > backup.iso」或「dd if=/dev/cdrom of=backup.iso」來備份光碟 (註:/dev/cdrom 在我的電腦實際是 /dev/sr0。如果放 DVD 會是 /dev/dvd?)

在 Windows 製作 iso 檔可用 Folder2Iso (免費免安裝,mkisofs 的 GUI)。掛載 iso 檔可用 PortableWinCDEmu-3.4.exe (開源免安裝,但還是會安裝驅動程式)

星期一, 4月 14, 2014

P5VD2-VM 主機板安裝 Lubuntu 13.10

在一台使用 P5VD2-VM 主機板、Pentium® D 3 GHz 處理器的電腦安裝 Lubuntu 13.10。這個主機板不支援 USB 開機,只好燒錄光碟,安裝好之後重開機,過沒多久螢幕就沒畫面,像是當機,原因不明,或許是缺驅動程式,嘗試用別的安裝方式。

再燒錄一塊 Ubuntu Server 13.10,安裝完成後再安裝 lubuntu-core 及 lubuntu-desktop 後就可以順利使用 LXDE 桌面。

檢討:
  1. 會自動安裝 lightdm-remote-session-uccsconfigure 及許多 unity 桌面相關的套件,這些可以移除。以後有機會可以嘗試 minimal CD 或 Alternate CD 安裝,或許可以減少安裝不需要的套件。
  2. 之前在 VirtualBox 下都安裝 Ubuntu Server 版本,可以改安裝更精簡的 Linux 版本,例如 minimal CD。
  3. 手上有 CF 轉 IDE 的轉接板及 CF 卡,但從沒用過,應該可以取代燒錄光碟。
註:
  • 安裝了 4096 MiB 記憶體,但只能用 3199MiB
  • BIOS 版本是 0402 (2006.07.11),網站最新版本是 1302 (2008.08.14)
後記