Add primitive iptables wrapper which can set up port forwards

Signed-off-by: David Scott <dave.scott@docker.com>
This commit is contained in:
David Scott 2016-06-17 12:57:26 +01:00
parent 0c471bdc09
commit 80b234dd3e
3 changed files with 86 additions and 3 deletions

1
alpine/packages/iptables/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
iptables

View File

@ -1,5 +1,7 @@
FROM ocaml/opam:alpine
RUN sudo apk add m4
RUN opam install ocamlfind astring -y
WORKDIR /app
ADD . /app
RUN sudo chown -R opam /app
RUN ocamlopt -o iptables main.ml
RUN opam config exec -- ocamlfind ocamlopt -package unix,astring -linkpkg -o iptables main.ml

View File

@ -1,2 +1,82 @@
let () =
print_string "Hello world!\n";;
(* ocamlfind ocamlopt -package unix,astring -linkpkg -o iptables iptables.ml *)
(*
--wait -t nat -I DOCKER-INGRESS -p tcp --dport 80 -j DNAT --to-destination 172.18.0.2:80
--wait -t nat -D DOCKER-INGRESS -p tcp --dport 80 -j DNAT --to-destination 172.18.0.2:80
*)
let _iptables = "/sbin/iptables"
let _proxy = "/usr/bin/docker-proxy"
let _pid_dir = "/var/run/service-port-opener"
type port = {
proto: string;
dport: string; (* host port *)
ip: string; (* container ip *)
port: string; (* container port *)
}
let log_fd = Unix.openfile "/var/run/log/service-port-opener.log" [ Unix.O_WRONLY; Unix.O_APPEND; Unix.O_CREAT ] 0o0644
let logf fmt =
Printf.ksprintf (fun s ->
let s = s ^ "\n" in
let rec loop ofs remaining =
if remaining > 0 then begin
let n = Unix.write log_fd s ofs remaining in
loop (ofs + n) (remaining - n)
end in
loop 0 (String.length s)
) fmt
let pid_filename { proto; dport; ip; port } =
Printf.sprintf "%s/%s.%s.%s.%s.pid" _pid_dir proto dport ip port
let insert ({ proto; dport; ip; port } as p) =
let filename = pid_filename p in
logf "insert: creating a proxy for %s" filename;
let args = [ _proxy; "-proto"; proto; "-container-ip"; ip; "-container-port"; port; "-host-ip"; "0.0.0.0"; "-host-port"; dport; "-i" ] in
let pid = Unix.fork () in
if pid != 0 then begin
(* write pid to a file (not atomically) *)
let oc = open_out filename in
output_string oc (string_of_int pid);
close_out oc;
logf "binary = %s args = %s" _proxy (String.concat "; " args);
(try Unix.execv _proxy (Array.of_list args) with e -> logf "Failed with %s" (Printexc.to_string e));
exit 1
end
let delete ({ proto; dport; ip; port } as p) =
let filename = pid_filename p in
logf "delete: removing a proxy for %s" filename;
(* read the pid from a file *)
try
let ic = open_in filename in
let pid = int_of_string (input_line ic) in
logf "Sending SIGTERM to %d" pid;
Unix.kill Sys.sigterm pid
with e ->
logf "delete: failed to remove proxy for %s: %s" filename (Printexc.to_string e);
raise e
let parse_ip_port ip_port = match Astring.String.cut ~sep:":" ip_port with
| None ->
failwith ("Failed to parse <ip:port>:" ^ ip_port)
| Some (ip, port) ->
ip, port
let _ =
( try Unix.mkdir _pid_dir 0o0755 with Unix.Unix_error(Unix.EEXIST, _, _) -> () );
logf "intercepted arguments [%s]" (String.concat "; " (Array.to_list Sys.argv));
( match Array.to_list Sys.argv with
| [ _; "--wait"; "-t"; "nat"; "-I"; "DOCKER-INGRESS"; "-p"; proto; "--dport"; dport; "-j"; "DNAT"; "--to-destination"; ip_port ] ->
let ip, port = parse_ip_port ip_port in
insert { proto; dport; ip; port }
| [ _; "--wait"; "-t"; "nat"; "-D"; "DOCKER-INGRESS"; "-p"; proto; "--dport"; dport; "-j"; "DNAT"; "--to-destination"; ip_port ] ->
let ip, port = parse_ip_port ip_port in
delete { proto; dport; ip; port }
| _ ->
()
);
Unix.execv _iptables Sys.argv