diff --git a/apps/epp_proxy/src/epp_tls_acceptor.erl b/apps/epp_proxy/src/epp_tls_acceptor.erl index 6ef5f3e..04696c2 100644 --- a/apps/epp_proxy/src/epp_tls_acceptor.erl +++ b/apps/epp_proxy/src/epp_tls_acceptor.erl @@ -28,7 +28,6 @@ {ok, CrlFile} -> CrlFile end). - %% gen_server callbacks -export([init/1, handle_cast/2, handle_call/3, start_link/1]). diff --git a/apps/epp_proxy/src/epp_tls_worker.erl b/apps/epp_proxy/src/epp_tls_worker.erl index ada1409..f322bf5 100644 --- a/apps/epp_proxy/src/epp_tls_worker.erl +++ b/apps/epp_proxy/src/epp_tls_worker.erl @@ -9,9 +9,9 @@ -export([init/1, handle_cast/2, handle_call/3, start_link/1]). -export([code_change/3]). --export([request/5]). +-export([request/6]). --record(state,{socket, length, session_id, common_name, client_cert}). +-record(state,{socket, session_id, common_name, client_cert, peer_ip}). init(Socket) -> logger:info("Created a worker process"), @@ -22,18 +22,17 @@ start_link(Socket) -> gen_server:start_link(?MODULE, Socket, []). handle_cast(serve, State = #state{socket=Socket}) -> + %% If certificate is revoked, this will fail right away here. + %% mod_epp does exactly the same thing. {ok, SecureSocket} = ssl:handshake(Socket), - {ok, PeerCert} = ssl:peercert(SecureSocket), - {SSL_CLIENT_S_DN_CN, SSL_CLIENT_CERT} = - epp_certs:headers_from_cert(PeerCert), - - {noreply, State#state{socket=SecureSocket, common_name=SSL_CLIENT_S_DN_CN, - client_cert=SSL_CLIENT_CERT}}; + NewState = state_from_socket(SecureSocket, State), + {noreply, NewState}; handle_cast(greeting, State = #state{socket=Socket, common_name=SSL_CLIENT_S_DN_CN, client_cert=SSL_CLIENT_CERT, - session_id=SessionId}) -> + session_id=SessionId, + peer_ip=PeerIp}) -> Request = request("hello", SessionId, "", SSL_CLIENT_S_DN_CN, - SSL_CLIENT_CERT), + SSL_CLIENT_CERT, PeerIp), logger:info("Request: ~p~n", [Request]), {_Status, _StatusCode, _Headers, ClientRef} = @@ -49,7 +48,8 @@ handle_cast(greeting, State = #state{socket=Socket, common_name=SSL_CLIENT_S_DN_ handle_cast(process_command, State = #state{socket=Socket, common_name=SSL_CLIENT_S_DN_CN, client_cert=SSL_CLIENT_CERT, - session_id=SessionId}) -> + session_id=SessionId, + peer_ip=PeerIp}) -> Length = case read_length(Socket) of {ok, Data} -> Data; @@ -69,7 +69,7 @@ handle_cast(process_command, State = #state{socket=Socket, Command = epp_xml:get_command(XMLRecord), Request = request(Command, SessionId, Frame, SSL_CLIENT_S_DN_CN, - SSL_CLIENT_CERT), + SSL_CLIENT_CERT, PeerIp), logger:info("Request: ~p~n", [Request]), {_Status, _StatusCode, _Headers, ClientRef} = @@ -119,7 +119,7 @@ read_frame(Socket, FrameLength) -> end. %% Map request and return values -request(Command, SessionId, RawFrame, CommonName, ClientCert) -> +request(Command, SessionId, RawFrame, CommonName, ClientCert, PeerIp) -> URL = epp_router:route_request(Command), RequestMethod = epp_router:request_method(Command), Cookie = hackney_cookie:setcookie("session", SessionId, []), @@ -131,7 +131,8 @@ request(Command, SessionId, RawFrame, CommonName, ClientCert) -> end, Headers = [{"SSL_CLIENT_CERT", ClientCert}, {"SSL_CLIENT_S_DN_CN", CommonName}, - {"User-Agent", <<"EPP proxy">>}], + {"User-Agent", <<"EPP proxy">>}, + {"X-Forwarded-for", epp_util:readable_ip(PeerIp)}], #epp_request{url=URL, method=RequestMethod, body=Body, cookies=[Cookie], headers=Headers}. @@ -141,3 +142,14 @@ frame_to_socket(Message, Socket) -> ByteSize = << Length:32/big >>, write_line(Socket, ByteSize), write_line(Socket, Message). + +%% Extract state info from socket. Fail if you must. +state_from_socket(Socket, State) -> + {ok, PeerCert} = ssl:peercert(Socket), + {ok, {PeerIp, _PeerPort}} = ssl:peername(Socket), + {SSL_CLIENT_S_DN_CN, SSL_CLIENT_CERT} = + epp_certs:headers_from_cert(PeerCert), + NewState = State#state{socket=Socket, common_name=SSL_CLIENT_S_DN_CN, + client_cert=SSL_CLIENT_CERT, peer_ip=PeerIp}, + logger:info("Established connection with: [~p]~n", [NewState]), + NewState. diff --git a/apps/epp_proxy/src/epp_util.erl b/apps/epp_proxy/src/epp_util.erl index a3e954a..1442f44 100644 --- a/apps/epp_proxy/src/epp_util.erl +++ b/apps/epp_proxy/src/epp_util.erl @@ -2,7 +2,7 @@ -export([create_map/1, create_session_id/1, frame_length/1, frame_length_to_receive/1, frame_length_to_send/1, - session_id/1]). + session_id/1, readable_ip/1]). -define(OFFSET, 4). @@ -48,3 +48,13 @@ frame_length(Frame) when is_binary(Frame) -> frame_length(Frame) when is_list(Frame) -> Bin = unicode:characters_to_binary(Frame), byte_size(Bin). + +%% Pass a tuple of IP address, return a binary for sending over the wire. +-spec readable_ip({integer(), integer(), integer(), integer()}) -> binary(). +readable_ip({FirstOctet, SecondOctet, ThirdOctet, FourthOctet}) -> + List = [integer_to_list(FirstOctet), ".", + integer_to_list(SecondOctet), ".", + integer_to_list(ThirdOctet), ".", + integer_to_list(FourthOctet)], + Binary = list_to_binary(List), + Binary. diff --git a/apps/epp_proxy/test/epp_util_tests.erl b/apps/epp_proxy/test/epp_util_tests.erl index 913466b..a3e055f 100644 --- a/apps/epp_proxy/test/epp_util_tests.erl +++ b/apps/epp_proxy/test/epp_util_tests.erl @@ -37,3 +37,7 @@ frame_length_to_receive_test() -> frame_length_to_send_test() -> ?assertEqual(18, epp_util:frame_length_to_send("")), ?assertEqual(4, epp_util:frame_length_to_send("")). + +readable_ip_test() -> + ?assertEqual(<<127,46,0,46,0,46,1>>, epp_util:readable_ip({127,0,0,1})), + ?assertError(function_clause, epp_util:readable_ip({127,0,0,1,0})). diff --git a/config/sys.config b/config/sys.config index d504f81..2132398 100644 --- a/config/sys.config +++ b/config/sys.config @@ -7,5 +7,5 @@ {cacertfile_path, "/opt/shared/ca/certs/ca.crt.pem"}, {certfile_path, "/opt/shared/ca/certs/cert.pem"}, {keyfile_path, "/opt/shared/ca/certs/key.pem"}, - {crlfile_path, "/opt/shared/ca/certs/key.pem"},]} + {crlfile_path, "/opt/shared/ca/certs/key.pem"}]} ].