libnet

libnet目前官方網站"似乎"已經停止維護了(libnet-0.10.11),所以到這裡使用新版本libnet-1.2-rc3。

雖然libnet很方便撰寫封包,但是個人發現容易讓初學者混淆一些觀念(而且在Mac OS X上有bug,暈...),但要跨平台最好使用Library,所以就見仁見智囉,個人則是喜歡直接寫Raw socket。

Bug Fix

在Mac OS X上使用libnet有個bug,就是無法修改Source MAC Address,問題出在原始碼src/libnet_link_bpf.c

...略
100 #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
101    uint spoof_eth_src = 1;
102 #endif
...略
162     /*
163      *  NetBSD and FreeBSD BPF have an ioctl for enabling/disabling
164      *  automatic filling of the link level source address.
165      */
166 #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
167     if (ioctl(l->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1)
168     {
169         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSHDRCMPLT: %s",
170                 __func__, strerror(errno));
171         goto bad;
172     }
173 #endif


使用BSD核心的系統中(包含Mac OS X啦),預設會自動填寫Source MAC Address,如果要關掉該選項,要使用ioctl()BIOCSHDRCMPLT參數關閉,可是這裡的判斷是:#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__),它把__APPLE__給否定了,所以改成:

...略
100 #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && (__APPLE__)
101    uint spoof_eth_src = 1;
102 #endif
...略
162     /*
163      *  NetBSD and FreeBSD BPF have an ioctl for enabling/disabling
164      *  automatic filling of the link level source address.
165      */
166 #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && (__APPLE__)
167     if (ioctl(l->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1)
168     {
169         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSHDRCMPLT: %s",
170                 __func__, strerror(errno));
171         goto bad;
172     }
173 #endif

!拿掉,就可以正確判斷並關掉自動填寫Source MAC Address這個選項了。

編譯

一樣記得指定--prefix 參數。


先建立安裝路徑。

~ % mkdir /usr/local/TU/libnet


然後切到libnet原始碼目錄使用configure腳本。

libnet-1.2-rc3 % ./configure --prefix=/usr/local/TU/libnet
beginning autoconfiguration process for libnet-1.2-rc3 ...
checking build system type... x86_64-apple-darwin15.2.0
...略
config.status: executing depfiles commands
config.status: executing libtool commands


然後make編譯。

libnet-1.2-rc3 % make
Making all in include
/Applications/Xcode.app/Contents/Developer/usr/bin/make  all-recursive
...略
make[1]: Nothing to be done for `all'.
make[1]: Nothing to be done for `all-am'.


最後make install安裝。

libnet-1.2-rc3 % make install
Making install in include
Making install in libnet
...略
 ./install-sh -c -d '/usr/local/bin'
 /usr/bin/install -c libnet-config '/usr/local/bin'
make[2]: Nothing to be done for `install-data-am'.


安裝完成~

Sample

在libnet的原始碼內有個資料夾sample在安裝完後有不少範例可以使用。

sample % ls
Makefile            fddi_tcp1           icmp_timestamp      ospf_lsa.o          tcp1.o
Makefile.am         fddi_tcp1.c         icmp_timestamp.c    ping_of_death       tcp2
Makefile.in         fddi_tcp1.o         icmp_timestamp.o    ping_of_death.c     tcp2.c
arp                 fddi_tcp2           icmp_unreach        ping_of_death.o     tcp2.o
arp.c               fddi_tcp2.c         icmp_unreach.c      rpc_tcp             test_ipv4
arp.o               fddi_tcp2.o         icmp_unreach.o      rpc_tcp.c           test_ipv4.c
bgp4_hdr            get_addr            ieee                rpc_tcp.o           test_ipv4.o
bgp4_hdr.c          get_addr.c          ieee.c              rpc_udp             test_ipv4_options
...略


我們就來挑一個來試用看看。

sample % sudo ./ospf_hello 192.168.1.100 192.168.1.1
libnet 1.1 OSPF Hello packet shaping[raw]
Wrote 68 byte OSPF packet; check the wire.

結果:

用範例就可以簡單送出一個OSPF Hello封包了,這個sample資料夾內有不少範例可以參考。

Xcode and Command Line Environment Settings

這邊在libpcap教學已經教學過了,只有路徑稍微不同,所以就不再多些不必要的文字簡介。

Xcode

Header的Search Paths/usr/local/TU/libnet/include,lib的Library Search Paths則是/usr/local/TU/libnet/lib


找到LinkingOther Linker Flags裡新增-lnet


有時候需要開啟Network Layer的Raw socket,而開啟Network Layer的Raw socket一定要root權限,所以來讓它能夠以root權限執行程式。

左上角Scheme->Edit Scheme...


中間的Debug Process Asroot就可以了。


第一次編譯的時候會需要輸入密碼。

Command Line

在指令列上在呼叫指令前加上sudo就好了(如果在有/etc/sudoers內,預設有)。

~ % gcc main.c -o hello -I /usr/local/TU/libnet/include -L /usr/local/TU/libnet/lib -lnet 
~ % sudo ./hello 
Password:
Hello TUTU


一樣的要用-I增加include搜尋路徑,-L增加library搜尋路徑,-l要連結library,第一次一樣需要輸入密碼。

在Windows上使用libnet需要搭配Winpcap才能夠使用。

Raw socket

這邊就要來介紹什麼是Raw socket啦,首先來講Socket。

所謂的Socket指的是兩個程序(Process)互相溝通的一個管道,而這兩個程序不限制在同一台電腦上可以在不同台電腦上,而網路用的Socket設計方式分成七層。

在OSI七層模型中,TCP/IP分成五層:

Application Layer
Transport Layer
Network Layer
Data-link Layer
Physical Layer

而在乙太網路中Data-link LayerPhysical Layer可以直接當成同一層看待。

一般Socket只能夠存取Application Layer的資料,不能存取其他層資訊。

Application Layer(∨)
Transport Layer(×)
Network Layer(×)
Data-link Layer(×)

那只要能夠存取Transport Layer以下的Socket通稱Raw socket,如果要存取Network Layer以下需要有root權限(函數setsockopt()其實能夠稍微修改一些Network Layer的欄位資料,不過這不是我們要講的)。

也就是說:

  1. Socket只能填寫Application Layer,以下自動填。
  2. Transport Layer的Raw socket,Transport Layer以上需要手動填寫,以下(不包含Transport Layer)系統填寫。
  3. Network Layer的Raw socket,Network Layer以上需要手動填寫,以下(不包含Network Layer)系統填寫。
  4. Data-link Layer的Raw socket,Data-link Layer以上需要手動填寫,以下(不包含Data-link Layer)系統填寫(當然啦,表尾CRC系統自己算)。
  5. Data-link Layer的Raw socket可以拿來當作Sniffer,因為要從網卡讀到的封包才有意義,從Network Layer讀取封包有問題,有些系統無法透過Network Layer的Raw scoket抓取TCP封包,因為有Port binding的問題。

那什麼時候該選擇怎樣的Socket呢? 左邊是一般Socket情況,包含了Socket、Transport Layer的Raw socket以及Network Layer的Raw socket,這三種Socket在送出去後,會交由給核心的Route table決定要往哪個Interface送出,如果要送往乙太介面(en0en1)會再經過ARP table填寫最後的MAC Address,最後才會交給NIC(網卡)送至網路上。

右邊是Data-link Layer的Raw socket,送出去會直接交給NIC(網卡)送至網路上,所以MAC Address必須自己填寫。

假如寫ARP封包,就開啟Data-link Layer的Raw socket,其他要寫IPv4或IPv6的封包,就看需求開啟哪層的Raw socket。

如果開啟Network Layer以上的Raw socket,目的IP地址假如是在同一個區域網路下但並不存在,會造成封包送到ARP table時無法填入目的MAC Address,所以封包就無法送出,如果一定要送出這個假封包,就必須開啟Data-link Layer的Raw socket並填寫Ethernet的表頭欄位才能夠送出。

libnet Support Protocol

  • Application Layer
    • Border Gateway Protocol
    • Remote Procedure Call
    • Domain Name System
    • Network Time Protocol
    • Bootstrap Protocol
    • Dynamic Host Configuration Protocol
  • Transport Layer
    • Transmission Control Protocol
    • User Datagram Protocol
  • Network Layer
    • Routing Information Protocol
    • Open Shortest Path First
    • Virtual Router Redundancy Protocol
    • Internet Control Message Protocol
    • Internet Group Management Protocol
    • Internet Protocol version 4
    • Internet Protocol version 6
    • Generic Routing Encapsulation
    • Encapsulating Security Payloads
    • Authentication Headers
  • Data-link Layer
    • Cisco Discovery Protocol
    • Fiber Distributed Data Interface
    • IEEE 802.1x
    • Ethernet
    • IEEE 802.1Q
    • IEEE 802.3
    • Multi-Protocol Label Switching
    • IEEE 802.5 LAN Protocol(Token Ring)
    • IEEE 802.2
    • Address Resolution Protocol
    • Reverse Address Resolution Protocol
    • SubNetwork Access Protocol

libnet不只有這些協定,以防誤人子弟我只列出我能夠理解的協定。

Source Code

  1. libnet/address_conversion.c
  2. libnet/send_an_arp_request.c
  3. libnet/arpoison.c
  4. libnet/icmp_echo_request_list.c
  5. libnet/udp_port_chain.c
  6. libnet/tcp_syn_flood.c
  7. libnet/ssdp.c

Compile Source Code

一樣下載我所提供的原始碼並且libnet和libpcap安裝路徑為/usr/local/TU/libnet/usr/local/TU/libpcap,也可以直接下make指令一次編譯所有檔案。

libnet % make
/usr/bin/gcc -lnet    address_conversion.c   -o address_conversion
/usr/bin/gcc -lnet    send_an_arp_request.c   -o send_an_arp_request
/usr/bin/gcc -lnet    arpoison.c   -o arpoison
/usr/bin/gcc -lnet    icmp_echo_request_list.c   -o icmp_echo_request_list
/usr/bin/gcc -lnet    udp_port_chain.c   -o udp_port_chain
/usr/bin/gcc -lnet    tcp_syn_flood.c   -o tcp_syn_flood
/usr/bin/gcc -lnet -lpcap ssdp.c -o ssdp

同樣如果不是照我的路徑安裝,直接修改檔案Makefile內的變數ROOT_DIR


如果只要編譯單一程式,指令make 程式就可以了,例如要編譯ssdp.c

libnet % make ssdp
/usr/bin/gcc -lnet -lpcap ssdp.c -o ssdp


指令make clean可以清除所有編譯完成的執行檔。

libnet % make clean
rm -f address_conversion send_an_arp_request arpoison icmp_echo_request_list udp_port_chain tcp_syn_flood ssdp

小結

libnet只介紹一小部分的封包,其他封包協定等有需要時再來回頭翻文件學習就好囉。

可能會有人想使用libnet來寫TCP連線的程式,但實際上用Raw socket是無法達成的,在後期Raw socket篇時才會講解如何完成TCP連線並傳送資料。

所以libnet用來撰寫Connectionless的封包很方便(像是ARP、ICMP、IP、UDP、DNS...等),但在Connection-Oriented的封包(像是TCP、HTTP、SSH)就非常鱉腳。

如果要關鍵字的話,使用函數connect()

results matching ""

    No results matching ""