module Pcap:sig..end
libpcap, packet sniffing,
packet injection and pcap file reading and writing.
All I want is sniffing packets:
To grab the first packet from "em1" interface and display it:
# let itf = Pcap.openif "em1";;
val itf : Pcap.iface = {Pcap.handler = ; name = "em1"; caplen = 1500}
# let pkt = Pcap.sniff itf;;
val pkt : Pcap.Pdu.t =
{Pcap.Pdu.source_name = "em1"; caplen = 1500;
dlt = Ethernet (10Mb); ts = 15:09:49.81;
payload = 66 bytes (74 46 a0 a1 28 8e 00...)}
# Packet.Pdu.unpack pkt;;
- : Packet.Pdu.layer list =
[Packet.Pdu.Pcap
{Pcap.Pdu.source_name = "em1"; caplen = 1500;
dlt = Ethernet (10Mb); ts = 15:09:49.81;
payload = 66 bytes (74 46 a2 a1 28 8e 00...)};
Packet.Pdu.Eth
{Eth.Pdu.src = Cisco:25:ac:42;
dst = 74:46:a2:a1:28:8e; proto = IP;
payload = 52 bytes (45 20 00 34 86 aa 40...)};
Packet.Pdu.Ip
{Ip.Pdu.tos = 32; tot_len = 52; id = 34474; dont_frag = true;
more_frags = false; frag_offset = 0; ttl = 58; proto = tcp;
src = 172.16.255.194; dst = 172.28.11.20;
options = ; payload = 32 bytes (02 02 bc c8 a2 6c d0...)};
Packet.Pdu.Tcp
{Tcp.Pdu.src_port = shell; dst_port = 48328;
seq_num = 0xA26CD0EB; ack_num = 0x304E4FC3;
win_size = 501; flags = Ack; urg_ptr = 0;
options = 01 01 08 0a 28 f5 dd 89 - 57 c2 c6 25 .....��.W��%
;
payload = empty}]
Following packets can be dumped easily with just
Pcap.sniff itf |> Packet.Pdu.unpack
("|>" is like the UNIX pipe).
All I want is editing pcap files:
To create a small pcap file with a single packet:
Tcp.Pdu.make ~dst_port:(Tcp.Port.o 5000) (bitstring_of_string "HTTP/1.2 pas glop") |>
Tcp.Pdu.pack |>
Ip.Pdu.make Ip.Proto.tcp (Ip.Addr.random ()) (Ip.Addr.random ()) |>
Ip.Pdu.pack |>
Eth.Pdu.make Arp.HwProto.ip4 (Eth.Addr.random ()) (Eth.Addr.random ()) |>
Eth.Pdu.pack |>
Pcap.save "/tmp/random.pcap";;
To grep a string into a pcap file and obtain another pcap file with matching packets only:
let grep needle haystack = try String.find haystack needle ; true with Not_found -> false in
Pcap.enum_of_file "input.pcap" |>
Enum.filter (fun pdu -> grep "needle" (string_of_bitstring (pdu.Pcap.Pdu.payload :> bitstring))) |>
Pcap.file_of_enum "output.pcap";;
val debug : booltype iface_handler
val inject_ : iface_handler -> string -> unitinject_ iface_handler packet inject this packet into this interfaceval sniff_ : iface_handler -> Clock.Time.t * stringsniff_ iface_handler will return the next available packet as a string,
as well as its capture timestamp.val openif_ : string -> bool -> string -> int -> iface_handleropenif_ "eth0" true "port 80" 96 returns the iface representing eth0,
in promiscuous mode, filtering port 80 and capturing only the first 96 bytes
of each packets. Notice that if caplen is set to 0 then a "default" value
of 65535 will be chosen, which is probably not what you want. You should set
caplen = your MTU size.module Dlt:sig..end
type global_header = {
|
name : |
(* |
The file name.
| *) |
|
endianness : |
(* |
Endianess of the file.
| *) |
|
version_major : |
(* |
Libpcap version.
| *) |
|
version_minor : |
|||
|
this_zone : |
(* |
Time zone (should be zero, unused).
| *) |
|
sigfigs : |
(* |
unused.
| *) |
|
snaplen : |
(* |
Indicate that no caplen will be smaller. We don't use this.
| *) |
|
dlt : |
(* |
The Data Link Type (see
Pcap.Dlt). | *) |
module Pdu:sig..end
val save : ?caplen:int -> ?dlt:Dlt.t -> string -> Tools.Payload.outer_t -> unitsave "file.pcap" returns a function that will save passed bitstrings as packets in
"file.pcap".
caplen : can be used to cap saved packet to a given number of bytesdlt : can be used to change the file's DLT (required if you do not write Ethernet packets)exception Not_a_pcap_file
val bitstring_of_global_header : global_header -> Bitstring.bitstring
val global_header_of_bitstring : string -> Bitstring.bitstring -> global_header
val read_global_header : string -> global_header * BatIO.inputread_global_header filename reads the pcap global header from the
given file, and returns both a Pcap.global_header and the input channel.val read_next_pkt : global_header -> Batteries.IO.input -> Pdu.tread_next_pkt global_header ic will return the next Pcap.Pdu.t that's to
be read from the input stream ic.val enum_of_file : string -> Pdu.t Batteries.Enum.t
val write_global_header : string -> global_header -> unit BatIO.outputwrite_global_header filename write a 'generic' pcap global header and
returns the output channel.val write_next_pkt : unit BatIO.output -> Pdu.t -> unitwrite_next_pkt global_header ic will return the next Pcap.Pdu.t that's to
be read from the input stream ic.val file_of_enum : string -> ?dlt:Dlt.t -> Pdu.t Batteries.Enum.t -> unit
type infos = {
|
filename : |
|
data_link_type : |
|
num_packets : |
|
data_size : |
|
start_time : |
|
stop_time : |
val infos_of : string -> infosval merge : Pdu.t Batteries.Enum.t list -> Pdu.t Batteries.Enum.tmerge [e1 ; e2 ; e3] will merge the three Enumt.t of packets in chronological
order.val repair_file : string -> unitval play : (Bitstring.bitstring -> 'a) -> string -> unitplay tx "file.pcap" will read packets from "file.pcap" and send them to tx
copying the pcap file frame rate. Notice that we use the internal
Clock for this, so it's both very accurate or not accurate at all,
depending on how you look at it.type iface = {
|
handler : |
|
name : |
|
caplen : |
val mtu : string -> intval openif : ?promisc:bool -> ?filter:string -> ?caplen:int -> string -> ifaceopenif "eth0" true "port 80" 96 returns the iface representing eth0,
in promiscuous mode, filtering port 80 and capturing only the first 96 bytes
of each packets. Notice that if caplen is not set then MTU for the
device will be chosen.val sniff : iface -> Pdu.tsniff iface will return the next available packet as a Pcap.Pdu.t.val packets_injected_ok : Metric.Atomic.tval packets_injected_err : Metric.Atomic.tval bytes_out : Metric.Counter.tval inject : iface -> Bitstring.bitstring -> unitinject iface bits inject the packet bits into interface iface.val packets_sniffed_ok : Metric.Atomic.tval bytes_in : Metric.Counter.tval sniffer : iface -> (Bitstring.bitstring -> unit) -> Thread.tsniffer iface rx returns a thread that continuously sniff packets
and pass them to the rx function (via the Clock).