PFCFBP: Port Forwarding Configuration Frontend-Backend Protocol (draft) by Vadim Goncharov , 14 Mar 2008. 1. Introduction. Network administrators in large companies, as well as owners of several computers in small home networks, are often need to do a sharing of one or several public IP addresses to a larger number of end users' private IP addresses. This can be done via NAT (Network Address Translation), a SOCKS 4/5 proxy or something else. But while this always ensures traversing connections from the private network to the Internet, connections arriving in opposite direction can't easily determine which private IP address should be selected, thus requiring manual port redirection setup. There are also some protocols, e.g. NAT-PMP or SOCKS5 which allow client programs to setup redirections automatically. It is usually one program which does handle connections in both directions, and it can be also of NAT-PMP or a SOCKS proxy server, but in some configurations this is hard to achieve, as several different computers can serve NAT, or SOCKS5 proxy protocol allows to have more then one public IP, etc. If it could be split into two parts, a frontend conversating with users about which ports to redirects, and a backend, let's call it "redirecting engine" (or simply "engine"), which does actual data-passing work, then system could be more scalable and extendable. Then the frontend can handle all the complex logic with user authorization, different protocols, etc., while backend could be simple and fast for bulk data. Imagine, for example, a SOCKS server doing it's work in a software (slow) which is then upgraded to other backend (fast in-kernel or hardware entity) without any changes in a frontend itself. This document defines standard protocol between engine and front-end, allowing one to combine any engine with any front-end (user can easily extend system). The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in "Key words for use in RFCs to Indicate Requirement Levels" [RFC 2119]. 2. Protocol. Protocol is simple, stream text-based and line-oriented. Valid line separators are both LF alone and CR LF pair, empty lines and lines beginning with "#" character MUST be ignored. Backend acts like a server processing frontend's requests. Backend listens on a UNIX domain socket or a TCP port. Both connection endpoints (path to socket or a TCP address and port) are configured on a frontend and backend, this is a responsibility of a system administrator as well as limiting access to backend: protocol doesn't deal with security to simplify backend implementation, security issues with end users should be handled by frontend. Backend is ready to operation immediately after connection was established, no commands are needed. Backend should be able to handle several frontends simltaneously, one per connection. There are no timeouts, connection could be idle for any amount of time and can be terminated at any time by any of the peers. Connection termination should not affect redirection state of backend - frontend can reconnect any time. In other words, communication is as stateless as possible. Protocol commands are always lines of characters terminated with a CR-LF (Carriage Return - Line Feed) pair (or LF alone), and these messages MUST MOT exceed 512 characters in length, counting all characters including the trailing CR-LF. Thus, there are 510 characters maximum allowed for the command and its parameters. There is no provision for continuation command lines. Protocol is case-sensitive (case MUST be preserved in both commands and description field). Frontend always makes one-command (one-line) requests, backend always MUST respond with one or more lines. Protocol commands (messages) have the same general format for both requests and replies. 2.1. Command format in 'pseudo' BNF. The protocol commands must be extracted from the contiguous stream of octets. For implementation simplicity, NUL characters are disallowed. Also, The BNF representation for this is: ::= '#' | [ ] ::= { | } ::= ' ' { ' ' } ::= { } ::= ::= ::= [ CR ] LF Other parameters syntax are: ::= { | | } ::= 'a' ... 'z' | 'A' ... 'Z' ::= '0' ... '9' ::= '_' ::= ::= There can be any number of SPACEs between parameters. Identifiers MUST NOT be longer 31 characters. 2.2. Requests, replies and protocol operation. Frontend issues requests, fronted replies. A request may be specification of new redirect, redirect deletion or request to list existing redirects. Upon creation of new redirect, backend assigns an identifier to it, which MUST be unique till the backend's lifetime (e.g. until it's reboot). Then it is returned to frontend as reply, or error can be returned, for example, if backend is low on resources or redirects conflict occured. Redirect deletion specifies an identifier of redirect to delete, which frontend can remember from previous addition or obtain from a list of all currently active redirects. Identifiers are strings opaque to frontend. Basic protocol operation requires only the 3 requests above. As several simultaneous frontends are supported (as well as backend may be only one of clients of the actual redirecting engine), there may be a possibility of races if frontend remebers own redirections - they could be removed by someone else at any time, or new redirects can be added without frontend knowing it. Thus in simple mode with only 3 commands, frontend should periodically refresh list. This protocol handles only TCP and UDP protocols port redirections. Any given redirection can be viewed as 7-tuple of protocol (TCP or UDP), IP address and port on the client machine in the private network ("local" address and port), IP address and port of an intermidiate machine ("public" address and port) and an IP address and port of remote machine from which conection will be originated. One can think that specification of "remote" address/port can be viewed as a security measure limiting connections from specified address (and possibly port), but it is not the only case. Backend can also be used to pass connections from private network to Internet (e.g. normal operation of SOCKS proxy), in which case "local" address is actually in the Internet and "remote" machine is in the local network (somewhat reverse). Only local address, port and public port are absolutely needed to create redirection. One can choose to not care about remote address/port (allowing connections from everyone) or about public IP address, allowing backend to open port on all of backend's IP addresses (if it has multiple one) or one it choose (randomly or configured default, this is left to implementor and system administrator). If the address is not cared of, it MUST be specified as 0.0.0.0, if port is not cared, it MUST be specified as 0. Redirections can be added by several frontends (and possibly manually by system administrator), thus they have "description" field which is passed to/from backend unchanged. Frontends can use this field to store optional info which can be used, for example, to not touch each other redirections or to provide human-readable descriptions. Each backend MUST support description field length of at least 63 characters. Description field is always last, so spaces in it are also preserved and not treated as parameter separators. It should be noted that redirections are distinguished by their unique identifier, not by public port (and address, if several are present). This allows to use backends which can utilize one public port for several local clients, e.g. by using specified remote address/port for different local clients or doing some kind of random selection/load balancing (or such other thing) on the same public port even if public IP, remote IP and remote port all not given. Thus, it is responsibility of frontend to be configured to properly select free ports to have no conflicts, etc. One can argue that with only 3 base commands, race possibility and frontend responsibility to do free port selection all thing is unreliable. However, this is supposed to be cooperation of several processes under a single administrative control, so in worst case problems can be solved by proper configuring frontends and backends, e.g., each frontend can use it's own port range. In best case, where backend has absolute control over the actual redirecting engine, optional extension commands can be used to inform frontends about all changes. For any protocol command backend can return either a success indication or an error report. Syntax for error reply is: ::= "ERROR" SPACE ::= "CMDSYNTAX" | "OPFAILED" | "NOTFOUND" Error reply can be one of the three possible error cases: * CMDSYNTAX for syntax error in request or unsupported command; * OPFAILED when syntax was correct, but backend was unable to satisfy request due to underlying hardware or software failure (e.g. out of resources); * NOTFOUND when syntax was correct, but specified in request unique ID or public IP in addition request was not found in backend's internal tables (e.g. redirection was already deleted by other frontend). 2.3. Base protocol commands. 2.3.1. ADD. This is main request from frontend to backend to add redirection. Syntax is: ::= "ADD" SPACE SPACE SPACE SPACE SPACE SPACE SPACE SPACE ::= "tcp" | "udp" ::= ::= ::= ::= ::= ::= ::= Parameters of the ADD command (distintc types of addresses and ports) were discussed in section 2.2. Backend MUST reply with a single-line message indicating either error condition or successful addition of redirect (in the latter case unique identifier of newly created redirection is returned. Syntax of successful reply to ADD command is: ::= "ADDED" SPACE 2.3.2. DELETE. Request to delete redirection which was established earlier. Syntax is: ::= "DELETE" SPACE It takes one parameter: unique ID of redirection obtained via previous ADD or LIST commands. If redirection removal was successful, reply is returned: ::= "DELETED" SPACE Here unique ID is just copied from DELETE request. 2.3.3. LIST. This request allows to get table of all currently active backend's redirections. It consists of the word "LIST" on the line alone without any parameters. Backend replies with zero or more replies, one line for each redirection, followed by a line with the word "ENDLIST" (without parameters), indicating end of list. Syntax for one redirection-specifying line of reply is: ::= "LIST" SPACE SPACE SPACE SPACE SPACE SPACE SPACE SPACE SPACE Meaning of the fields is the same as for ADD and DELETE requests. If list is emty, no error is returned and reply consists of "ENDLIST" line only. 2.4. Optional commands. Backend implementor MAY choose to support one or more optional extension commands to make frontend implementor's life a bit easier. There is a special command to get a list of all supported extensions, which MUST be supported by every backend implementing extensions in addition to 3 base required commands. This is a one-word "CAPABILITIES" request from frontend (no parameters). Simple backend will answer "ERROR CMDSYNTAX" signalling that no extensions are supported. More complicated backend will reply with supported command list with a following syntax: ::= "CAPABILITIES" SPACE { SPACE } So this is just space-separated list of extension commands (base 3 are not included) which backend will accept. These could be either defined in this document commands or vendor-specific extensions. It is implied that backend responding to CAPABILITIES request MUST support at least one extension command (except CAPABILITIES itself), so reply MUST have at least 1 argument. Example reply with all extensions defined in this document: CAPABILITIES LISTID OTHERCHANGED GETIPLIST 2.4.1. LISTID. This is request for showing exactly one line from redirection table instead of returning entire list as with LIST command. Syntax is: ::= "LISTID" SPACE Here unique ID is specified as with DELETE command. If ID was found in table, one-line reply is returned with syntax defined earlier for replies to LIST, but without trailing "ENDLIST" line. If ID was not found, corresponding ERROR is returned. 2.4.2. OTHERCHANGED. This commands indicates that backend has absolute control over the actual underlying redirecting engine and thus is able inform frontend about it's table state changing when it occurs, e.g. after modifying by other frontend. Such notifications, though, MUST be disabled by default, and are enabled by frontend issuing OTHERCHANGED command, without parameters. Backend responds with the following reply: ::= "OTHERCHANGED" SPACE { } Here number in reply is total count of all currently connected frontends to this backend. Once enabled, notifications can't be disabled, ond subsequent OTHERCHANGED commands are useful only for statistical purposes of getting up-to-date number of connected frontends. Notifications, in contrast to other protocol parts, consist of gratuitous messages from backend without any frontend commands, a kind of "reply which is not a reply to a something", so, as mentioned before, they MUST be disabled by default to not confuse frontends which are not prepared to receive a reply without a command. Notifications consist of "OTHERCHANGED" command word with parameters filled with a copy of reply to another frontend which made an actual request, for example, it could be OTHERCHANGED ADDED nat1_id44 or OTHERCHANGED DELETED rF5_xck7 2.4.3. GETIPLIST. This request allows frontend to retrieve list of IP addresses which can be used as "public" in subsequent requests. It consists of the word "GETIPLIST" on the line alone without any parameters. Backend replies with one or more replies, one line for each IP address, followed by a line with the word "ENDIPLIST" (without parameters), indicating end of list. Syntax for one IP address line of reply is: ::= "IPLIST" SPACE [ SPACE SPACE ] ::= { } ::= { } So this will be list of all IP adresses, one per line, available to backend engine. If backend knows interfaces bandwidth, it MAY return this information also for each IP address. Two optional paramters and here specify upload and download bandwidth of corresponfing to that IP interface in bits per second, where "upload" means direction from local addresses to remote ones and "download" - the most used direction from remote addresses to local ones. 3. References. [SOCKS5] Leech, M., Ganis, M., Lee, Y., Kuris, R., Koblas, D., Jones, L., "SOCKS Protocol Version 5", RFC 1928, March 1996. [NATPMP] Cheshire, S., Krochmal, M., Sekar, K., "NAT Port Mapping Protocol (NAT-PMP)", Internet Draft, September 2006,