package tcpip
OCaml TCP/IP networking stack, used in MirageOS
Install
Dune Dependency
Authors
Maintainers
Sources
tcpip-9.0.1.tbz
sha256=fac07ce986811cf5e3d71373d92b631cc30fbef548d6da21b0917212dcf90b03
sha512=01de13f560d58b1524c39619e4e4cb6ebbf069155eb43d0f264aa12b00e0cc8c39792719e3ca46585dd596b692b8e1e3f8c132f005ed9e2d77747c0c158bf4d9
doc/src/tcpip.ipv4/static_ipv4.ml.html
Source file static_ipv4.ml
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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
(* * Copyright (c) 2010-2011 Anil Madhavapeddy <anil@recoil.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS l SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *) open Lwt.Infix let src = Logs.Src.create "ipv4" ~doc:"Mirage IPv4" module Log = (val Logs.src_log src : Logs.LOG) module Make (Ethernet: Ethernet.S) (Arpv4 : Arp.S) = struct module Routing = Routing.Make(Log)(Arpv4) (** IO operation errors *) type error = [ Tcpip.Ip.error | `Would_fragment | `Ethif of Ethernet.error ] let pp_error ppf = function | #Tcpip.Ip.error as e -> Tcpip.Ip.pp_error ppf e | `Ethif e -> Ethernet.pp_error ppf e type ipaddr = Ipaddr.V4.t type callback = src:ipaddr -> dst:ipaddr -> Cstruct.t -> unit Lwt.t let pp_ipaddr = Ipaddr.V4.pp type prefix = Ipaddr.V4.Prefix.t let pp_prefix = Ipaddr.V4.Prefix.pp type t = { ethif : Ethernet.t; arp : Arpv4.t; cidr: Ipaddr.V4.Prefix.t; gateway: Ipaddr.V4.t option; mutable cache: Fragments.Cache.t; } let write t ?(fragment = true) ?(ttl = 38) ?src dst proto ?(size = 0) headerf bufs = Routing.destination_mac t.cidr t.gateway t.arp dst >>= function | Error `Local -> Log.warn (fun f -> f "Could not find %a on the local network" Ipaddr.V4.pp dst); Lwt.return @@ Error (`No_route "no response for IP on local network") | Error `Gateway when t.gateway = None -> Log.warn (fun f -> f "Write to %a would require an external route, which was not provided" Ipaddr.V4.pp dst); Lwt.return @@ Ok () | Error `Gateway -> Log.warn (fun f -> f "Write to %a requires an external route, and the provided %a was not reachable" Ipaddr.V4.pp dst (Fmt.option Ipaddr.V4.pp) t.gateway); (* when a gateway is specified the user likely expects their traffic to be passed to it *) Lwt.return @@ Error (`No_route "no route to default gateway to outside world") | Ok mac -> (* need first to deal with fragmentation decision - find out mtu *) let mtu = Ethernet.mtu t.ethif in (* no options here, always 20 bytes! *) let hdr_len = Ipv4_wire.sizeof_ipv4 in let needed_bytes = Cstruct.lenv bufs + hdr_len + size in let multiple = needed_bytes > mtu in (* construct the header (will be reused across fragments) *) if not fragment && multiple then Lwt.return (Error `Would_fragment) else let off = match fragment, multiple with | true, true -> 0x2000 | false, false -> 0x4000 | true, false -> 0x0000 | false, true -> assert false (* handled by conditional above *) in let hdr = let src = match src with None -> Ipaddr.V4.Prefix.address t.cidr | Some x -> x in let id = if multiple then Randomconv.int16 Mirage_crypto_rng.generate else 0 in Ipv4_packet.{ options = Cstruct.empty ; src ; dst ; ttl ; off ; id ; proto = Ipv4_packet.Marshal.protocol_to_int proto } in let writeout size fill = Ethernet.write t.ethif mac `IPv4 ~size fill >|= function | Error e -> Log.warn (fun f -> f "Error sending Ethernet frame: %a" Ethernet.pp_error e); Error (`Ethif e) | Ok () -> Ok () in Log.debug (fun m -> m "ip write: mtu is %d, hdr_len is %d, size %d \ payload len %d, needed_bytes %d" mtu hdr_len size (Cstruct.lenv bufs) needed_bytes) ; let leftover = ref Cstruct.empty in (* first fragment *) let fill buf = let payload_buf = Cstruct.shift buf hdr_len in let header_len = headerf payload_buf in if header_len > size then begin Log.err (fun m -> m "headers returned length exceeding size") ; invalid_arg "headerf exceeds size" end ; (* need to copy the given payload *) let len, rest = Cstruct.fillv ~src:bufs ~dst:(Cstruct.shift payload_buf header_len) in leftover := Cstruct.concat rest; let payload_len = header_len + len in match Ipv4_packet.Marshal.into_cstruct ~payload_len hdr buf with | Ok () -> payload_len + hdr_len | Error msg -> Log.err (fun m -> m "failure while assembling ip frame: %s" msg) ; invalid_arg msg in writeout (min mtu needed_bytes) fill >>= function | Error e -> Lwt.return (Error e) | Ok () -> if not multiple then Lwt.return (Ok ()) else let remaining = Fragments.fragment ~mtu hdr !leftover in Lwt_list.fold_left_s (fun acc p -> match acc with | Error e -> Lwt.return (Error e) | Ok () -> let l = Cstruct.length p in writeout l (fun buf -> Cstruct.blit p 0 buf 0 l ; l)) (Ok ()) remaining let input t ~tcp ~udp ~default buf = match Ipv4_packet.Unmarshal.of_cstruct buf with | Error s -> Log.info (fun m -> m "error %s while parsing IPv4 frame %a" s Cstruct.hexdump_pp buf); Lwt.return_unit | Ok (packet, payload) -> let of_interest ip = Ipaddr.V4.(compare ip (Prefix.address t.cidr) = 0 || compare ip broadcast = 0 || compare ip (Prefix.broadcast t.cidr) = 0) in if not (of_interest packet.dst) then begin Log.debug (fun m -> m "dropping IP fragment not for us or broadcast %a" Ipv4_packet.pp packet); Lwt.return_unit end else if Cstruct.length payload = 0 then begin Log.debug (fun m -> m "dropping zero length IPv4 frame %a" Ipv4_packet.pp packet) ; Lwt.return_unit end else let ts = Mirage_mtime.elapsed_ns () in let cache, res = Fragments.process t.cache ts packet payload in t.cache <- cache ; match res with | None -> Lwt.return_unit | Some (packet, payload) -> let src, dst = packet.src, packet.dst in match Ipv4_packet.Unmarshal.int_to_protocol packet.proto with | Some `TCP -> tcp ~src ~dst payload | Some `UDP -> udp ~src ~dst payload | Some `ICMP | None -> default ~proto:packet.proto ~src ~dst payload let connect ?(no_init = false) ~cidr ?gateway ?(fragment_cache_size = 1024 * 256) ethif arp = (if no_init then Lwt.return_unit else Arpv4.set_ips arp [Ipaddr.V4.Prefix.address cidr]) >|= fun () -> let cache = Fragments.Cache.empty fragment_cache_size in { ethif; arp; cidr; gateway; cache } let disconnect _ = Lwt.return_unit let get_ip t = [Ipaddr.V4.Prefix.address t.cidr] let configured_ips t = [t.cidr] let pseudoheader t ?src dst proto len = let src = match src with None -> Ipaddr.V4.Prefix.address t.cidr | Some x -> x in Ipv4_packet.Marshal.pseudoheader ~src ~dst ~proto len let src t ~dst:_ = Ipaddr.V4.Prefix.address t.cidr let mtu t ~dst:_ = Ethernet.mtu t.ethif - Ipv4_wire.sizeof_ipv4 end
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>