Skip to content
Snippets Groups Projects
Commit 69a1fbfa authored by NGUYEN Do Duc Anh's avatar NGUYEN Do Duc Anh
Browse files

Merge branch 'update-to-functor' into 'opportunistic'

funtorize the network read and write callbacks

See merge request !2
parents af92feba deb94281
No related branches found
No related tags found
1 merge request!2funtorize the network read and write callbacks
(* mirage >= 4.8.1 *)
(* mirage >= 4.8.1 & < 4.9.0 *)
open Mirage
(* we need two network interfaces: a public side and a private side *)
......@@ -19,7 +19,6 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public5" "public5")
(netif ~group:"public5" "0"))
let private_netif5 =
Key.(if_impl is_solo5
(netif ~group:"private5" "private5")
......@@ -29,7 +28,6 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public6" "public6")
(netif ~group:"public6" "0"))
let private_netif6 =
Key.(if_impl is_solo5
(netif ~group:"private6" "private6")
......@@ -39,7 +37,6 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public7" "public7")
(netif ~group:"public7" "0"))
let private_netif7 =
Key.(if_impl is_solo5
(netif ~group:"private7" "private7")
......@@ -49,7 +46,6 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public8" "public8")
(netif ~group:"public8" "0"))
let private_netif8 =
Key.(if_impl is_solo5
(netif ~group:"private8" "private8")
......@@ -59,7 +55,6 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public9" "public9")
(netif ~group:"public9" "0"))
let private_netif9 =
Key.(if_impl is_solo5
(netif ~group:"private9" "private9")
......@@ -69,7 +64,6 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public10" "public10")
(netif ~group:"public10" "0"))
let private_netif10 =
Key.(if_impl is_solo5
(netif ~group:"private10" "private10")
......@@ -79,7 +73,6 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public11" "public11")
(netif ~group:"public11" "0"))
let private_netif11 =
Key.(if_impl is_solo5
(netif ~group:"private11" "private11")
......@@ -89,7 +82,6 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public12" "public12")
(netif ~group:"public12" "0"))
let private_netif12 =
Key.(if_impl is_solo5
(netif ~group:"private12" "private12")
......@@ -99,52 +91,18 @@ let public_netif5 =
Key.(if_impl is_solo5
(netif ~group:"public13" "public13")
(netif ~group:"public13" "0"))
let private_netif13 =
Key.(if_impl is_solo5
(netif ~group:"private13" "private13")
(netif ~group:"private13" "1"))
(* build ethernet interfaces on top of those network interfaces *)
let public_ethernet4 = ethif public_netif4
let private_ethernet4 = ethif private_netif4
let public_ethernet5 = ethif public_netif5
let private_ethernet5 = ethif private_netif5
let public_ethernet6 = ethif public_netif6
let private_ethernet6 = ethif private_netif6
let public_ethernet7 = ethif public_netif7
let private_ethernet7 = ethif private_netif7
let public_ethernet8 = ethif public_netif8
let private_ethernet8 = ethif private_netif8
let public_ethernet9 = ethif public_netif9
let private_ethernet9 = ethif private_netif9
let public_ethernet10 = ethif public_netif10
let private_ethernet10 = ethif private_netif10
let public_ethernet11 = ethif public_netif11
let private_ethernet11 = ethif private_netif11
let public_ethernet12 = ethif public_netif12
let private_ethernet12 = ethif private_netif12
let public_ethernet13 = ethif public_netif13
let private_ethernet13 = ethif private_netif13
let packages = [
package "ethernet";
package "ipaddr";
package ~min:"8.2.0" ~sublibs:["ipv4";"tcp"] "tcpip"; (* There was a breaking API changes in the 8.2 series *)
package "re";
package "logs";
(* package ~min:"4.0.0" "mirage-runtime"; *) (* We want to avoid runtime argument at any cost *)
package ~min:"4.8.1" "mirage-runtime"; (* we need at least mirage 4.8.1 *)
]
(* our unikernel needs to know about physical network, and ethernet modules
......@@ -186,15 +144,15 @@ let () = register "simple-ids" [ main
$ public_netif11 $ private_netif11
$ public_netif12 $ private_netif12
$ public_netif13 $ private_netif13
$ public_ethernet4 $ private_ethernet4
$ public_ethernet5 $ private_ethernet5
$ public_ethernet6 $ private_ethernet6
$ public_ethernet7 $ private_ethernet7
$ public_ethernet8 $ private_ethernet8
$ public_ethernet9 $ private_ethernet9
$ public_ethernet10 $ private_ethernet10
$ public_ethernet11 $ private_ethernet11
$ public_ethernet12 $ private_ethernet12
$ public_ethernet13 $ private_ethernet13
$ ethif public_netif4 $ ethif private_netif4
$ ethif public_netif5 $ ethif private_netif5
$ ethif public_netif6 $ ethif private_netif6
$ ethif public_netif7 $ ethif private_netif7
$ ethif public_netif8 $ ethif private_netif8
$ ethif public_netif9 $ ethif private_netif9
$ ethif public_netif10 $ ethif private_netif10
$ ethif public_netif11 $ ethif private_netif11
$ ethif public_netif12 $ ethif private_netif12
$ ethif public_netif13 $ ethif private_netif13
$ default_random $ default_monotonic_clock
]
let log = Logs.Src.create "ids" ~doc:"IDS rules"
module Log = (val Logs.src_log log : Logs.LOG)
(* Creates a set of rules (empty) and a default action (claim a packet is not an attack) *)
let ids_rules =
Rules.init false
let attacker_ip_lst = ref []
let node_id = ref 0l
(* Takes an IPv4 [packet], unmarshal it, examine to detect attackers' IPs in TCP packets*)
let detect_and_output_private packet header frame inter_num output_private output_ether_private =
(* Handle IPv4 only... *)
match Ipv4_packet.Unmarshal.of_cstruct packet with
| Result.Error s ->
Logs.err (fun m -> m "Can't parse IPv4 packet: %s" s);
Lwt.return_unit
(* Otherwise unmarshal it, match rules with IPs, ports, proto *)
| Result.Ok (ipv4_hdr, payload) ->
(match Rules.is_match_rule ids_rules (ipv4_hdr, payload) with
| false ->
()
| true ->
attacker_ip_lst := ipv4_hdr.src :: !attacker_ip_lst;
());
let options = ipv4_hdr.options in
match List.exists (fun attacker_ip -> Ipaddr.V4.compare ipv4_hdr.dst attacker_ip = 0) !attacker_ip_lst with
| false ->
(* If the packet is NOT an attack, just look for registration request *)
Custom_option.read_custom_opt ipv4_hdr.src options;
output_private frame
| true ->
(* If the packet IS an attack, look for registration request AND embed reaction decision *)
let new_options_cs = Custom_option.read_and_append_custom_opt ipv4_hdr.src ipv4_hdr.dst options (!node_id, inter_num) in
let new_ipv4_hdr = {ipv4_hdr with options= new_options_cs} in
let len_payload = Cstruct.length payload in
let new_ipv4_hdr_cs = Ipv4_packet.Marshal.make_cstruct ~payload_len:len_payload new_ipv4_hdr in
let new_packet = Cstruct.append new_ipv4_hdr_cs payload in
output_ether_private header.Ethernet.Packet.source header.Ethernet.Packet.destination new_packet
open Lwt.Infix
module Make
(Public_net: Mirage_net.S) (Private_net: Mirage_net.S)
(Public_ethernet : Ethernet.S) (Private_ethernet : Ethernet.S)
= struct
(* configure logs, so we can use them later *)
let log = Logs.Src.create "listener" ~doc:"Listener for public and private interfaces"
module Log = (val Logs.src_log log : Logs.LOG)
(* output callbacks we need *)
let output_public public_netif packet =
let len = Cstruct.length packet in
Public_net.write public_netif ~size:len (fun b -> Cstruct.blit packet 0 b 0 len ; len) >|= function
| Ok () -> ()
| Error e ->
Log.warn (fun f -> f "netif write errored %a" Public_net.pp_error e)
(* Forward the (dest, packet) [packet] to the private interface, using [dest] to understand how to route *)
let output_private private_netif packet =
let len = Cstruct.length packet in
Private_net.write private_netif ~size:len (fun b -> Cstruct.blit packet 0 b 0 len ; len) >|= function
| Ok () -> ()
| Error e ->
Log.warn (fun f -> f "netif write errored %a" Private_net.pp_error e)
let output_ether_private private_ethernet mac_src mac_dst packet =
Private_ethernet.write private_ethernet ~src:mac_src mac_dst `IPv4 (fun b ->
let len = Cstruct.length packet in
Cstruct.blit packet 0 b 0 len ;len) >>= function
| Error e ->
Log.err (fun f -> f "Failed to send packet from private interface: %a" Private_ethernet.pp_error e);
Lwt.return_unit
| Ok () -> Lwt.return_unit
(* we need to establish listeners for the and public interfaces *)
(* we're interested in all traffic to the physical interface; we'd like to
send ARP traffic to the normal ARP listener and responder,
handle ipv4 traffic with the functions we've defined above for detection,
and ignore all ipv6 traffic. *)
let listen_public public_netif private_netif private_ethernet inter_num =
let header_size = Ethernet.Packet.sizeof_ethernet
and input frame = (* Takes an ethernet packet and send it to the relevant callback *)
match Ethernet.Packet.of_cstruct frame with
| Ok (header, payload) ->
begin
match header.Ethernet.Packet.ethertype with
| `ARP -> output_private private_netif frame
| `IPv4 -> Ids.detect_and_output_private payload header frame inter_num (output_private private_netif) (output_ether_private private_ethernet)
| _ -> Lwt.return_unit
end
| Error s ->
Log.debug (fun f -> f "Forward Ethernet frame if I cannot parse %s" s);
output_private private_netif frame;
in
Public_net.listen ~header_size public_netif input >>= function
| Error e -> Log.debug (fun f -> f "public interface stopped: %a" Public_net.pp_error e); Lwt.return_unit
| Ok () -> Log.debug (fun f -> f "public interface terminated normally");
Lwt.return_unit
let listen_private public_netif private_netif =
let header_size = Ethernet.Packet.sizeof_ethernet
and input frame =
output_public public_netif frame
in
Private_net.listen ~header_size private_netif input >>= function
| Error e -> Log.debug (fun f -> f "private interface stopped: %a" Private_net.pp_error e); Lwt.return_unit
| Ok () -> Log.debug (fun f -> f "private interface terminated normally"); Lwt.return_unit
end
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment