| <html><head> |
| <title>Generic sockets with Socat</title> |
| <link rel="stylesheet" type="text/css" href="dest-unreach.css"> |
| </head> |
| |
| <body> |
| |
| <h1>Generic sockets with Socat</h1> |
| |
| <h2>Introduction</h2> |
| <p>Beginning with version 1.7.0 socat provides means to freely control |
| important aspects of socket handling. This allows to experiment with socket |
| types and protocols that are not explicitely implemented in socat. |
| </p> |
| |
| <p>The related socat features fall into three major categories:<p> |
| |
| <ul> |
| <li>address options for changing socket parameters while using common |
| socket types: |
| <tt>pf (protocol-family), so-type (socktype), so-prototype (protocol)</tt> |
| </li> |
| <li>address options for setting arbitrary socket options: |
| <tt>setsockopt-int, setsockopt-string, setsockopt-bin</tt></li> |
| <li>address types for passing almost arbitrary parameters and address data to |
| the standard system calls: |
| <tt>socket-connect, socket-listen, socket-sendto, socket-recv, |
| socket-recvfrom, socket-datagram</tt></li> |
| </ul> |
| |
| <p>In practice this gives you two possibilities:</p> |
| |
| <p>If you want to cope with sockets staying within the usual domains ( = |
| protocol families = address families) which are IPv4, IPv6, UNIX/local, and |
| raw interface for socat 1.7.0, it is sufficient to learn about a couple of |
| <a href="#GENERIC_OPTIONS">address options</a> that allow to change default |
| parameters, and to apply generic socket options.</p> |
| |
| <p>For other address families socat provides <a |
| href="#GENERIC_ADDRESSES">generic socket addresses</a>. |
| </p> |
| |
| |
| <a name="GENERIC_OPTIONS"></a> |
| <h2>Generic socket options</h2> |
| |
| <h3>Example 1: DCCP communication</h3> |
| |
| <p>A relatively new communication protocol has been introduced in the Internet |
| community for which no socat address type has been implemented up to version |
| 1.7.0 |
| (see <a href="http://www.ietf.org/html.charters/dccp-charter.html">IETF's |
| Datagram Congestion Control Protocol</a> |
| and <a href="http://www.linuxfoundation.org/en/Net:DCCP#python_support">Linux |
| foundation Net:DCCP</a> for more info). Taken that the |
| operating system implements DCCP, it is possible to use this protocol |
| with socat while just employing standard socket addresses and some options. |
| </p> |
| |
| <p>A simple server that accepts a DCCP connection, passes the arriving data to a |
| subprocess for converting upper case to lower case characters, and then |
| returns it to the client: |
| </p> |
| |
| <span class="shell">socat \ |
| TCP4-LISTEN:4096,reuseaddr,type=6,prototype=33 \ |
| EXEC:'tr A-Z a-z',pty,raw,echo=0 |
| </span> |
| |
| <p>A simple client that sends some upper case characters to the server via DCCP |
| and prints what the server returns: |
| </p> |
| |
| <span class="shell">echo ABCD | \ |
| socat - \ |
| TCP4-CONNECT:localhost:4096,type=6,prototype=33 |
| </span> |
| |
| <p>We choose the TCP4 addresses as base because it best matches the DCCP |
| requirements: |
| <ol> |
| <li>DCCP is (here) based on IPv4</li> |
| <li>DCCP is stream oriented and uses <tt>connect()</tt> and <tt>listen(); |
| accept()</tt> calls</li> |
| <li>DCCP protocol uses ports</li> |
| </ol> |
| </p> |
| |
| <p>Option <tt><a href="socat.html#OPTION_SO_TYPE">type</a>=6</tt> changes TCP's |
| <tt>SOCK_STREAM</tt> parameter to <tt>SOCK_DCCP</tt>, and <tt> |
| <a href="socat.html#OPTION_SO_PROTOTYPE">prototype</a>=33</tt> replaces the |
| default <tt>IPPROTO_TCP</tt> with <tt>IPPROTO_DCCP</tt>. |
| </p> |
| |
| <p>DCCP has an important parameter, the service code. It provides another |
| multiplexing layer beyond the protocol ports. The Linux implementation of DCCP |
| allows to set this parameter with code like <tt>setsocktopt(fd, SOL_DCCP, |
| DCCP_SOCKOPT_SERVICE, {1}, sizeof(int))</tt>. The equivalent generic socat |
| option is: <tt><a href="socat.html#OPTION_SETSOCKOPT_INT">setsockopt-int</a>=269:2:1</tt> for service code 1. |
| If the service codes on server and client do not match the <tt>connect()</tt> |
| operation fails with error:<p> |
| |
| <span class="error">... E connect(3, AF=2 127.0.0.1:4096, 16): Invalid request code</span> |
| |
| <p>Please note that this examples works with IPv6 as well, you just need to |
| replace the TCP4 words with TCP6, and the IPv4 socket address with an |
| appropriate IPv6 socket address, e.g. <tt>[::1]</tt>! |
| </p> |
| |
| <a name="GENERIC_ADDRESSES"></a> |
| <h2>Generic socket addresses</h2> |
| |
| <p>socat's generic socket addresses are a more comprehensive mechanism that |
| allows to deal with protocol families whose socket addresses are not supported |
| by socat - no semantical parsing, no structured assignment to the struct |
| components are available. Instead, the socket address records for binding and |
| connecting/sending are specified in unstructured hexadecimal form. The |
| following example demonstrates this by performing simple data transfer over |
| raw AppleTalk protocol. |
| </p> |
| |
| <p>Note: I do not have any knowledge about AppleTalk. I just managed to |
| configure my Linux host to tolerate the creation of a receiving and a sending |
| socket. Don't blame me nor ask me for support if it does not work for you. |
| </p> |
| |
| <a name="EXAMPLE_APPLETALK"></a> |
| <h3>Enabling AppleTalk protocol</h3> |
| |
| <p>Install the <tt>netatalk</tt> package. Check that <tt>/etc/netatalk/atalkd.conf</tt> |
| has an entry like <tt>eth0 -phase 2 -net 0-65534 -addr 65280.243</tt>. The |
| last part is an arbitrary (?) host address, some of the following values must |
| fit it. Make sure the <tt>atalkd</tt> daemon is running. Run the AppleTalk |
| ping command: |
| </p> |
| |
| <span class="shell">aecho 65280.243 |
| </span> |
| |
| <p>If you get an error like: |
| </p> |
| |
| <span class="error">Device or resource busy</span> |
| |
| <p>then try to restart <tt>atalkd</tt>:</p> |
| |
| <span class="shell">/etc/init.d/atalkd restart |
| </span> |
| |
| <p>When <tt>aecho</tt> works like <tt>ping</tt> you are ready for the next step. |
| </p> |
| |
| <h3>Example 2: AppleTalk datagram communication</h3> |
| |
| <p>We start a socat process with a receiver and echo service: |
| </p> |
| |
| <span class="shell">socat \ |
| SOCKET-RECVFROM:5:2:0:x40x00x0000x00x00x0000000000000000 \ |
| PIPE |
| </span> |
| |
| <p>Then, in another shell on the same host, we start a client socket process |
| that sends data to the server and gets the answer: |
| </p> |
| |
| <span class="shell">echo ABCD | \ |
| socat - \ |
| SOCKET-DATAGRAM:5:2:0:x40x00xff00xf3x00x0000000000000000 |
| </span> |
| |
| <p>The client process should print the data. |
| </p> |
| |
| <p>How did this work? The generic socat address has just used the system call |
| parameters that were provided on command line, without knowing anything about |
| AppleTalk sockets and protocol. The values 5, 2, and 0 are directly used for |
| the <tt>socket()</tt> call: they specify the domain (<tt>PF_APPLETALK=5</tt>), |
| socket type (<tt>SOCK_DGRAM=2</tt>), and no protocol (0) - values for Linux. |
| The long hex strings define the socket addresses. They can only be constructed |
| with knowledge of the underlying structure. In |
| <tt>/usr/include/linux/atalk.h</tt> we find the following declarations: |
| </p> |
| |
| <pre> |
| struct atalk_addr { |
| __be16 s_net; |
| __u8 s_node; |
| }; |
| |
| struct sockaddr_at { |
| sa_family_t sat_family; |
| __u8 sat_port; |
| struct atalk_addr sat_addr; |
| char sat_zero[8]; |
| </pre> |
| |
| <p>After rolling out <tt>atalk_addr</tt> and considering implicit padding by the |
| C programming language we get the following byte map: |
| </p> |
| |
| <table border="1"> |
| <tr><th>component</th><th>offset</th><th>length</th><th>value</th><th>meaning</th></tr> |
| <tr><td>sat_family</td><td>0</td><td>2</td><td>x0005</td><td>address family</td></tr> |
| <tr><td>sat_port</td><td>2</td><td>1</td><td>x40</td><td>port</td></tr> |
| <tr><td>-</td><td>3</td><td>1</td><td>x00</td><td>padding</td></tr> |
| <tr><td>sat_addr.s_net</td><td>4</td><td>2</td><td>xff00</td><td>network address</td></tr> |
| <tr><td>sat_addr.s_node</td><td>6</td><td>1</td><td>xf3</td><td>node address</td></tr> |
| <tr><td>-</td><td>7</td><td>1</td><td>x00</td><td>padding</td></tr> |
| <tr><td>sat_zero</td><td>8</td><td>8</td><td>x0000000000000000</td><td>padding</td></tr> |
| </table> |
| |
| <p>Note that hexadecimal ff00 is the same as decimal 65280, and hexadecimal xf3 |
| is the same as decimal 243 - these are the numbers specified in |
| <tt>atalkd.conf</tt>. |
| </p> |
| |
| <p>The address family component must be omitted from the socket address because |
| it is added by socat implicitely. The resulting hexadecimal representation of |
| the target socket address is therefore: |
| </p> |
| <tt>x40x00xff00xf3x00x0000000000000000</tt> |
| |
| <p>The receiver just has to specify the port, so its bind address data is: |
| </p> |
| <tt>x40x00x0000x00x00x0000000000000000</tt> |
| |
| <h2>Parameters for well known socket types</h2> |
| |
| <p>Finding the correct parameters and socket addresses is not always trivial. |
| Therefore this section provides tables with the parameters of common socket |
| types. Some of these types are directly implemented by socat (and other |
| programs). Establishing interoperability between a directly implemented |
| socket and a generic socket might be your first step before entering unknown |
| ground.</p> |
| |
| <h3>Socket parameters</h3> |
| |
| <h4>Table: parameter names for "well known" sockets:</h4> |
| |
| <table border=1> |
| <tr><th>name</th><th>domain</th><th>socktype</th><th>protocol</th><th> </th><th>level</th><th>remark</th></tr> |
| <tr><td>UDP4</td><td>PF_INET</td><td>SOCK_DGRAM</td><td>IPPROTO_UDP</td><td> </td><td>SOL_UDP</td><td></td></tr> |
| <tr><td>UDP6</td><td>PF_INET6</td><td>SOCK_DGRAM</td><td>IPPROTO_UDP</td><td> </td><td>SOL_UDP</td><td></td></tr> |
| <tr><td>raw IPv4</td><td>PF_INET</td><td>SOCK_RAW</td><td>IPPROTO_RAW</td><td> </td><td>SOL_IP</td><td></td></tr> |
| <tr><td>raw IPv6</td><td>PF_INET6</td><td>SOCK_RAW</td><td>IPPROTO_RAW</td><td> </td><td>SOL_IPV6</td><td></td></tr> |
| <tr><td>UNIX</td><td>PF_LOCAL</td><td>SOCK_DGRAM</td><td>0</td><td> </td><td>SOL_SOCKET</td><td> </td></tr> |
| <tr><td>PACKET</td><td>PF_PACKET</td><td>SOCK_RAW</td><td>768</td><td></td><td>SOL_PACKET</td><td>tcpdump (include layer 2 header)</td></tr> |
| <tr><td>PACKET</td><td>PF_PACKET</td><td>SOCK_DGRAM</td><td>768</td><td></td><td>SOL_PACKET</td><td>no level 2 header</td></tr> |
| <tr><td>SCTP4</td><td>PF_INET</td><td>SOCK_SEQPACKET</td><td>IPPROTO_SCTP</td><td> </td><td>SOL_SCTP</td><td> </td></tr> |
| </table> |
| |
| <h4>Table: parameter values:</h4> |
| |
| <table border=1> |
| <tr><th>name</th><th>Linux</th><th>FreeBSD</th><th>NetBSD</th><th>OpenBSD</th><th>Solaris</th><th>AIX</th><th>Cygwin</th><th>Mac OS X</th><th>HP-UX</th></tr> |
| <tr><td>PF_LOCAL</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td><td>1</td></tr> |
| <tr><td>PF_INET</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td><td>2</td></tr> |
| <tr><td>PF_APPLETALK</td><td>5</td><td>16</td><td>16</td><td>16</td><td>16</td><td>16</td><td>16</td><td>16</td><td>16</td></tr> |
| <tr><td>PF_INET6</td><td>10</td><td>28</td><td>24</td><td>24</td><td>26</td><td>24</td><td>-</td><td>30</td><td>22</td></tr> |
| <tr><td>PF_PACKET</td><td>17</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr> |
| <tr><td>SOCK_STREAM</td><td>1</td><td>1</td><td>1</td><td>1</td><td>2</td><td>1</td><td>1</td><td>1</td><td>1</td></tr> |
| <tr><td>SOCK_DGRAM</td><td>2</td><td>2</td><td>2</td><td>2</td><td>1</td><td>2</td><td>2</td><td>2</td><td>2</td></tr> |
| <tr><td>SOCK_RAW</td><td>3</td><td>3</td><td>3</td><td>3</td><td>4</td><td>3</td><td>3</td><td>3</td><td>3</td></tr> |
| <tr><td>SOCK_SEQPACKET</td><td>5</td><td>5</td><td>5</td><td>5</td><td>6</td><td>5</td><td>5</td><td>5</td><td>5</td></tr> |
| <tr><td>SOCK_DCCP</td><td>(6)</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr> |
| <tr><td>SOCK_PACKET</td><td>10</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr> |
| <tr><td>IPPROTO_IP</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr> |
| <tr><td>IPPROTO_TCP</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td></tr> |
| <tr><td>IPPROTO_UDP</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td><td>17</td></tr> |
| <tr><td>IPPROTO_DCCP</td><td>33</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr> |
| <tr><td>IPPROTO_SCTP</td><td>132</td><td>132</td><td>-</td><td>-</td><td>132</td><td>132</td><td>-</td><td>-</td><td>-</td></tr> |
| <tr><td>IPPROTO_RAW</td><td>255</td><td>255</td><td>255</td><td>255</td><td>255</td><td>-</td><td>-</td><td>-</td><td>-</td></tr> |
| <tr><td>SOL_SOCKET</td><td>1</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td><td>65535</td></tr> |
| <tr><td>SOL_IP</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr> |
| <tr><td>SOL_TCP</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td><td>6</td></tr> |
| <tr><td>SOL_UDP</td><td>17</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>17</td><td>-</td><td>-</td></tr> |
| <tr><td>SOL_IPV6</td><td>41</td><td>41</td><td>41</td><td>41</td><td>41</td><td>41</td><td>-</td><td>41</td><td>41</td></tr> |
| <tr><td>SOL_PACKET</td><td>263</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr> |
| <tr><td>SOL_DCCP</td><td>269</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr> |
| </table> |
| |
| |
| <h3>Socket address specifications</h3> |
| |
| <p>These hexadecimal data define socket addresses for local and remote sockets, |
| and for bind and range options. The basis is the <tt>struct sockaddr_*</tt> for |
| the respective address family that should be declared in the C include files. |
| Please keep in mind that their first two bytes (<tt>sa_family</tt> and - on BSD |
| - <tt>sa_len</tt>) are implicitely prepended by socat.</p> |
| |
| <h4>Linux on 32bit Intel:</h4> |
| |
| <table border=1> |
| <tr><th>name</th><th>socket address type (without leading address family)</th><th>binary specification</th></tr> |
| <tr><td>IPv4</td><td>2 bytes port, 4 bytes IPv4 addr, 8 bytes 0</td><td>x0016 |
| x7f000001 x0000000000000000</td></tr> |
| <tr><td>IPv6</td><td>2 bytes port, 4 bytes flowinfo, 16 bytes IPv6 addr, 4 bytes scope-id</td><td>x0016 x00000000 x0102030405060708090a0b0c0d0e0f x00000000</td></tr> |
| <tr><td>UNIX</td><td>variable length path name, 0 terminated</td><td>x2f746d702f736f636b00</td></tr> |
| <tr><td>PACKET</td><td>2 bytes protocol (0x0003), interface index as int in host byte order, 8 bytes 0</td><td>x0003 x02000000 x0000000000000000</td></tr> |
| </table> |
| |
| <p>For AppleTalk see above <a href="#EXAMPLE_APPLETALK">example</a>.</p> |
| |
| <h4>Solaris on 32bit Intel:</h4> |
| |
| <table border=1> |
| <tr><th>name</th><th>socket address type (without leading address family)</th><th>binary specification</th></tr> |
| <tr><td>IPv6</td><td>2 bytes port, 4 bytes flowinfo, 16 bytes IPv6 addr, 4 |
| bytes scope-id, 4 bytes src-id</td><td>x0016 x00000000 x0102030405060708090a0b0c0d0e0f x00000000 x00000000</td></tr> |
| </table> |
| |
| <h3>Forever - play on...</h3> |
| |
| <p>Eager to experiment with exotic socket types? Run nmap's protocol scan and |
| see what is available on your system: |
| </p> |
| |
| <span class="shell">nmap -sO localhost |
| </span> |
| |
| <p> |
| <small>Copyright: Gerhard Rieger 2008</small><br> |
| <small>License: <a href="http://www.fsf.org/licensing/licenses/fdl.html">GNU Free Documentation License (FDL)</a></small> |
| </p> |
| |
| </body> |
| </html> |