1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
open Lwt.Infix
let src = Logs.Src.create "udp" ~doc:"Mirage UDP"
module Log = (val Logs.src_log src : Logs.LOG)
module Make (Ip : Tcpip.Ip.S) (Random : Mirage_crypto_rng_mirage.S) = struct
type ipaddr = Ip.ipaddr
type callback = src:ipaddr -> dst:ipaddr -> src_port:int -> Cstruct.t -> unit Lwt.t
type error = [ `Ip of Ip.error ]
let pp_error ppf (`Ip e) = Ip.pp_error ppf e
type t = {
ip : Ip.t;
listeners : (int, callback) Hashtbl.t;
}
let pp_ip = Ip.pp_ipaddr
let listen t ~port callback =
if port < 0 || port > 65535 then
raise (Invalid_argument (Printf.sprintf "invalid port number (%d)" port))
else
Hashtbl.replace t.listeners port callback
let unlisten t ~port = Hashtbl.remove t.listeners port
let input t ~src ~dst buf =
match Udp_packet.Unmarshal.of_cstruct buf with
| Error s ->
Log.debug (fun f ->
f "Discarding received UDP message: error parsing: %s" s);
Lwt.return_unit
| Ok ({ Udp_packet.src_port; dst_port}, payload) ->
match Hashtbl.find_opt t.listeners dst_port with
| None -> Lwt.return_unit
| Some fn -> fn ~src ~dst ~src_port payload
let writev ?src ?src_port ?ttl ~dst ~dst_port t bufs =
let src_port = match src_port with
| None -> Randomconv.int ~bound:65535 (fun x -> Random.generate x)
| Some p -> p
in
let fill_hdr buf =
let payload_size = Cstruct.lenv bufs in
let ph =
Ip.pseudoheader t.ip ?src dst `UDP (payload_size + Udp_wire.sizeof_udp)
in
let = Udp_packet.({ src_port; dst_port; }) in
match Udp_packet.Marshal.into_cstruct udp_header buf ~pseudoheader:ph ~payload:(Cstruct.concat bufs) with
| Ok () -> 8
| Error msg ->
Logs.err (fun m -> m "error while assembling udp header: %s, ignoring" msg);
8
in
Ip.write t.ip ?src dst ?ttl `UDP ~size:8 fill_hdr bufs >|= function
| Ok () -> Ok ()
| Error e ->
Log.err (fun f -> f "IP module couldn't send UDP packet to %a: %a"
pp_ip dst Ip.pp_error e);
Ok ()
let write ?src ?src_port ?ttl ~dst ~dst_port t buf =
writev ?src ?src_port ?ttl ~dst ~dst_port t [buf]
let connect ip =
Log.info (fun f -> f "UDP layer connected on %a"
Fmt.(list ~sep:(any ", ") Ip.pp_prefix)
(Ip.configured_ips ip));
let t = { ip ; listeners = Hashtbl.create 7 } in
Lwt.return t
let disconnect t =
Log.info (fun f -> f "UDP layer disconnected on %a"
Fmt.(list ~sep:(any ", ") Ip.pp_prefix)
(Ip.configured_ips t.ip));
Lwt.return_unit
end