2019年1月19日 星期六

pcap 封包擷取過濾式

pcap 封包擷取過濾式 (filter expression) 用在 tcpdumpWireshark (TShark)、Dumpcap 等程式,在擷取階段就篩選封包。其基本表示式 (primitive) 至少會有一個以上前置限定詞 (qualifier),然後可能會有一個數字或名稱的 id。

限定詞可大致分類成通訊協定 (proto)、傳送方向 (dir)、類型 (type) 三種:
  • type:說明 id 是指什麼,未指明預設是 host
    • host host:位址或主機名稱,如果沒指明 proto 是指 IPv4 或 IPv6 的位址或主機名稱。
    • net net [mask netmask] 或 net net/len:IPv4 或 IPv6 位址、subnet,可指明 netmask。
    • port port:TCP 或 UDP 的通訊埠。
    • portrange port1-port2:TCP 或 UDP 通訊埠的範圍。
  • dir:限定方向
    • srcdstsrc or dst (預設)、和 src and dst
    • proto wlan 限定:rataaddr1addr2addr3addr4dir
  • proto:限定協定,有 etheripip6arprarptcpudp 等,未指明則預設所有跟 type 能一致的協定。
此外還有其它特殊 keyword gatewaybroadcast 等,以及算術運算。較複雜的過濾表示用邏輯 and (&&)、or (||)、not (!)、以及「( )」來組合基本表示式。

範例

Ethernet 信頭
  • ether dst|src|host ehost:Ethernet 目的或來源位址是 ehostehost 可以是來自 /etc/ethers 的名稱或十六進位數字表示的 MAC 位址 (會忽略中間參雜的「:」、「.」、和「-」)。
  • ether ehost:錯誤。
  • [ether] broadcast:Ethernet 廣播封包。ether 可省略。
  • [ether] multicast:Ethernet 群播封包。ether 可省略。相當於 ether[0] & 1 != 0
  • [ether protoprotocol:Ethernet 的 Ether Type 是 protocolprotocol 可以是數字或名稱 ipip6arprarpatalkaarpdecnetscalatmopdlmoprcisostpipx、或 netbeui。註:由於這些名稱也是保留字,所以需要 backslash (\) 跳脫。
  • vlan [vlan_id]:
  • pppoed
  • pppoes [session_id]:
  • wlan ra|ta|addr1|addr2|addr3|addr4 ehost
  • [type wlan_type] [subtyp wlan_subtype]:
  • dir dir:
IP 位址或主機名稱
  • [ip|arp|rarp|ipv6] [dst|src] host hosthost 是 IPv4/IPv6 位址或主機名稱。前面可加協定限制、方向限制。ip host host 相當於 ether proto \ip and host host
  • gateway host:使用 host 作為 gateway 的封包,也就是使用 host 的 Ethernet 位址,但不是 host 的 IP 位址。host 的 IP 位址和 MAC 位址需要查得到。相當於 ether host ehost and not host host。
  • [dst|src] net net [mask netmask]:
  • [dst|src] net net[/len]:
  • ip broadcast
  • [ip|ip6] multicast
  • [[ip|ip6] proto] tcp|udp|icmp:協定是 tcp、ucp、或 icmp 封包。註:tcp, udp, and icmp 也是 keyword,所以需要 backslash (\) 跳脫。註:不能 chase the protocol header chain。
  • [ip|ip6] proto protocol:IPv4 或 IPv6 protocol type 是 protocol。protocol 可以是數字或名稱 icmp6, igmp, igrp, pim, ah, esp, or vrrp。註:不能 chase the protocol header chain.
  • [ip|ip6] protochain protocol:IPv4 或 IPv6 protocol chain 中含有 protocol。產生的 BPF 程式碼較複雜,且 kernel 不支援。
  • [tcp|udp] [dst|srcport port
  • [tcp|udp] [dst|srcportrange port1-port2
算術
  • expr relop exprrelop 是比大小 ><>=<==!= 之一。expr 可能是某個值、封包長度 len、或封包資料和正整數的 +-*/&|<<>>%^ 運算。(註:Linux 3.7 以後在 kernel 才能算 %^。) 封包資料用 proto[expr[:size]] 表示,指特定 proto 協定的 expr byte offset 的 size byte。size 可以是 1、2、4,預設是 1。特定 offset 或欄位可以用名稱表示,例如 tcp[tcpflags]。特定值可以用名稱表示,例如 tcp-syntcp-fin 等。
  • less|greater length:封包長度。相當於 len <= length 和 len >= length
其它

這些過濾描述會先編譯成 BPF 虛擬機器的指令碼,才給 BPF 執行。

參考來源

  1. Manpage of PCAP-FILTER
延伸閱讀
  • 顯示過濾式

2019年1月16日 星期三

pcapsipdump

pcapsipdump 基於 libpcap,將網路界面或 pcap 檔的封包以每個 SIP session (包括 RTP 或 T38 media) 儲存成不同的檔案。封包除了用 BPF 先行過濾外,可以用正規表示式過濾出需要的電話號碼或 SIP Method。另外,在每個 session 開始或結束時可以指定執行 shell 指令。

編譯

需要 libpcap-dev、libbsd-dev 等。
git svn clone --stdlayout https://svn.code.sf.net/p/pcapsipdump/code pcapsipdump
cd pcapsipdump
make
sudo make install

指令格式

pcapsipdump [-fpU] [-i interface | -r file] [-d output_directory] [-P pid_file]
            [-v level] [-R filter] [-m filter] [-n filter] [-l filter]
            [-B size] [-T limit] [-t trigger:action:param] [expression]
參數
  • -f:不 fork,也就是不成為 daemon
  • -p
  • -U
  • -i interface 或 -r file:必須指定網路界面或檔案
  • -d:指定輸出目錄和檔名,不然預設是 ... 
    • %f %t %i
  • -P:
  • -v:
  • -R:
  • -m filter:Method 過濾,預設是「^(INVITE|OPTIONS|REGISTER)$」。
  • -n:電話號碼過濾 (正規表示式)
  • -l:
  • -B:
  • -T:
  • -t:
  • expression:BPF 過濾表示式

使用範例

pcapsipdump ; 顯示使用說明
pcapsipdump -f -r test.pcapng -m '^INVIT$' -d ./%Y%m%d-%H%M%S-%f-%t.pcap

程式

main() @pcapsipdump.cpp
  1. 取得參數,剩下的部份是額外的 BPF 表示式。
  2. ...
  3. 使用 pcap_create() 或 pcap_open_offline() 取得網路界面或 pcap 檔的 pcap_t handle。
  4. 用 pcap_compile() 和 pcap_setfilter() 編譯和設定 BPF 過濾。預設過濾式「udp or vlan」,指令參數之外剩餘的部份就是 BPF 表示式。
  5. pcap_datalink() 查看 datalink 類型,換算出 IP 信頭位置。
  6. 可以 fork() 為 daemon。
  7. pcap_next_ex() 處理每個封包
    1. 每封包時間 15 秒檢查是否 session 過長應該結束
    2. fragment 封包:看是否需要儲存,然後處理下個封包。
    3. 如果是要儲存的 RTP 封包,儲存然後處理下個封包。
    4. 如果是 SIP 封包的話
      1. 檢查號碼是否符合儲存然後處理下個封包。
      2. 新 callid:檢查 Method 符合後產生輸出檔名。
      3. BYE
      4. 解析 SDP
      5. 是否有 fragment
    5. 其它封包:可開顯示
  8. 結束所有 session
  9. 結束 pcap_t
  10. 等候子行程
讀取封包需要取得 pcap_t
  • 從網路界面:pcap_create() → 設定選項 → pcap_activate()。pcap_findalldevs() 列出界面,然後 pcap_freealldevs() 釋出。pcap_lookupdev() 取得第一個非「loopback」的界面。
  • 從檔案:pcap_open_offline() 或 pcap_fopen_offline()。
  • 「假」的:pcap_open_dead()
  • 讀取封包:pcap_dispatch(), pacp_loop(), pcap_next(), pcap_next_ex()。
  • 結束取得封包:pcap_close()
過濾:pcap_compile() ...
寫 pcap 檔:pcap_dump_open() -> pcap_dump() -> pcap_dump_close()。
送出封包:pcap_inject()、pcap_sendpacket()

參考

2019年1月15日 星期二

primitive

primitive 是原始的、遠古的、早期的意思,含有不是從其它東西衍生出來的意思,也隱含有簡陋的、未分化的意思。
原始人叫 primitive man

primitive 也可以當名詞,就是原始人的意思,用在計算機科學的函數是指基本的原始函數,可翻作「原函數」、「原始函數」、「基元函數」

參考

Firefox 網頁轉成 PDF 檔的擴充

PDF Mage:支援本地檔案 (如 .md) 產生的網頁,可正確產生含有超連接的 PDF 檔。可設定頁寬 (Web page width) 1024px 以下或 Firefox 視窗不要開太大,避免字太小。

其它大多不支援本地檔案產生的網頁 (如 Save as PDFWeb to PDFPDF CreatorPrint Friendly & PDF) 或只跟內建的 Print 一樣沒有超連接 (如 Print to PDFWebsite to PDF)。

2018年12月28日 星期五

RFC 5424 Syslog Message Format

廣為使用的 syslog 來自 BSD,訊息格式並沒有標準化,共通點只有都是以「<數字>」開始。RFC 3164 只是說明觀察到的格式,認定送到 syslog UDP port (514) 的封包都是 syslog 訊息。

RFC 5424ANBF 定義了格式:
SYSLOG-MSG      = HEADER SP STRUCTURED-DATA [SP MSG]
HEADER          = "<" PRIVAL ">" VERSION SP TIMESTAMP SP HOSTNAME
                  SP APP-NAME SP PROCID SP MSGID
STRUCTURED-DATA = "-" / 1*SD-ELEMENT
SD-ELEMENT      = "[" ID *(SP NAME "=" %d34 VALUE %d34) "]"

依序包括下列以空白區隔的欄位:

  • <PRIVAL>VERSIONPRIVAL 是優先值數字 = facility * 8 + severity。facility 值和 severity 值的表見下面。VERSION 是格式的版本,目前 = 1。
  • TIMESTAMP:格式「為西元年--T::.fraction時區」,小數點後可有 6 位精度達微秒,可有時區。如不知道時間填「-」。RFC 3164 的時間精度較差、沒「年」和「時區」。
  • HOSTNAME:可以是 FQDN、IP、主機名稱。在 RFC 3164 沒明確說明。
  • APP-NAME:應用程式名稱。RFC 3164 的 TAG 大致分成 APP-NAME、PROCID、和 MSGID。
  • PROCID
  • MSGID
  • STRUCTURED-DATA:可以是「-」或一個以上連續 [SD-ELEMENT] (之間沒空白)。RFC 3164 沒有這部份。
  • MSG:之後可選擇性加空白後放任意資訊 (MSG)。相當於 RFC 3164 的 CONTENT。
例如:
<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] BOMAn application event log entry...
可看到:
  • PRIVAL 165 = 20 * 8 + 5,所以 facility 值 = 20,severity 值 = 5。
  • VERSION = 1。
  • TIMESTAMP 小數點後有 3 位,精度毫秒。Z 代表???。
  • HOSTNAME 為 FQDN。
  • APP-NAME 為 evntslog。
  • PROCID 為 -
  • MSGID 為 ID47
  • 一個 SD-ELEMENT 由 [] 框起來,有一個 ID 和多個空白隔開的 NAME="VALUE" 參數。
    • ID 和 NAME 是 1 ~ 32 字元 PRINTUSASCII,不含 '=', SP, ']', '"'。
    • VALUE 是 utf-8 資料,但 '"', '\' 和 ']' 分別 escape 為 '\"', '\\', and '\]'。   Escape ']' 是為了避免 syslog 實作錯誤。'\' 之後不是這三個字元視為一般的 '\'。
    • 可有多個 SD-ELEMENT,但 ID 不能重複。ID 有兩類:
      • 不含「@」的 ID 要跟 IANA 註冊,目前有的見 Section 7。
      • 可自行定義的格式是 name@<private enterprise number>, e.g., "ourSDID@32473"。private enterprise number 見 Section 7.2.2。
  • MSG 任意訊息,開頭 BOM (實際上傳的是 utf-8 的 BOM 0xEF 0xBB 0xBF) 代表傳的是 utf-8 資料。如果不是 BOM 開頭則是其它編碼。小於 32 的字元是合法的,但可能被改變 (例如 0 可能被改為 "\0"),所以應該要避免。
數值Facility
0kernel messages
1user-level messages
2mail system
3system daemons
4security/authorization messages
5messages generated internally by syslogd
6line printer subsystem
7network news subsystem
8UUCP subsystem
9clock daemon
10security/authorization messages
11FTP daemon
12NTP subsystem
13log audit
14log alert
15clock daemon (note 2)
16local use 0 (local0)
17local use 1 (local1)
18local use 2 (local2)
19local use 3 (local3)
20local use 4 (local4)
21local use 5 (local5)
22local use 6 (local6)
23local use 7 (local7)
數值Severity
0Emergency: system is unusable
1Alert: action must be taken immediately
2Critical: critical conditions
3Error: error conditions
4Warning: warning conditions
5Notice: normal but significant condition
6Informational: informational messages
7Debug: debug-level messages

sect6.1 訊息長度 sect6.1
...

A.2.  Message Length

   Implementers should note the message size limitations outlined in
   Section 6.1 and try to keep the most important data early in the
   message (within the minimum guaranteed length).  This ensures the
   data will be seen by the collector or relay even if a transport
   receiver at a relay on the message path truncates the message.

   The reason syslog transport receivers need only support receiving up
   to and including 480 octets has, among other things, to do with
   difficult delivery problems in a broken network.  Syslog messages may
   use a UDP transport mapping with this 480 octet restriction to avoid
   session overhead and message fragmentation.  In a network with
   problems, the likelihood of getting one single-packet message
   delivered successfully is higher than getting two message fragments
   delivered successfully.  Therefore, using a larger size may prevent
   the operator from getting some critical information about the
   problem, whereas using small messages might get that information to
   the operator.  It is recommended that messages intended for
   troubleshooting purposes should not be larger than 480 octets.  To
   further strengthen this point, it has also been observed that some
   UDP implementations generally do not support message sizes of more
   than 480 octets.  This behavior is very rare and may no longer be an
   issue.

   There are other use cases where syslog messages are used to transmit
   inherently lengthy information, e.g., audit data.  By not enforcing
   any upper limit on the message size, syslog applications can be
   implemented with any size needed and still be compliant with this
   document.  In such cases, it is the operator's responsibility to
   ensure that all components in a syslog infrastructure support the
   required message sizes.  Transport mappings may recommend specific
   message size limits that must be implemented to be compliant.

   Implementers are reminded that the message length is specified in
   octets.  There is a potentially large difference between the length
   in characters and the length in octets for UTF-8 strings.

   It must be noted that the IPv6 MTU is about 2.5 times 480.  An
   implementation targeted towards an IPv6-only environment might thus
   assume this as a larger minimum size.

參考

RFC 5424: The Syslog Protocl §6, Appendix A
延伸閱讀
  • RFC 3164 有描述 relay 行為,RFC5424 沒有 (可能會放在不同文件)

2018年12月22日 星期六

SDP simcap

RFC 3407:SDP Simple Capability Declaration (simcap)
SDP 簡易通話能力宣告

定義一組新 SDP 屬性,在一個 session 描述裡放一個 capability set,列出所有支援的媒體功能,可作為其它 session 協商的資訊來源。

SDP simcap 新增的屬性有:
a=sqn: <sqn-num>
a=cdsc: <cap-num> <media> <proto> <fmt list>
a=cpar: <cap-par>
a=cparmin: <cap-par>
a=cparmax: <cap-par>
可以放在 session-level 或 media-level。一個 capability set 以 a=sqn 開始,緊接著第 1 個 a=cdsc,剩下可以散落各處。

a=sqn 說明 capability set 的序號 (sequence number),<sqn-num> 從 0 開始。每次新發表一個 capability set 取代舊的,序號加 1 後 modulo 256。接收端可能不會收到所有序號的 capability set,不能因為有跳號而拒絕。

a=cdsc 是 capability description,類似 m= 行,不需要 <port>,但多了 <cap-num>。全部 a=cdsc 中的 fmt 從 1 開始編號,<cap-num> 是每個 a=cdsc 中第一個 fmt 的編號。如此一來,傳送或接收端、<sqn-num>、加上 fmt 的編號就可以參照到一個特定媒體。接收端不能因為 fmt 編號有跳號而拒絕。
註:fmt 本身在不同 a=cdsc 可能重複。
註:包含在 m= 行的所有 fmt 也必須出現在 capability set。

cpar、cparmin、cparmax 可分別指定 capability 能支援的參數值、最小值、和最大值。
<cap-par> 可以是 "b=" 頻寬資訊或完整的 "a=" 屬性。

範例:
v=0
o=- 25678 753849 IN IP4 128.96.41.1
s=
c=IN IP4 128.96.41.1
t=0 0
m=audio 3456 RTP/AVP 18 96
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15,32-35
a=sqn: 0
a=cdsc: 1 audio RTP/AVP 0 18 96
a=cpar: a=fmtp:96 0-16,32-35
a=cdsc: 4 image udptl t38
a=cdsc: 5 image tcp t38
準備送收 G.729 語音和 telephone-event 0-15、32-35。告知對方另外還可以支援:
  • PCMU 語音
  • telephone event 16
  • udp 或 tcp T.38 傳真 (見 T.38 Annex D, "SIP/SDP Call Establishment Procedures").
註:a=rtpmap:96 已 specified,所以沒包含在 capability description

範例 (多個媒體串流):
v=0
o=- 25678 753849 IN IP4 128.96.41.1
s=
c=IN IP4 128.96.41.1
t=0 0
m=audio 3456 RTP/AVP 18
a=sqn: 0
a=cdsc: 1 audio RTP/AVP 0 18
m=video 3458 RTP/AVP 31
a=cdsc: 3 video RTP/AVP 31 34
準備送收 G.729 語音和 H.261 影像。告知對方還可以支援:
  • PCMU 語音
  • H.263 影像
等效範例 (capability set 改放在 session-level):
v=0
o=- 25678 753849 IN IP4 128.96.41.1
s=
c=IN IP4 128.96.41.1
t=0 0
a=sqn: 0
a=cdsc: 1 audio RTP/AVP 0 18
a=cdsc: 3 video RTP/AVP 31 34
m=audio 3456 RTP/AVP 18
m=video 3458 RTP/AVP 31

2018年12月14日 星期五

C Library rand()

產生虛擬亂數 (pseudo-random number),不是真的亂數,也不是機密的,而是一系列看起來像亂數的數列,這些數字實際上是有固定順序的。

#include <stdlib.h>

void srand(unsigned int seed); // 設定函式庫內部的 seed,一開始預設是 1。

int rand(void); // 依據 seed 運算產生範圍為 [0, RAND_MAX] 的虛擬亂數回傳,並儲存為新的 seed。

int rand_r(unsigned int *seedp); //

rand_r() 為 reentrant 版的 rand(),需要傳入儲存 seed 的記憶體指標,在 thread 程式得以不被其它 thread 干擾來產生同樣的數列。在 POSIX.1-2008 標注為廢棄。

POSIX.1-2001 rand() 和 srand() 的實作範例:

static unsigned long next = 1;

/* RAND_MAX assumed to be 32767 */
int myrand(void) {
    next = next * 1103515245 + 12345;
    return((unsigned)(next/65536) % 32768);
}

void mysrand(unsigned int seed) {
    next = seed;
}

注意

  • 虛擬亂數是有一定順序的,知道 seed 就知道下一個產生的值。假設初始 seed 設為目前的時間秒數,已知是今年的話,大約有 225 個可能的值,縮小範圍後依現今運算能力很容易試出來。
  • 產生序列的最低 bit 固定 01010101..,其實不夠亂。
  • 1995 發現 Netscape 瀏覽器產生的 SSL session keys 使用時間和 process ID 作為 seed,猜得到,所以 SSL sessions 可在幾分鐘內破壞。...

以上經驗告訴我們,作為 secure 的虛擬亂數產生器,有兩個基本原則:

  1. seed 必須是無法預測的 (實際上只能難以預測?)。要有足夠的可能性,例如 2128 就足夠 (隨著計算能力越來越強,暴力破解越容易,需要更多 bit),所有可能出現的機率相同,沒有東西讓攻擊者可以縮小範圍。
  2. 產生虛擬亂數的 algorithm 必須是 secure,pseudorandom bits 沒有可辨別的 patterns。即使攻擊者學到或猜到一些 pseudorandom bits,也無法預測其它 pseudorandom bits。

參考

  1. https://inst.eecs.berkeley.edu//~cs161/fa08/Notes/random.pdf

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...